Skip to content

Commit 9fee709

Browse files
committed
Replace COA.call with COA.callWithSigAndArgs for reduced computation cost
1 parent 2953e7d commit 9fee709

10 files changed

Lines changed: 260 additions & 116 deletions

File tree

cadence/contracts/connectors/evm/ERC4626SinkConnectors.cdc

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -131,19 +131,19 @@ access(all) contract ERC4626SinkConnectors {
131131

132132
// approve the ERC4626 vault to spend the assets on deposit
133133
let uintAmount = FlowEVMBridgeUtils.convertCadenceAmountToERC20Amount(amount, erc20Address: self.assetEVMAddress)
134-
let approveRes = self._call(
135-
to: self.assetEVMAddress,
136-
signature: "approve(address,uint256)",
137-
args: [self.vault, uintAmount],
138-
gasLimit: 500_000
139-
)!
134+
let approveRes = self._callWithSigAndArgs(
135+
to: self.assetEVMAddress,
136+
signature: "approve(address,uint256)",
137+
args: [self.vault, uintAmount],
138+
gasLimit: 500_000
139+
)!
140140
if approveRes.status != EVM.Status.successful {
141141
// Cadence panic reverts all EVM state changes in this transaction, so no need to bridge token back.
142142
panic(self._approveErrorMessage(ufixAmount: amount, uintAmount: uintAmount, approveRes: approveRes))
143143
}
144144

145145
// deposit the assets to the ERC4626 vault
146-
let depositRes = self._call(
146+
let depositRes = self._callWithSigAndArgs(
147147
to: self.vault,
148148
signature: "deposit(uint256,address)",
149149
args: [uintAmount, self.coa.borrow()!.address()],
@@ -182,6 +182,7 @@ access(all) contract ERC4626SinkConnectors {
182182
access(contract) fun setID(_ id: DeFiActions.UniqueIdentifier?) {
183183
self.uniqueID = id
184184
}
185+
185186
/// Performs a call to the ERC4626 vault
186187
///
187188
/// @param to The address of the ERC4626 vault
@@ -199,6 +200,30 @@ access(all) contract ERC4626SinkConnectors {
199200
}
200201
return nil
201202
}
203+
204+
/// Performs a call to the ERC4626 vault
205+
///
206+
/// @param to The address of the ERC4626 vault
207+
/// @param signature The signature of the function to call
208+
/// @param args The arguments to pass to the function
209+
/// @param gasLimit The gas limit to use for the call
210+
///
211+
/// @return The result of `nil` if the COA capability is invalid
212+
access(self)
213+
fun _callWithSigAndArgs(to: EVM.EVMAddress, signature: String, args: [AnyStruct], gasLimit: UInt64): EVM.ResultDecoded? {
214+
if let coa = self.coa.borrow() {
215+
return coa.callWithSigAndArgs(
216+
to: to,
217+
signature: signature,
218+
args: args,
219+
gasLimit: gasLimit,
220+
value: EVM.Balance(attoflow: 0),
221+
resultTypes: nil
222+
)
223+
}
224+
return nil
225+
}
226+
202227
/// Returns an error message for a failed approve call
203228
///
204229
/// @param ufixAmount: the amount of assets to approve
@@ -208,7 +233,7 @@ access(all) contract ERC4626SinkConnectors {
208233
/// @return an error message for a failed approve call
209234
///
210235
access(self)
211-
fun _approveErrorMessage(ufixAmount: UFix64, uintAmount: UInt256, approveRes: EVM.Result): String {
236+
fun _approveErrorMessage(ufixAmount: UFix64, uintAmount: UInt256, approveRes: EVM.ResultDecoded): String {
212237
return "Failed to approve ERC4626 vault \(self.vault.toString()) to spend \(ufixAmount) assets \(self.assetEVMAddress.toString()). approvee: \(self.vault.toString()), amount: \(uintAmount). Error code: \(approveRes.errorCode) Error message: \(approveRes.errorMessage)"
213238
}
214239
/// Returns an error message for a failed deposit call
@@ -220,7 +245,7 @@ access(all) contract ERC4626SinkConnectors {
220245
/// @return an error message for a failed deposit call
221246
///
222247
access(self)
223-
fun _depositErrorMessage(ufixAmount: UFix64, uintAmount: UInt256, depositRes: EVM.Result): String {
248+
fun _depositErrorMessage(ufixAmount: UFix64, uintAmount: UInt256, depositRes: EVM.ResultDecoded): String {
224249
let coaHex = self.coa.borrow()!.address().toString()
225250
return "Failed to deposit \(ufixAmount) assets \(self.assetEVMAddress.toString()) to ERC4626 vault \(self.vault.toString()). amount: \(uintAmount), to: \(coaHex). Error code: \(depositRes.errorCode) Error message: \(depositRes.errorMessage)"
226251
}

cadence/contracts/connectors/evm/UniswapV2SwapConnectors.cdc

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -227,19 +227,22 @@ access(all) contract UniswapV2SwapConnectors {
227227
coa.depositTokens(vault: <-exactVaultIn, feeProvider: feeVaultRef)
228228

229229
// approve the router to swap tokens
230-
var res = self.call(to: inTokenAddress,
230+
var res = self.callWithSigAndArgs(
231+
to: inTokenAddress,
231232
signature: "approve(address,uint256)",
232233
args: [self.routerAddress, evmAmountIn],
233234
gasLimit: 100_000,
234235
value: 0,
236+
resultTypes: nil,
235237
dryCall: false
236238
)!
237239
if res.status != EVM.Status.successful {
238240
UniswapV2SwapConnectors._callError("approve(address,uint256)",
239241
res, inTokenAddress, idType, id, self.getType())
240242
}
241243
// perform the swap
242-
res = self.call(to: self.routerAddress,
244+
res = self.callWithSigAndArgs(
245+
to: self.routerAddress,
243246
signature: "swapExactTokensForTokens(uint256,uint256,address[],address,uint256)", // amountIn, amountOutMin, path, to, deadline (timestamp)
244247
args: [
245248
evmAmountIn,
@@ -250,15 +253,15 @@ access(all) contract UniswapV2SwapConnectors {
250253
],
251254
gasLimit: 1_000_000,
252255
value: 0,
256+
resultTypes: [Type<[UInt256]>()],
253257
dryCall: false
254258
)!
255259
if res.status != EVM.Status.successful {
256260
// revert because the funds have already been deposited to the COA - a no-op would leave the funds in EVM
257261
UniswapV2SwapConnectors._callError("swapExactTokensForTokens(uint256,uint256,address[],address,uint256)",
258262
res, self.routerAddress, idType, id, self.getType())
259263
}
260-
let decoded = EVM.decodeABI(types: [Type<[UInt256]>()], data: res.data)
261-
let amountsOut = decoded[0] as! [UInt256]
264+
let amountsOut = res.results![0] as! [UInt256]
262265

263266
// withdraw tokens from EVM
264267
let outVault <- coa.withdrawTokens(type: self.outType(),
@@ -287,18 +290,19 @@ access(all) contract UniswapV2SwapConnectors {
287290
/// the values in, otherwise the array contains the values out for each swap along the path
288291
///
289292
access(self) fun getAmount(out: Bool, amount: UInt256, path: [EVM.EVMAddress]): UFix64? {
290-
let callRes = self.call(to: self.routerAddress,
293+
let callRes = self.callWithSigAndArgs(
294+
to: self.routerAddress,
291295
signature: out ? "getAmountsOut(uint,address[])" : "getAmountsIn(uint,address[])",
292296
args: [amount, path],
293297
gasLimit: 1_000_000,
294298
value: 0,
299+
resultTypes: [Type<[UInt256]>()],
295300
dryCall: true
296301
)
297302
if callRes == nil || callRes!.status != EVM.Status.successful {
298303
return nil
299304
}
300-
let decoded = EVM.decodeABI(types: [Type<[UInt256]>()], data: callRes!.data) // can revert if the type cannot be decoded
301-
let uintAmounts: [UInt256] = decoded.length > 0 ? decoded[0] as! [UInt256] : []
305+
let uintAmounts: [UInt256] = callRes.results!.length > 0 ? callRes.results![0] as! [UInt256] : []
302306
if uintAmounts.length == 0 {
303307
return nil
304308
} else if out {
@@ -343,11 +347,47 @@ access(all) contract UniswapV2SwapConnectors {
343347
}
344348
return nil
345349
}
350+
351+
/// Makes a call to the Swapper's routerEVMAddress via the contained COA Capability with the provided signature,
352+
/// args, and value. If flagged as dryCall, the more efficient and non-mutating COA.dryCall is used. A result is
353+
/// returned as long as the COA Capability is valid, otherwise `nil` is returned.
354+
access(self) fun callWithSigAndArgs(
355+
to: EVM.EVMAddress,
356+
signature: String,
357+
args: [AnyStruct],
358+
gasLimit: UInt64,
359+
value: UInt,
360+
resultTypes: [Type]?
361+
dryCall: Bool
362+
): EVM.ResultDecoded? {
363+
if let coa = self.borrowCOA() {
364+
if dryCall {
365+
return coa.dryCallWithSigAndArgs(
366+
to: to,
367+
signature: signature,
368+
args: args,
369+
gasLimit: gasLimit,
370+
value: EVM.Balance(attoflow: value),
371+
resultTypes: resultTypes
372+
)
373+
}
374+
375+
return coa.callWithSigAndArgs(
376+
to: to,
377+
signature: signature,
378+
args: args,
379+
gasLimit: gasLimit,
380+
value: EVM.Balance(attoflow: value),
381+
resultTypes: resultTypes
382+
)
383+
}
384+
return nil
385+
}
346386
}
347387

348-
/// Reverts with a message constructed from the provided args. Used in the event of a coa.call() error
388+
/// Reverts with a message constructed from the provided args. Used in the event of a coa.callWithSigAndArgs() error
349389
access(self)
350-
fun _callError(_ signature: String, _ res: EVM.Result,_ target: EVM.EVMAddress, _ uniqueIDType: String, _ id: String, _ swapperType: Type) {
390+
fun _callError(_ signature: String, _ res: EVM.ResultDecoded,_ target: EVM.EVMAddress, _ uniqueIDType: String, _ id: String, _ swapperType: Type) {
351391
panic("Call to \(target.toString()).\(signature) from Swapper \(swapperType.identifier) with UniqueIdentifier \(uniqueIDType) ID \(id) failed: \n\tStatus value: \(res.status.rawValue)\n\tError code: \(res.errorCode)\n\tErrorMessage: \(res.errorMessage)\n")
352392
}
353393
}

cadence/contracts/connectors/evm/UniswapV3SwapConnectors.cdc

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -660,12 +660,13 @@ access(all) contract UniswapV3SwapConnectors {
660660
let pathBytes = self._buildPathBytes(reverse: reverse, exactOutput: false, numHops: nil)
661661

662662
// Approve
663-
let allowanceRes = self._call(
663+
let allowanceRes = self._callWithSigAndArgs(
664664
to: inToken,
665665
signature: "approve(address,uint256)",
666666
args: [self.routerAddress, evmAmountIn],
667667
gasLimit: 120_000,
668-
value: 0
668+
value: 0,
669+
resultTypes: nil
669670
)!
670671
if allowanceRes.status != EVM.Status.successful {
671672
UniswapV3SwapConnectors._callError("approve(address,uint256)", allowanceRes, inToken, idType, id, self.getType())
@@ -693,39 +694,36 @@ access(all) contract UniswapV3SwapConnectors {
693694
amountOutMinimum: minOutUint
694695
)
695696

696-
let calldata = EVM.encodeABIWithSignature(
697-
"exactInput((bytes,address,uint256,uint256))",
698-
[exactInputParams]
699-
)
700-
701697
// Call the router with raw calldata
702-
let swapRes = self._callRaw(
698+
let swapRes = self._callWithSigAndArgs(
703699
to: self.routerAddress,
704-
calldata: calldata,
700+
signature: "exactInput((bytes,address,uint256,uint256))",
701+
args: [exactInputParams],
705702
gasLimit: 10_000_000,
706-
value: 0
703+
value: 0,
704+
resultTypes: nil
707705
)!
708706
if swapRes.status != EVM.Status.successful {
709707
UniswapV3SwapConnectors._callError(
710-
EVMAbiHelpers.toHex(calldata),
708+
"exactInput((bytes,address,uint256,uint256))",
711709
swapRes, self.routerAddress, idType, id, self.getType()
712710
)
713711
}
714712
// Reset allowance
715-
let resetAllowanceRes = self._call(
713+
let resetAllowanceRes = self._callWithSigAndArgs(
716714
to: inToken,
717715
signature: "approve(address,uint256)",
718716
args: [self.routerAddress, 0 as UInt256],
719717
gasLimit: 60_000,
720-
value: 0
718+
value: 0,
719+
resultTypes: [Type<UInt256>()]
721720
)!
722721

723722
if resetAllowanceRes.status != EVM.Status.successful {
724723
UniswapV3SwapConnectors._callError("approve(address,uint256)", resetAllowanceRes, inToken, idType, id, self.getType())
725724
}
726-
let decoded = EVM.decodeABI(types: [Type<UInt256>()], data: swapRes.data)
727-
assert(decoded.length == 1, message: "invalid swap return data")
728-
let amountOut = decoded[0] as! UInt256
725+
assert(resetAllowanceRes.results!.length == 1, message: "invalid swap return data")
726+
let amountOut = resetAllowanceRes.results![0] as! UInt256
729727

730728
let outVaultType = reverse ? self.inType() : self.outType()
731729
let outTokenEVMAddress =
@@ -795,6 +793,27 @@ access(all) contract UniswapV3SwapConnectors {
795793
return nil
796794
}
797795

796+
access(self) fun _callWithSigAndArgs(
797+
to: EVM.EVMAddress,
798+
signature: String,
799+
args: [AnyStruct],
800+
gasLimit: UInt64,
801+
value: UInt,
802+
resultTypes: [Type]?
803+
): EVM.ResultDecoded? {
804+
if let coa = self.borrowCOA() {
805+
return coa.callWithSigAndArgs(
806+
to: to,
807+
signature: signature,
808+
args: args,
809+
gasLimit: gasLimit,
810+
value: EVM.Balance(attoflow: value),
811+
resultTypes: resultTypes
812+
)
813+
}
814+
return nil
815+
}
816+
798817
access(self) fun _handleRemainingFeeVault(_ vault: @FlowToken.Vault) {
799818
if vault.balance > 0.0 {
800819
self.borrowCOA()!.deposit(from: <-vault)
@@ -849,7 +868,7 @@ access(all) contract UniswapV3SwapConnectors {
849868
access(self)
850869
fun _callError(
851870
_ signature: String,
852-
_ res: EVM.Result,
871+
_ res: EVM.ResultDecoded,
853872
_ target: EVM.EVMAddress,
854873
_ uniqueIDType: String,
855874
_ id: String,

0 commit comments

Comments
 (0)