Skip to content

Commit

Permalink
Merge pull request #133 from argentlabs/issue/encoding-long-tuples
Browse files Browse the repository at this point in the history
Fix encoding of tuples containing static content tuples
  • Loading branch information
DarthMike authored Mar 8, 2021
2 parents dae0590 + 0f41127 commit 1c99504
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 12 deletions.
149 changes: 139 additions & 10 deletions web3sTests/Contract/ABIFunctionEncoderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class ABIFunctionEncoderTests: XCTestCase {
func testGivenPositiveInt_WhenInvalidSizeBiggerThan256_ThenFailsEncoding() {
XCTAssertThrowsError(try encoder.encode(BigInt(100), staticSize: 257))
}

func testGivenEmptyData_ThenEncodesCorrectly() {
XCTAssertNoThrow(try encoder.encode(Data()))
let encoded = try! encoder.encoded()
Expand Down Expand Up @@ -108,7 +108,7 @@ class ABIFunctionEncoderTests: XCTestCase {
"0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"0x8c2dc702371d73febc50c6e6ced100bf9dbcb029",
"0x007eedb5044ed5512ed7b9f8b42fe3113452491e"].map(EthereumAddress.init)

XCTAssertNoThrow(try encoder.encode(addresses))
let encoded = try! encoder.encoded()
XCTAssertEqual(String(hexFromBytes: encoded.web3.bytes), "0xd57498ea0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000500000000000000000000000026fc876db425b44bf6c377a7beef65e9ebad0ec300000000000000000000000025a01a05c188dacbcf1d61af55d4a5b4021f7eed000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee0000000000000000000000008c2dc702371d73febc50c6e6ced100bf9dbcb029000000000000000000000000007eedb5044ed5512ed7b9f8b42fe3113452491e")
Expand All @@ -127,7 +127,7 @@ class ABIFunctionEncoderTests: XCTestCase {

func testGivenArrayOfBigUInt_ThenEncodesCorrectly() {
let values = [BigUInt(1),BigUInt(2),BigUInt(3)]

XCTAssertNoThrow(try encoder.encode(values))
let encoded = try! encoder.encoded()
XCTAssertEqual(String(hexFromBytes: encoded.web3.bytes), "0xca16068400000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003")
Expand Down Expand Up @@ -175,13 +175,41 @@ class ABIFunctionEncoderTests: XCTestCase {
try encoder.encode(tuple)
try encoder.encode(BigUInt(1))
XCTAssertEqual(try encoder.encoded().web3.hexString,
"0x969569a200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000036162630000000000000000000000000000000000000000000000000000000000")
"0x969569a200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000036162630000000000000000000000000000000000000000000000000000000000")
} catch let error {
print(error.localizedDescription)
XCTFail()
}
}

func test_GivenLongTupleArgument_ThenEncodesCorrectly() {
let tuple = LongTuple(value1: "https://ethereum.org/abcde",
value2: "https://ethereum.org/xyz",
value3: Data(hex: "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8")!,
value4: Data(hex: "0x8452c9b9140222b08593a26daa782707297be9f7b3e8281d7b4974769f19afd0")!)

let encoder = ABIFunctionEncoder("TestLongTuple")

try? encoder.encode(tuple)
XCTAssertEqual(try? encoder.encoded().web3.hexString, "0xfe83fc010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c01c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac88452c9b9140222b08593a26daa782707297be9f7b3e8281d7b4974769f19afd0000000000000000000000000000000000000000000000000000000000000001a68747470733a2f2f657468657265756d2e6f72672f6162636465000000000000000000000000000000000000000000000000000000000000000000000000001868747470733a2f2f657468657265756d2e6f72672f78797a0000000000000000")

}

func test_GivenSomeArgumentsAndLongTuple_ThenEncodesCorrectly() {
let tuple = LongTuple(value1: "https://ipfs.fleek.co/ipfs/bafybeib7trltlf567dqq3jvok73k7vpnkxdq3gf6evj2ltezzzzhquc6ea",
value2: "https://ipfs.fleek.co/ipfs/bafybeiezpaegcxyltpw3qjmxtfxqiaddqbrdrzoyvmbaghqdhwhuuliciy",
value3: Data(hex: "0x7efef35dcd300eec8819c4ce5cb6b57be685254d583954273c5cc16edee83790")!,
value4: Data(hex: "0xba42a7d804d9eff383efb1864514f5f15c82f1c333a777dd8f76dba1c1977029")!)

let encoder = ABIFunctionEncoder("TestLongTuple")
try? encoder.encode(tuple)
try? encoder.encode(BigUInt(0))
try? encoder.encode(BigUInt(hex: "0xa688906bd8b00000")!)
try? encoder.encode(BigUInt(hex: "0x4c53ecdc18a600000")!)
XCTAssertEqual(try? encoder.encoded().web3.hexString, "0x51746d2300000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a688906bd8b00000000000000000000000000000000000000000000000000004c53ecdc18a600000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001007efef35dcd300eec8819c4ce5cb6b57be685254d583954273c5cc16edee83790ba42a7d804d9eff383efb1864514f5f15c82f1c333a777dd8f76dba1c1977029000000000000000000000000000000000000000000000000000000000000005668747470733a2f2f697066732e666c65656b2e636f2f697066732f62616679626569623774726c746c66353637647171336a766f6b37336b3776706e6b7864713367663665766a326c74657a7a7a7a6871756336656100000000000000000000000000000000000000000000000000000000000000000000000000000000005668747470733a2f2f697066732e666c65656b2e636f2f697066732f62616679626569657a706165676378796c74707733716a6d78746678716961646471627264727a6f79766d62616768716468776875756c6963697900000000000000000000")

}

func testGivenArrayOfTuples_ThenEncodesCorrectly() {
let tuples = [
SimpleTuple(address: EthereumAddress("0x64d0eA4FC60f27E74f1a70Aa6f39D403bBe56793"), amount: 30),
Expand All @@ -190,7 +218,7 @@ class ABIFunctionEncoderTests: XCTestCase {
do {
try encoder.encode(tuples)
XCTAssertEqual(try encoder.encoded().web3.hexString,
"0xae4f5efa0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000064d0ea4fc60f27e74f1a70aa6f39d403bbe56793000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000003c1bd6b420448cf16a389c8b0115ccb3660bb8540000000000000000000000000000000000000000000000000000000000000078")
"0xae4f5efa0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000064d0ea4fc60f27e74f1a70aa6f39d403bbe56793000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000003c1bd6b420448cf16a389c8b0115ccb3660bb8540000000000000000000000000000000000000000000000000000000000000078")
} catch let error {
print(error.localizedDescription)
XCTFail()
Expand All @@ -207,7 +235,7 @@ class ABIFunctionEncoderTests: XCTestCase {
try encoder.encode("1234567890".data(using: .utf8)!, staticSize: 10)
try encoder.encode("Hello, world!".data(using: .utf8)!)
XCTAssertEqual(try encoder.encoded().web3.hexString,
"0x8be6524600000000000000000000000000000000000000000000000000000000000001230000000000000000000000000000000000000000000000000000000000000080313233343536373839300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000004560000000000000000000000000000000000000000000000000000000000000789000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20776f726c642100000000000000000000000000000000000000")
"0x8be6524600000000000000000000000000000000000000000000000000000000000001230000000000000000000000000000000000000000000000000000000000000080313233343536373839300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000004560000000000000000000000000000000000000000000000000000000000000789000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20776f726c642100000000000000000000000000000000000000")
} catch {
XCTFail()
}
Expand Down Expand Up @@ -236,6 +264,23 @@ class ABIFunctionEncoderTests: XCTestCase {
XCTFail()
}
}

func test_GivenLongTupleAndSimpleTupleOfTuples_EncodesCorrectly() {
let tuple = LongTuple(value1: "https://ipfs.fleek.co/ipfs/bafybeib7trltlf567dqq3jvok73k7vpnkxdq3gf6evj2ltezzzzhquc6ea",
value2: "https://ipfs.fleek.co/ipfs/bafybeiezpaegcxyltpw3qjmxtfxqiaddqbrdrzoyvmbaghqdhwhuuliciy",
value3: Data(hex: "0x7efef35dcd300eec8819c4ce5cb6b57be685254d583954273c5cc16edee83790")!,
value4: Data(hex: "0xba42a7d804d9eff383efb1864514f5f15c82f1c333a777dd8f76dba1c1977029")!)

let tupleOfTuples = TupleOfTuples(value1: NumberTuple(value: 0),
value2: NumberTuple(value: BigUInt(hex: "0xa688906bd8b00000")!),
value3: NumberTuple(value: BigUInt(hex: "0x4c53ecdc18a600000")!))

let encoder = ABIFunctionEncoder("mint")
try? encoder.encode(tuple)
try? encoder.encode(tupleOfTuples)
XCTAssertEqual(try? encoder.encoded().web3.hexString, "0x2cca323700000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a688906bd8b00000000000000000000000000000000000000000000000000004c53ecdc18a600000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001007efef35dcd300eec8819c4ce5cb6b57be685254d583954273c5cc16edee83790ba42a7d804d9eff383efb1864514f5f15c82f1c333a777dd8f76dba1c1977029000000000000000000000000000000000000000000000000000000000000005668747470733a2f2f697066732e666c65656b2e636f2f697066732f62616679626569623774726c746c66353637647171336a766f6b37336b3776706e6b7864713367663665766a326c74657a7a7a7a6871756336656100000000000000000000000000000000000000000000000000000000000000000000000000000000005668747470733a2f2f697066732e666c65656b2e636f2f697066732f62616679626569657a706165676378796c74707733716a6d78746678716961646471627264727a6f79766d62616768716468776875756c6963697900000000000000000000")

}
}

fileprivate struct SimpleTuple: ABITuple {
Expand Down Expand Up @@ -263,6 +308,41 @@ fileprivate struct SimpleTuple: ABITuple {
var encodableValues: [ABIType] { [address, amount] }
}

fileprivate struct LongTuple: ABITuple {
static var types: [ABIType.Type] { [String.self, String.self, Data32.self, Data32.self] }

var value1: String
var value2: String
var value3: Data
var value4: Data

init(value1: String,
value2: String,
value3: Data,
value4: Data) {
self.value1 = value1
self.value2 = value2
self.value3 = value3
self.value4 = value4
}

init?(values: [ABIDecoder.DecodedValue]) throws {
self.value1 = try values[0].decoded()
self.value2 = try values[1].decoded()
self.value3 = try values[2].decoded()
self.value4 = try values[3].decoded()
}

func encode(to encoder: ABIFunctionEncoder) throws {
try encoder.encode(value1)
try encoder.encode(value2)
try encoder.encode(value3, staticSize: 32)
try encoder.encode(value4, staticSize: 32)
}

var encodableValues: [ABIType] { [value1, value2, value3, value4] }
}

fileprivate struct DynamicContentTuple: ABITuple {
static var types: [ABIType.Type] { [String.self] }

Expand Down Expand Up @@ -319,15 +399,15 @@ fileprivate struct RelayerExecute: ABIFunction {
let from: EthereumAddress?
var gasPrice: BigUInt?
var gasLimit: BigUInt?

struct Response: ABIResponse {
static var types: [ABIType.Type] = []

init?(values: [ABIDecoder.DecodedValue]) throws {

}
}

let wallet: EthereumAddress
let data: Data
let nonce: BigUInt
Expand All @@ -345,3 +425,52 @@ fileprivate struct RelayerExecute: ABIFunction {
}
}

fileprivate struct NumberTuple: ABITuple {
func encode(to encoder: ABIFunctionEncoder) throws {
try encoder.encode(value)
}

static var types: [ABIType.Type] { [BigUInt.self] }

var value: BigUInt

init(value: BigUInt) {
self.value = value
}

init?(values: [ABIDecoder.DecodedValue]) throws {
self.value = try values[0].decoded()
}

var encodableValues: [ABIType] { [value] }
}

fileprivate struct TupleOfTuples: ABITuple {
func encode(to encoder: ABIFunctionEncoder) throws {
try encoder.encode(value1)
try encoder.encode(value2)
try encoder.encode(value3)
}

static var types: [ABIType.Type] { [NumberTuple.self, NumberTuple.self, NumberTuple.self] }

var value1: NumberTuple
var value2: NumberTuple
var value3: NumberTuple

init(value1: NumberTuple,
value2: NumberTuple,
value3: NumberTuple) {
self.value1 = value1
self.value2 = value2
self.value3 = value3
}

init?(values: [ABIDecoder.DecodedValue]) throws {
self.value1 = try values[0].decoded()
self.value2 = try values[1].decoded()
self.value3 = try values[2].decoded()
}

var encodableValues: [ABIType] { [value1, value2, value3] }
}
8 changes: 6 additions & 2 deletions web3swift/src/Contract/ABIEncoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,12 @@ public class ABIEncoder {
switch self {
case .value(_, _, let staticLength):
return staticLength
case .container:
return 32
case .container(let values, let isDynamic, let size):
if isDynamic {
return 32
} else {
return values.map(\.staticLength).reduce(0, +)
}
}
}

Expand Down

0 comments on commit 1c99504

Please sign in to comment.