Conversation
sisyphusSmiling
left a comment
There was a problem hiding this comment.
I think this connector needs some more testing and perhaps a different approach (EVM-side helper) until tuple encoding is natively available. The lack of testing and application-level byte packing creates potential security & bug surface area and likely lots of computation overhead we can optimize.
There was a problem hiding this comment.
In general, I think this contract will be low hanging fruit for optimization. Without the ability to encode a tuple from Cadence (see onflow/flow-go#8020), packing the bytes is quite inefficient and difficult to test.
Second to native encoding/decoding, I think having a helper contract in EVM to which we can pass/get natively encodable/decodable types will be preferred to this approach. But I suppose it's not a blocker for initial tracer deployment & setup.
| access(all) fun encodeTuple_bytes_addr_u256_u256( | ||
| path: [UInt8], | ||
| recipient: EVM.EVMAddress, | ||
| amountOne: UInt256, | ||
| amountTwo: UInt256 | ||
| ): [UInt8] { |
There was a problem hiding this comment.
Param comments would be helpful here
| // ===== Utilities: concat & padding ===== | ||
| access(all) fun concat(_ parts: [[UInt8]]): [UInt8] { | ||
| var out: [UInt8] = [] | ||
| for p in parts { out = out.concat(p) } |
There was a problem hiding this comment.
appendAll would probably be more performant here
| let hex: [String] = ["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"] | ||
| var out = "" | ||
| var i = 0 | ||
| while i < bytes.length { | ||
| let b = bytes[i] | ||
| out = out.concat(hex[Int(b / 16)]).concat(hex[Int(b % 16)]) | ||
| i = i + 1 | ||
| } | ||
| return out |
There was a problem hiding this comment.
can't this just be return String.encodeHex(bytes)
|
|
||
| // Represents one ABI argument chunk | ||
| access(all) struct ABIArg { | ||
| access(all) let isDynamic: Bool |
There was a problem hiding this comment.
It's not clear to me what is meant by dynamic here
| // exactInput((bytes,address,uint256,uint256)) selector = 0xb858183f | ||
| let selector: [UInt8] = [0xb8, 0x58, 0x18, 0x3f] |
There was a problem hiding this comment.
It's not apparent that the selector values match the commented selector which on its own need to match the .sol contract selector. This seems to work:
| // exactInput((bytes,address,uint256,uint256)) selector = 0xb858183f | |
| let selector: [UInt8] = [0xb8, 0x58, 0x18, 0x3f] | |
| // exactInput((bytes,address,uint256,uint256)) selector = 0xb858183f | |
| let selector: [UInt8] = EVM.encodeABIWithSignature("exactInput((bytes,address,uint256,uint256))", []) |
| access(self) fun _firstUint256(_ data: [UInt8]): UInt256 { | ||
| let decoded = EVM.decodeABI(types: [Type<UInt256>()], data: data) | ||
| if decoded.length > 0 { return decoded[0] as! UInt256 } | ||
| return UInt256(0) | ||
| } |
There was a problem hiding this comment.
I don't see this used anywhere
| access(self) fun _firstUint256(_ data: [UInt8]): UInt256 { | |
| let decoded = EVM.decodeABI(types: [Type<UInt256>()], data: data) | |
| if decoded.length > 0 { return decoded[0] as! UInt256 } | |
| return UInt256(0) | |
| } |
| let SEL_SLOT0: [UInt8] = [0x38, 0x50, 0xc7, 0xbd] | ||
| let SEL_LIQUIDITY: [UInt8] = [0x1a, 0x68, 0x65, 0x02] | ||
| let SEL_FEE: [UInt8] = [0xdd, 0xca, 0x3f, 0x43] | ||
| let SEL_TICK_BITMAP: [UInt8] = [0x53, 0x39, 0xc2, 0x96] | ||
| let SEL_TICKS: [UInt8] = [0xf3, 0x0d, 0xba, 0x93] | ||
| let SEL_TICK_SPACING: [UInt8] = [0xd0, 0xc9, 0x3a, 0x7c] |
There was a problem hiding this comment.
Same comment as elsewhere - it's difficult to catch any mismatch against the desired selector. Suggest decoding the signature for each using EVM.encodeABIWithSignature() using empty data array.
| return EVM.EVMAddress(bytes: addrBytes) | ||
| } | ||
|
|
||
| access(self) fun getMaxAmount(zeroForOne: Bool): UInt256 { |
There was a problem hiding this comment.
It's going to be very difficult to test these nested function definitions directly. If we do continue down the path of Cadence-side byte packing, we'll want to move these to a scope that we can test and validate directly.
| access(self) fun to20(_ b: [UInt8]): [UInt8; 20] { | ||
| if b.length != 20 { panic("to20: need exactly 20 bytes") } | ||
| return [ | ||
| b[0], b[1], b[2], b[3], b[4], | ||
| b[5], b[6], b[7], b[8], b[9], | ||
| b[10], b[11], b[12], b[13], b[14], | ||
| b[15], b[16], b[17], b[18], b[19] | ||
| ] | ||
| } |
There was a problem hiding this comment.
Can just use b.toConstantSized<[UInt8; 20]>()!.
Co-authored-by: Giovanni Sanchez <108043524+sisyphusSmiling@users.noreply.github.com>
sisyphusSmiling
left a comment
There was a problem hiding this comment.
Approving to unblock. Once revisiting, I'm fairly confident the production version will require a redeployment
Uniswap v3 SwapRouterV2 connector
EVM ABI helpers for tuple encoding