Skip to content

Replace COA.call with COA.callWithSigAndArgs for reduced computation cost#150

Open
m-Peter wants to merge 3 commits intomainfrom
mpeter/optimiza-evm-call-usage
Open

Replace COA.call with COA.callWithSigAndArgs for reduced computation cost#150
m-Peter wants to merge 3 commits intomainfrom
mpeter/optimiza-evm-call-usage

Conversation

@m-Peter
Copy link
Copy Markdown
Collaborator

@m-Peter m-Peter commented Mar 16, 2026

Related: onflow/flow-go#8401
Closes: #149

Description

Previously, to perform contract calls using a COA, it was necessary to produce the callData on Cadence side:

let calldata = EVM.encodeABIWithSignature(signature, args)

To be able to ABI-decode the returned data from the COA call, another step was needed:

let decoded = EVM.decodeABI(types: [Type<[UInt256]>()], data: res.data)
let amountsOut = decoded[0] as! [UInt256]

After doing some profiling on Cadence transactions, the computation cost of ABI encoding/decoding, amounted to about 15%-20% of the total computation, which is not trivial.

To optimize this case, we have a new wrapper function, callWithSigAndArgs, which does all this more efficiently:

coa.callWithSigAndArgs(
    to: to,
    signature: "approve(address,uint256)",
    args: [self.routerAddress, evmAmountIn],
    gasLimit: gasLimit,
    value: valueBalance.attoflow,
    resultTypes: [Type<[UInt256]>()]
)

We do the same for dryCall, by replacing it with dryCallWithSigAndArgs .

NOTE: CI is failing because we still need to deploy the EVM system contract on testnet/mainnet, for these new functions to be available.

@m-Peter m-Peter self-assigned this Mar 16, 2026
@m-Peter m-Peter added the enhancement New feature or request label Mar 16, 2026
@m-Peter m-Peter force-pushed the mpeter/optimiza-evm-call-usage branch 4 times, most recently from d5edfcc to e5ea029 Compare March 18, 2026 10:48
120_000
to: self.factoryAddress,
signature: "getPool(address,address,uint24)",
args: [tokenA, tokenB, UInt256(fee)],
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fee is of type UInt32, not sure why it is being casted to UInt256.

The Solidity function expects a uint24, as can be seen from the signature: getPool(address,address,uint24). Cadence doesn't have an equivalent of UInt24, but I suppose that a UInt32 would work just fine.

message: "unable to get pool: tokenA \(tokenA.toString()), tokenB \(tokenB.toString()), fee: \(fee)"
)

// ABI return is one 32-byte word; the last 20 bytes are the address
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is more efficient to use the ABI-decoded result from coa.dryCallWithSigAndArgs, than to do word manipulation in Cadence, on-chain.

@m-Peter m-Peter force-pushed the mpeter/optimiza-evm-call-usage branch from e5ea029 to 155943f Compare March 18, 2026 11:20
let s0Res = self._dryCallRaw(
// slot0() returns (uint160 sqrtPriceX96, int24, uint16, uint16, uint16, uint8, bool)
let types = [
Type<UInt>(), Type<Int32>(), Type<UInt16>(), Type<UInt16>(), Type<UInt16>(), Type<UInt8>(), Type<Bool>()
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UInt should be large enough to hold a uint160 Solidity value.
Int32 should also be large enough to hold a int24 Solidity value.

)!
assert(res.status == EVM.Status.successful, message: "token0() call failed")

let word = res.data
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is more efficient to use the ABI-decoded result from coa.dryCallWithSigAndArgs, than to do word manipulation in Cadence, on-chain.

@m-Peter m-Peter marked this pull request as ready for review March 18, 2026 11:39
@m-Peter m-Peter force-pushed the mpeter/optimiza-evm-call-usage branch from 155943f to f278020 Compare March 23, 2026 09:33
Copy link
Copy Markdown
Member

@joshuahannan joshuahannan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks okay to me, but I'm not very familiar with these contracts, so someone else should give a review too

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Optimization] Replace call & dryCall with their optimized versions

2 participants