Skip to content

Commit 89a9863

Browse files
committed
add more test for encodeTopic
1 parent df87030 commit 89a9863

File tree

3 files changed

+94
-27
lines changed

3 files changed

+94
-27
lines changed

Sources/Web3Core/EthereumABI/ABIElements.swift

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -219,27 +219,34 @@ extension ABI.Element.Event {
219219
return eventContent
220220
}
221221

222-
func encodeTopic(input: ABI.Element.Event.Input, value: Any) -> EventFilterParameters.Topic? {
223-
if case .string = input.type {
222+
public static func encodeTopic(input: ABI.Element.Event.Input, value: Any) -> EventFilterParameters.Topic? {
223+
switch input.type {
224+
case .string:
224225
guard let string = value as? String else {
225226
return nil
226227
}
227228
return .string(string.sha3(.keccak256).addHexPrefix())
228-
} else if case .dynamicBytes = input.type {
229+
case .dynamicBytes:
229230
guard let data = ABIEncoder.convertToData(value) else {
230231
return nil
231232
}
232233
return .string(data.sha3(.keccak256).toHexString().addHexPrefix())
233-
} else if case .address = input.type {
234-
guard let encoded = ABIEncoder.encode(types: [input.type], values: [value]) else {
234+
case .bytes(length: _):
235+
guard let data = value as? Data, let data = data.setLengthLeft(32) else {
236+
return nil
237+
}
238+
return .string(data.toHexString().addHexPrefix())
239+
case .address, .uint(bits: _), .int(bits: _), .bool:
240+
guard let encoded = ABIEncoder.encodeSingleType(type: input.type, value: value) else {
235241
return nil
236242
}
237243
return .string(encoded.toHexString().addHexPrefix())
244+
default:
245+
guard let data = try? ABIEncoder.abiEncode(value).setLengthLeft(32) else {
246+
return nil
247+
}
248+
return .string(data.toHexString().addHexPrefix())
238249
}
239-
guard let data = ABIEncoder.convertToData(value)?.setLengthLeft(32) else {
240-
return nil
241-
}
242-
return .string(data.toHexString().addHexPrefix())
243250
}
244251

245252
public func encodeParameters(_ parameters: [Any?]) -> [EventFilterParameters.Topic?] {
@@ -260,14 +267,25 @@ extension ABI.Element.Event {
260267
return []
261268
}
262269
if p == nil {
263-
topics.append(.string(nil))
264-
} else if input.type.isArray {
270+
topics.append(nil)
271+
} else if input.type.isArray || input.type.isTuple {
265272
// filtering with tuples or arrays not supported
266273
return []
267274
} else if let p = p as? Array<Any> {
268-
topics.append(.strings(p.map { encodeTopic(input: input, value: $0) }))
275+
topics.append(.strings(p.map { Self.encodeTopic(input: input, value: $0) }))
276+
} else {
277+
topics.append(Self.encodeTopic(input: input, value: p!))
278+
}
279+
}
280+
281+
// Trim off trailing nulls
282+
while let last = topics.last {
283+
if last == nil {
284+
topics.removeLast()
285+
} else if case .string(let string) = last, string == nil {
286+
topics.removeLast()
269287
} else {
270-
topics.append(encodeTopic(input: input, value: p!))
288+
break
271289
}
272290
}
273291
return topics

Tests/web3swiftTests/localTests/EventTests.swift

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,44 @@
77

88
import XCTest
99
import Web3Core
10+
import BigInt
1011

1112
@testable import web3swift
1213

1314
class EventTests: XCTestCase {
14-
func testEncodeTopc() throws {
15+
16+
/// Solidity event allows up to 3 indexed field, this is just for test.
17+
let testEvent = """
18+
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"string","name":"a","type":"string"},{"indexed":true,"internalType":"bool","name":"b","type":"bool"},{"indexed":true,"internalType":"bytes","name":"c","type":"bytes"},{"indexed":true,"internalType":"uint256","name":"d","type":"uint256"}],"name":"UserOperationEvent","type":"event"}]
19+
"""
20+
21+
func testEncodeTopicToJSON() throws {
1522
let encoder = JSONEncoder()
1623
let t1: [EventFilterParameters.Topic] = []
1724
let t2: [EventFilterParameters.Topic] = [.string(nil)]
1825
let t3: [EventFilterParameters.Topic] = [.strings([.string(nil), .string("1")])]
26+
let t4: [EventFilterParameters.Topic] = [.strings([nil, .string("1")])]
1927
XCTAssertNoThrow(try encoder.encode(t1))
2028
XCTAssertNoThrow(try encoder.encode(t2))
2129
XCTAssertNoThrow(try encoder.encode(t3))
30+
XCTAssertNoThrow(try encoder.encode(t4))
2231

23-
let t4: [EventFilterParameters.Topic] = [
32+
let topics: [EventFilterParameters.Topic] = [
2433
.string("1"),
2534
.strings([
2635
.string("2"),
2736
.string("3"),
2837
]
2938
)]
30-
let encoded = try encoder.encode(t4)
39+
let encoded = try encoder.encode(topics)
3140
let json = try JSONSerialization.jsonObject(with: encoded)
3241
XCTAssertEqual(json as? NSArray, ["1", ["2", "3"]])
3342
}
3443

3544
func testEncodeLogs() throws {
36-
let contract = try EthereumContract(TestEvent)
37-
let logs = contract.events["UserOperationEvent"]?.encodeParameters(
45+
let contract = try EthereumContract(testEvent)
46+
let topic = contract.events["UserOperationEvent"]!.topic
47+
let logs = contract.events["UserOperationEvent"]!.encodeParameters(
3848
[
3949
"0x2c16c07e1c68d502e9c7ad05f0402b365671a0e6517cb807b2de4edd95657042",
4050
"0x581074D2d9e50913eB37665b07CAFa9bFFdd1640",
@@ -44,11 +54,34 @@ class EventTests: XCTestCase {
4454
nil
4555
]
4656
)
57+
XCTAssertEqual(logs.count, 6)
4758

48-
XCTAssert(logs?.count == 7)
59+
XCTAssertTrue(logs[0] == topic.toHexString().addHexPrefix())
60+
XCTAssertTrue(logs[1] == nil)
61+
XCTAssertTrue(logs[2] == "0x000000000000000000000000581074d2d9e50913eb37665b07cafa9bffdd1640")
62+
XCTAssertTrue(logs[3] == "0xab036729af8b8f9b610af4e11b14fa30c348f40c2c230cce92ef6ef37726fee7")
63+
XCTAssertTrue(logs[4] == "0x0000000000000000000000000000000000000000000000000000000000000001")
64+
XCTAssertTrue(logs[5] == "0x56f5a6cba57d26b32db8dc756fda960dcd3687770a300575a5f8107591eff63f")
4965
}
5066

51-
let TestEvent = """
52-
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"string","name":"a","type":"string"},{"indexed":true,"internalType":"bool","name":"b","type":"bool"},{"indexed":true,"internalType":"bytes","name":"c","type":"bytes"},{"indexed":true,"internalType":"uint256","name":"d","type":"uint256"}],"name":"UserOperationEvent","type":"event"}]
53-
"""
67+
func testEncodeTopic() throws {
68+
XCTAssertTrue(ABI.Element.Event.encodeTopic(input: .init(name: "", type: .string, indexed: true), value: "hello,world") == "0xab036729af8b8f9b610af4e11b14fa30c348f40c2c230cce92ef6ef37726fee7")
69+
XCTAssertTrue(ABI.Element.Event.encodeTopic(input: .init(name: "", type: .address, indexed: true), value: "0x003e36550908907c2a2da960fd19a419b9a774b7") == "0x000000000000000000000000003e36550908907c2a2da960fd19a419b9a774b7")
70+
XCTAssertTrue(ABI.Element.Event.encodeTopic(input: .init(name: "", type: .address, indexed: true), value: EthereumAddress("0x003e36550908907c2a2da960fd19a419b9a774b7")!) == "0x000000000000000000000000003e36550908907c2a2da960fd19a419b9a774b7")
71+
XCTAssertTrue(ABI.Element.Event.encodeTopic(input: .init(name: "", type: .bool, indexed: true), value: true) == "0x0000000000000000000000000000000000000000000000000000000000000001")
72+
XCTAssertTrue(ABI.Element.Event.encodeTopic(input: .init(name: "", type: .uint(bits: 256), indexed: true), value: BigUInt("dbe20a", radix: 16)!) == "0x0000000000000000000000000000000000000000000000000000000000dbe20a")
73+
XCTAssertTrue(ABI.Element.Event.encodeTopic(input: .init(name: "", type: .int(bits: 32), indexed: true), value: 100) == "0x0000000000000000000000000000000000000000000000000000000000000064")
74+
XCTAssertTrue(ABI.Element.Event.encodeTopic(input: .init(name: "", type: .dynamicBytes, indexed: true), value: Data(hex: "6761766f66796f726b")) == "0xe0859ceea0a2fd2474deef2b2183f10f4c741ebba702e9a07d337522c0af55fb")
75+
XCTAssertTrue(ABI.Element.Event.encodeTopic(input: .init(name: "", type: .bytes(length: 32), indexed: true), value: Data(hex: "6761766f66796f726b")) == "0x00000000000000000000000000000000000000000000006761766f66796f726b")
76+
}
77+
}
78+
79+
private func ==(lhs: EventFilterParameters.Topic?, rhs: String?) -> Bool {
80+
if let lhs = lhs, case .string(let string) = lhs {
81+
return string == rhs
82+
}
83+
if lhs == nil && rhs == nil {
84+
return true
85+
}
86+
return false
5487
}

Tests/web3swiftTests/remoteTests/EventFilterTests.swift

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@
77

88
import XCTest
99
import Web3Core
10-
10+
import BigInt
11+
import CryptoSwift
1112
@testable import web3swift
1213

1314
class EventFilerTests: XCTestCase {
1415

16+
/// This test tx can be found at here:
17+
/// https://etherscan.io/tx/0x1a1daac5b3158f16399baec9abba2c8a4b4b7ffea5992490079b6bfc4ce70004
1518
func testErc20Transfer() async throws {
1619
let web3 = try await Web3.InfuraMainnetWeb3(accessToken: Constants.infuraToken)
1720
let address = EthereumAddress("0xdac17f958d2ee523a2206206994597c13d831ec7")!
@@ -20,11 +23,24 @@ class EventFilerTests: XCTestCase {
2023
let topics = erc20.contract.contract.event("Transfer", parameters: [
2124
"0x003e36550908907c2a2da960fd19a419b9a774b7"
2225
])
23-
let block = try await web3.eth.block(by: .latest)
24-
let parameters = EventFilterParameters(fromBlock: .exact(block.number - 1000), address: [address], topics: topics)
26+
27+
let parameters = EventFilterParameters(fromBlock: .exact(17983395), toBlock: .exact(17983395), address: [address], topics: topics)
2528
let result = try await web3.eth.getLogs(eventFilter: parameters)
2629

27-
// result not always has a log in it.
28-
print(result)
30+
XCTAssertEqual(result.count, 1)
31+
32+
let log = result.first!
33+
XCTAssertEqual(log.address.address.lowercased(), "0xdac17f958d2ee523a2206206994597c13d831ec7")
34+
XCTAssertEqual(log.transactionHash.toHexString().lowercased(), "1a1daac5b3158f16399baec9abba2c8a4b4b7ffea5992490079b6bfc4ce70004")
35+
36+
let logTopics = log.topics.map { $0.toHexString() }
37+
topics.compactMap { t -> String? in
38+
if let t = t, case EventFilterParameters.Topic.string(let topic) = t {
39+
return topic
40+
}
41+
return nil
42+
}.forEach { t in
43+
XCTAssertTrue(logTopics.contains(t.stripHexPrefix()))
44+
}
2945
}
3046
}

0 commit comments

Comments
 (0)