From 652971fa52ebcaca27c6dbb12af6c0e01d82d183 Mon Sep 17 00:00:00 2001 From: Facu Spagnuolo Date: Wed, 12 Nov 2025 20:40:21 -0300 Subject: [PATCH 1/4] examples: standardize amounts and logs --- examples/1-simple-transfer/tests/task.spec.ts | 11 ++++++-- .../10-dollar-cost-averaging/manifest.yaml | 4 +-- examples/10-dollar-cost-averaging/src/task.ts | 27 +++++++------------ examples/11-automated-refunds/manifest.yaml | 10 +++---- examples/11-automated-refunds/src/task.ts | 8 +++--- .../manifest.yaml | 4 +-- .../2-simple-transfer-with-inputs/src/task.ts | 6 +++-- .../tests/task.spec.ts | 21 ++++++++++----- .../manifest.yaml | 6 ++--- .../3-transfer-balance-threshold/src/task.ts | 12 ++++++--- .../tests/task.spec.ts | 23 +++++++++++----- .../manifest.yaml | 6 ++--- .../src/task.ts | 10 ++++--- .../tests/task.spec.ts | 12 ++++----- .../5-invest-aave-idle-balance/manifest.yaml | 4 +-- .../5-invest-aave-idle-balance/src/task.ts | 6 ++--- .../tests/task.spec.ts | 4 +-- .../manifest.yaml | 4 +-- .../src/task.ts | 17 ++++++------ .../tests/task.spec.ts | 4 +-- examples/8-rebalancing-tokens/src/task.ts | 12 ++++----- examples/9-subgraph-query/manifest.yaml | 2 +- examples/9-subgraph-query/src/task.ts | 11 ++++---- examples/9-subgraph-query/tests/task.spec.ts | 2 +- 24 files changed, 124 insertions(+), 102 deletions(-) diff --git a/examples/1-simple-transfer/tests/task.spec.ts b/examples/1-simple-transfer/tests/task.spec.ts index f8e568b..4f20449 100644 --- a/examples/1-simple-transfer/tests/task.spec.ts +++ b/examples/1-simple-transfer/tests/task.spec.ts @@ -1,5 +1,5 @@ import { OpType } from '@mimicprotocol/sdk' -import { Context, runTask, Transfer } from '@mimicprotocol/test-ts' +import { Context, ContractCallMock, runTask, Transfer } from '@mimicprotocol/test-ts' import { expect } from 'chai' describe('Task', () => { @@ -11,8 +11,15 @@ describe('Task', () => { timestamp: Date.now(), } + const calls: ContractCallMock[] = [ + { + request: { to: '0x7F5c764cBc14f9669B88837ca1490cCa17c31607', chainId: 10, fnSelector: '0x313ce567' }, // decimals + response: { value: '6', abiType: 'uint8' }, + }, + ] + it('produces the expected intents', async () => { - const result = await runTask(taskDir, context) + const result = await runTask(taskDir, context, { calls }) expect(result.success).to.be.true expect(result.timestamp).to.be.equal(context.timestamp) diff --git a/examples/10-dollar-cost-averaging/manifest.yaml b/examples/10-dollar-cost-averaging/manifest.yaml index 34e7a03..8b56dc4 100644 --- a/examples/10-dollar-cost-averaging/manifest.yaml +++ b/examples/10-dollar-cost-averaging/manifest.yaml @@ -5,6 +5,6 @@ inputs: - chainId: uint32 - tokenIn: address - tokenOut: address - - amount: string # "1.5" = 1.5 tokenIn - - slippageBps: uint16 # 100 = 1% + - amount: string # e.g., '1.5' = 1.5 tokenIn + - slippageBps: uint16 # e.g., 50 = 0.50% - recipient: address diff --git a/examples/10-dollar-cost-averaging/src/task.ts b/examples/10-dollar-cost-averaging/src/task.ts index 368e5ac..131803c 100644 --- a/examples/10-dollar-cost-averaging/src/task.ts +++ b/examples/10-dollar-cost-averaging/src/task.ts @@ -2,33 +2,26 @@ import { BigInt, ERC20Token, log, SwapBuilder, TokenAmount } from '@mimicprotoco import { inputs } from './types' +const BPS_DENOMINATOR = BigInt.fromI32(10_000) + export default function main(): void { // Log input parameters - log.info('Starting DCA swap: amountFromToken={}, slippageBps={}, chainId={}, recipient={}', [ - inputs.amount, - inputs.slippageBps.toString(), - inputs.chainId.toString(), - inputs.recipient.toString(), - ]) + log.info( + `Starting DCA swap: amountFromToken=${inputs.amount}, slippageBps=${inputs.slippageBps}, chainId=${inputs.chainId}, recipient=${inputs.recipient}` + ) // Create token instances const tokenIn = ERC20Token.fromAddress(inputs.tokenIn, inputs.chainId) const tokenOut = ERC20Token.fromAddress(inputs.tokenOut, inputs.chainId) - // Create amount from decimal string and estimatate amount out + // Create amount from decimal string and estimate amount out const amountIn = TokenAmount.fromStringDecimal(tokenIn, inputs.amount) - const amountOut = amountIn.toTokenAmount(tokenOut) + const expectedOut = amountIn.toTokenAmount(tokenOut) // Apply slippage to calculate the expected minimum amount out - const basisPoints = BigInt.fromU16(10000) - const slippageBps = basisPoints.minus(BigInt.fromU16(inputs.slippageBps)) - const minAmountOut = amountOut.times(slippageBps).div(basisPoints) - - log.info('Calculated minOut: {} (equivalent={}, slippageBps={})', [ - minAmountOut.toString(), - amountOut.toString(), - inputs.slippageBps.toString(), - ]) + const slippageFactor = BPS_DENOMINATOR.minus(BigInt.fromI32(inputs.slippageBps as i32)) + const minAmountOut = expectedOut.times(slippageFactor).div(BPS_DENOMINATOR) + log.info(`Calculated minOut: ${minAmountOut} (equivalent=${expectedOut}, slippageBps=${inputs.slippageBps})`) // Create and execute swap SwapBuilder.forChain(inputs.chainId) diff --git a/examples/11-automated-refunds/manifest.yaml b/examples/11-automated-refunds/manifest.yaml index 73a18fd..c0579eb 100644 --- a/examples/11-automated-refunds/manifest.yaml +++ b/examples/11-automated-refunds/manifest.yaml @@ -2,8 +2,8 @@ version: 1.0.0 name: Client refunds description: Refunds clients based on past orders inputs: - - chainId: uint32 # Example: 42161 for Arbitrum - - token: string # Token contract address - - amount: string # Amount in wei (as string) - - recipient: string # Recipient address - - maxFee: string # Max fee in wei (as string) + - chainId: uint32 + - token: string + - amount: string # Amount in wei (as string) + - recipient: address + - maxFee: string # e.g., '0.01' = 0.01 of the given token diff --git a/examples/11-automated-refunds/src/task.ts b/examples/11-automated-refunds/src/task.ts index 3d58c97..62144ad 100644 --- a/examples/11-automated-refunds/src/task.ts +++ b/examples/11-automated-refunds/src/task.ts @@ -1,4 +1,4 @@ -import { Address, BigInt, ERC20Token, log, TokenAmount, Transfer } from '@mimicprotocol/lib-ts' +import { BigInt, ERC20Token, log, TokenAmount, Transfer } from '@mimicprotocol/lib-ts' import { inputs } from './types' @@ -6,9 +6,7 @@ export default function main(): void { const token = ERC20Token.fromString(inputs.token, inputs.chainId) const tokenAmount = TokenAmount.fromStringDecimal(token, inputs.amount) const maxFee = BigInt.fromStringDecimal(inputs.maxFee, token.decimals) - const recipient = Address.fromString(inputs.recipient) - Transfer.create(token, tokenAmount.amount, recipient, maxFee).send() - - log.info('Created transfer intent of {}', [tokenAmount]) + Transfer.create(token, tokenAmount.amount, inputs.recipient, maxFee).send() + log.info(`Created transfer intent of ${tokenAmount}`) } diff --git a/examples/2-simple-transfer-with-inputs/manifest.yaml b/examples/2-simple-transfer-with-inputs/manifest.yaml index 99242ac..0d8fdd4 100644 --- a/examples/2-simple-transfer-with-inputs/manifest.yaml +++ b/examples/2-simple-transfer-with-inputs/manifest.yaml @@ -4,6 +4,6 @@ description: Automated task to execute parameterized transfers inputs: - chainId: uint32 - token: address - - amount: uint256 + - amount: string # e.g., '15.3' = 15.3 of the given token - recipient: address - - maxFee: uint256 + - maxFee: string # e.g., '0.01' = 0.01 of the given token diff --git a/examples/2-simple-transfer-with-inputs/src/task.ts b/examples/2-simple-transfer-with-inputs/src/task.ts index f9150aa..115fe21 100644 --- a/examples/2-simple-transfer-with-inputs/src/task.ts +++ b/examples/2-simple-transfer-with-inputs/src/task.ts @@ -1,8 +1,10 @@ -import { ERC20Token, Transfer } from '@mimicprotocol/lib-ts' +import { BigInt, ERC20Token, Transfer } from '@mimicprotocol/lib-ts' import { inputs } from './types' export default function main(): void { const token = ERC20Token.fromAddress(inputs.token, inputs.chainId) - Transfer.create(token, inputs.amount, inputs.recipient, inputs.maxFee).send() + const amount = BigInt.fromStringDecimal(inputs.amount, token.decimals) + const maxFee = BigInt.fromStringDecimal(inputs.maxFee, token.decimals) + Transfer.create(token, amount, inputs.recipient, maxFee).send() } diff --git a/examples/2-simple-transfer-with-inputs/tests/task.spec.ts b/examples/2-simple-transfer-with-inputs/tests/task.spec.ts index e7674c7..52b9c58 100644 --- a/examples/2-simple-transfer-with-inputs/tests/task.spec.ts +++ b/examples/2-simple-transfer-with-inputs/tests/task.spec.ts @@ -1,5 +1,5 @@ -import { OpType } from '@mimicprotocol/sdk' -import { Context, runTask, Transfer } from '@mimicprotocol/test-ts' +import { fp, OpType } from '@mimicprotocol/sdk' +import { Context, ContractCallMock, runTask, Transfer } from '@mimicprotocol/test-ts' import { expect } from 'chai' describe('Task', () => { @@ -14,13 +14,20 @@ describe('Task', () => { const inputs = { chainId: 10, // Optimism token: '0x7f5c764cbc14f9669b88837ca1490cca17c31607', // USDC - amount: '1000000', // 1 USDC + amount: '1.5', // 1.5 USDC recipient: '0xbce3248ede29116e4bd18416dcc2dfca668eeb84', - maxFee: '100000', // 0.1 USDC + maxFee: '0.1', } + const calls: ContractCallMock[] = [ + { + request: { to: inputs.token, chainId: inputs.chainId, fnSelector: '0x313ce567' }, // decimals + response: { value: '6', abiType: 'uint8' }, + }, + ] + it('produces the expected intents', async () => { - const result = await runTask(taskDir, context, { inputs }) + const result = await runTask(taskDir, context, { inputs, calls }) expect(result.success).to.be.true expect(result.timestamp).to.be.equal(context.timestamp) @@ -33,11 +40,11 @@ describe('Task', () => { expect(intents[0].chainId).to.be.equal(inputs.chainId) expect(intents[0].maxFees).to.have.lengthOf(1) expect(intents[0].maxFees[0].token).to.be.equal(inputs.token) - expect(intents[0].maxFees[0].amount).to.be.equal(inputs.maxFee) + expect(intents[0].maxFees[0].amount).to.be.equal(fp(inputs.maxFee, 6).toString()) expect(intents[0].transfers).to.have.lengthOf(1) expect(intents[0].transfers[0].token).to.be.equal(inputs.token) - expect(intents[0].transfers[0].amount).to.be.equal(inputs.amount) + expect(intents[0].transfers[0].amount).to.be.equal(fp(inputs.amount, 6).toString()) expect(intents[0].transfers[0].recipient).to.be.equal(inputs.recipient) }) }) diff --git a/examples/3-transfer-balance-threshold/manifest.yaml b/examples/3-transfer-balance-threshold/manifest.yaml index b3e9cd5..1e03ca5 100644 --- a/examples/3-transfer-balance-threshold/manifest.yaml +++ b/examples/3-transfer-balance-threshold/manifest.yaml @@ -4,9 +4,9 @@ description: Automated task to execute parameterized transfers based on balance inputs: - chainId: uint32 - token: address - - amount: uint256 + - amount: string # e.g., '10.2' = 10.2 of the given token - recipient: address - - maxFee: uint256 - - threshold: uint256 + - maxFee: string # e.g., '0.01' = 0.01 of the given token + - threshold: string # e.g., '20.5' = 20.5 of the given token abis: - ERC20: ./abis/ERC20.json diff --git a/examples/3-transfer-balance-threshold/src/task.ts b/examples/3-transfer-balance-threshold/src/task.ts index 6b7f922..7c5e685 100644 --- a/examples/3-transfer-balance-threshold/src/task.ts +++ b/examples/3-transfer-balance-threshold/src/task.ts @@ -1,4 +1,4 @@ -import { ERC20Token, Transfer } from '@mimicprotocol/lib-ts' +import { BigInt, ERC20Token, Transfer } from '@mimicprotocol/lib-ts' import { ERC20 } from './types/ERC20' import { inputs } from './types' @@ -7,8 +7,12 @@ export default function main(): void { const tokenContract = new ERC20(inputs.token, inputs.chainId) const balance = tokenContract.balanceOf(inputs.recipient) - if (balance.lt(inputs.threshold)) { - const token = ERC20Token.fromAddress(inputs.token, inputs.chainId) - Transfer.create(token, inputs.amount, inputs.recipient, inputs.maxFee).send() + const token = ERC20Token.fromAddress(inputs.token, inputs.chainId) + const threshold = BigInt.fromStringDecimal(inputs.threshold, token.decimals) + + if (balance.lt(threshold)) { + const amount = BigInt.fromStringDecimal(inputs.amount, token.decimals) + const maxFee = BigInt.fromStringDecimal(inputs.maxFee, token.decimals) + Transfer.create(token, amount, inputs.recipient, maxFee).send() } } diff --git a/examples/3-transfer-balance-threshold/tests/task.spec.ts b/examples/3-transfer-balance-threshold/tests/task.spec.ts index 0d48b4d..37d5529 100644 --- a/examples/3-transfer-balance-threshold/tests/task.spec.ts +++ b/examples/3-transfer-balance-threshold/tests/task.spec.ts @@ -1,4 +1,4 @@ -import { OpType } from '@mimicprotocol/sdk' +import { fp, OpType } from '@mimicprotocol/sdk' import { Context, ContractCallMock, runTask, Transfer } from '@mimicprotocol/test-ts' import { expect } from 'chai' @@ -14,10 +14,10 @@ describe('Task', () => { const inputs = { chainId: 10, // Optimism token: '0x7f5c764cbc14f9669b88837ca1490cca17c31607', // USDC - amount: '1000000', // 1 USDC + amount: '1', // 1 USDC recipient: '0xbce3248ede29116e4bd18416dcc2dfca668eeb84', - maxFee: '100000', // 0.1 USDC - threshold: '10000000', // 10 USDC + maxFee: '0.1', // 0.1 USDC + threshold: '10.2', // 10 USDC } const buildCalls = (balance: string): ContractCallMock[] => [ @@ -38,6 +38,17 @@ describe('Task', () => { abiType: 'uint256', }, }, + { + request: { + to: inputs.token, + chainId: inputs.chainId, + fnSelector: '0x313ce567', // `decimals` + }, + response: { + value: '6', + abiType: 'uint8', + }, + }, ] describe('when the balance is below the threshold', () => { @@ -58,11 +69,11 @@ describe('Task', () => { expect(intents[0].chainId).to.be.equal(inputs.chainId) expect(intents[0].maxFees).to.have.lengthOf(1) expect(intents[0].maxFees[0].token).to.be.equal(inputs.token) - expect(intents[0].maxFees[0].amount).to.be.equal(inputs.maxFee) + expect(intents[0].maxFees[0].amount).to.be.equal(fp(inputs.maxFee, 6).toString()) expect(intents[0].transfers).to.have.lengthOf(1) expect(intents[0].transfers[0].token).to.be.equal(inputs.token) - expect(intents[0].transfers[0].amount).to.be.equal(inputs.amount) + expect(intents[0].transfers[0].amount).to.be.equal(fp(inputs.amount, 6).toString()) expect(intents[0].transfers[0].recipient).to.be.equal(inputs.recipient) }) }) diff --git a/examples/4-transfer-balance-threshold-with-oracles/manifest.yaml b/examples/4-transfer-balance-threshold-with-oracles/manifest.yaml index e5bcfde..b256027 100644 --- a/examples/4-transfer-balance-threshold-with-oracles/manifest.yaml +++ b/examples/4-transfer-balance-threshold-with-oracles/manifest.yaml @@ -4,9 +4,9 @@ description: Automated task to execute parameterized transfers based on balance inputs: - chainId: uint32 - token: address - - amount: uint256 + - amount: string # e.g., '10.2' = 10.2 of the given token - recipient: address - - maxFee: uint256 - - thresholdUSD: uint32 + - maxFee: string # e.g., '0.01' = 0.01 of the given token + - thresholdUsd: string # e.g., '30.5' = 30.5 USD abis: - ERC20: ./abis/ERC20.json diff --git a/examples/4-transfer-balance-threshold-with-oracles/src/task.ts b/examples/4-transfer-balance-threshold-with-oracles/src/task.ts index e9c835f..b7f9770 100644 --- a/examples/4-transfer-balance-threshold-with-oracles/src/task.ts +++ b/examples/4-transfer-balance-threshold-with-oracles/src/task.ts @@ -1,4 +1,4 @@ -import { ERC20Token, log, TokenAmount, Transfer, USD } from '@mimicprotocol/lib-ts' +import { BigInt, ERC20Token, log, TokenAmount, Transfer, USD } from '@mimicprotocol/lib-ts' import { ERC20 } from './types/ERC20' import { inputs } from './types' @@ -9,10 +9,12 @@ export default function main(): void { const token = ERC20Token.fromAddress(inputs.token, inputs.chainId) const balanceInUsd = TokenAmount.fromBigInt(token, balance).toUsd() - const thresholdUsd = USD.fromI32(inputs.thresholdUSD) - log.info('Balance in USD: ' + balanceInUsd.toString()) + const thresholdUsd = USD.fromStringDecimal(inputs.thresholdUsd) + log.info(`Balance in USD: ${balanceInUsd}`) if (balanceInUsd.lt(thresholdUsd)) { - Transfer.create(token, inputs.amount, inputs.recipient, inputs.maxFee).send() + const amount = BigInt.fromStringDecimal(inputs.amount, token.decimals) + const maxFee = BigInt.fromStringDecimal(inputs.maxFee, token.decimals) + Transfer.create(token, amount, inputs.recipient, maxFee).send() } } diff --git a/examples/4-transfer-balance-threshold-with-oracles/tests/task.spec.ts b/examples/4-transfer-balance-threshold-with-oracles/tests/task.spec.ts index f7b4409..b67e717 100644 --- a/examples/4-transfer-balance-threshold-with-oracles/tests/task.spec.ts +++ b/examples/4-transfer-balance-threshold-with-oracles/tests/task.spec.ts @@ -1,4 +1,4 @@ -import { OpType } from '@mimicprotocol/sdk' +import { fp, OpType } from '@mimicprotocol/sdk' import { Context, ContractCallMock, GetPriceMock, runTask, Transfer } from '@mimicprotocol/test-ts' import { expect } from 'chai' @@ -14,10 +14,10 @@ describe('Task', () => { const inputs = { chainId: 10, // Optimism token: '0x7f5c764cbc14f9669b88837ca1490cca17c31607', // USDC - amount: '1000000', // 1 USDC + amount: '1', // 1 USDC recipient: '0xbce3248ede29116e4bd18416dcc2dfca668eeb84', - maxFee: '100000', // 0.1 USDC - thresholdUSD: 10, // 10 USD + maxFee: '0.1', // 0.1 USDC + thresholdUsd: '10.5', // 10 USD } const prices: GetPriceMock[] = [ @@ -79,11 +79,11 @@ describe('Task', () => { expect(intents[0].chainId).to.be.equal(inputs.chainId) expect(intents[0].maxFees.length).to.be.equal(1) expect(intents[0].maxFees[0].token).to.be.equal(inputs.token) - expect(intents[0].maxFees[0].amount).to.be.equal(inputs.maxFee) + expect(intents[0].maxFees[0].amount).to.be.equal(fp(inputs.maxFee, 6).toString()) expect(intents[0].transfers).to.have.lengthOf(1) expect(intents[0].transfers[0].token).to.be.equal(inputs.token) - expect(intents[0].transfers[0].amount).to.be.equal(inputs.amount) + expect(intents[0].transfers[0].amount).to.be.equal(fp(inputs.amount, 6).toString()) expect(intents[0].transfers[0].recipient).to.be.equal(inputs.recipient) expect(result.logs).to.have.lengthOf(1) diff --git a/examples/5-invest-aave-idle-balance/manifest.yaml b/examples/5-invest-aave-idle-balance/manifest.yaml index 73785e9..edca98f 100644 --- a/examples/5-invest-aave-idle-balance/manifest.yaml +++ b/examples/5-invest-aave-idle-balance/manifest.yaml @@ -4,9 +4,9 @@ description: Automated task to invest in AAVE idle balance above certain thresho inputs: - chainId: uint32 - aToken: address - - thresholdUSD: uint32 - smartAccount: address - - maxFee: string + - thresholdUsd: string # e.g., '30.5' = 30.5 USD + - maxFeeUsd: string # e.g., '0.05' = 0.05 USD abis: - ERC20: ./abis/ERC20.json - AaveToken: ./abis/AaveToken.json diff --git a/examples/5-invest-aave-idle-balance/src/task.ts b/examples/5-invest-aave-idle-balance/src/task.ts index 267d075..dd37297 100644 --- a/examples/5-invest-aave-idle-balance/src/task.ts +++ b/examples/5-invest-aave-idle-balance/src/task.ts @@ -18,8 +18,8 @@ export default function main(): void { const underlyingTokenBalanceAmount = underlyingTokenContract.balanceOf(inputs.smartAccount) const underlyingTokenBalance = TokenAmount.fromBigInt(underlyingToken, underlyingTokenBalanceAmount) const underlyingTokenBalanceInUsd = underlyingTokenBalance.toUsd() - const thresholdUsd = USD.fromI32(inputs.thresholdUSD) - log.info('Underlying balance in USD: ' + underlyingTokenBalanceInUsd.toString()) + const thresholdUsd = USD.fromStringDecimal(inputs.thresholdUsd) + log.info(`Underlying balance in USD: ${underlyingTokenBalanceInUsd}`) if (underlyingTokenBalanceInUsd.lt(thresholdUsd)) { log.info('Threshold not met') @@ -33,6 +33,6 @@ export default function main(): void { ) // Use mimic credits to pay for the transaction fee - const feeWithCredits = TokenAmount.fromStringDecimal(DenominationToken.USD(), inputs.maxFee) + const feeWithCredits = TokenAmount.fromStringDecimal(DenominationToken.USD(), inputs.maxFeeUsd) calls.addUser(inputs.smartAccount).addMaxFee(feeWithCredits).build().send() } diff --git a/examples/5-invest-aave-idle-balance/tests/task.spec.ts b/examples/5-invest-aave-idle-balance/tests/task.spec.ts index b00110d..3b74e1a 100644 --- a/examples/5-invest-aave-idle-balance/tests/task.spec.ts +++ b/examples/5-invest-aave-idle-balance/tests/task.spec.ts @@ -22,8 +22,8 @@ describe('Task', () => { chainId: 10, // Optimism aToken: '0x625e7708f30ca75bfd92586e17077590c60eb4cd', // Aave Optimism USDC smartAccount: '0x756f45e3fa69347a9a973a725e3c98bc4db0b5a1', - thresholdUSD: 10, // 10 USD - maxFee: '0.1', // 0.1 USD + thresholdUsd: '10.5', // 10 USD + maxFeeUsd: '0.1', // 0.1 USD } const underlyingToken = '0x7f5c764cbc14f9669b88837ca1490cca17c31607' // USDC diff --git a/examples/6-withdraw-from-aave-balance-threshold/manifest.yaml b/examples/6-withdraw-from-aave-balance-threshold/manifest.yaml index 3b0e7b5..b15cd26 100644 --- a/examples/6-withdraw-from-aave-balance-threshold/manifest.yaml +++ b/examples/6-withdraw-from-aave-balance-threshold/manifest.yaml @@ -4,9 +4,9 @@ description: Automated task to withdraw from AAVE based on balance threshold in inputs: - chainId: uint32 - aToken: address - - slippage: uint32 - recipient: address - - thresholdUSD: uint32 + - slippageBps: uint16 # e.g., 50 = 0.50% + - thresholdUsd: string # e.g., '30.5' = 30.5 USD abis: - ERC20: ./abis/ERC20.json - AaveToken: ./abis/AaveToken.json diff --git a/examples/6-withdraw-from-aave-balance-threshold/src/task.ts b/examples/6-withdraw-from-aave-balance-threshold/src/task.ts index 6e77c70..f373df7 100644 --- a/examples/6-withdraw-from-aave-balance-threshold/src/task.ts +++ b/examples/6-withdraw-from-aave-balance-threshold/src/task.ts @@ -4,8 +4,10 @@ import { AaveToken } from './types/AaveToken' import { ERC20 } from './types/ERC20' import { inputs } from './types' +const BPS_DENOMINATOR = BigInt.fromI32(10_000) + export default function main(): void { - if (inputs.slippage > 100) throw new Error('Slippage must be between 0 and 100') + if (BigInt.fromI32(inputs.slippageBps as i32) > BPS_DENOMINATOR) throw new Error('Slippage must be between 0 and 100') const aToken = ERC20Token.fromAddress(inputs.aToken, inputs.chainId) const aTokenContract = new AaveToken(aToken.address, aToken.chainId) @@ -17,8 +19,8 @@ export default function main(): void { const underlyingTokenBalanceAmount = underlyingTokenContract.balanceOf(inputs.recipient) const underlyingTokenBalance = TokenAmount.fromBigInt(underlyingToken, underlyingTokenBalanceAmount) const underlyingTokenBalanceInUsd = underlyingTokenBalance.toUsd() - const thresholdUsd = USD.fromI32(inputs.thresholdUSD) - log.info('Recipient underlying balance in USD: ' + underlyingTokenBalanceInUsd.toString()) + const thresholdUsd = USD.fromStringDecimal(inputs.thresholdUsd) + log.info(`Recipient underlying balance in USD: ${underlyingTokenBalanceInUsd}`) if (underlyingTokenBalanceInUsd.gt(thresholdUsd)) log.info('Recipient threshold not met') else { @@ -31,12 +33,9 @@ export default function main(): void { if (aTokenBalance.lt(aTokenDepositAmount)) log.info('Sender balance not enough') else { - const slippagePct = BigInt.fromI32(100).minus(BigInt.fromI32(inputs.slippage)) - const minAmountOut = aTokenDepositAmount - .toTokenAmount(underlyingToken) - .times(slippagePct) - .div(BigInt.fromI32(100)) - log.info('Min amount out: ' + minAmountOut.toString()) + const slippageFactor = BPS_DENOMINATOR.minus(BigInt.fromI32(inputs.slippageBps as i32)) + const minAmountOut = aTokenDepositAmount.toTokenAmount(underlyingToken).times(slippageFactor).div(BPS_DENOMINATOR) + log.info(`Min amount out: ${minAmountOut}`) SwapBuilder.forChain(inputs.chainId) .addTokenInFromTokenAmount(aTokenDepositAmount) diff --git a/examples/6-withdraw-from-aave-balance-threshold/tests/task.spec.ts b/examples/6-withdraw-from-aave-balance-threshold/tests/task.spec.ts index 2f93a0b..ab28ef5 100644 --- a/examples/6-withdraw-from-aave-balance-threshold/tests/task.spec.ts +++ b/examples/6-withdraw-from-aave-balance-threshold/tests/task.spec.ts @@ -14,8 +14,8 @@ describe('Task', () => { const inputs = { chainId: 10, // Optimism aToken: '0x625e7708f30ca75bfd92586e17077590c60eb4cd', // Aave Optimism USDC - slippage: 2, // 2% - thresholdUSD: 10, // 10 USD + slippageBps: 200, // 2% + thresholdUsd: '10', // 10.2 USD recipient: '0xbce3248ede29116e4bd18416dcc2dfca668eeb84', } diff --git a/examples/8-rebalancing-tokens/src/task.ts b/examples/8-rebalancing-tokens/src/task.ts index 0590305..8fc90c4 100644 --- a/examples/8-rebalancing-tokens/src/task.ts +++ b/examples/8-rebalancing-tokens/src/task.ts @@ -34,7 +34,7 @@ export default function main(): void { const targetBps = [inputs.targetBpsA as i32, inputs.targetBpsB as i32, inputs.targetBpsC as i32] const totalTargetBps = targetBps[0] + targetBps[1] + targetBps[2] - if (totalTargetBps != 10_000) throw new Error('Targets BPS must sum to 10000') + if (BigInt.fromI32(totalTargetBps) != BPS_DENOMINATOR) throw new Error('Targets BPS must sum to 10000') const tokensMetadata = [ ERC20Token.fromAddress(tokenAddresses[0], inputs.chainId), @@ -84,18 +84,18 @@ export default function main(): void { const surplusTokenIndex = surpluses[surplusIndex].index const deficitTokenIndex = deficits[deficitIndex].index - const amountInToken = movedUSD.toTokenAmount(tokensMetadata[surplusTokenIndex]) - const expectedOutToken = movedUSD.toTokenAmount(tokensMetadata[deficitTokenIndex]) + const tokenInAmount = movedUSD.toTokenAmount(tokensMetadata[surplusTokenIndex]) + const expectedTokenOutAmount = movedUSD.toTokenAmount(tokensMetadata[deficitTokenIndex]) const slippageFactor = BPS_DENOMINATOR.minus(BigInt.fromI32(inputs.slippageBps as i32)) - const minimumOutAmount = expectedOutToken.amount.times(slippageFactor).div(BPS_DENOMINATOR) + const minAmountOut = expectedTokenOutAmount.amount.times(slippageFactor).div(BPS_DENOMINATOR) Swap.create( inputs.chainId, tokensMetadata[surplusTokenIndex], - amountInToken.amount, + tokenInAmount.amount, tokensMetadata[deficitTokenIndex], - minimumOutAmount + minAmountOut ).send() surpluses[surplusIndex].amountUSD = surpluses[surplusIndex].amountUSD.minus(movedUSD) diff --git a/examples/9-subgraph-query/manifest.yaml b/examples/9-subgraph-query/manifest.yaml index 422bc6b..e092ba7 100644 --- a/examples/9-subgraph-query/manifest.yaml +++ b/examples/9-subgraph-query/manifest.yaml @@ -5,7 +5,7 @@ inputs: - chainId: uint32 - tokenIn: address - tokenOut: address - - slippage: uint32 + - slippageBps: uint16 # e.g., 50 = 0.50% - subgraphId: string abis: - ERC20: ./abis/ERC20.json diff --git a/examples/9-subgraph-query/src/task.ts b/examples/9-subgraph-query/src/task.ts index c8f8c43..d5ddd4b 100644 --- a/examples/9-subgraph-query/src/task.ts +++ b/examples/9-subgraph-query/src/task.ts @@ -18,10 +18,11 @@ class UniswapPoolsData { } const PRICE_PRECISION: u8 = 40 +const BPS_DENOMINATOR = BigInt.fromI32(10_000) export default function main(): void { - if (inputs.slippage > 100) throw new Error('Slippage must be between 0 and 100') if (inputs.tokenIn == inputs.tokenOut) throw new Error('Token in and out must be different') + if (BigInt.fromI32(inputs.slippageBps as i32) > BPS_DENOMINATOR) throw new Error('Slippage must be between 0 and 100') const me = environment.getContext().user const amountIn = new ERC20(inputs.tokenIn, inputs.chainId).balanceOf(me) @@ -34,9 +35,8 @@ export default function main(): void { .times(price) .upscale(tokenOut.decimals) .downscale(tokenIn.decimals + PRICE_PRECISION) - const slippagePct = BigInt.fromI32(100).minus(BigInt.fromI32(inputs.slippage)) - const minAmountOut = expectedOut.times(slippagePct).div(BigInt.fromI32(100)) - + const slippageFactor = BPS_DENOMINATOR.minus(BigInt.fromI32(inputs.slippageBps as i32)) + const minAmountOut = expectedOut.times(slippageFactor).div(BPS_DENOMINATOR) Swap.create(inputs.chainId, tokenIn, amountIn, tokenOut, minAmountOut).send() } @@ -51,8 +51,7 @@ function getTokenPrice(chainId: i32, subgraphId: string, tokenIn: Address, token token1 = tokenIn } - const query = `{pools(where: { token0: "${token0.toString()}", token1: "${token1.toString()}" }) {token0Price token1Price}}` - + const query = `{pools(where: { token0: "${token0}", token1: "${token1}" }) {token0Price token1Price}}` const response = environment.subgraphQuery(chainId, subgraphId, query, null) const data = JSON.parse(response.data) diff --git a/examples/9-subgraph-query/tests/task.spec.ts b/examples/9-subgraph-query/tests/task.spec.ts index acfbf3d..b9c8fa9 100644 --- a/examples/9-subgraph-query/tests/task.spec.ts +++ b/examples/9-subgraph-query/tests/task.spec.ts @@ -16,7 +16,7 @@ describe('Task', () => { chainId: 1, tokenIn: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // USDC tokenOut: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // WETH - slippage: 1, + slippageBps: 100, // 1% } const subgraphQueries: SubgraphQueryMock[] = [ From 87b221c92a5f2efc7589b072fa27d5c72f465b23 Mon Sep 17 00:00:00 2001 From: Facu Spagnuolo Date: Thu, 13 Nov 2025 19:23:56 -0300 Subject: [PATCH 2/4] Apply suggestions from code review Co-authored-by: lgalende <63872655+lgalende@users.noreply.github.com> --- examples/2-simple-transfer-with-inputs/tests/task.spec.ts | 2 +- examples/3-transfer-balance-threshold/tests/task.spec.ts | 2 +- .../tests/task.spec.ts | 2 +- examples/5-invest-aave-idle-balance/tests/task.spec.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/2-simple-transfer-with-inputs/tests/task.spec.ts b/examples/2-simple-transfer-with-inputs/tests/task.spec.ts index 52b9c58..9668773 100644 --- a/examples/2-simple-transfer-with-inputs/tests/task.spec.ts +++ b/examples/2-simple-transfer-with-inputs/tests/task.spec.ts @@ -16,7 +16,7 @@ describe('Task', () => { token: '0x7f5c764cbc14f9669b88837ca1490cca17c31607', // USDC amount: '1.5', // 1.5 USDC recipient: '0xbce3248ede29116e4bd18416dcc2dfca668eeb84', - maxFee: '0.1', + maxFee: '0.1', // 0.1 USDC } const calls: ContractCallMock[] = [ diff --git a/examples/3-transfer-balance-threshold/tests/task.spec.ts b/examples/3-transfer-balance-threshold/tests/task.spec.ts index 37d5529..a36560f 100644 --- a/examples/3-transfer-balance-threshold/tests/task.spec.ts +++ b/examples/3-transfer-balance-threshold/tests/task.spec.ts @@ -17,7 +17,7 @@ describe('Task', () => { amount: '1', // 1 USDC recipient: '0xbce3248ede29116e4bd18416dcc2dfca668eeb84', maxFee: '0.1', // 0.1 USDC - threshold: '10.2', // 10 USDC + threshold: '10.2', // 10.2 USDC } const buildCalls = (balance: string): ContractCallMock[] => [ diff --git a/examples/4-transfer-balance-threshold-with-oracles/tests/task.spec.ts b/examples/4-transfer-balance-threshold-with-oracles/tests/task.spec.ts index b67e717..51ae567 100644 --- a/examples/4-transfer-balance-threshold-with-oracles/tests/task.spec.ts +++ b/examples/4-transfer-balance-threshold-with-oracles/tests/task.spec.ts @@ -17,7 +17,7 @@ describe('Task', () => { amount: '1', // 1 USDC recipient: '0xbce3248ede29116e4bd18416dcc2dfca668eeb84', maxFee: '0.1', // 0.1 USDC - thresholdUsd: '10.5', // 10 USD + thresholdUsd: '10.5', // 10.5 USD } const prices: GetPriceMock[] = [ diff --git a/examples/5-invest-aave-idle-balance/tests/task.spec.ts b/examples/5-invest-aave-idle-balance/tests/task.spec.ts index 3b74e1a..3204c2f 100644 --- a/examples/5-invest-aave-idle-balance/tests/task.spec.ts +++ b/examples/5-invest-aave-idle-balance/tests/task.spec.ts @@ -22,7 +22,7 @@ describe('Task', () => { chainId: 10, // Optimism aToken: '0x625e7708f30ca75bfd92586e17077590c60eb4cd', // Aave Optimism USDC smartAccount: '0x756f45e3fa69347a9a973a725e3c98bc4db0b5a1', - thresholdUsd: '10.5', // 10 USD + thresholdUsd: '10.5', // 10.5 USD maxFeeUsd: '0.1', // 0.1 USD } From 3361ca367c69f73a14447ee43d546b6eedb6e0f6 Mon Sep 17 00:00:00 2001 From: Facu Spagnuolo Date: Thu, 13 Nov 2025 19:24:34 -0300 Subject: [PATCH 3/4] tasks: remove unnecessary mocked calls --- examples/1-simple-transfer/tests/task.spec.ts | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/examples/1-simple-transfer/tests/task.spec.ts b/examples/1-simple-transfer/tests/task.spec.ts index 4f20449..6f287cc 100644 --- a/examples/1-simple-transfer/tests/task.spec.ts +++ b/examples/1-simple-transfer/tests/task.spec.ts @@ -11,15 +11,8 @@ describe('Task', () => { timestamp: Date.now(), } - const calls: ContractCallMock[] = [ - { - request: { to: '0x7F5c764cBc14f9669B88837ca1490cCa17c31607', chainId: 10, fnSelector: '0x313ce567' }, // decimals - response: { value: '6', abiType: 'uint8' }, - }, - ] - it('produces the expected intents', async () => { - const result = await runTask(taskDir, context, { calls }) + const result = await runTask(taskDir, context) expect(result.success).to.be.true expect(result.timestamp).to.be.equal(context.timestamp) From 8a677935767c26d8d22d940d75cb57778798a987 Mon Sep 17 00:00:00 2001 From: Facu Spagnuolo Date: Thu, 13 Nov 2025 19:35:27 -0300 Subject: [PATCH 4/4] fixup --- examples/1-simple-transfer/tests/task.spec.ts | 2 +- .../6-withdraw-from-aave-balance-threshold/tests/task.spec.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/1-simple-transfer/tests/task.spec.ts b/examples/1-simple-transfer/tests/task.spec.ts index 6f287cc..f8e568b 100644 --- a/examples/1-simple-transfer/tests/task.spec.ts +++ b/examples/1-simple-transfer/tests/task.spec.ts @@ -1,5 +1,5 @@ import { OpType } from '@mimicprotocol/sdk' -import { Context, ContractCallMock, runTask, Transfer } from '@mimicprotocol/test-ts' +import { Context, runTask, Transfer } from '@mimicprotocol/test-ts' import { expect } from 'chai' describe('Task', () => { diff --git a/examples/6-withdraw-from-aave-balance-threshold/tests/task.spec.ts b/examples/6-withdraw-from-aave-balance-threshold/tests/task.spec.ts index ab28ef5..59773e8 100644 --- a/examples/6-withdraw-from-aave-balance-threshold/tests/task.spec.ts +++ b/examples/6-withdraw-from-aave-balance-threshold/tests/task.spec.ts @@ -15,7 +15,7 @@ describe('Task', () => { chainId: 10, // Optimism aToken: '0x625e7708f30ca75bfd92586e17077590c60eb4cd', // Aave Optimism USDC slippageBps: 200, // 2% - thresholdUsd: '10', // 10.2 USD + thresholdUsd: '10', // 10 USD recipient: '0xbce3248ede29116e4bd18416dcc2dfca668eeb84', }