From 28b1334f1229f3bd77288f478fe74f7ae918b828 Mon Sep 17 00:00:00 2001 From: Jenea Vranceanu Date: Fri, 10 Mar 2023 17:36:27 +0200 Subject: [PATCH] feat: transaction polling task --- .../Transaction/TransactionPollingTask.swift | 66 +++++++++++++++++++ .../TransactionPollingTaskTest.swift | 33 ++++++++++ 2 files changed, 99 insertions(+) create mode 100644 Sources/web3swift/Transaction/TransactionPollingTask.swift create mode 100644 Tests/web3swiftTests/localTests/TransactionPollingTaskTest.swift diff --git a/Sources/web3swift/Transaction/TransactionPollingTask.swift b/Sources/web3swift/Transaction/TransactionPollingTask.swift new file mode 100644 index 000000000..08593e42c --- /dev/null +++ b/Sources/web3swift/Transaction/TransactionPollingTask.swift @@ -0,0 +1,66 @@ +// +// TransactionPollingTask.swift +// +// Created by JeneaVranceanu on 10.03.2023. +// + +import Foundation +import Web3Core + +/// Monitors a transaction's state on blockchain until transaction is completed successfully or not. +final public class TransactionPollingTask { + + private enum DelayUnit: UInt64 { + case shortest = 1 + case medium = 5 + case longest = 60 + + func shouldIncreaseDelay(_ startTime: Date) -> Bool { + let timePassed = Date().timeIntervalSince1970 - startTime.timeIntervalSince1970 + switch self { + case .shortest: + return timePassed > 10 + case .medium: + return timePassed > 120 + case .longest: + return false + } + } + + var nextDelayUnit: DelayUnit { + switch self { + case .shortest: + return .medium + case .medium, .longest: + return .longest + } + } + } + + public let transactionHash: Data + + private let web3Instance: Web3 + private var delayUnit: DelayUnit = .shortest + + public init(transactionHash: Data, web3Instance: Web3) { + self.transactionHash = transactionHash + self.web3Instance = web3Instance + } + + public func wait() async throws -> TransactionReceipt { + let startTime = Date() + while true { + let transactionReceipt = try await web3Instance.eth.transactionReceipt(transactionHash) + + if transactionReceipt.status != .notYetProcessed { + return transactionReceipt + } + + if delayUnit.shouldIncreaseDelay(startTime) { + delayUnit = delayUnit.nextDelayUnit + } + + try await Task.sleep(nanoseconds: delayUnit.rawValue) + } + } +} diff --git a/Tests/web3swiftTests/localTests/TransactionPollingTaskTest.swift b/Tests/web3swiftTests/localTests/TransactionPollingTaskTest.swift new file mode 100644 index 000000000..1ded4ce8a --- /dev/null +++ b/Tests/web3swiftTests/localTests/TransactionPollingTaskTest.swift @@ -0,0 +1,33 @@ +// +// TransactionPollingTaskTest.swift +// +// Created by JeneaVranceanu on 10.03.2023. +// + +import XCTest +import Foundation +@testable import web3swift +@testable import Web3Core + +class TransactionPollingTaskTest: LocalTestCase { + + func testTransactionPolling() async throws { + let web3 = try await Web3.new(LocalTestCase.url) + let sendToAddress = EthereumAddress("0xe22b8979739D724343bd002F9f432F5990879901")! + let allAddresses = try await web3.eth.ownedAccounts() + let contract = web3.contract(Web3.Utils.coldWalletABI, at: sendToAddress) + let writeTX = contract!.createWriteOperation("fallback")! + writeTX.transaction.from = allAddresses[0] + writeTX.transaction.value = 1 + + let policies = Policies(gasLimitPolicy: .automatic) + let result = try await writeTX.writeToChain(password: "", policies: policies, sendRaw: false) + + let txHash = Data.fromHex(result.hash.stripHexPrefix())! + + let transactionReceipt = try await TransactionPollingTask(transactionHash: txHash, web3Instance: web3).wait() + + XCTAssertEqual(transactionReceipt.status, .ok) + } + +}