-
Notifications
You must be signed in to change notification settings - Fork 0
/
Web3Services.swift
231 lines (181 loc) · 9.52 KB
/
Web3Services.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
//
// Web3Services.swift
// Crypta
//
// Created by Mitch on 7/6/22.
//
import Foundation
import web3swift
import BigInt
// MARK: Web3Services
/// Guts of interacting with are contract and other chain data
/// For more info about these methods check out web3swift docs
/// https://github.com/skywinder/web3swift/blob/develop/Documentation/Usage.md#get-balance
///
class Web3Services {
static let shared = Web3Services()
private var w3:web3
private let cryptaWallet:Wallet
init(){
let keystore = KeyStoreServices.shared.keystoreManager!
let name = "Crypta Wallet"
let keyData = try! JSONEncoder().encode(keystore.keystoreParams)
let address = keystore.addresses!.first!.address
let wallet = Wallet(address: address, data: keyData, name: name, isHD: false)
// add wallet data to keystoreManager
let keystoreManager = KeystoreManager([keystore])
self.cryptaWallet = wallet // set wallet
// Set up provider ie alfajores testnet
let provider = Web3HttpProvider(URL(string: alfajoresTestnet.rpcEndpoint)!, network: .Custom(networkID: alfajoresTestnet.chainId))
w3 = web3(provider:provider!)
// add keystoreManager to web3 object
w3.addKeystoreManager(keystoreManager)
}
struct Web3ServiceError:Error,LocalizedError,Identifiable {
var id:String {description}
let title:String
let description:String
}
// MARK: getWallet
/// Returns wallet struct
func getWallet() -> Wallet {
return self.cryptaWallet
}
// MARK: readContractMethod
/// Async method to read contract data.
/// - Note: Read data from contract is free unlike `writeContractMethod`.
/// - Parameter method: ContractMethods variable represents the contract method to call.
/// - Parameter parameters: parameters for contract method.
/// - Returns: Escaping result.
/// < Success: [String:Any], Failure: Web3Error >
///
func readContractMethod(method:ContractMethods,parameters:[AnyObject],completion:@escaping(Result<[String:Any],Web3Error>) -> Void) {
DispatchQueue.global().async{ [unowned self] in
do{
let senderAddress = EthereumAddress(cryptaWallet.address)
let contractAddress = EthereumAddress(contractAddress)
let extraData: Data = Data() // Extra data for contract method
let contract = w3.contract(contractABI, at: contractAddress, abiVersion: abiVersion)!
var options = TransactionOptions.defaultOptions
options.from = senderAddress
options.gasPrice = .automatic
options.gasLimit = .automatic
//
let tx = contract.read(method.rawValue,
parameters: parameters,
extraData: extraData,
transactionOptions: options)!
let result = try tx.call()
completion(.success(result))
}catch {
completion(.failure(error as! Web3Error))
}
}
}
// MARK: readContractMethod
/// Async method to read contract data.
/// - Note: Adjustable contract parameters work great for fetching token balances.
/// - Parameter contractAddress:String of contract address.
/// - Parameter contractABI: String of contract abi.
/// - Parameter method: String of contract method to call (Must match contract ABI)
/// - Parameter parameters: List of AnyObject's used for parameters of contract method .
/// - Returns: Escaping result.
/// < Success: [String:Any], Failure: Web3Error >
///
func readContractMethod(contractAddress:String, contractABI:String, method:String,parameters:[AnyObject],completion:@escaping(Result<[String:Any],Web3Error>) -> Void) {
DispatchQueue.global().async{ [unowned self] in
do{
let senderAddress = EthereumAddress(cryptaWallet.address)
let contractAddress = EthereumAddress(contractAddress)
let extraData: Data = Data() // Extra data for contract method
let contract = w3.contract(contractABI, at: contractAddress, abiVersion: abiVersion)!
var options = TransactionOptions.defaultOptions
options.from = senderAddress
options.gasPrice = .automatic
options.gasLimit = .automatic
let tx = contract.read(method,
parameters: parameters,
extraData: extraData,
transactionOptions: options)!
let result = try tx.call()
completion(.success(result))
}catch {
completion(.failure(error as! Web3Error))
}
}
}
// MARK: writeContractMethod
/// Async method to write contract data // Called when data is being written to the contract or on chain
///
/// - Note: This requires keystore password as the tx need to be signed by the private key
/// - Parameter method: ContractMethods enum, contract method to call (Using the rawValue String)
/// - Parameter parameters:list of Any objects used for input for contract method
/// - Parameter password: String password that was used to create the keystore (ie encrypt the privatekey)
/// - Returns: Escaping Result.
/// <Success: TransactionSendingResult, Failure: Web3Error>
///
func writeContractMethod(method:ContractMethods,parameters:[AnyObject],password:String,completion:@escaping(Result<TransactionSendingResult,Web3Error>) -> Void) {
DispatchQueue.global().async{ [unowned self] in
do{
let senderAddress = EthereumAddress(cryptaWallet.address)
let contractAddress = EthereumAddress(contractAddress)
// if your contract method is payable then you can also send value
//let amount = Web3.Utils.parseToBigUInt(value, units: .eth)
let extraData: Data = Data() // Extra data for contract method
let contract = w3.contract(contractABI, at: contractAddress, abiVersion: abiVersion)!
var options = TransactionOptions.defaultOptions
//options.value = amount // Only needed if sending native coin not token
options.from = senderAddress
options.gasPrice = .automatic
options.gasLimit = .automatic
let tx = contract.write(
method.rawValue,
parameters: parameters,
extraData: extraData,
transactionOptions: options)!
let result = try tx.send(password: password)
completion(.success(result))
}catch {
completion(.failure(error as! Web3Error))
}
}
}
// MARK: writeContractMethod
/// Async method to write contract data
///
///
/// - Note: This requires keystore (Wallet) password as the tx need to be signed by the private key
/// - Parameter contractAddress:String of contract address.
/// - Parameter contractABI: String of contract abi.
/// - Parameter method: String of contract method to call (Must match contract ABI)
/// - Parameter parameters:list of Any objects used for input for contract method
/// - Parameter password: String password that was used to create the keystore (ie encrypt the privatekey)
/// - Returns: Escaping Result.
/// <Success: TransactionSendingResult, Failure: Web3Error>
///
func writeContractMethod(contractAddress:String,contractABI:String,method:String,parameters:[AnyObject],password:String,completion:@escaping(Result<TransactionSendingResult,Web3Error>) -> Void) {
DispatchQueue.global().async{ [unowned self] in
do{
let senderAddress = EthereumAddress(cryptaWallet.address)
let contractAddress = EthereumAddress(contractAddress)
// if your contract method is payable then you can also send value
//let amount = Web3.Utils.parseToBigUInt(value, units: .eth)
let extraData: Data = Data() // Extra data for contract method
let contract = w3.contract(contractABI, at: contractAddress, abiVersion: abiVersion)!
var options = TransactionOptions.defaultOptions
options.from = senderAddress
options.gasPrice = .automatic
options.gasLimit = .automatic
let tx = contract.write(
method,
parameters: parameters,
extraData: extraData,
transactionOptions: options)!
let result = try tx.send(password: password)
completion(.success(result))
}catch {
completion(.failure(error as! Web3Error))
}
}
}
}