// SPDX-License-Identifier: GPL-3.0-or-later// Deployed with donations via Gitcoin GR9pragmasolidity 0.7.6;interfaceIWETH{
functiondeposit() externalpayable;
functiontransfer(address to, uint256 value) externalreturns (bool);
functionwithdraw(uint256) external;
}
Contract Source Code
File 10 of 16: Math.sol
// SPDX-License-Identifier: GPL-3.0-or-later// Deployed with donations via Gitcoin GR9pragmasolidity 0.7.6;// a library for performing various math operationslibraryMath{
functionmin(uint256 x, uint256 y) internalpurereturns (uint256 z) {
z = x < y ? x : y;
}
functionmax(uint256 x, uint256 y) internalpurereturns (uint256 z) {
z = x > y ? x : y;
}
// babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)functionsqrt(uint256 y) internalpurereturns (uint256 z) {
if (y >3) {
z = y;
uint256 x = y /2+1;
while (x < z) {
z = x;
x = (y / x + x) /2;
}
} elseif (y !=0) {
z =1;
}
}
}
Contract Source Code
File 11 of 16: Orders.sol
// SPDX-License-Identifier: GPL-3.0-or-later// Deployed with donations via Gitcoin GR9pragmasolidity 0.7.6;pragmaabicoderv2;import'./SafeMath.sol';
import'../libraries/Math.sol';
import'../interfaces/ITwapFactory.sol';
import'../interfaces/ITwapPair.sol';
import'../interfaces/ITwapOracle.sol';
import'../libraries/TokenShares.sol';
libraryOrders{
usingSafeMathforuint256;
usingTokenSharesforTokenShares.Data;
usingTransferHelperforaddress;
enumOrderType {
Empty,
Deposit,
Withdraw,
Sell,
Buy
}
enumOrderStatus {
NonExistent,
EnqueuedWaiting,
EnqueuedReady,
ExecutedSucceeded,
ExecutedFailed,
Canceled
}
eventMaxGasLimitSet(uint256 maxGasLimit);
eventGasPriceInertiaSet(uint256 gasPriceInertia);
eventMaxGasPriceImpactSet(uint256 maxGasPriceImpact);
eventTransferGasCostSet(address token, uint256 gasCost);
eventDepositEnqueued(uint256indexed orderId, Order order);
eventWithdrawEnqueued(uint256indexed orderId, Order order);
eventSellEnqueued(uint256indexed orderId, Order order);
eventBuyEnqueued(uint256indexed orderId, Order order);
eventOrderDisabled(address pair, Orders.OrderType orderType, bool disabled);
eventRefundFailed(addressindexed to, addressindexed token, uint256 amount, bytes data);
uint256publicconstant DEPOSIT_TYPE =1;
uint256publicconstant WITHDRAW_TYPE =2;
uint256publicconstant BUY_TYPE =3;
uint256publicconstant BUY_INVERTED_TYPE =4;
uint256publicconstant SELL_TYPE =5;
uint256publicconstant SELL_INVERTED_TYPE =6;
// Note on gas estimation for the full order execution in the UI:// Add (ORDER_BASE_COST + token transfer costs) to the actual gas usage// of the TwapDelay._execute* functions when updating gas cost in the UI.// Remember that ETH unwrap is part of those functions. It is optional,// but also needs to be included in the estimate.uint256privateconstant ETHER_TRANSFER_COST = ETHER_TRANSFER_CALL_COST +2600+1504; // Std cost + EIP-2929 acct access cost + Gnosis Safe receive ETH costuint256privateconstant BOT_ETHER_TRANSFER_COST =10_000;
uint256privateconstant BUFFER_COST =10_000;
uint256privateconstant ORDER_EXECUTED_EVENT_COST =3700;
uint256privateconstant EXECUTE_PREPARATION_COST =30_000; // dequeue + gas calculation before calls to _execute* functionsuint256publicconstant ETHER_TRANSFER_CALL_COST =10_000;
uint256publicconstant PAIR_TRANSFER_COST =55_000;
uint256publicconstant REFUND_BASE_COST =
BOT_ETHER_TRANSFER_COST + ETHER_TRANSFER_COST + BUFFER_COST + ORDER_EXECUTED_EVENT_COST;
uint256publicconstant ORDER_BASE_COST = EXECUTE_PREPARATION_COST + REFUND_BASE_COST;
// Masks used for setting order disabled// Different bits represent different order typesuint8privateconstant DEPOSIT_MASK =uint8(1<<uint8(OrderType.Deposit)); // 00000010uint8privateconstant WITHDRAW_MASK =uint8(1<<uint8(OrderType.Withdraw)); // 00000100uint8privateconstant SELL_MASK =uint8(1<<uint8(OrderType.Sell)); // 00001000uint8privateconstant BUY_MASK =uint8(1<<uint8(OrderType.Buy)); // 00010000structData {
uint256 delay;
uint256 newestOrderId;
uint256 lastProcessedOrderId;
mapping(uint256=>bytes32) orderQueue;
address factory;
uint256 maxGasLimit;
uint256 gasPrice;
uint256 gasPriceInertia;
uint256 maxGasPriceImpact;
mapping(address=>uint256) transferGasCosts;
mapping(uint256=>bool) canceled;
// Bit on specific positions indicates whether order type is disabled (1) or enabled (0) on specific pairmapping(address=>uint8) orderDisabled;
mapping(uint256=>bool) refundFailed;
}
structOrder {
uint256 orderId;
uint256 orderType;
uint256 validAfterTimestamp;
bool unwrap;
uint256 timestamp;
uint256 gasLimit;
uint256 gasPrice;
uint256 liquidity;
uint256 value0; // Deposit: share0, Withdraw: amount0Min, Sell: shareIn, Buy: shareInMaxuint256 value1; // Deposit: share1, Withdraw: amount1Min, Sell: amountOutMin, Buy: amountOutaddress token0; // Sell: tokenIn, Buy: tokenInaddress token1; // Sell: tokenOut, Buy: tokenOutaddress to;
uint256 minSwapPrice;
uint256 maxSwapPrice;
bool swap;
uint256 priceAccumulator;
uint256 amountLimit0;
uint256 amountLimit1;
}
functiongetOrderStatus(
Data storage data,
uint256 orderId,
uint256 validAfterTimestamp
) internalviewreturns (OrderStatus) {
if (orderId > data.newestOrderId) {
return OrderStatus.NonExistent;
}
if (data.canceled[orderId]) {
return OrderStatus.Canceled;
}
if (data.refundFailed[orderId]) {
return OrderStatus.ExecutedFailed;
}
if (data.orderQueue[orderId] ==bytes32(0)) {
return OrderStatus.ExecutedSucceeded;
}
if (validAfterTimestamp >=block.timestamp) {
return OrderStatus.EnqueuedWaiting;
}
return OrderStatus.EnqueuedReady;
}
functiongetPair(
Data storage data,
address tokenA,
address tokenB
) internalviewreturns (address pair, bool inverted) {
pair = ITwapFactory(data.factory).getPair(tokenA, tokenB);
require(pair !=address(0), 'OS17');
inverted = tokenA > tokenB;
}
functiongetDepositDisabled(Data storage data, address pair) internalviewreturns (bool) {
return data.orderDisabled[pair] & DEPOSIT_MASK !=0;
}
functiongetWithdrawDisabled(Data storage data, address pair) internalviewreturns (bool) {
return data.orderDisabled[pair] & WITHDRAW_MASK !=0;
}
functiongetSellDisabled(Data storage data, address pair) internalviewreturns (bool) {
return data.orderDisabled[pair] & SELL_MASK !=0;
}
functiongetBuyDisabled(Data storage data, address pair) internalviewreturns (bool) {
return data.orderDisabled[pair] & BUY_MASK !=0;
}
functionsetOrderDisabled(
Data storage data,
address pair,
Orders.OrderType orderType,
bool disabled
) external{
require(orderType != Orders.OrderType.Empty, 'OS32');
uint8 currentSettings = data.orderDisabled[pair];
// zeros with 1 bit set at position specified by orderTypeuint8 mask =uint8(1<<uint8(orderType));
// set/unset a bit accordingly to 'disabled' valueif (disabled) {
// OR operation to disable order// e.g. for disable DEPOSIT// currentSettings = 00010100 (BUY and WITHDRAW disabled)// mask for DEPOSIT = 00000010// the result of OR = 00010110
currentSettings = currentSettings | mask;
} else {
// AND operation with a mask negation to enable order// e.g. for enable DEPOSIT// currentSettings = 00010100 (BUY and WITHDRAW disabled)// 0xff = 11111111// mask for Deposit = 00000010// mask negation = 11111101// the result of AND = 00010100
currentSettings = currentSettings & (mask ^0xff);
}
require(currentSettings != data.orderDisabled[pair], 'OS01');
data.orderDisabled[pair] = currentSettings;
emit OrderDisabled(pair, orderType, disabled);
}
functionmarkRefundFailed(Data storage data) internal{
data.refundFailed[data.lastProcessedOrderId] =true;
}
/// @dev The passed in order.oderId is ignored and overwritten with the correct value, i.e. an updated data.newestOrderId./// This is done to ensure atomicity of these two actions while optimizing gas usage - adding an order to the queue and incrementing/// data.newestOrderId (which should not be done anywhere else in the contract)./// Must only be called on verified orders.functionenqueueOrder(Data storage data, Order memory order) internal{
order.orderId =++data.newestOrderId;
data.orderQueue[order.orderId] = getOrderDigest(order);
}
structDepositParams {
address token0;
address token1;
uint256 amount0;
uint256 amount1;
uint256 minSwapPrice;
uint256 maxSwapPrice;
bool wrap;
bool swap;
address to;
uint256 gasLimit;
uint32 submitDeadline;
}
functiondeposit(
Data storage data,
DepositParams calldata depositParams,
TokenShares.Data storage tokenShares
) external{
{
// scope for checks, avoids stack too deep errorsuint256 token0TransferCost = data.transferGasCosts[depositParams.token0];
uint256 token1TransferCost = data.transferGasCosts[depositParams.token1];
require(token0TransferCost !=0&& token1TransferCost !=0, 'OS0F');
checkOrderParams(
data,
depositParams.to,
depositParams.gasLimit,
depositParams.submitDeadline,
ORDER_BASE_COST.add(token0TransferCost).add(token1TransferCost)
);
}
require(depositParams.amount0 !=0|| depositParams.amount1 !=0, 'OS25');
(address pairAddress, bool inverted) = getPair(data, depositParams.token0, depositParams.token1);
require(!getDepositDisabled(data, pairAddress), 'OS46');
{
// scope for value, avoids stack too deep errorsuint256 value =msg.value;
// allocate gas refundif (depositParams.wrap) {
if (depositParams.token0 == tokenShares.weth) {
value =msg.value.sub(depositParams.amount0, 'OS1E');
} elseif (depositParams.token1 == tokenShares.weth) {
value =msg.value.sub(depositParams.amount1, 'OS1E');
}
}
allocateGasRefund(data, value, depositParams.gasLimit);
}
uint256 shares0 = tokenShares.amountToShares(
inverted ? depositParams.token1 : depositParams.token0,
inverted ? depositParams.amount1 : depositParams.amount0,
depositParams.wrap
);
uint256 shares1 = tokenShares.amountToShares(
inverted ? depositParams.token0 : depositParams.token1,
inverted ? depositParams.amount0 : depositParams.amount1,
depositParams.wrap
);
(uint256 priceAccumulator, uint256 timestamp) = ITwapOracle(ITwapPair(pairAddress).oracle()).getPriceInfo();
Order memory order = Order(
0,
DEPOSIT_TYPE,
timestamp + data.delay, // validAfterTimestamp
depositParams.wrap,
timestamp,
depositParams.gasLimit,
data.gasPrice,
0, // liquidity
shares0,
shares1,
inverted ? depositParams.token1 : depositParams.token0,
inverted ? depositParams.token0 : depositParams.token1,
depositParams.to,
depositParams.minSwapPrice,
depositParams.maxSwapPrice,
depositParams.swap,
priceAccumulator,
inverted ? depositParams.amount1 : depositParams.amount0,
inverted ? depositParams.amount0 : depositParams.amount1
);
enqueueOrder(data, order);
emit DepositEnqueued(order.orderId, order);
}
structWithdrawParams {
address token0;
address token1;
uint256 liquidity;
uint256 amount0Min;
uint256 amount1Min;
bool unwrap;
address to;
uint256 gasLimit;
uint32 submitDeadline;
}
functionwithdraw(Data storage data, WithdrawParams calldata withdrawParams) external{
(address pair, bool inverted) = getPair(data, withdrawParams.token0, withdrawParams.token1);
require(!getWithdrawDisabled(data, pair), 'OS0A');
checkOrderParams(
data,
withdrawParams.to,
withdrawParams.gasLimit,
withdrawParams.submitDeadline,
ORDER_BASE_COST.add(PAIR_TRANSFER_COST)
);
require(withdrawParams.liquidity !=0, 'OS22');
allocateGasRefund(data, msg.value, withdrawParams.gasLimit);
pair.safeTransferFrom(msg.sender, address(this), withdrawParams.liquidity);
Order memory order = Order(
0,
WITHDRAW_TYPE,
block.timestamp+ data.delay, // validAfterTimestamp
withdrawParams.unwrap,
0, // timestamp
withdrawParams.gasLimit,
data.gasPrice,
withdrawParams.liquidity,
inverted ? withdrawParams.amount1Min : withdrawParams.amount0Min,
inverted ? withdrawParams.amount0Min : withdrawParams.amount1Min,
inverted ? withdrawParams.token1 : withdrawParams.token0,
inverted ? withdrawParams.token0 : withdrawParams.token1,
withdrawParams.to,
0, // minSwapPrice0, // maxSwapPricefalse, // swap0, // priceAccumulator0, // amountLimit00// amountLimit1
);
enqueueOrder(data, order);
emit WithdrawEnqueued(order.orderId, order);
}
structSellParams {
address tokenIn;
address tokenOut;
uint256 amountIn;
uint256 amountOutMin;
bool wrapUnwrap;
address to;
uint256 gasLimit;
uint32 submitDeadline;
}
functionsell(
Data storage data,
SellParams calldata sellParams,
TokenShares.Data storage tokenShares
) external{
uint256 tokenTransferCost = data.transferGasCosts[sellParams.tokenIn];
require(tokenTransferCost !=0, 'OS0F');
checkOrderParams(
data,
sellParams.to,
sellParams.gasLimit,
sellParams.submitDeadline,
ORDER_BASE_COST.add(tokenTransferCost)
);
(address pairAddress, bool inverted) = sellHelper(data, tokenShares, sellParams);
(uint256 priceAccumulator, uint256 timestamp) = ITwapOracle(ITwapPair(pairAddress).oracle()).getPriceInfo();
uint256 shares = tokenShares.amountToShares(sellParams.tokenIn, sellParams.amountIn, sellParams.wrapUnwrap);
Order memory order = Order(
0,
inverted ? SELL_INVERTED_TYPE : SELL_TYPE,
timestamp + data.delay, // validAfterTimestamp
sellParams.wrapUnwrap,
timestamp,
sellParams.gasLimit,
data.gasPrice,
0, // liquidity
shares,
sellParams.amountOutMin,
sellParams.tokenIn,
sellParams.tokenOut,
sellParams.to,
0, // minSwapPrice0, // maxSwapPricefalse, // swap
priceAccumulator,
sellParams.amountIn,
0// amountLimit1
);
enqueueOrder(data, order);
emit SellEnqueued(order.orderId, order);
}
functionrelayerSell(
Data storage data,
SellParams calldata sellParams,
TokenShares.Data storage tokenShares
) external{
checkOrderParams(data, sellParams.to, sellParams.gasLimit, sellParams.submitDeadline, ORDER_BASE_COST);
(, bool inverted) = sellHelper(data, tokenShares, sellParams);
uint256 shares = tokenShares.amountToSharesWithoutTransfer(
sellParams.tokenIn,
sellParams.amountIn,
sellParams.wrapUnwrap
);
Order memory order = Order(
0,
inverted ? SELL_INVERTED_TYPE : SELL_TYPE,
block.timestamp+ data.delay, // validAfterTimestampfalse, // Never wrap/unwrapblock.timestamp,
sellParams.gasLimit,
data.gasPrice,
0, // liquidity
shares,
sellParams.amountOutMin,
sellParams.tokenIn,
sellParams.tokenOut,
sellParams.to,
0, // minSwapPrice0, // maxSwapPricefalse, // swap0, // priceAccumulator - oracleV3 pairs don't need priceAccumulator
sellParams.amountIn,
0// amountLimit1
);
enqueueOrder(data, order);
emit SellEnqueued(order.orderId, order);
}
functionsellHelper(
Data storage data,
TokenShares.Data storage tokenShares,
SellParams calldata sellParams
) internalreturns (address pairAddress, bool inverted) {
require(sellParams.amountIn !=0, 'OS24');
(pairAddress, inverted) = getPair(data, sellParams.tokenIn, sellParams.tokenOut);
require(!getSellDisabled(data, pairAddress), 'OS13');
// allocate gas refunduint256 value =msg.value;
if (sellParams.wrapUnwrap && sellParams.tokenIn == tokenShares.weth) {
value =msg.value.sub(sellParams.amountIn, 'OS1E');
}
allocateGasRefund(data, value, sellParams.gasLimit);
}
structBuyParams {
address tokenIn;
address tokenOut;
uint256 amountInMax;
uint256 amountOut;
bool wrapUnwrap;
address to;
uint256 gasLimit;
uint32 submitDeadline;
}
functionbuy(
Data storage data,
BuyParams calldata buyParams,
TokenShares.Data storage tokenShares
) external{
uint256 tokenTransferCost = data.transferGasCosts[buyParams.tokenIn];
require(tokenTransferCost !=0, 'OS0F');
checkOrderParams(
data,
buyParams.to,
buyParams.gasLimit,
buyParams.submitDeadline,
ORDER_BASE_COST.add(tokenTransferCost)
);
require(buyParams.amountOut !=0, 'OS23');
(address pairAddress, bool inverted) = getPair(data, buyParams.tokenIn, buyParams.tokenOut);
require(!getBuyDisabled(data, pairAddress), 'OS49');
uint256 value =msg.value;
// allocate gas refundif (buyParams.tokenIn == tokenShares.weth && buyParams.wrapUnwrap) {
value =msg.value.sub(buyParams.amountInMax, 'OS1E');
}
allocateGasRefund(data, value, buyParams.gasLimit);
uint256 shares = tokenShares.amountToShares(buyParams.tokenIn, buyParams.amountInMax, buyParams.wrapUnwrap);
(uint256 priceAccumulator, uint256 timestamp) = ITwapOracle(ITwapPair(pairAddress).oracle()).getPriceInfo();
Order memory order = Order(
0,
inverted ? BUY_INVERTED_TYPE : BUY_TYPE,
timestamp + data.delay, // validAfterTimestamp
buyParams.wrapUnwrap,
timestamp,
buyParams.gasLimit,
data.gasPrice,
0, // liquidity
shares,
buyParams.amountOut,
buyParams.tokenIn,
buyParams.tokenOut,
buyParams.to,
0, // minSwapPrice0, // maxSwapPricefalse, // swap
priceAccumulator,
buyParams.amountInMax,
0// amountLimit1
);
enqueueOrder(data, order);
emit BuyEnqueued(order.orderId, order);
}
functioncheckOrderParams(
Data storage data,
address to,
uint256 gasLimit,
uint32 submitDeadline,
uint256 minGasLimit
) privateview{
require(submitDeadline >=block.timestamp, 'OS04');
require(gasLimit <= data.maxGasLimit, 'OS3E');
require(gasLimit >= minGasLimit, 'OS3D');
require(to !=address(0), 'OS26');
}
functionallocateGasRefund(
Data storage data,
uint256 value,
uint256 gasLimit
) privatereturns (uint256 futureFee) {
futureFee = data.gasPrice.mul(gasLimit);
require(value >= futureFee, 'OS1E');
if (value > futureFee) {
TransferHelper.safeTransferETH(msg.sender, value.sub(futureFee), data.transferGasCosts[address(0)]);
}
}
functionupdateGasPrice(Data storage data, uint256 gasUsed) external{
uint256 scale = Math.min(gasUsed, data.maxGasPriceImpact);
data.gasPrice = data.gasPrice.mul(data.gasPriceInertia.sub(scale)).add(tx.gasprice.mul(scale)).div(
data.gasPriceInertia
);
}
functionsetMaxGasLimit(Data storage data, uint256 _maxGasLimit) external{
require(_maxGasLimit != data.maxGasLimit, 'OS01');
require(_maxGasLimit <=10000000, 'OS2B');
data.maxGasLimit = _maxGasLimit;
emit MaxGasLimitSet(_maxGasLimit);
}
functionsetGasPriceInertia(Data storage data, uint256 _gasPriceInertia) external{
require(_gasPriceInertia != data.gasPriceInertia, 'OS01');
require(_gasPriceInertia >=1, 'OS35');
data.gasPriceInertia = _gasPriceInertia;
emit GasPriceInertiaSet(_gasPriceInertia);
}
functionsetMaxGasPriceImpact(Data storage data, uint256 _maxGasPriceImpact) external{
require(_maxGasPriceImpact != data.maxGasPriceImpact, 'OS01');
require(_maxGasPriceImpact <= data.gasPriceInertia, 'OS33');
data.maxGasPriceImpact = _maxGasPriceImpact;
emit MaxGasPriceImpactSet(_maxGasPriceImpact);
}
functionsetTransferGasCost(
Data storage data,
address token,
uint256 gasCost
) external{
require(gasCost != data.transferGasCosts[token], 'OS01');
data.transferGasCosts[token] = gasCost;
emit TransferGasCostSet(token, gasCost);
}
functionrefundLiquidity(address pair,
address to,
uint256 liquidity,
bytes4 selector
) internalreturns (bool) {
if (liquidity ==0) {
returntrue;
}
(bool success, bytesmemory data) =address(this).call{ gas: PAIR_TRANSFER_COST }(
abi.encodeWithSelector(selector, pair, to, liquidity, false)
);
if (!success) {
emit RefundFailed(to, pair, liquidity, data);
}
return success;
}
functiondequeueOrder(Data storage data, uint256 orderId) internal{
++data.lastProcessedOrderId;
require(orderId == data.lastProcessedOrderId, 'OS72');
}
functionforgetOrder(Data storage data, uint256 orderId) internal{
delete data.orderQueue[orderId];
}
functionforgetLastProcessedOrder(Data storage data) internal{
delete data.orderQueue[data.lastProcessedOrderId];
}
functiongetOrderDigest(Order memory order) internalpurereturns (bytes32) {
// Used to avoid the 'stack too deep' error.bytesmemory partialOrderData =abi.encodePacked(
order.orderId,
order.orderType,
order.validAfterTimestamp,
order.unwrap,
order.timestamp,
order.gasLimit,
order.gasPrice,
order.liquidity,
order.value0,
order.value1,
order.token0,
order.token1,
order.to,
order.minSwapPrice
);
returnkeccak256(
abi.encodePacked(
partialOrderData,
order.maxSwapPrice,
order.swap,
order.priceAccumulator,
order.amountLimit0,
order.amountLimit1
)
);
}
functionverifyOrder(Data storage data, Order memory order) externalview{
require(getOrderDigest(order) == data.orderQueue[order.orderId], 'OS71');
}
}
Contract Source Code
File 12 of 16: SafeMath.sol
// SPDX-License-Identifier: GPL-3.0-or-later// Deployed with donations via Gitcoin GR9pragmasolidity 0.7.6;// a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math)librarySafeMath{
int256privateconstant _INT256_MIN =-2**255;
functionadd(uint256 x, uint256 y) internalpurereturns (uint256 z) {
require((z = x + y) >= x, 'SM4E');
}
functionsub(uint256 x, uint256 y) internalpurereturns (uint256 z) {
z = sub(x, y, 'SM12');
}
functionsub(uint256 x,
uint256 y,
stringmemory message
) internalpurereturns (uint256 z) {
require((z = x - y) <= x, message);
}
functionmul(uint256 x, uint256 y) internalpurereturns (uint256 z) {
require(y ==0|| (z = x * y) / y == x, 'SM2A');
}
functiondiv(uint256 a, uint256 b) internalpurereturns (uint256) {
require(b >0, 'SM43');
return a / b;
}
functionceil_div(uint256 a, uint256 b) internalpurereturns (uint256 c) {
c = div(a, b);
if (a != mul(b, c)) {
return add(c, 1);
}
}
functiontoUint32(uint256 n) internalpurereturns (uint32) {
require(n <=type(uint32).max, 'SM50');
returnuint32(n);
}
functiontoUint64(uint256 n) internalpurereturns (uint64) {
require(n <=type(uint64).max, 'SM54');
returnuint64(n);
}
functiontoUint112(uint256 n) internalpurereturns (uint112) {
require(n <=type(uint112).max, 'SM51');
returnuint112(n);
}
functiontoInt256(uint256 unsigned) internalpurereturns (int256 signed) {
require(unsigned <=uint256(type(int256).max), 'SM34');
signed =int256(unsigned);
}
// int256functionadd(int256 a, int256 b) internalpurereturns (int256 c) {
c = a + b;
require((b >=0&& c >= a) || (b <0&& c < a), 'SM4D');
}
functionsub(int256 a, int256 b) internalpurereturns (int256 c) {
c = a - b;
require((b >=0&& c <= a) || (b <0&& c > a), 'SM11');
}
functionmul(int256 a, int256 b) internalpurereturns (int256 c) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the// benefit is lost if 'b' is also tested.// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522if (a ==0) {
return0;
}
require(!(a ==-1&& b == _INT256_MIN), 'SM29');
c = a * b;
require(c / a == b, 'SM29');
}
functiondiv(int256 a, int256 b) internalpurereturns (int256) {
require(b !=0, 'SM43');
require(!(b ==-1&& a == _INT256_MIN), 'SM42');
return a / b;
}
functionneg_floor_div(int256 a, int256 b) internalpurereturns (int256 c) {
c = div(a, b);
if ((a <0&& b >0) || (a >=0&& b <0)) {
if (a != mul(b, c)) {
c = sub(c, 1);
}
}
}
}