Skip to content

Commit c8869dc

Browse files
committed
finish cleanup
1 parent 91bd902 commit c8869dc

File tree

4 files changed

+133
-166
lines changed

4 files changed

+133
-166
lines changed

Sources/web3swift/Web3/Web3+MutatingTransaction.swift

Lines changed: 105 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -10,163 +10,121 @@ import BigInt
1010
public class WriteTransaction: ReadTransaction {
1111

1212
public func assemblePromise(transactionOptions: TransactionOptions? = nil) async throws -> EthereumTransaction {
13-
var assembledTransaction: EthereumTransaction = self.transaction
14-
let queue = self.web3.requestDispatcher.queue
15-
let returnPromise = Promise<EthereumTransaction> { seal in
16-
if self.method != "fallback" {
17-
let m = self.contract.methods[self.method]
18-
if m == nil {
19-
seal.reject(Web3Error.inputError(desc: "Contract's ABI does not have such method"))
20-
return
21-
}
22-
switch m! {
23-
case .function(let function):
24-
if function.constant {
25-
seal.reject(Web3Error.inputError(desc: "Trying to transact to the constant function"))
26-
return
27-
}
28-
case .constructor(_):
29-
break
30-
default:
31-
seal.reject(Web3Error.inputError(desc: "Contract's ABI does not have such method"))
32-
return
33-
}
34-
}
13+
var assembledTransaction: EthereumTransaction = self.transaction
3514

36-
var mergedOptions = self.transactionOptions.merge(transactionOptions)
37-
if mergedOptions.value != nil {
38-
assembledTransaction.value = mergedOptions.value!
39-
}
40-
var forAssemblyPipeline: (EthereumTransaction, EthereumContract, TransactionOptions) = (assembledTransaction, self.contract, mergedOptions)
41-
42-
for hook in self.web3.preAssemblyHooks {
43-
let prom: Promise<Bool> = Promise<Bool> {seal in
44-
hook.queue.async {
45-
let hookResult = hook.function(forAssemblyPipeline)
46-
if hookResult.3 {
47-
forAssemblyPipeline = (hookResult.0, hookResult.1, hookResult.2)
48-
}
49-
seal.fulfill(hookResult.3)
50-
}
51-
}
52-
let shouldContinue = try prom.wait()
53-
if !shouldContinue {
54-
seal.reject(Web3Error.processingError(desc: "Transaction is canceled by middleware"))
55-
return
56-
}
15+
if self.method != "fallback" {
16+
let m = self.contract.methods[self.method]
17+
if m == nil {
18+
throw Web3Error.inputError(desc: "Contract's ABI does not have such method")
19+
}
20+
switch m! {
21+
case .function(let function):
22+
if function.constant {
23+
throw Web3Error.inputError(desc: "Trying to transact to the constant function")
5724
}
25+
case .constructor(_):
26+
break
27+
default:
28+
throw Web3Error.inputError(desc: "Contract's ABI does not have such method")
29+
}
30+
}
5831

59-
assembledTransaction = forAssemblyPipeline.0
60-
mergedOptions = forAssemblyPipeline.2
32+
var mergedOptions = self.transactionOptions.merge(transactionOptions)
33+
if mergedOptions.value != nil {
34+
assembledTransaction.value = mergedOptions.value!
35+
}
36+
var forAssemblyPipeline: (EthereumTransaction, EthereumContract, TransactionOptions) = (assembledTransaction, self.contract, mergedOptions)
6137

62-
guard let from = mergedOptions.from else {
63-
seal.reject(Web3Error.inputError(desc: "No 'from' field provided"))
64-
return
65-
}
38+
for hook in self.web3.preAssemblyHooks {
39+
let hookResult = hook.function(forAssemblyPipeline)
40+
if hookResult.3 {
41+
forAssemblyPipeline = (hookResult.0, hookResult.1, hookResult.2)
42+
}
6643

67-
// assemble promise for gas estimation
68-
var optionsForGasEstimation = TransactionOptions()
69-
optionsForGasEstimation.from = mergedOptions.from
70-
optionsForGasEstimation.to = mergedOptions.to
71-
optionsForGasEstimation.value = mergedOptions.value
72-
optionsForGasEstimation.gasLimit = mergedOptions.gasLimit
73-
optionsForGasEstimation.callOnBlock = mergedOptions.callOnBlock
74-
75-
// assemble promise for gasLimit
76-
var gasEstimatePromise: Promise<BigUInt>? = nil
77-
guard let gasLimitPolicy = mergedOptions.gasLimit else {
78-
seal.reject(Web3Error.inputError(desc: "No gasLimit policy provided"))
79-
return
80-
}
81-
switch gasLimitPolicy {
82-
case .automatic, .withMargin, .limited:
83-
gasEstimatePromise = self.web3.eth.estimateGasPromise(assembledTransaction, transactionOptions: optionsForGasEstimation)
84-
case .manual(let gasLimit):
85-
gasEstimatePromise = Promise<BigUInt>.value(gasLimit)
86-
}
44+
let shouldContinue = hookResult.3
45+
if !shouldContinue {
46+
throw Web3Error.processingError(desc: "Transaction is canceled by middleware")
47+
}
48+
}
8749

88-
// assemble promise for nonce
89-
var getNoncePromise: Promise<BigUInt>?
90-
guard let noncePolicy = mergedOptions.nonce else {
91-
seal.reject(Web3Error.inputError(desc: "No nonce policy provided"))
92-
return
93-
}
94-
switch noncePolicy {
95-
case .latest:
96-
getNoncePromise = self.web3.eth.getTransactionCountPromise(address: from, onBlock: "latest")
97-
case .pending:
98-
getNoncePromise = self.web3.eth.getTransactionCountPromise(address: from, onBlock: "pending")
99-
case .manual(let nonce):
100-
getNoncePromise = Promise<BigUInt>.value(nonce)
101-
}
50+
assembledTransaction = forAssemblyPipeline.0
51+
mergedOptions = forAssemblyPipeline.2
10252

103-
// assemble promise for gasPrice
104-
var gasPricePromise: Promise<BigUInt>? = nil
105-
guard let gasPricePolicy = mergedOptions.gasPrice else {
106-
seal.reject(Web3Error.inputError(desc: "No gasPrice policy provided"))
107-
return
108-
}
109-
switch gasPricePolicy {
110-
case .automatic, .withMargin:
111-
gasPricePromise = self.web3.eth.getGasPricePromise()
112-
case .manual(let gasPrice):
113-
gasPricePromise = Promise<BigUInt>.value(gasPrice)
114-
}
115-
var promisesToFulfill: [Promise<BigUInt>] = [getNoncePromise!, gasPricePromise!, gasEstimatePromise!]
116-
when(resolved: getNoncePromise!, gasEstimatePromise!, gasPricePromise!).map(on: queue, { (results: [PromiseResult<BigUInt>]) throws -> EthereumTransaction in
117-
118-
promisesToFulfill.removeAll()
119-
guard case .fulfilled(let nonce) = results[0] else {
120-
throw Web3Error.processingError(desc: "Failed to fetch nonce")
121-
}
122-
guard case .fulfilled(let gasEstimate) = results[1] else {
123-
throw Web3Error.processingError(desc: "Failed to fetch gas estimate")
124-
}
125-
guard case .fulfilled(let gasPrice) = results[2] else {
126-
throw Web3Error.processingError(desc: "Failed to fetch gas price")
127-
}
128-
129-
let estimate = mergedOptions.resolveGasLimit(gasEstimate)
130-
let finalGasPrice = mergedOptions.resolveGasPrice(gasPrice)
131-
132-
var finalOptions = TransactionOptions()
133-
finalOptions.nonce = .manual(nonce)
134-
finalOptions.gasLimit = .manual(estimate)
135-
finalOptions.gasPrice = .manual(finalGasPrice)
136-
137-
assembledTransaction.applyOptions(finalOptions)
138-
139-
forAssemblyPipeline = (assembledTransaction, self.contract, mergedOptions)
140-
141-
for hook in self.web3.postAssemblyHooks {
142-
let prom: Promise<Bool> = Promise<Bool> {seal in
143-
hook.queue.async {
144-
let hookResult = hook.function(forAssemblyPipeline)
145-
if hookResult.3 {
146-
forAssemblyPipeline = (hookResult.0, hookResult.1, hookResult.2)
147-
}
148-
seal.fulfill(hookResult.3)
149-
}
150-
}
151-
let shouldContinue = try prom.wait()
152-
if !shouldContinue {
153-
throw Web3Error.processingError(desc: "Transaction is canceled by middleware")
154-
}
155-
}
156-
157-
assembledTransaction = forAssemblyPipeline.0
158-
mergedOptions = forAssemblyPipeline.2
159-
160-
return assembledTransaction
161-
}).done(on: queue) {tx in
162-
seal.fulfill(tx)
163-
}.catch(on: queue) {err in
164-
seal.reject(err)
165-
}
53+
guard let from = mergedOptions.from else {
54+
throw Web3Error.inputError(desc: "No 'from' field provided")
55+
}
56+
57+
// assemble promise for gas estimation
58+
var optionsForGasEstimation = TransactionOptions()
59+
optionsForGasEstimation.from = mergedOptions.from
60+
optionsForGasEstimation.to = mergedOptions.to
61+
optionsForGasEstimation.value = mergedOptions.value
62+
optionsForGasEstimation.gasLimit = mergedOptions.gasLimit
63+
optionsForGasEstimation.callOnBlock = mergedOptions.callOnBlock
64+
65+
// assemble promise for gasLimit
66+
67+
guard let gasLimitPolicy = mergedOptions.gasLimit else {
68+
throw Web3Error.inputError(desc: "No gasLimit policy provided")
69+
}
70+
71+
guard let gasPricePolicy = mergedOptions.gasPrice else {
72+
throw Web3Error.inputError(desc: "No gasPrice policy provided")
73+
}
74+
75+
guard let noncePolicy = mergedOptions.nonce else {
76+
throw Web3Error.inputError(desc: "No nonce policy provided")
77+
}
78+
79+
80+
let assembledTransactionPostHood = assembledTransaction
81+
let optionsForGasEstimationPostHood = optionsForGasEstimation
82+
83+
async let gasEstimatePromise = gasEstimate(for: gasLimitPolicy, assembledTransaction: assembledTransactionPostHood, optionsForGasEstimation: optionsForGasEstimationPostHood)
84+
85+
// assemble promise for nonce
86+
async let getNoncePromise = nonce(for: noncePolicy, from: from)
87+
88+
89+
// assemble promise for gasPrice
90+
async let gasPricePromise = gasPrice(for: gasPricePolicy)
91+
92+
93+
let results = try await [getNoncePromise, gasPricePromise, gasEstimatePromise]
94+
95+
let nonce = results[0]
96+
let gasEstimate = results[1]
97+
let gasPrice = results[2]
98+
99+
100+
let estimate = mergedOptions.resolveGasLimit(gasEstimate)
101+
let finalGasPrice = mergedOptions.resolveGasPrice(gasPrice)
102+
103+
var finalOptions = TransactionOptions()
104+
finalOptions.nonce = .manual(nonce)
105+
finalOptions.gasLimit = .manual(estimate)
106+
finalOptions.gasPrice = .manual(finalGasPrice)
107+
108+
assembledTransaction.applyOptions(finalOptions)
109+
110+
forAssemblyPipeline = (assembledTransaction, self.contract, mergedOptions)
111+
112+
for hook in self.web3.postAssemblyHooks {
113+
let hookResult = hook.function(forAssemblyPipeline)
114+
if hookResult.3 {
115+
forAssemblyPipeline = (hookResult.0, hookResult.1, hookResult.2)
116+
}
117+
let shouldContinue = hookResult.3
118+
if !shouldContinue {
119+
throw Web3Error.processingError(desc: "Transaction is canceled by middleware")
166120
}
167-
return returnPromise
168121
}
169122

123+
124+
return assembledTransaction
125+
126+
}
127+
170128
public func sendPromise(password: String = "web3swift", transactionOptions: TransactionOptions? = nil) async throws -> TransactionSendingResult{
171129
let transaction = try await self.assemblePromise(transactionOptions: transactionOptions)
172130
let mergedOptions = self.transactionOptions.merge(transactionOptions)

Tests/web3swiftTests/localTests/web3swiftTransactionsTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -641,7 +641,7 @@ class web3swiftTransactionsTests: XCTestCase {
641641

642642
Thread.sleep(forTimeInterval: 1.0)
643643

644-
let receipt = try web3.eth.getTransactionReceipt(txHash)
644+
let receipt = try await web3.eth.getTransactionReceipt(txHash)
645645
print(receipt)
646646
XCTAssert(receipt.status == .ok)
647647

@@ -652,7 +652,7 @@ class web3swiftTransactionsTests: XCTestCase {
652652
break
653653
}
654654

655-
let details = try web3.eth.getTransactionDetails(txHash)
655+
let details = try await web3.eth.getTransactionDetails(txHash)
656656
print(details)
657657
let txnGasLimit = details.transaction.parameters.gasLimit
658658
XCTAssert(txnGasLimit == BigUInt(78423))

Tests/web3swiftTests/localTests/web3swiftUserCases.swift

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,19 +54,18 @@ class web3swiftUserCases: XCTestCase {
5454
let web3 = try await Web3.new(URL.init(string: "http://127.0.0.1:8545")!)
5555
let allAddresses = try await web3.eth.getAccounts()
5656
let gasPrice = try await web3.eth.getGasPrice()
57-
let assembled = try writeTX.assemblePromise().wait()
58-
let txnGasLimit = assembled.parameters.gasLimit
59-
XCTAssert(txnGasLimit == gasEstimate + 1234)
6057
let sendToAddress = EthereumAddress("0xe22b8979739D724343bd002F9f432F5990879901")!
61-
guard let writeTX = web3.eth.sendETH(to: sendToAddress, amount: "0.001") else {return XCTFail()}
58+
guard let writeTX = web3.eth.sendETH(to: sendToAddress, amount: "0.001") else {
59+
return XCTFail()
60+
}
6261
writeTX.transactionOptions.from = allAddresses[0]
6362
writeTX.transactionOptions.gasPrice = .manual(gasPrice * 2)
6463
let gasEstimate = try await writeTX.estimateGasPromise()
6564
writeTX.transactionOptions.gasLimit = .manual(gasEstimate + 1234)
6665
let assembled = try await writeTX.assemblePromise()
6766
let txnGasLimit = assembled.parameters.gasLimit
6867
let txnGasPrice = assembled.parameters.gasPrice
69-
68+
7069
XCTAssert(txnGasLimit == gasEstimate + 1234)
7170
XCTAssert(txnGasPrice == gasPrice * 2)
7271
}

Tests/web3swiftTests/remoteTests/GasOracleTests.swift

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,37 +13,43 @@ import BigInt
1313
// MARK: Works only with network connection
1414
class OracleTests: XCTestCase {
1515

16-
let web3 = Web3.InfuraMainnetWeb3(accessToken: Constants.infuraToken)
16+
1717

1818
let blockNumber: BigUInt = 14571792
1919

20-
lazy var oracle: Web3.Oracle = .init(web3, block: .exact(blockNumber), blockCount: 20, percentiles: [10, 40, 60, 90])
2120

22-
func testPretictBaseFee() throws {
21+
22+
func testPretictBaseFee() async throws {
23+
let web3 = await Web3.InfuraMainnetWeb3(accessToken: Constants.infuraToken)
24+
lazy var oracle: Web3.Oracle = .init(web3, block: .exact(blockNumber), blockCount: 20, percentiles: [10, 40, 60, 90])
2325
let etalonPercentiles: [BigUInt] = [
2426
71456911562, // 10 percentile
2527
92735433497, // 40 percentile
2628
105739785122, // 60 percentile
2729
118929912191 // 90 percentile
2830
]
2931

30-
let baseFeePercentiles = oracle.baseFeePercentiles
32+
let baseFeePercentiles = await oracle.baseFeePercentiles()
3133
XCTAssertEqual(baseFeePercentiles, etalonPercentiles, "Arrays should be equal")
3234
}
3335

34-
func testPredictTip() throws {
36+
func testPredictTip() async throws {
37+
let web3 = await Web3.InfuraMainnetWeb3(accessToken: Constants.infuraToken)
38+
lazy var oracle: Web3.Oracle = .init(web3, block: .exact(blockNumber), blockCount: 20, percentiles: [10, 40, 60, 90])
3539
let etalonPercentiles: [BigUInt] = [
3640
1251559157, // 10 percentile
3741
1594062500, // 40 percentile
3842
2268157275, // 60 percentile
3943
11394017894 // 90 percentile
4044
]
4145

42-
let tipFeePercentiles = oracle.tipFeePercentiles
46+
let tipFeePercentiles = await oracle.tipFeePercentiles()
4347
XCTAssertEqual(tipFeePercentiles, etalonPercentiles, "Arrays should be equal")
4448
}
4549

46-
func testPredictBothFee() throws {
50+
func testPredictBothFee() async throws {
51+
let web3 = await Web3.InfuraMainnetWeb3(accessToken: Constants.infuraToken)
52+
lazy var oracle: Web3.Oracle = .init(web3, block: .exact(blockNumber), blockCount: 20, percentiles: [10, 40, 60, 90])
4753
let etalonPercentiles: ([BigUInt], [BigUInt]) = (
4854
baseFee: [
4955
71456911562, // 10 percentile
@@ -59,25 +65,29 @@ class OracleTests: XCTestCase {
5965
]
6066
)
6167

62-
let bothFeesPercentiles = oracle.bothFeesPercentiles
68+
let bothFeesPercentiles = await oracle.bothFeesPercentiles()
6369
XCTAssertEqual(bothFeesPercentiles?.baseFee, etalonPercentiles.0, "Arrays should be equal")
6470
XCTAssertEqual(bothFeesPercentiles?.tip, etalonPercentiles.1, "Arrays should be equal")
6571
}
6672

67-
func testPredictLegacyGasPrice() throws {
73+
func testPredictLegacyGasPrice() async throws {
74+
let web3 = await Web3.InfuraMainnetWeb3(accessToken: Constants.infuraToken)
75+
lazy var oracle: Web3.Oracle = .init(web3, block: .exact(blockNumber), blockCount: 20, percentiles: [10, 40, 60, 90])
6876
let etalonPercentiles: [BigUInt] = [
6977
93253857566, // 10 percentile
7078
106634912620, // 40 percentile
7179
111000000000, // 60 percentile
7280
127210686305 // 90 percentile
7381
]
7482

75-
let gasPriceLegacyPercentiles = oracle.gasPriceLegacyPercentiles
83+
let gasPriceLegacyPercentiles = await oracle.gasPriceLegacyPercentiles()
7684
XCTAssertEqual(gasPriceLegacyPercentiles, etalonPercentiles, "Arrays should be equal")
7785
}
7886

79-
func testAllTransactionInBlockDecodesWell() throws {
80-
let blockWithTransaction = try web3.eth.getBlockByNumber(blockNumber, fullTransactions: true)
87+
func testAllTransactionInBlockDecodesWell() async throws {
88+
let web3 = await Web3.InfuraMainnetWeb3(accessToken: Constants.infuraToken)
89+
lazy var oracle: Web3.Oracle = .init(web3, block: .exact(blockNumber), blockCount: 20, percentiles: [10, 40, 60, 90])
90+
let blockWithTransaction = try await web3.eth.getBlockByNumber(blockNumber, fullTransactions: true)
8191

8292
let nullTransactions = blockWithTransaction.transactions.filter {
8393
guard case .null = $0 else { return false }

0 commit comments

Comments
 (0)