diff --git a/contracts/collections/pools.ral b/contracts/collections/pools.ral index 5dadfc0..f0bc485 100644 --- a/contracts/collections/pools.ral +++ b/contracts/collections/pools.ral @@ -1,6 +1,7 @@ Contract Pools( poolTemplateContractId: ByteVec, clamm: CLAMM, + uints: Uints, mut invariantId: Address, mut positionsId: Address, mut swapUtilsId: Address, @@ -45,7 +46,9 @@ Contract Pools( lastTimestamp: currentTimestamp, feeReceiver: feeReceiver }, - clamm) + clamm, + uints + ) let _ = copyCreateSubContract!{originalCaller -> ALPH: 1 alph}( poolKey, poolTemplateContractId, diff --git a/contracts/collections/positions.ral b/contracts/collections/positions.ral index 599a7dd..c3f3411 100644 --- a/contracts/collections/positions.ral +++ b/contracts/collections/positions.ral @@ -3,7 +3,8 @@ Contract Positions( positionsCounterContractId: ByteVec, mut invariantId: Address, mut areAdminsSet: Bool, - clammContract: CLAMM + clammContract: CLAMM, + uints: Uints ) { enum PositionsError { NotAdmin = 500 @@ -58,7 +59,8 @@ Contract Positions( owner: originalCaller }, true, - clammContract + clammContract, + uints ) let _ = copyCreateSubContract!{originalCaller -> ALPH: 1 alph}( toByteVec!(length + 1), diff --git a/contracts/math/clamm.ral b/contracts/math/clamm.ral index 3477b41..a91d1f7 100644 --- a/contracts/math/clamm.ral +++ b/contracts/math/clamm.ral @@ -31,9 +31,9 @@ Contract CLAMM(uints: Uints) extends Log() { let amountAfterFee = mul(amount, (one(PercentageScale) - fee), PercentageScale) if (xToY) { - amountIn = getDeltaX(targetSqrtPrice, currentSqrtPrice, liquidity, true) + amountIn = uints.unwrapU256(getDeltaX(targetSqrtPrice, currentSqrtPrice, liquidity, true)) } else { - amountIn = getDeltaY(currentSqrtPrice, targetSqrtPrice, liquidity, true) + amountIn = uints.unwrapU256(getDeltaY(currentSqrtPrice, targetSqrtPrice, liquidity, true)) } if (amountAfterFee >= amountIn) { @@ -43,9 +43,9 @@ Contract CLAMM(uints: Uints) extends Log() { } } else { if (xToY) { - amountOut = getDeltaY(targetSqrtPrice, currentSqrtPrice, liquidity, false) + amountOut = uints.unwrapU256(getDeltaY(targetSqrtPrice, currentSqrtPrice, liquidity, false)) } else { - amountOut = getDeltaX(currentSqrtPrice, targetSqrtPrice, liquidity, false) + amountOut = uints.unwrapU256(getDeltaX(currentSqrtPrice, targetSqrtPrice, liquidity, false)) } if (amount >= amountOut) { @@ -59,17 +59,17 @@ Contract CLAMM(uints: Uints) extends Log() { if (xToY) { if (notMax || !byAmountIn) { - amountIn = getDeltaX(nextSqrtPrice, currentSqrtPrice, liquidity, true) + amountIn = uints.unwrapU256(getDeltaX(nextSqrtPrice, currentSqrtPrice, liquidity, true)) } if (notMax || byAmountIn) { - amountOut = getDeltaY(nextSqrtPrice, currentSqrtPrice, liquidity, false) + amountOut = uints.unwrapU256(getDeltaY(nextSqrtPrice, currentSqrtPrice, liquidity, false)) } } else { if (notMax|| !byAmountIn) { - amountIn = getDeltaY(currentSqrtPrice, nextSqrtPrice, liquidity, true) + amountIn = uints.unwrapU256(getDeltaY(currentSqrtPrice, nextSqrtPrice, liquidity, true)) } if (notMax || byAmountIn) { - amountOut = getDeltaX(currentSqrtPrice, nextSqrtPrice, liquidity, false) + amountOut = uints.unwrapU256(getDeltaX(currentSqrtPrice, nextSqrtPrice, liquidity, false)) } } @@ -98,7 +98,7 @@ Contract CLAMM(uints: Uints) extends Log() { sqrtPriceB: U256, liquidity: U256, roundingUp: Bool - ) -> U256 { + ) -> ResultU256 { let mut deltaSqrtPrice = 0u if (sqrtPriceA > sqrtPriceB) { deltaSqrtPrice = sqrtPriceA - sqrtPriceB @@ -106,7 +106,12 @@ Contract CLAMM(uints: Uints) extends Log() { deltaSqrtPrice = sqrtPriceB - sqrtPriceA } - let nominator = uints.bigMulDiv256(deltaSqrtPrice, liquidity, one(LiquidityScale)) + let wrappedResult = uints.bigMulDiv256(deltaSqrtPrice, liquidity, one(LiquidityScale)) + if (wrappedResult.error != 0) { + return ResultU256 { value: u256Max!(), error: wrappedResult.error } + } + let nominator = uints.unwrapU512(wrappedResult) + if (roundingUp) { let denominator = mul(sqrtPriceA, sqrtPriceB, SqrtPriceScale) return uints.bigDivToTokenUp(nominator, denominator, one(SqrtPriceScale)) @@ -121,7 +126,7 @@ Contract CLAMM(uints: Uints) extends Log() { sqrtPriceB: U256, liquidity: U256, roundingUp: Bool - ) -> U256 { + ) -> ResultU256 { let mut deltaSqrtPrice = 0u if (sqrtPriceA > sqrtPriceB) { deltaSqrtPrice = sqrtPriceA - sqrtPriceB @@ -129,16 +134,43 @@ Contract CLAMM(uints: Uints) extends Log() { deltaSqrtPrice = sqrtPriceB - sqrtPriceA } + let mut wrappedResult = ResultU512 { value: U512 { higher: 0, lower: 0 }, error: 0} + let u256Max = u256Max!() let mut result = U512 { lower: 0, higher: 0 } if (roundingUp) { - result = uints.bigMulDiv256(deltaSqrtPrice, liquidity, one(LiquidityScale)) - result = uints.bigAdd512(result, uints.toU512(almostOne(SqrtPriceScale))) - result = uints.bigDiv512(result, one(SqrtPriceScale), 1) + wrappedResult = uints.bigMulDiv256(deltaSqrtPrice, liquidity, one(LiquidityScale)) + if (wrappedResult.error != 0) { + return ResultU256 { value: u256Max, error: wrappedResult.error } + } + result = uints.unwrapU512(wrappedResult) + + wrappedResult = uints.bigAdd512(result, uints.toU512(almostOne(SqrtPriceScale))) + if (wrappedResult.error != 0) { + return ResultU256 { value: u256Max, error: wrappedResult.error } + } + result = uints.unwrapU512(wrappedResult) + + wrappedResult = uints.bigDiv(result, one(SqrtPriceScale), 1) + if (wrappedResult.error != 0) { + return ResultU256 { value: u256Max, error: wrappedResult.error } + } + result = uints.unwrapU512(wrappedResult) + return uints.toU256(result) } else { - result = uints.bigMulDiv256(deltaSqrtPrice, liquidity, one(LiquidityScale)) - result = uints.bigDiv512(result, one(SqrtPriceScale), 1) + wrappedResult = uints.bigMulDiv256(deltaSqrtPrice, liquidity, one(LiquidityScale)) + if (wrappedResult.error != 0) { + return ResultU256 { value: u256Max, error: wrappedResult.error } + } + result = uints.unwrapU512(wrappedResult) + + wrappedResult = uints.bigDiv(result, one(SqrtPriceScale), 1) + if (wrappedResult.error != 0) { + return ResultU256 { value: u256Max, error: wrappedResult.error } + } + result = uints.unwrapU512(wrappedResult) + return uints.toU256(result) } } @@ -226,33 +258,33 @@ Contract CLAMM(uints: Uints) extends Log() { let mut updateLiquidity = false if (currentTickIndex < lowerTick) { - amountX = getDeltaX( + amountX = uints.unwrapU256(getDeltaX( sqrtPriceFromTick(lowerTick), sqrtPriceFromTick(upperTick), liquidityDelta, liquiditySign - ) + )) } else if (currentTickIndex < upperTick) { - amountX = getDeltaX( + amountX = uints.unwrapU256(getDeltaX( currentSqrtPrice, sqrtPriceFromTick(upperTick), liquidityDelta, liquiditySign - ) - amountY = getDeltaY( + )) + amountY = uints.unwrapU256(getDeltaY( sqrtPriceFromTick(lowerTick), currentSqrtPrice, liquidityDelta, liquiditySign - ) + )) updateLiquidity = true } else { - amountY = getDeltaY( + amountY = uints.unwrapU256(getDeltaY( sqrtPriceFromTick(lowerTick), sqrtPriceFromTick(upperTick), liquidityDelta, liquiditySign - ) + )) } return amountX, amountY, updateLiquidity @@ -331,13 +363,23 @@ Contract CLAMM(uints: Uints) extends Log() { return true } - pub fn toFee(feeGrowth: U256, liquidity: U256) -> U256 { - let fee = uints.bigMulDiv256(feeGrowth, liquidity, one(FeeGrowthScale + LiquidityScale)) + pub fn toFee(feeGrowth: U256, liquidity: U256) -> ResultU256 { + let wrappedResult = uints.bigMulDiv256(feeGrowth, liquidity, one(FeeGrowthScale + LiquidityScale)) + if (wrappedResult.error != 0) { + return ResultU256 { value: u256Max!(), error: wrappedResult.error } + } + let fee = uints.unwrapU512(wrappedResult) + return uints.toU256(fee) } - pub fn feeGrowthFromFee(liquidity: U256, fee: U256) -> U256 { - let feeGrowth = uints.bigMulDiv256(fee, one(LiquidityScale + FeeGrowthScale), liquidity) + pub fn feeGrowthFromFee(liquidity: U256, fee: U256) -> ResultU256 { + let wrappedResult = uints.bigMulDiv256(fee, one(LiquidityScale + FeeGrowthScale), liquidity) + if (wrappedResult.error != 0) { + return ResultU256 { value: u256Max!(), error: wrappedResult.error } + } + let feeGrowth = uints.unwrapU512(wrappedResult) + return uints.toU256(feeGrowth) } } \ No newline at end of file diff --git a/contracts/math/uints.ral b/contracts/math/uints.ral index 356e47e..1e19d7b 100644 --- a/contracts/math/uints.ral +++ b/contracts/math/uints.ral @@ -1,64 +1,99 @@ -struct Result { - mut value: U512, - mut error: Bool -} - struct U512 { mut higher: U256, mut lower: U256 } +struct ResultU256 { + mut value: U256, + mut error: U256 +} + +struct ResultU512 { + mut value: U512, + mut error: U256 +} + Contract Uints () { const MaxU256 = 115792089237316195423570985008687907853269984665640564039457584007913129639935 - enum ArithmeticErrors { + enum ArithmeticError { CastOverflow = 100001 - NotPositiveDivisor = 100002 + AddOverflow = 100002 + MulOverflow = 100003 + DivNotPositiveDivisor = 100004 + DivNotPositiveDenominator = 100005 + MulNotPositiveDenominator = 100006 + } + + pub fn unwrapU256(result: ResultU256) -> U256 { + assert!(result.error == 0, result.error) + return result.value + } + + pub fn unwrapU512(result: ResultU512) -> U512 { + assert!(result.error == 0, result.error) + return result.value } - pub fn toU512(v: U256) -> U512 { + pub fn toU512(value: U256) -> U512 { return U512 { higher: 0, - lower: v + lower: value } } - pub fn toU256(v: U512) -> U256 { - assert!(v.higher == 0, ArithmeticErrors.CastOverflow) - return v.lower + pub fn toU256(value: U512) -> ResultU256 { + if(value.higher > 0) { + return ResultU256 { value: MaxU256, error: ArithmeticError.CastOverflow } + } + + return ResultU256 { value: value.lower, error: 0 } } pub fn bigAdd256(a: U256, b: U256) -> U512 { - if (MaxU256 - a < b) { - return U512 { - higher: 1, - lower: (b - (MaxU256 - a)) - 1 - } - } else { - return U512 { - higher: 0, - lower: a + b - } + let (lower, overflow) = overflowingAdd(a, b) + + if(overflow == 1) { + return U512 { higher: 1, lower: lower } } + + return U512 { higher: 0, lower: lower } } - pub fn bigAdd(a: U512, b: U256) -> U512 { - let (lower, overflow) = overflowingAdd(a.lower, b) - let higher = wrappingAdd(a.higher, overflow) - return U512 { lower: lower, higher: higher } + pub fn bigAdd(a: U512, b: U256) -> ResultU512 { + let (lower, lowerOverflow) = overflowingAdd(a.lower, b) + let (higher, higherOverflow) = overflowingAdd(a.higher, lowerOverflow) + + if(higherOverflow == 1) { + return ResultU512 { value: U512 { higher: MaxU256, lower: MaxU256 }, error: ArithmeticError.AddOverflow } + } + + return ResultU512 { value: U512 { higher: higher, lower: lower }, error: 0 } } - pub fn bigAdd512(a: U512, b: U512) -> U512 { - let (aLowerB, overflow) = overflowingAdd(a.lower, b.lower) - let aHigherOverflow = wrappingAdd(wrappingAdd(a.higher, b.higher), overflow) - return U512 { lower: aLowerB, higher: aHigherOverflow } + pub fn bigAdd512(a: U512, b: U512) -> ResultU512 { + let (lower, lowerOverflow) = overflowingAdd(a.lower, b.lower) + let (higherIntermediate, higherIntermediateOverflow) = overflowingAdd(a.higher, b.higher) + let (higher, higherOverflow) = overflowingAdd(higherIntermediate, lowerOverflow) + + if(higherIntermediateOverflow == 1 || higherOverflow == 1) { + return ResultU512 { value: U512 { higher: MaxU256, lower: MaxU256 }, error: ArithmeticError.AddOverflow } + } + + return ResultU512 { value: U512 { higher: higher, lower: lower }, error: 0 } } - pub fn bigDivWrapper(a: U512, b: U256, bDenominator: U256, up: Bool) -> U512 { - assert!(b > 0, ArithmeticErrors.NotPositiveDivisor) + pub fn bigDivWrapper(a: U512, b: U256, bDenominator: U256, up: Bool) -> ResultU512 { + if(b == 0) { + return ResultU512 { value: U512 { higher: MaxU256, lower: MaxU256 }, error: ArithmeticError.DivNotPositiveDivisor } + } + + if(bDenominator == 0) { + return ResultU512 { value: U512 { higher: MaxU256, lower: MaxU256 }, error: ArithmeticError.DivNotPositiveDenominator } + } if (b == 1) { - return a + return ResultU512 { value: a, error: 0 } } // Calculate new higher @@ -82,25 +117,17 @@ Contract Uints () { } } - return U512 { - higher: higher, - lower: deltaLower - } + return ResultU512 { value: U512 { higher: higher, lower: deltaLower }, error: 0 } } - pub fn bigDiv512(a: U512, b: U256, bDenominator: U256) -> U512 { + pub fn bigDiv(a: U512, b: U256, bDenominator: U256) -> ResultU512 { return bigDivWrapper(a, b, bDenominator, false) } - pub fn bigDivUp512(a: U512, b: U256, bDenominator: U256) -> U512 { + pub fn bigDivUp(a: U512, b: U256, bDenominator: U256) -> ResultU512 { return bigDivWrapper(a, b, bDenominator, true) } - pub fn bigMul512(a: U512, b: U256) -> U512 { - let result = bigMul256(a.lower, b) - return bigAdd512(result, U512 { higher: a.higher * b, lower: 0 }) - } - pub fn bigMul256(a: U256, b: U256) -> U512 { let aLower = low128(a) let aHigher = high128(a) @@ -122,36 +149,62 @@ Contract Uints () { return U512 { higher: higher, lower: lower } } - pub fn bigMulDiv256(a: U256, b: U256, bDenominator: U256) -> U512 { - let mut result = bigMul256(a, b) + pub fn bigMul(a: U512, b: U256) -> ResultU512 { + let result = bigMul256(a.lower, b) + let higher = toU256(bigMul256(a.higher, b)) + + if(higher.error != 0) { + return ResultU512 { value: U512 { higher: MaxU256, lower: MaxU256 }, error: ArithmeticError.MulOverflow } + } + + return bigAdd512(result, U512 { higher: higher.value, lower: 0 }) + } + + pub fn bigMulDiv256(a: U256, b: U256, bDenominator: U256) -> ResultU512 { + if(bDenominator == 0) { + return ResultU512 { value: U512 { higher: MaxU256, lower: MaxU256 }, error: ArithmeticError.MulNotPositiveDenominator } + } - result = bigDiv512(result, bDenominator, 1) + let mut result = bigMul256(a, b) + result = unwrapU512(bigDiv(result, bDenominator, 1)) - return result + return ResultU512 { value: result, error: 0 } } - pub fn bigMulDivUp256(a: U256, b: U256, bDenominator: U256) -> U512 { + pub fn bigMulDivUp256(a: U256, b: U256, bDenominator: U256) -> ResultU512 { + if(bDenominator == 0) { + return ResultU512 { value: U512 { higher: MaxU256, lower: MaxU256 }, error: ArithmeticError.MulNotPositiveDenominator } + } + let mut result = bigMul256(a, b) - result = bigAdd512(result, toU512(bDenominator - 1)) - result = bigDiv512(result, bDenominator, 1) + result = unwrapU512(bigAdd512(result, toU512(bDenominator - 1))) + result = unwrapU512(bigDiv(result, bDenominator, 1)) - return result + return ResultU512 { value: result, error: 0 } } pub fn overflowingAdd(a: U256, b: U256) -> (U256, U256) { if (MaxU256 - a >= b) { return a + b, 0 + } + + if (a > b) { + return a - (MaxU256 - b) - 1, 1 } else { - return b + (MaxU256 - a) - 1, 1 + return b - (MaxU256 - a) - 1, 1 } } pub fn wrappingAdd(a: U256, b: U256) -> U256 { if (MaxU256 - a >= b) { return a + b + } + + if (a > b) { + return a - (MaxU256 - b) - 1 } else { - return b + (MaxU256 - a) - 1 + return b - (MaxU256 - a) - 1 } } @@ -163,19 +216,59 @@ Contract Uints () { return a >> 128 } - pub fn bigDivToTokenUp(nominator: U512, denominator: U256, sqrtPriceDenominator: U256) -> U256 { - let mut result = bigMul512(nominator, sqrtPriceDenominator) - result = bigAdd(result, denominator - 1) - result = bigDiv512(result, denominator, 1) - result = bigAdd(result, sqrtPriceDenominator - 1) - result = bigDiv512(result, sqrtPriceDenominator, 1) + pub fn bigDivToTokenUp(nominator: U512, denominator: U256, sqrtPriceDenominator: U256) -> ResultU256 { + let mut wrappedResult = bigMul(nominator, sqrtPriceDenominator) + if (wrappedResult.error != 0) { + return ResultU256 { value: u256Max!(), error: wrappedResult.error } + } + let mut result = unwrapU512(wrappedResult) + + wrappedResult = bigAdd(result, denominator - 1) + if (wrappedResult.error != 0) { + return ResultU256 { value: u256Max!(), error: wrappedResult.error } + } + result = unwrapU512(wrappedResult) + + wrappedResult = bigDiv(result, denominator, 1) + if (wrappedResult.error != 0) { + return ResultU256 { value: u256Max!(), error: wrappedResult.error } + } + result = unwrapU512(wrappedResult) + + wrappedResult = bigAdd(result, sqrtPriceDenominator - 1) + if (wrappedResult.error != 0) { + return ResultU256 { value: u256Max!(), error: wrappedResult.error } + } + result = unwrapU512(wrappedResult) + + wrappedResult = bigDiv(result, sqrtPriceDenominator, 1) + if (wrappedResult.error != 0) { + return ResultU256 { value: u256Max!(), error: wrappedResult.error } + } + result = unwrapU512(wrappedResult) + return toU256(result) } - pub fn bigDivToToken(nominator: U512, denominator: U256, sqrtPriceDenominator: U256) -> U256 { - let mut result = bigMul512(nominator, sqrtPriceDenominator) - result = bigDiv512(result, denominator, 1) - result = bigDiv512(result, sqrtPriceDenominator, 1) + pub fn bigDivToToken(nominator: U512, denominator: U256, sqrtPriceDenominator: U256) -> ResultU256 { + let mut wrappedResult = bigMul(nominator, sqrtPriceDenominator) + if (wrappedResult.error != 0) { + return ResultU256 { value: u256Max!(), error: wrappedResult.error } + } + let mut result = unwrapU512(wrappedResult) + + wrappedResult = bigDiv(result, denominator, 1) + if (wrappedResult.error != 0) { + return ResultU256 { value: u256Max!(), error: wrappedResult.error } + } + result = unwrapU512(wrappedResult) + + wrappedResult = bigDiv(result, sqrtPriceDenominator, 1) + if (wrappedResult.error != 0) { + return ResultU256 { value: u256Max!(), error: wrappedResult.error } + } + result = unwrapU512(wrappedResult) + return toU256(result) } } diff --git a/contracts/storage/pool.ral b/contracts/storage/pool.ral index 06f0c77..f65029c 100644 --- a/contracts/storage/pool.ral +++ b/contracts/storage/pool.ral @@ -17,7 +17,8 @@ struct PoolState { Contract Pool( admin: Address, mut pool: PoolState, - clamm: CLAMM + clamm: CLAMM, + uints: Uints ) extends Decimal() { enum PoolError { NotAdmin = 1200 @@ -115,7 +116,7 @@ Contract Pool( return } - let feeGrowth = clamm.feeGrowthFromFee(pool.liquidity, poolFee) + let feeGrowth = uints.unwrapU256(clamm.feeGrowthFromFee(pool.liquidity, poolFee)) if (inX) { pool.feeGrowthGlobalX = wrappingAdd(pool.feeGrowthGlobalX, feeGrowth) diff --git a/contracts/storage/position.ral b/contracts/storage/position.ral index 8fe9dbe..a008f81 100644 --- a/contracts/storage/position.ral +++ b/contracts/storage/position.ral @@ -15,7 +15,8 @@ Contract Position( admin: Address, mut position: PositionState, mut isActive: Bool, - clammContractInstance: CLAMM + clammContractInstance: CLAMM, + uints: Uints ) extends Decimal() { enum PositionError { NotAdmin = 900 @@ -135,8 +136,8 @@ Contract Position( assert!(liquidityDelta != 0 || position.liquidity != 0, PositionError.EmptyPositionPokes) - let tokensOwedX = clammContractInstance.toFee(wrappingSub(feeGrowthInsideX, position.feeGrowthInsideX), position.liquidity) - let tokensOwedY = clammContractInstance.toFee(wrappingSub(feeGrowthInsideY, position.feeGrowthInsideY), position.liquidity) + let tokensOwedX = uints.unwrapU256(clammContractInstance.toFee(wrappingSub(feeGrowthInsideX, position.feeGrowthInsideX), position.liquidity)) + let tokensOwedY = uints.unwrapU256(clammContractInstance.toFee(wrappingSub(feeGrowthInsideY, position.feeGrowthInsideY), position.liquidity)) position.liquidity = calculateNewLiquidity(sign, liquidityDelta) position.feeGrowthInsideX = feeGrowthInsideX diff --git a/src/utils.ts b/src/utils.ts index e7903cb..bc04181 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -47,22 +47,29 @@ export async function waitTxConfirmed(promise: Promi export async function deployInvariant(signer: SignerProvider, protocolFee: bigint) { const account = await signer.getSelectedAccount() + const uints = await deployUints(signer) const clamm = await deployCLAMM(signer) const feeTier = await deployFeeTier(signer) const feeTiers = await deployFeeTiers(signer, feeTier.contractInstance.contractId) const poolKey = await deployPoolKey(signer) const poolKeys = await deployPoolKeys(signer, poolKey.contractInstance.contractId) - const pool = await deployPool(signer, clamm.contractInstance.contractId) - const pools = await deployPools(signer, pool.contractInstance.contractId, clamm.contractInstance.contractId) + const pool = await deployPool(signer, clamm.contractInstance.contractId, uints.contractInstance.contractId) + const pools = await deployPools( + signer, + pool.contractInstance.contractId, + clamm.contractInstance.contractId, + uints.contractInstance.contractId + ) const tick = await deployTick(signer) const ticks = await deployTicks(signer, tick.contractInstance.contractId) - const position = await deployPosition(signer, clamm.contractInstance.contractId) + const position = await deployPosition(signer, clamm.contractInstance.contractId, uints.contractInstance.contractId) const positionsCounter = await deployPositionsCounter(signer) const positions = await deployPositions( signer, position.contractInstance.contractId, positionsCounter.contractInstance.contractId, - clamm.contractInstance.contractId + clamm.contractInstance.contractId, + uints.contractInstance.contractId ) const chunk = await deployChunk(signer) const tickmap = await deployTickmap(signer, chunk.contractInstance.contractId) @@ -154,7 +161,8 @@ export async function deployPositions( signer: SignerProvider, positionId: string, positionsCounterContractId: string, - clammId: string + clammId: string, + uintsId: string ) { return await waitTxConfirmed( Positions.deploy(signer, { @@ -163,13 +171,14 @@ export async function deployPositions( positionsCounterContractId, invariantId: ZERO_ADDRESS, areAdminsSet: false, - clammContract: clammId + clammContract: clammId, + uints: uintsId } }) ) } -export async function deployPosition(signer: SignerProvider, clammId: string) { +export async function deployPosition(signer: SignerProvider, clammId: string, uintsId: string) { return await waitTxConfirmed( Position.deploy(signer, { initialFields: { @@ -187,7 +196,8 @@ export async function deployPosition(signer: SignerProvider, clammId: string) { owner: ZERO_ADDRESS }, isActive: false, - clammContractInstance: clammId + clammContractInstance: clammId, + uints: uintsId } }) ) @@ -230,7 +240,7 @@ export async function deployPoolKeys(signer: SignerProvider, poolKeyId: string) ) } -export async function deployPool(signer: SignerProvider, clammId: string) { +export async function deployPool(signer: SignerProvider, clammId: string, uintsId: string) { return await waitTxConfirmed( Pool.deploy(signer, { initialFields: { @@ -250,18 +260,20 @@ export async function deployPool(signer: SignerProvider, clammId: string) { lastTimestamp: 0n, feeReceiver: ZERO_ADDRESS }, - clamm: clammId + clamm: clammId, + uints: uintsId } }) ) } -export async function deployPools(signer: SignerProvider, poolId: string, clammId: string) { +export async function deployPools(signer: SignerProvider, poolId: string, clammId: string, uintsId: string) { return await waitTxConfirmed( Pools.deploy(signer, { initialFields: { poolTemplateContractId: poolId, clamm: clammId, + uints: uintsId, areAdminsSet: false, invariantId: ZERO_ADDRESS, positionsId: ZERO_ADDRESS, @@ -442,3 +454,14 @@ export function hexToBytes(hex: string): Uint8Array { export function decodeU256(string: string): bigint { return BigInt(compactUnsignedIntCodec.decodeU256(Buffer.from(hexToBytes(string)))) } + +export const ArithmeticError = { + CastOverflow: 100001n, + AddOverflow: 100002n, + MulOverflow: 100003n, + DivNotPositiveDivisor: 100004n, + DivNotPositiveDenominator: 100005n, + MulNotPositiveDenominator: 100006n +} + +export const MaxU256 = 115792089237316195423570985008687907853269984665640564039457584007913129639935n diff --git a/test/clamm.test.ts b/test/clamm.test.ts index 40de60b..8fcd09f 100644 --- a/test/clamm.test.ts +++ b/test/clamm.test.ts @@ -3,7 +3,7 @@ import { getSigner } from '@alephium/web3-test' import { PrivateKeyWallet } from '@alephium/web3-wallet' import { assert } from 'console' import { CLAMMInstance } from '../artifacts/ts' -import { deployCLAMM, expectError } from '../src/utils' +import { ArithmeticError, MaxU256, deployCLAMM } from '../src/utils' web3.setCurrentNodeProvider('http://127.0.0.1:22973') @@ -21,28 +21,28 @@ describe('math tests', () => { const amount = 1n const result = (await clamm.contractInstance.methods.feeGrowthFromFee({ args: { liquidity, fee: amount } })) .returns - expect(result).toBe(10000000000000000000000000000n) + expect(result).toStrictEqual({ value: 10000000000000000000000000000n, error: 0n }) } { const liquidity = 2n * 10n ** 5n const amount = 1n const result = (await clamm.contractInstance.methods.feeGrowthFromFee({ args: { liquidity, fee: amount } })) .returns - expect(result).toBe(5n * 10n ** 27n) + expect(result).toStrictEqual({ value: 5n * 10n ** 27n, error: 0n }) } { const liquidity = ((1n << 64n) - 1n) * 10n ** 5n const amount = 1n const result = (await clamm.contractInstance.methods.feeGrowthFromFee({ args: { liquidity, fee: amount } })) .returns - expect(result).toBe(542101086n) + expect(result).toStrictEqual({ value: 542101086n, error: 0n }) } { const liquidity = 100n * 10n ** 5n const amount = 1000000n const result = (await clamm.contractInstance.methods.feeGrowthFromFee({ args: { liquidity, fee: amount } })) .returns - expect(result).toBe(10000n * 10n ** 28n) + expect(result).toStrictEqual({ value: 10000n * 10n ** 28n, error: 0n }) } }) test('fee growth from fee - domain', async () => { @@ -68,7 +68,7 @@ describe('math tests', () => { const feeGrowth = ( await clamm.contractInstance.methods.feeGrowthFromFee({ args: { liquidity: maxLiquidity, fee: maxToken } }) ).returns - expect(feeGrowth).toBe(473129365723326089999999999999999n) + expect(feeGrowth).toStrictEqual({ value: 473129365723326089999999999999999n, error: 0n }) } // min FeeGrowth case inside of domain { @@ -80,31 +80,36 @@ describe('math tests', () => { args: { liquidity: maxLiquidity, fee: minToken + basisPoint } }) ).returns - expect(feeGrowth).toBe(1n) + expect(feeGrowth).toStrictEqual({ value: 1n, error: 0n }) } // outside of domain trigger overflow due to result not fit into FeeGrowth { const liquidity = 1n const fee = (1n << 256n) - 1n - await expectError( - clamm.contractInstance.methods.feeGrowthFromFee({ + const feeGrowth = ( + await clamm.contractInstance.methods.feeGrowthFromFee({ args: { liquidity, fee } }) - ) + ).returns + expect(feeGrowth).toStrictEqual({ + value: MaxU256, + error: ArithmeticError.CastOverflow + }) } // amount = 0 { const liquidity = 1000n * 10n ** 5n const fee = 0n const feeGrowth = (await clamm.contractInstance.methods.feeGrowthFromFee({ args: { liquidity, fee } })).returns - expect(feeGrowth).toBe(0n) + expect(feeGrowth).toStrictEqual({ value: 0n, error: 0n }) } // L = 0 { const liquidity = 0n const fee = 1100n - await expectError(clamm.contractInstance.methods.feeGrowthFromFee({ args: { liquidity, fee } })) + const feeGrowth = (await clamm.contractInstance.methods.feeGrowthFromFee({ args: { liquidity, fee } })).returns + expect(feeGrowth).toStrictEqual({ value: MaxU256, error: ArithmeticError.MulNotPositiveDenominator }) } }) test('fee growth to fee', async () => { @@ -115,9 +120,9 @@ describe('math tests', () => { const liquidity = 1000000n * 10n ** 5n const params = { args: { liquidity, fee: amount } } const feeGrowth = (await clamm.contractInstance.methods.feeGrowthFromFee(params)).returns - const outParams = { args: { liquidity, feeGrowth } } + const outParams = { args: { liquidity, feeGrowth: feeGrowth.value } } const out = (await clamm.contractInstance.methods.toFee(outParams)).returns - expect(out).toBe(amount) + expect(out).toStrictEqual({ value: amount, error: 0n }) } // Greater Liquidity { @@ -126,9 +131,9 @@ describe('math tests', () => { const liquidityAfter = 10000000n * 10n ** 5n const params = { args: { liquidity: liquidityBefore, fee: amount } } const feeGrowth = (await clamm.contractInstance.methods.feeGrowthFromFee(params)).returns - const outParams = { args: { liquidity: liquidityAfter, feeGrowth } } + const outParams = { args: { liquidity: liquidityAfter, feeGrowth: feeGrowth.value } } const out = (await clamm.contractInstance.methods.toFee(outParams)).returns - expect(out).toBe(1000n) + expect(out).toStrictEqual({ value: 1000n, error: 0n }) } // huge liquidity { @@ -138,12 +143,12 @@ describe('math tests', () => { const feeGrowth = (await clamm.contractInstance.methods.feeGrowthFromFee(params)).returns // real 6.61744490042422139897126953655970282852649688720703125 × 10^-10 // expected 6617444900424221398 - expect(feeGrowth).toBe(6617444900424221398n) - const outParams = { args: { liquidity, feeGrowth } } + expect(feeGrowth).toStrictEqual({ value: 6617444900424221398n, error: 0n }) + const outParams = { args: { liquidity, feeGrowth: feeGrowth.value } } const out = (await clamm.contractInstance.methods.toFee(outParams)).returns // real 9.99999999999999999853225897430980027744256 × 10^13 // expected 99999999999999 - expect(out).toBe(99_999_999_999_999n) + expect(out).toStrictEqual({ value: 99_999_999_999_999n, error: 0n }) } }) test('fee growth to fee - domain', async () => { @@ -154,37 +159,44 @@ describe('math tests', () => { const liquidity = 10000000000000000000n * 10n ** 5n const params = { args: { liquidity, fee: amount } } const feeGrowth = (await clamm.contractInstance.methods.feeGrowthFromFee(params)).returns - expect(feeGrowth).toBe(600000000000000000000000000n) - const outParams = { args: { liquidity, feeGrowth } } + expect(feeGrowth).toStrictEqual({ value: 600000000000000000000000000n, error: 0n }) + const outParams = { args: { liquidity, feeGrowth: feeGrowth.value } } const out = (await clamm.contractInstance.methods.toFee(outParams)).returns - expect(out).toBe(amount) + expect(out).toStrictEqual({ value: amount, error: 0n }) } // max value inside domain { const liquidity = (1n << 256n) - 1n const feeGrowth = 100000n * 10n ** 28n const out = (await clamm.contractInstance.methods.toFee({ args: { liquidity, feeGrowth } })).returns - expect(out).toBe(115792089237316195423570985008687907853269983999999999999999999999999999999999n) + expect(out).toStrictEqual({ + value: 115792089237316195423570985008687907853269983999999999999999999999999999999999n, + error: 0n + }) } // Overflow { const liquidity = (1n << 256n) - 1n const feeGrowth = (1n << 256n) - 1n - await expectError(clamm.contractInstance.methods.toFee({ args: { liquidity, feeGrowth } })) + const out = (await clamm.contractInstance.methods.toFee({ args: { liquidity, feeGrowth } })).returns + expect(out).toStrictEqual({ + value: MaxU256, + error: ArithmeticError.CastOverflow + }) } // FeeGrowth = 0 { const liquidity = 1000n * 10n ** 5n const feeGrowth = 0n const out = (await clamm.contractInstance.methods.toFee({ args: { liquidity, feeGrowth } })).returns - expect(out).toBe(0n) + expect(out).toStrictEqual({ value: 0n, error: 0n }) } // Liquidity = 0 { const liquidity = 0n const feeGrowth = 1000n * 10n ** 28n const out = (await clamm.contractInstance.methods.toFee({ args: { liquidity, feeGrowth } })).returns - expect(out).toBe(0n) + expect(out).toStrictEqual({ value: 0n, error: 0n }) } }) test('tick from sqrt price', async () => { @@ -355,8 +367,8 @@ describe('math tests', () => { const paramsDown = { args: { sqrtPriceA, sqrtPriceB, liquidity, roundingUp: false } } const resultUp = (await clamm.contractInstance.methods.getDeltaX(paramsUp)).returns const resultDown = (await clamm.contractInstance.methods.getDeltaX(paramsDown)).returns - expect(resultUp).toEqual(0n) - expect(resultDown).toEqual(0n) + expect(resultUp).toEqual({ value: 0n, error: 0n }) + expect(resultDown).toEqual({ value: 0n, error: 0n }) }) test('equal at equal liquidity', async () => { const sqrtPriceA = 1n * 10n ** 24n @@ -366,8 +378,8 @@ describe('math tests', () => { const paramsDown = { args: { sqrtPriceA, sqrtPriceB, liquidity, roundingUp: false } } const resultUp = (await clamm.contractInstance.methods.getDeltaX(paramsUp)).returns const resultDown = (await clamm.contractInstance.methods.getDeltaX(paramsDown)).returns - expect(resultUp).toEqual(1n) - expect(resultDown).toEqual(1n) + expect(resultUp).toEqual({ value: 1n, error: 0n }) + expect(resultDown).toEqual({ value: 1n, error: 0n }) }) test('complex', async () => { const sqrtPriceA = 234878324943782000000000000n @@ -378,8 +390,8 @@ describe('math tests', () => { const resultUp = (await clamm.contractInstance.methods.getDeltaX(paramsUp)).returns const resultDown = (await clamm.contractInstance.methods.getDeltaX(paramsDown)).returns // 7010.8199533068819376891841727789301497024557314488455622925765280 - expect(resultUp).toEqual(70109n) - expect(resultDown).toEqual(70108n) + expect(resultUp).toEqual({ value: 70109n, error: 0n }) + expect(resultDown).toEqual({ value: 70108n, error: 0n }) }) test('big', async () => { const sqrtPriceA = 1n * 10n ** 24n @@ -389,8 +401,8 @@ describe('math tests', () => { const paramsDown = { args: { sqrtPriceA, sqrtPriceB, liquidity, roundingUp: false } } const resultUp = (await clamm.contractInstance.methods.getDeltaX(paramsUp)).returns const resultDown = (await clamm.contractInstance.methods.getDeltaX(paramsDown)).returns - expect(resultUp).toEqual(2n ** 64n - 1n) - expect(resultDown).toEqual(2n ** 64n - 1n) + expect(resultUp).toEqual({ value: 2n ** 64n - 1n, error: 0n }) + expect(resultDown).toEqual({ value: 2n ** 64n - 1n, error: 0n }) }) test('shouldnt overflow in intermediate opeartions', async () => { const sqrtPriceA = 1n * 10n ** 24n @@ -434,10 +446,16 @@ describe('math tests', () => { const resultDown = (await clamm.contractInstance.methods.getDeltaX(paramsDown)).returns // expected: 75884792730156830614567103553061795263351065677581979504561495713443442818879n // received: 75884792730156830614567103553061795263351065677581979478702815696568066130226n - expect(resultUp).toEqual(75884792730156830614567103553061795263351065677581979478702815696568066130226n) + expect(resultUp).toEqual({ + value: 75884792730156830614567103553061795263351065677581979478702815696568066130226n, + error: 0n + }) // expected: 75884792730156830614567103553061795263351065677581979504561495713443442818878n // received: 75884792730156830614567103553061795263351065677581979478702815696568066130226n - expect(resultDown).toEqual(75884792730156830614567103553061795263351065677581979478702815696568066130225n) + expect(resultDown).toEqual({ + value: 75884792730156830614567103553061795263351065677581979478702815696568066130225n, + error: 0n + }) }) test('maximalize delta sqrt price and minimalize liquidity', async () => { const params = { @@ -449,8 +467,8 @@ describe('math tests', () => { const paramsDown = { args: { ...params, roundingUp: false } } const resultUp = (await clamm.contractInstance.methods.getDeltaX(paramsUp)).returns const resultDown = (await clamm.contractInstance.methods.getDeltaX(paramsDown)).returns - expect(resultUp).toEqual(1n) - expect(resultDown).toEqual(0n) + expect(resultUp).toEqual({ value: 1n, error: 0n }) + expect(resultDown).toEqual({ value: 0n, error: 0n }) }) test('minimize denominator on maximize liquidity which fit into token amounts', async () => { const params = { @@ -464,10 +482,16 @@ describe('math tests', () => { const resultDown = (await clamm.contractInstance.methods.getDeltaX(paramsDown)).returns // expected: 3794315473971847510172532341754979462199874072217062973965311338137066234n // received: 3794315473971847510172532341754979462199874072217062972672351494741127621n - expect(resultUp).toEqual(3794315473971847510172532341754979462199874072217062972672351494741127621n) + expect(resultUp).toEqual({ + value: 3794315473971847510172532341754979462199874072217062972672351494741127621n, + error: 0n + }) // expected: 3794315473971847510172532341754979462199874072217062973965311338137066233n // received: 3794315473971847510172532341754979462199874072217062972672351494741127620n - expect(resultDown).toEqual(3794315473971847510172532341754979462199874072217062972672351494741127620n) + expect(resultDown).toEqual({ + value: 3794315473971847510172532341754979462199874072217062972672351494741127620n, + error: 0n + }) }) test('minimize denominator on minimize liquidity which fit into token amounts', async () => { const params = { @@ -479,8 +503,8 @@ describe('math tests', () => { const paramsDown = { args: { ...params, roundingUp: false } } const resultUp = (await clamm.contractInstance.methods.getDeltaX(paramsUp)).returns const resultDown = (await clamm.contractInstance.methods.getDeltaX(paramsDown)).returns - expect(resultUp).toEqual(1n) - expect(resultDown).toEqual(0n) + expect(resultUp).toEqual({ value: 1n, error: 0n }) + expect(resultDown).toEqual({ value: 0n, error: 0n }) }) test('delta price limited by search range on max liquidity', async () => { const searchLimit = 256n @@ -501,7 +525,10 @@ describe('math tests', () => { const resultUp = (await clamm.contractInstance.methods.getDeltaX(paramsUp)).returns // Expected: 45875017378130362421757891862614875858481775310156442203847653871247n // Received: 45875017378130362421757891862614875858481775310156442188214428734988n - expect(resultUp).toEqual(45875017378130362421757891862614875858481775310156442188214428734988n) + expect(resultUp).toEqual({ + value: 45875017378130362421757891862614875858481775310156442188214428734988n, + error: 0n + }) }) test('minimal price diffrence', async () => { const almostMaxSqrtPrice = maxSqrtPrice - 1n * 10n ** 24n @@ -516,11 +543,14 @@ describe('math tests', () => { const resultDown = (await clamm.contractInstance.methods.getDeltaX(paramsBottomBound)).returns // expected: 269608649375997235557394191156352599353486422139915865816324471n // received: 269608649375997235557394191156352599353486422139915864876650088n - expect(resultUp).toEqual(269608649375997235557394191156352599353486422139915864876650088n) + expect(resultUp).toEqual({ value: 269608649375997235557394191156352599353486422139915864876650088n, error: 0n }) // expected: 75883634844601460750582416171430603974060896681619645705711819135499453546638n // received: 75883634844601460750582416171430603974060896681619645679853533682422635835345n - expect(resultDown).toEqual(75883634844601460750582416171430603974060896681619645679853533682422635835345n) + expect(resultDown).toEqual({ + value: 75883634844601460750582416171430603974060896681619645679853533682422635835345n, + error: 0n + }) }) test('zero liquidity', async () => { const params = { @@ -532,8 +562,8 @@ describe('math tests', () => { const paramsDown = { args: { ...params, roundingUp: false } } const resultUp = (await clamm.contractInstance.methods.getDeltaX(paramsUp)).returns const resultDown = (await clamm.contractInstance.methods.getDeltaX(paramsDown)).returns - expect(resultUp).toEqual(0n) - expect(resultDown).toEqual(0n) + expect(resultUp).toEqual({ value: 0n, error: 0n }) + expect(resultDown).toEqual({ value: 0n, error: 0n }) }) }) @@ -552,7 +582,7 @@ describe('math tests', () => { const params = { args: { sqrtPriceA, sqrtPriceB, liquidity, roundingUp: false } } const result = await clamm.methods.getDeltaY(params) - expect(result.returns).toEqual(0n) + expect(result.returns).toEqual({ value: 0n, error: 0n }) }) test('equal at equal liquidity', async () => { @@ -563,7 +593,7 @@ describe('math tests', () => { const params = { args: { sqrtPriceA, sqrtPriceB, liquidity, roundingUp: false } } const result = await clamm.methods.getDeltaY(params) - expect(result.returns).toEqual(2n) + expect(result.returns).toEqual({ value: 2n, error: 0n }) }) test('big numbers', async () => { @@ -576,8 +606,8 @@ describe('math tests', () => { const resultUp = await clamm.methods.getDeltaY(paramsUp) const resultDown = await clamm.methods.getDeltaY(paramsDown) - expect(resultUp.returns).toEqual(1446690239n) - expect(resultDown.returns).toEqual(1446690238n) + expect(resultUp.returns).toEqual({ value: 1446690239n, error: 0n }) + expect(resultDown.returns).toEqual({ value: 1446690238n, error: 0n }) }) test('big', async () => { @@ -590,8 +620,8 @@ describe('math tests', () => { const resultUp = await clamm.methods.getDeltaY(paramsUp) const resultDown = await clamm.methods.getDeltaY(paramsDown) - expect(resultUp.returns).toEqual(liquidity / 1_00000n) - expect(resultDown.returns).toEqual(liquidity / 1_00000n) + expect(resultUp.returns).toEqual({ value: liquidity / 1_00000n, error: 0n }) + expect(resultDown.returns).toEqual({ value: liquidity / 1_00000n, error: 0n }) }) test('overflow', async () => { @@ -601,8 +631,11 @@ describe('math tests', () => { const paramsUp = { args: { sqrtPriceA, sqrtPriceB, liquidity, roundingUp: true } } const paramsDown = { args: { sqrtPriceA, sqrtPriceB, liquidity, roundingUp: false } } - await expectError(clamm.methods.getDeltaY(paramsUp)) - await expectError(clamm.methods.getDeltaY(paramsDown)) + const resultUp = await clamm.methods.getDeltaY(paramsUp) + const resultDown = await clamm.methods.getDeltaY(paramsDown) + + expect(resultUp.returns).toEqual({ value: MaxU256, error: ArithmeticError.CastOverflow }) + expect(resultDown.returns).toEqual({ value: MaxU256, error: ArithmeticError.CastOverflow }) }) test('huge liquidity', async () => { @@ -615,8 +648,14 @@ describe('math tests', () => { const resultUp = await clamm.methods.getDeltaY(paramsUp) const resultDown = await clamm.methods.getDeltaY(paramsDown) - expect(resultUp.returns).toEqual(1157920892373161954235709850086879078532699846656405641n) - expect(resultDown.returns).toEqual(1157920892373161954235709850086879078532699846656405640n) + expect(resultUp.returns).toStrictEqual({ + value: 1157920892373161954235709850086879078532699846656405640n, + error: 0n + }) + expect(resultDown.returns).toStrictEqual({ + value: 1157920892373161954235709850086879078532699846656405640n, + error: 0n + }) }) }) @@ -641,8 +680,14 @@ describe('math tests', () => { const resultUp = await clamm.methods.getDeltaY(paramsUp) const resultDown = await clamm.methods.getDeltaY(paramsDown) - expect(resultUp.returns).toEqual(75884790229800029582010010030152469040784228171629896039591333116952600000001n) - expect(resultDown.returns).toEqual(75884790229800029582010010030152469040784228171629896039591333116952599999999n) + expect(resultUp.returns).toStrictEqual({ + value: 75884790229800029582010010030152469040784228171629896039591333116952600000000n, + error: 0n + }) + expect(resultDown.returns).toStrictEqual({ + value: 75884790229800029582010010030152469040784228171629896039591333116952599999999n, + error: 0n + }) }) it('can be zero', async () => { @@ -651,7 +696,7 @@ describe('math tests', () => { } const result = await clamm.methods.getDeltaY(params) - expect(result.returns).toEqual(0n) + expect(result.returns).toStrictEqual({ value: 0n, error: 0n }) }) it('liquidity is zero', async () => { @@ -660,7 +705,7 @@ describe('math tests', () => { } const result = await clamm.methods.getDeltaY(params) - expect(result.returns).toEqual(0n) + expect(result.returns).toStrictEqual({ value: 0n, error: 0n }) }) it('all max', async () => { @@ -669,7 +714,7 @@ describe('math tests', () => { } const result = await clamm.methods.getDeltaY(params) - expect(result.returns).toEqual(0n) + expect(result.returns).toStrictEqual({ value: 0n, error: 0n }) }) }) diff --git a/test/uints.test.ts b/test/uints.test.ts index 927d8a2..753c7da 100644 --- a/test/uints.test.ts +++ b/test/uints.test.ts @@ -1,394 +1,777 @@ -import { ONE_ALPH, web3 } from '@alephium/web3' +import { ONE_ALPH, SignerProvider, web3 } from '@alephium/web3' import { getSigner } from '@alephium/web3-test' -import { PrivateKeyWallet } from '@alephium/web3-wallet' -import { deployUints } from '../src/utils' +import { UintsInstance } from '../artifacts/ts' +import { ArithmeticError, MaxU256, deployUints, expectError } from '../src/utils' web3.setCurrentNodeProvider('http://127.0.0.1:22973') -let sender: PrivateKeyWallet - describe('uints tests', () => { + let sender: SignerProvider + let uints: UintsInstance + beforeAll(async () => { sender = await getSigner(ONE_ALPH * 100000n, 0) + uints = (await deployUints(sender)).contractInstance + }) + + test('unwrap result u256 works', async () => { + const resultU256 = { value: 1n, error: 0n } + const result = (await uints.methods.unwrapU256({ args: { result: resultU256 } })).returns + expect(result).toEqual(resultU256.value) + }) + + test('unwrap result u256 throws error when error is not 0', async () => { + const resultU256 = { value: 1n, error: ArithmeticError.CastOverflow } + expectError(uints.methods.unwrapU256({ args: { result: resultU256 } })) + }) + + test('unwrap result u512 works', async () => { + const resultU256 = { value: { higher: 2n, lower: 1n }, error: 0n } + const result = (await uints.methods.unwrapU512({ args: { result: resultU256 } })).returns + expect(result).toEqual(resultU256.value) + }) + + test('unwrap result u512 throws error when error is not 0', async () => { + const resultU256 = { value: { higher: 2n, lower: 1n }, error: ArithmeticError.CastOverflow } + expectError(uints.methods.unwrapU512({ args: { result: resultU256 } })) }) - test('test casting between u512 and u256', async () => { - const uints = await deployUints(sender) - const v = 100n - const result = (await uints.contractInstance.methods.toU512({ args: { v } })).returns - expect(result).toStrictEqual({ higher: 0n, lower: 100n }) - const castBack = (await uints.contractInstance.methods.toU256({ args: { v: result } })).returns - expect(castBack).toStrictEqual(v) + test('to u256 works', async () => { + const value = { higher: 0n, lower: 1n } + const result = (await uints.methods.toU256({ args: { value } })).returns + expect(result).toEqual({ value: value.lower, error: 0n }) + }) + + test('to u256 returns an error if number is higher than u256', async () => { + const value = { higher: 2n, lower: 1n } + const result = (await uints.methods.toU256({ args: { value } })).returns + expect(result).toEqual({ value: MaxU256, error: ArithmeticError.CastOverflow }) + }) + + test('to u512 works', async () => { + const value = 1n + const result = (await uints.methods.toU512({ args: { value } })).returns + expect(result).toEqual({ higher: 0n, lower: value }) }) test('big add 256', async () => { - const uints = await deployUints(sender) { - const a = 115792089237316195423570985008687907853269984665640564039457584007913129639935n - const b = 999n - const result = (await uints.contractInstance.methods.bigAdd256({ args: { a, b } })).returns - expect(result).toStrictEqual({ higher: 1n, lower: b - 1n }) + const a = 1n + const b = 2n + const result = (await uints.methods.bigAdd256({ args: { a, b } })).returns + expect(result).toStrictEqual({ higher: 0n, lower: 3n }) } { - const a = 777n - const b = 115792089237316195423570985008687907853269984665640564039457584007913129639935n - const result = (await uints.contractInstance.methods.bigAdd256({ args: { a, b } })).returns - expect(result).toStrictEqual({ higher: 1n, lower: a - 1n }) + const a = MaxU256 + const b = 2n + const result = (await uints.methods.bigAdd256({ args: { a, b } })).returns + expect(result).toStrictEqual({ higher: 1n, lower: 1n }) } { - const a = 115792089237316195423570985008687907853269984665640564039457584007913129639935n - const b = 115792089237316195423570985008687907853269984665640564039457584007913129639935n - const result = (await uints.contractInstance.methods.bigAdd256({ args: { a, b } })).returns + const a = MaxU256 + const b = MaxU256 + const result = (await uints.methods.bigAdd256({ args: { a, b } })).returns expect(result).toStrictEqual({ higher: 1n, lower: a - 1n }) } }) - test('big div 512 / big div up 512', async () => { - const uints = await deployUints(sender) + test('big add', async () => { + { + const a = { higher: 0n, lower: 1n } + const b = 2n + const result = (await uints.methods.bigAdd({ args: { a, b } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 3n }, error: 0n }) + } + { + const a = { higher: 0n, lower: MaxU256 } + const b = 2n + const result = (await uints.methods.bigAdd({ args: { a, b } })).returns + expect(result).toStrictEqual({ value: { higher: 1n, lower: 1n }, error: 0n }) + } + { + const a = { higher: 0n, lower: MaxU256 } + const b = MaxU256 + const result = (await uints.methods.bigAdd({ args: { a, b } })).returns + expect(result).toStrictEqual({ value: { higher: 1n, lower: a.lower - 1n }, error: 0n }) + } + { + const a = { higher: MaxU256, lower: 0n } + const b = MaxU256 + const result = (await uints.methods.bigAdd({ args: { a, b } })).returns + expect(result).toStrictEqual({ + value: { + higher: MaxU256, + lower: MaxU256 + }, + error: 0n + }) + } + }) + + test('big add returns an error if number if higher than u512', async () => { { const a = { - higher: 21n, - lower: 37n - } - const b = 50n - const bDenominator = 10n - { - const result = (await uints.contractInstance.methods.bigDiv512({ args: { a, b, bDenominator } })).returns - // expected: 486326774796728020778998137036489212983733935595690368965721000000000000000000 - // received: 486326774796728020778998137036489212983733935595690368965721852833235144487731 - expect(result).toStrictEqual({ - higher: 4n, - lower: 23158417847463239084714197001737581570653996933128112807891516801582625927987n - }) - } - { - const result = (await uints.contractInstance.methods.bigDivUp512({ args: { a, b, bDenominator } })).returns - expect(result).toStrictEqual({ - higher: 4n, - lower: 23158417847463239084714197001737581570653996933128112807891516801582625927988n - }) + higher: MaxU256, + lower: MaxU256 } + const b = 1n + const result = (await uints.methods.bigAdd({ args: { a, b } })).returns + expect(result).toStrictEqual({ + value: { + higher: MaxU256, + lower: MaxU256 + }, + error: ArithmeticError.AddOverflow + }) } { const a = { - higher: 50216813883093446110686315385661331328818843555712276103168n, - lower: 0n - } - const b = 2n - const bDenominator = 1n - { - const result = (await uints.contractInstance.methods.bigDiv512({ args: { a, b, bDenominator } })).returns - // expected: 2907354897182427562197295231552018137414565442749272241125960796722557152453591693304764202855054262243050086425064711734138406514458624n - // received: 2907354897182427562197295231552018137414565442749272241125960796722557152453591693304764202855054262243050086425064711734138406514458624n - expect(result).toStrictEqual({ - higher: 25108406941546723055343157692830665664409421777856138051584n, - lower: 0n - }) + higher: MaxU256, + lower: 1n } - { - const result = (await uints.contractInstance.methods.bigDivUp512({ args: { a, b, bDenominator } })).returns - expect(result).toStrictEqual({ - higher: 25108406941546723055343157692830665664409421777856138051584n, - lower: 0n - }) + const b = MaxU256 + const result = (await uints.methods.bigAdd({ args: { a, b } })).returns + expect(result).toStrictEqual({ + value: { + higher: MaxU256, + lower: MaxU256 + }, + error: ArithmeticError.AddOverflow + }) + } + }) + + test('big add 512', async () => { + { + const a = { higher: 0n, lower: 1n } + const b = { higher: 0n, lower: 2n } + const result = (await uints.methods.bigAdd512({ args: { a, b } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 3n }, error: 0n }) + } + { + const a = { higher: 0n, lower: MaxU256 } + const b = { higher: 0n, lower: 2n } + const result = (await uints.methods.bigAdd512({ args: { a, b } })).returns + expect(result).toStrictEqual({ value: { higher: 1n, lower: 1n }, error: 0n }) + } + { + const a = { higher: 0n, lower: MaxU256 } + const b = { higher: 0n, lower: MaxU256 } + const result = (await uints.methods.bigAdd512({ args: { a, b } })).returns + expect(result).toStrictEqual({ value: { higher: 1n, lower: a.lower - 1n }, error: 0n }) + } + { + const a = { higher: 0n, lower: MaxU256 } + const b = { + higher: MaxU256, + lower: 0n } + const result = (await uints.methods.bigAdd512({ args: { a, b } })).returns + expect(result).toStrictEqual({ + value: { + higher: MaxU256, + lower: MaxU256 + }, + error: 0n + }) } + }) + + test('big add 512 returns an error if number if higher than u512', async () => { { const a = { + higher: MaxU256, + lower: MaxU256 + } + const b = { higher: 0n, lower: 1n } - const b = 2n - const bDenominator = 1n - { - const result = (await uints.contractInstance.methods.bigDiv512({ args: { a, b, bDenominator } })).returns - expect(result).toStrictEqual({ - higher: 0n, - lower: 0n - }) - } - { - const result = (await uints.contractInstance.methods.bigDivUp512({ args: { a, b, bDenominator } })).returns - expect(result).toStrictEqual({ - higher: 0n, - lower: 1n - }) - } + const result = (await uints.methods.bigAdd512({ args: { a, b } })).returns + expect(result).toStrictEqual({ + value: { + higher: MaxU256, + lower: MaxU256 + }, + error: ArithmeticError.AddOverflow + }) } { const a = { - higher: 0n, - lower: 10n + higher: 1n, + lower: MaxU256 } - const b = 1n - const bDenominator = 1000n - { - const result = (await uints.contractInstance.methods.bigDiv512({ args: { a, b, bDenominator } })).returns - expect(result).toStrictEqual({ - higher: 0n, - lower: 10n - }) - } - { - const result = (await uints.contractInstance.methods.bigDivUp512({ args: { a, b, bDenominator } })).returns - expect(result).toStrictEqual({ - higher: 0n, - lower: 10n - }) + const b = { + higher: MaxU256, + lower: 0n } + const result = (await uints.methods.bigAdd512({ args: { a, b } })).returns + expect(result).toStrictEqual({ + value: { + higher: MaxU256, + lower: MaxU256 + }, + error: ArithmeticError.AddOverflow + }) } { const a = { - higher: 0n, - lower: 6n * 10n ** 1n - } - - const b = 3n * 10n ** 3n - const bDenominator = 1000n - { - const result = (await uints.contractInstance.methods.bigDiv512({ args: { a, b, bDenominator } })).returns - expect(result).toStrictEqual({ - higher: 0n, - lower: 20n - }) + higher: 1n, + lower: 0n } - { - const result = (await uints.contractInstance.methods.bigDivUp512({ args: { a, b, bDenominator } })).returns - expect(result).toStrictEqual({ - higher: 0n, - lower: 20n - }) + const b = { + higher: MaxU256, + lower: 0n } + const result = (await uints.methods.bigAdd512({ args: { a, b } })).returns + expect(result).toStrictEqual({ + value: { + higher: MaxU256, + lower: MaxU256 + }, + error: ArithmeticError.AddOverflow + }) } }) - test('big add 512', async () => { - const uints = await deployUints(sender) + test('big div', async () => { + { + const a = { higher: 0n, lower: 2n } + const b = 1n + const bDenominator = 1n + const result = (await uints.methods.bigDiv({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 2n }, error: 0n }) + } { - const a = { higher: 0n, lower: 10n } - const b = { higher: 0n, lower: 20n } - const result = (await uints.contractInstance.methods.bigAdd512({ args: { a, b } })).returns - expect(result).toStrictEqual({ higher: 0n, lower: 30n }) + const a = { higher: 0n, lower: 2n } + const b = 2n + const bDenominator = 1n + const result = (await uints.methods.bigDiv({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 1n }, error: 0n }) } { - const a = { higher: 0n, lower: 115792089237316195423570985008687907853269984665640564039457584007913129639935n } - const b = { higher: 0n, lower: 20n } - const result = (await uints.contractInstance.methods.bigAdd512({ args: { a, b } })).returns - expect(result).toStrictEqual({ higher: 1n, lower: 19n }) + const a = { higher: 0n, lower: 1n } + const b = 2n + const bDenominator = 1n + const result = (await uints.methods.bigDiv({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 0n }, error: 0n }) + } + { + const a = { higher: 1n, lower: 0n } + const b = 1n + const bDenominator = 1n + const result = (await uints.methods.bigDiv({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 1n, lower: 0n }, error: 0n }) + } + { + const a = { higher: 20n, lower: 20n } + const b = 10n + const bDenominator = 1n + const result = (await uints.methods.bigDiv({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 2n, lower: 2n }, error: 0n }) + } + { + const a = { higher: MaxU256, lower: MaxU256 } + const b = MaxU256 + const bDenominator = 1n + const result = (await uints.methods.bigDiv({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 1n, lower: 1n }, error: 0n }) } - }) - - test('big mul 512', async () => { - const uints = await deployUints(sender) { - const a = { higher: 0n, lower: 123n } + const a = { higher: MaxU256, lower: 0n } + const b = MaxU256 + const bDenominator = 1n + const result = (await uints.methods.bigDiv({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 1n, lower: 0n }, error: 0n }) + } + { + const a = { higher: 0n, lower: 2n } + const b = 10n + const bDenominator = 10n + const result = (await uints.methods.bigDiv({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 2n }, error: 0n }) + } + { + const a = { higher: 0n, lower: 1n } + const b = 2n + const bDenominator = 10n + const result = (await uints.methods.bigDiv({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 5n }, error: 0n }) + } + { + const a = { higher: 0n, lower: 0n } + const b = MaxU256 + const bDenominator = 1n + const result = (await uints.methods.bigDiv({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 0n }, error: 0n }) + } + { + const a = { higher: MaxU256, lower: MaxU256 } + const b = 1n + const bDenominator = 100n + const result = (await uints.methods.bigDiv({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: MaxU256, lower: MaxU256 }, error: 0n }) + } + { + const a = { higher: 0n, lower: 1n } const b = 2n - const result = (await uints.contractInstance.methods.bigMul512({ args: { a, b } })).returns - expect(result).toStrictEqual({ higher: 0n, lower: 246n }) - // expected: 246 - // real: 246 + const bDenominator = 1n + const result = (await uints.methods.bigDiv({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 0n }, error: 0n }) } + }) + + test('big div return error when dividing by zero or b denominator is zero', async () => { { - const a = { higher: 0n, lower: 340282366920938463463374607431768211457n } - const b = 340282366920938463463374607431768211457n - const result = (await uints.contractInstance.methods.bigMul512({ args: { a, b } })).returns - expect(result).toStrictEqual({ higher: 1n, lower: 680564733841876926926749214863536422913n }) - // expected: 115792089237316195423570985008687907853950549399482440966384333222776666062849 - // real: 115792089237316195423570985008687907853950549399482440966384333222776666062849 + const a = { higher: 0n, lower: 2n } + const b = 0n + const bDenominator = 1n + const result = (await uints.methods.bigDiv({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ + value: { higher: MaxU256, lower: MaxU256 }, + error: ArithmeticError.DivNotPositiveDivisor + }) } { - const a = { higher: 0n, lower: 115792089237316195423570985008687907853269984665640564039457584007913129639935n } - const b = 115792089237316195423570985008687907853269984665640564039457584007913129639935n - const result = (await uints.contractInstance.methods.bigMul512({ args: { a, b } })).returns + const a = { higher: 0n, lower: 2n } + const b = 1n + const bDenominator = 0n + const result = (await uints.methods.bigDiv({ args: { a, b, bDenominator } })).returns expect(result).toStrictEqual({ - higher: 115792089237316195423570985008687907853269984665640564039457584007913129639934n, - lower: 1n + value: { higher: MaxU256, lower: MaxU256 }, + error: ArithmeticError.DivNotPositiveDenominator }) - // expected: 13407807929942597099574024998205846127479365820592393377723561443721764030073315392623399665776056285720014482370779510884422601683867654778417822746804225 - // real: 13407807929942597099574024998205846127479365820592393377723561443721764030073315392623399665776056285720014482370779510884422601683867654778417822746804225 + } + }) + + test('big div up', async () => { + { + const a = { higher: 0n, lower: 2n } + const b = 1n + const bDenominator = 1n + const result = (await uints.methods.bigDivUp({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 2n }, error: 0n }) } { - const a = { higher: 0n, lower: 500n } - const b = 0n - const result = (await uints.contractInstance.methods.bigMul512({ args: { a, b } })).returns - expect(result).toStrictEqual({ higher: 0n, lower: 0n }) + const a = { higher: 0n, lower: 2n } + const b = 2n + const bDenominator = 1n + const result = (await uints.methods.bigDivUp({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 1n }, error: 0n }) + } + { + const a = { higher: 0n, lower: 1n } + const b = 2n + const bDenominator = 1n + const result = (await uints.methods.bigDivUp({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 1n }, error: 0n }) + } + { + const a = { higher: 1n, lower: 0n } + const b = 1n + const bDenominator = 1n + const result = (await uints.methods.bigDivUp({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 1n, lower: 0n }, error: 0n }) + } + { + const a = { higher: 20n, lower: 20n } + const b = 10n + const bDenominator = 1n + const result = (await uints.methods.bigDivUp({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 2n, lower: 2n }, error: 0n }) + } + { + const a = { higher: MaxU256, lower: MaxU256 } + const b = MaxU256 + const bDenominator = 1n + const result = (await uints.methods.bigDivUp({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 1n, lower: 1n }, error: 0n }) + } + { + const a = { higher: MaxU256, lower: 0n } + const b = MaxU256 + const bDenominator = 1n + const result = (await uints.methods.bigDivUp({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 1n, lower: 0n }, error: 0n }) + } + { + const a = { higher: 0n, lower: 2n } + const b = 10n + const bDenominator = 10n + const result = (await uints.methods.bigDivUp({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 2n }, error: 0n }) } { - const a = { higher: 1n, lower: 115792089237316195423570985008687907853269984665640564039457584007913129639935n } - const b = 100n - const result = (await uints.contractInstance.methods.bigMul512({ args: { a, b } })).returns + const a = { higher: 0n, lower: 1n } + const b = 2n + const bDenominator = 10n + const result = (await uints.methods.bigDivUp({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 5n }, error: 0n }) + } + { + const a = { higher: 0n, lower: 0n } + const b = MaxU256 + const bDenominator = 1n + const result = (await uints.methods.bigDivUp({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 0n }, error: 0n }) + } + { + const a = { higher: MaxU256, lower: MaxU256 } + const b = 1n + const bDenominator = 100n + const result = (await uints.methods.bigDivUp({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: MaxU256, lower: MaxU256 }, error: 0n }) + } + { + const a = { higher: 0n, lower: 1n } + const b = 2n + const bDenominator = 1n + const result = (await uints.methods.bigDivUp({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 1n }, error: 0n }) + } + }) + + test('big div up return error when dividing by zero or b denominator is zero', async () => { + { + const a = { higher: 0n, lower: 2n } + const b = 0n + const bDenominator = 1n + const result = (await uints.methods.bigDivUp({ args: { a, b, bDenominator } })).returns expect(result).toStrictEqual({ - higher: 199n, - lower: 115792089237316195423570985008687907853269984665640564039457584007913129639836n + value: { higher: MaxU256, lower: MaxU256 }, + error: ArithmeticError.DivNotPositiveDivisor }) } { - const a = { higher: 340282366920938463463374607431768211455n, lower: 340282366920938463463374607431768211455n } - const b = 340282366920938463463374607431768211455n - const result = (await uints.contractInstance.methods.bigMul512({ args: { a, b } })).returns + const a = { higher: 0n, lower: 2n } + const b = 1n + const bDenominator = 0n + const result = (await uints.methods.bigDivUp({ args: { a, b, bDenominator } })).returns expect(result).toStrictEqual({ - higher: 115792089237316195423570985008687907852589419931798687112530834793049593217025n, - lower: 115792089237316195423570985008687907852589419931798687112530834793049593217025n + value: { higher: MaxU256, lower: MaxU256 }, + error: ArithmeticError.DivNotPositiveDenominator }) } }) + test('big mul 256', async () => { + { + const a = 1n + const b = 2n + const result = (await uints.methods.bigMul256({ args: { a, b } })).returns + expect(result).toStrictEqual({ higher: 0n, lower: 2n }) + } + { + const a = MaxU256 + const b = 2n + const result = (await uints.methods.bigMul256({ args: { a, b } })).returns + expect(result).toStrictEqual({ higher: 1n, lower: MaxU256 - 1n }) + } + { + const a = MaxU256 + const b = MaxU256 + const result = (await uints.methods.bigMul256({ args: { a, b } })).returns + expect(result).toStrictEqual({ higher: MaxU256 - 1n, lower: 1n }) + } + { + const a = MaxU256 + const b = 0n + const result = (await uints.methods.bigMul256({ args: { a, b } })).returns + expect(result).toStrictEqual({ higher: 0n, lower: 0n }) + } + { + const a = 0n + const b = 0n + const result = (await uints.methods.bigMul256({ args: { a, b } })).returns + expect(result).toStrictEqual({ higher: 0n, lower: 0n }) + } + }) + + test('big mul', async () => { + { + const a = { higher: 0n, lower: 1n } + const b = 2n + const result = (await uints.methods.bigMul({ args: { a, b } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 2n }, error: 0n }) + } + { + const a = { higher: 0n, lower: MaxU256 } + const b = 2n + const result = (await uints.methods.bigMul({ args: { a, b } })).returns + expect(result).toStrictEqual({ value: { higher: 1n, lower: MaxU256 - 1n }, error: 0n }) + } + { + const a = { higher: 0n, lower: MaxU256 } + const b = MaxU256 + const result = (await uints.methods.bigMul({ args: { a, b } })).returns + expect(result).toStrictEqual({ value: { higher: MaxU256 - 1n, lower: 1n }, error: 0n }) + } + { + const a = { higher: 0n, lower: MaxU256 } + const b = 0n + const result = (await uints.methods.bigMul({ args: { a, b } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 0n }, error: 0n }) + } + { + const a = { higher: 0n, lower: 0n } + const b = 0n + const result = (await uints.methods.bigMul({ args: { a, b } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 0n }, error: 0n }) + } + }) + + test('big mul returns an error if number is higher than u512', async () => { + { + const a = { higher: MaxU256, lower: MaxU256 } + const b = 2n + const result = (await uints.methods.bigMul({ args: { a, b } })).returns + expect(result).toStrictEqual({ value: { higher: MaxU256, lower: MaxU256 }, error: ArithmeticError.MulOverflow }) + } + { + const a = { higher: MaxU256, lower: 1n } + const b = MaxU256 + const result = (await uints.methods.bigMul({ args: { a, b } })).returns + expect(result).toStrictEqual({ value: { higher: MaxU256, lower: MaxU256 }, error: ArithmeticError.MulOverflow }) + } + { + const a = { higher: MaxU256 - 1n, lower: MaxU256 } + const b = MaxU256 + const result = (await uints.methods.bigMul({ args: { a, b } })).returns + expect(result).toStrictEqual({ value: { higher: MaxU256, lower: MaxU256 }, error: ArithmeticError.MulOverflow }) + } + { + const a = { higher: MaxU256, lower: MaxU256 } + const b = MaxU256 + const result = (await uints.methods.bigMul({ args: { a, b } })).returns + expect(result).toStrictEqual({ value: { higher: MaxU256, lower: MaxU256 }, error: ArithmeticError.MulOverflow }) + } + }) + test('big mul div 256', async () => { - const uints = await deployUints(sender) { - const a = 123n + const a = 1n const b = 2n - const result = (await uints.contractInstance.methods.bigMulDiv256({ args: { a, b, bDenominator: 1n } })).returns - expect(result).toStrictEqual({ higher: 0n, lower: 246n }) - // expected: 246 - // real: 246 + const bDenominator = 1n + const result = (await uints.methods.bigMulDiv256({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 2n }, error: 0n }) } { - const a = 340282366920938463463374607431768211457n - const b = 340282366920938463463374607431768211457n - const result = (await uints.contractInstance.methods.bigMulDiv256({ args: { a, b, bDenominator: 1n } })).returns - expect(result).toStrictEqual({ higher: 1n, lower: 680564733841876926926749214863536422913n }) - // expected: 115792089237316195423570985008687907853950549399482440966384333222776666062849 - // real: 115792089237316195423570985008687907853950549399482440966384333222776666062849 + const a = MaxU256 + const b = 2n + const bDenominator = 1n + const result = (await uints.methods.bigMulDiv256({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 1n, lower: MaxU256 - 1n }, error: 0n }) } { - const a = 115792089237316195423570985008687907853269984665640564039457584007913129639935n - const b = 115792089237316195423570985008687907853269984665640564039457584007913129639935n - const result = (await uints.contractInstance.methods.bigMulDiv256({ args: { a, b, bDenominator: 1n } })).returns + const a = MaxU256 + const b = MaxU256 + const bDenominator = 1n + const result = (await uints.methods.bigMulDiv256({ args: { a, b, bDenominator } })).returns expect(result).toStrictEqual({ - higher: 115792089237316195423570985008687907853269984665640564039457584007913129639934n, - lower: 1n + value: { + higher: MaxU256 - 1n, + lower: 1n + }, + error: 0n }) - // expected: 13407807929942597099574024998205846127479365820592393377723561443721764030073315392623399665776056285720014482370779510884422601683867654778417822746804225 - // real: 13407807929942597099574024998205846127479365820592393377723561443721764030073315392623399665776056285720014482370779510884422601683867654778417822746804225 } { - const a = 500n + const a = MaxU256 const b = 0n - const result = (await uints.contractInstance.methods.bigMulDiv256({ args: { a, b, bDenominator: 1n } })).returns - expect(result).toStrictEqual({ higher: 0n, lower: 0n }) + const bDenominator = 1n + const result = (await uints.methods.bigMulDiv256({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 0n }, error: 0n }) + } + { + const a = 0n + const b = 0n + const bDenominator = 1n + const result = (await uints.methods.bigMulDiv256({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 0n }, error: 0n }) } { const a = 100n - const b = 100n - const result = (await uints.contractInstance.methods.bigMulDiv256({ args: { a, b, bDenominator: 100n } })).returns - expect(result).toStrictEqual({ higher: 0n, lower: 100n }) + const b = 200n + const bDenominator = 100n + const result = (await uints.methods.bigMulDiv256({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 200n }, error: 0n }) } { - const a = 30n - const b = 1n - const result = (await uints.contractInstance.methods.bigMulDiv256({ args: { a, b, bDenominator: 10n } })).returns - expect(result).toStrictEqual({ higher: 0n, lower: 3n }) + const a = 1n + const b = 150n + const bDenominator = 100n + const result = (await uints.methods.bigMulDiv256({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 1n }, error: 0n }) } { - const a = 500n - const b = 4000n - const result = (await uints.contractInstance.methods.bigMulDiv256({ args: { a, b, bDenominator: 1000n } })) - .returns - expect(result).toStrictEqual({ higher: 0n, lower: 2000n }) + const a = MaxU256 + const b = MaxU256 + const bDenominator = MaxU256 + const result = (await uints.methods.bigMulDiv256({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: MaxU256 - 1n }, error: 0n }) } + }) + + test('big mul div 256 returns an error if b denominator is zero', async () => { { - const a = 10n - const b = 37n - const result = (await uints.contractInstance.methods.bigMulDiv256({ args: { a, b, bDenominator: 100n } })).returns - expect(result).toStrictEqual({ higher: 0n, lower: 3n }) + const a = 1n + const b = 1n + const bDenominator = 0n + const result = (await uints.methods.bigMulDiv256({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ + value: { higher: MaxU256, lower: MaxU256 }, + error: ArithmeticError.MulNotPositiveDenominator + }) } }) test('big mul div up 256', async () => { - const uints = await deployUints(sender) { - const a = 123n + const a = 1n const b = 2n - const result = (await uints.contractInstance.methods.bigMulDivUp256({ args: { a, b, bDenominator: 1n } })).returns - expect(result).toStrictEqual({ higher: 0n, lower: 246n }) - // expected: 246 - // real: 246 + const bDenominator = 1n + const result = (await uints.methods.bigMulDivUp256({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 2n }, error: 0n }) } { - const a = 340282366920938463463374607431768211457n - const b = 340282366920938463463374607431768211457n - const result = (await uints.contractInstance.methods.bigMulDivUp256({ args: { a, b, bDenominator: 1n } })).returns - expect(result).toStrictEqual({ higher: 1n, lower: 680564733841876926926749214863536422913n }) - // expected: 115792089237316195423570985008687907853950549399482440966384333222776666062849 - // real: 115792089237316195423570985008687907853950549399482440966384333222776666062849 + const a = MaxU256 + const b = 2n + const bDenominator = 1n + const result = (await uints.methods.bigMulDivUp256({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 1n, lower: MaxU256 - 1n }, error: 0n }) } { - const a = 115792089237316195423570985008687907853269984665640564039457584007913129639935n - const b = 115792089237316195423570985008687907853269984665640564039457584007913129639935n - const result = (await uints.contractInstance.methods.bigMulDivUp256({ args: { a, b, bDenominator: 1n } })).returns + const a = MaxU256 + const b = MaxU256 + const bDenominator = 1n + const result = (await uints.methods.bigMulDivUp256({ args: { a, b, bDenominator } })).returns expect(result).toStrictEqual({ - higher: 115792089237316195423570985008687907853269984665640564039457584007913129639934n, - lower: 1n + value: { + higher: MaxU256 - 1n, + lower: 1n + }, + error: 0n }) - // expected: 13407807929942597099574024998205846127479365820592393377723561443721764030073315392623399665776056285720014482370779510884422601683867654778417822746804225 - // real: 13407807929942597099574024998205846127479365820592393377723561443721764030073315392623399665776056285720014482370779510884422601683867654778417822746804225 } { - const a = 500n + const a = MaxU256 const b = 0n - const result = (await uints.contractInstance.methods.bigMulDivUp256({ args: { a, b, bDenominator: 1n } })).returns - expect(result).toStrictEqual({ higher: 0n, lower: 0n }) + const bDenominator = 1n + const result = (await uints.methods.bigMulDivUp256({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 0n }, error: 0n }) + } + { + const a = 0n + const b = 0n + const bDenominator = 1n + const result = (await uints.methods.bigMulDivUp256({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 0n }, error: 0n }) } { const a = 100n - const b = 100n - const result = (await uints.contractInstance.methods.bigMulDivUp256({ args: { a, b, bDenominator: 100n } })) - .returns - expect(result).toStrictEqual({ higher: 0n, lower: 100n }) + const b = 200n + const bDenominator = 100n + const result = (await uints.methods.bigMulDivUp256({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 200n }, error: 0n }) } { - const a = 30n - const b = 1n - const result = (await uints.contractInstance.methods.bigMulDivUp256({ args: { a, b, bDenominator: 10n } })) - .returns - expect(result).toStrictEqual({ higher: 0n, lower: 3n }) + const a = 1n + const b = 150n + const bDenominator = 100n + const result = (await uints.methods.bigMulDivUp256({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ value: { higher: 0n, lower: 2n }, error: 0n }) } { - const a = 500n - const b = 4000n - const result = (await uints.contractInstance.methods.bigMulDivUp256({ args: { a, b, bDenominator: 1000n } })) - .returns - expect(result).toStrictEqual({ higher: 0n, lower: 2000n }) + const a = MaxU256 + const b = MaxU256 + const bDenominator = MaxU256 + const result = (await uints.methods.bigMulDivUp256({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ + value: { + higher: 0n, + lower: MaxU256 + }, + error: 0n + }) } + }) + + test('big mul div up 256 returns an error if b denominator is zero', async () => { { - const a = 10n - const b = 37n - const result = (await uints.contractInstance.methods.bigMulDivUp256({ args: { a, b, bDenominator: 100n } })) - .returns - expect(result).toStrictEqual({ higher: 0n, lower: 4n }) + const a = 1n + const b = 1n + const bDenominator = 0n + const result = (await uints.methods.bigMulDivUp256({ args: { a, b, bDenominator } })).returns + expect(result).toStrictEqual({ + value: { higher: MaxU256, lower: MaxU256 }, + error: ArithmeticError.MulNotPositiveDenominator + }) } }) test('overflowing add', async () => { - const uints = await deployUints(sender) { - const a = 10n - const b = 20n - const result = (await uints.contractInstance.methods.overflowingAdd({ args: { a, b } })).returns - expect(result).toStrictEqual([30n, 0n]) + const a = 1n + const b = 2n + const result = (await uints.methods.overflowingAdd({ args: { a, b } })).returns + expect(result).toStrictEqual([3n, 0n]) + } + { + const a = MaxU256 + const b = 2n + const result = (await uints.methods.overflowingAdd({ args: { a, b } })).returns + expect(result).toStrictEqual([1n, 1n]) } { - const a = 115792089237316195423570985008687907853269984665640564039457584007913129639935n - const b = 20n - const result = (await uints.contractInstance.methods.overflowingAdd({ args: { a, b } })).returns - expect(result).toStrictEqual([19n, 1n]) + const a = MaxU256 + const b = MaxU256 + const result = (await uints.methods.overflowingAdd({ args: { a, b } })).returns + expect(result).toStrictEqual([MaxU256 - 1n, 1n]) + } + { + const a = MaxU256 + const b = 0n + const result = (await uints.methods.overflowingAdd({ args: { a, b } })).returns + expect(result).toStrictEqual([MaxU256, 0n]) + } + { + const a = MaxU256 + const b = 1n + const result = (await uints.methods.overflowingAdd({ args: { a, b } })).returns + expect(result).toStrictEqual([0n, 1n]) } }) test('wrapping add', async () => { - const uints = await deployUints(sender) { - const a = 10n - const b = 20n - const result = (await uints.contractInstance.methods.wrappingAdd({ args: { a, b } })).returns - expect(result).toStrictEqual(30n) + const a = 1n + const b = 2n + const result = (await uints.methods.wrappingAdd({ args: { a, b } })).returns + expect(result).toStrictEqual(3n) + } + { + const a = MaxU256 + const b = 2n + const result = (await uints.methods.wrappingAdd({ args: { a, b } })).returns + expect(result).toStrictEqual(1n) + } + { + const a = MaxU256 + const b = MaxU256 + const result = (await uints.methods.wrappingAdd({ args: { a, b } })).returns + expect(result).toStrictEqual(MaxU256 - 1n) } { - const a = 115792089237316195423570985008687907853269984665640564039457584007913129639935n - const b = 20n - const result = (await uints.contractInstance.methods.wrappingAdd({ args: { a, b } })).returns - expect(result).toStrictEqual(19n) + const a = MaxU256 + const b = 0n + const result = (await uints.methods.wrappingAdd({ args: { a, b } })).returns + expect(result).toStrictEqual(MaxU256) + } + { + const a = MaxU256 + const b = 1n + const result = (await uints.methods.wrappingAdd({ args: { a, b } })).returns + expect(result).toStrictEqual(0n) } }) })