Skip to content

Commit c2d8444

Browse files
Merge pull request #613 from yaroslavyaroslav/transaction-refactor
Transaction refactor
2 parents 3876bfa + bdc52be commit c2d8444

File tree

163 files changed

+3310
-5443
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

163 files changed

+3310
-5443
lines changed

Documentation/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ let parameters: [AnyObject] = <PARAMETERS>
154154
let extraData: Data = <DATA>
155155
let transactionOptions: TransactionOptions = <OPTIONS>
156156

157-
let transaction = contract.read(method, parameters: parameters, extraData: extraData, transactionOptions: transactionOptions)
157+
let transaction = contract.read(method, parameters: parameters, extraData: extraData )
158158
```
159159

160160
Here is the example how you should send transaction to some contract method:
@@ -164,7 +164,7 @@ let method: String = <CONTRACT METHOD NAME>
164164
let parameters: [AnyObject] = <PARAMETERS>
165165
let extraData: Data = <DATA>
166166
let transactionOptions: TransactionOptions = <OPTIONS>
167-
let transaction = contract.write(method, parameters: parameters, extraData: extraData, transactionOptions: transactionOptions)
167+
let transaction = contract.write(method, parameters: parameters, extraData: extraData )
168168
```
169169

170170
> How to test on a local node?

Documentation/web3swift 2.0 Migration Guide.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,8 @@ web3.addKeystoreManager(KeysService().keystoreManager())
109109
guard let ethAddressFrom = EthereumAddress(selectedKey) else {return}
110110
guard let contract = web3.contract(Web3.Utils.coldWalletABI, at: destinationEthAddress, abiVersion: 2) else {return}
111111
guard let writeTX = contract.write("fallback") else {return}
112-
writeTX.transactionOptions.from = ethAddressFrom
113-
writeTX.transactionOptions.value = value
112+
writeTX.transaction.from = ethAddressFrom
113+
writeTX.transaction.value = value
114114
return writeTX
115115
```
116116

@@ -152,8 +152,8 @@ web3.addKeystoreManager(KeysService().keystoreManager())
152152
guard let ethAddressFrom = EthereumAddress(selectedKey) else {return}
153153
guard let contract = web3.contract(Web3.Utils.erc20ABI, at: contractAddress, abiVersion: 2) else {return}
154154
guard let writeTX = contract.write("transfer") else {return}
155-
writeTX.transactionOptions.from = ethAddressFrom
156-
writeTX.transactionOptions.value = value
155+
writeTX.transaction.from = ethAddressFrom
156+
writeTX.transaction.value = value
157157
return writeTX
158158
```
159159

@@ -195,8 +195,8 @@ guard let writeTX = contract.write(method,
195195
parameters: parameters,
196196
extraData: data,
197197
transactionOptions: predefinedOptions) else {return}
198-
writeTX.transactionOptions.from = ethAddressFrom
199-
writeTX.transactionOptions.value = value
198+
writeTX.transaction.from = ethAddressFrom
199+
writeTX.transaction.value = value
200200
return writeTX
201201
```
202202

@@ -218,7 +218,7 @@ return value
218218
let options = options ?? transaction.transactionOptions
219219
guard let result = password == nil ?
220220
try? transaction.send() :
221-
try? transaction.send(password: <your password>, transactionOptions: options) else {return}
221+
try? transaction.send(password: <your password> ) else {return}
222222
return result
223223
```
224224

@@ -234,7 +234,7 @@ return value
234234

235235
// web3swift 2.0
236236
let options = options ?? transaction.transactionOptions
237-
guard let result = try? transaction.call(transactionOptions: options) else {return}
237+
guard let result = try? transaction.decodedData(with: options) else {return}
238238
return result
239239
```
240240

@@ -273,7 +273,7 @@ let contractAddress = EthereumAddress("<Contract address>")! // w3s token on Eth
273273
let contract = web3.contract(Web3.Utils.erc20ABI, at: contractAddress, abiVersion: 2) // utilize precompiled ERC20 ABI for your concenience
274274
let userAddress = EthereumAddress("<address>")!
275275
guard let readTX = contract?.read("balanceOf", parameters: [addressOfUser] as [AnyObject]) else {return}
276-
readTX.transactionOptions.from = EthereumAddress("<address>")!
276+
readTX.transaction.from = EthereumAddress("<address>")!
277277
let tokenBalance = try readTX.callPromise()
278278
guard let balance = tokenBalance["0"] as? BigUInt else {return}
279279
```

Package.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ let package = Package(
2121
],
2222
dependencies: [
2323
.package(url: "https://github.com/attaswift/BigInt.git", from: "5.3.0"),
24-
.package(url: "https://github.com/daltoniam/Starscream.git", from: "4.0.4"),
2524
.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", from: "1.5.1")
2625
],
2726
targets: [
@@ -32,7 +31,7 @@ let package = Package(
3231
),
3332
.target(
3433
name: "web3swift",
35-
dependencies: ["Core", "BigInt", "secp256k1", "Starscream"],
34+
dependencies: ["Core", "BigInt", "secp256k1"],
3635
exclude: excludeFiles,
3736
resources: [
3837
.copy("./Browser/browser.js"),

Sources/web3swift/Contract/ContractProtocol.swift renamed to Sources/Core/Contract/ContractProtocol.swift

Lines changed: 70 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,64 @@
88

99
import Foundation
1010
import BigInt
11-
import Core
1211

1312
/// Standard representation of a smart contract.
13+
///
14+
/// ## How to
15+
/// To create a smart contract deployment transaction there is only one requirement - `bytecode`.
16+
/// That is the compiled smart contract that is ready to be executed by EVM, or eWASM if that is a Serenity.
17+
/// Creating a transaction is as simple as:
18+
///
19+
/// ```swift
20+
/// contractInstance.deploy(bytecode: smartContractBytecode)
21+
/// ```
22+
///
23+
/// One of the default implementations of `ContractProtocol` is ``EthereumContract``.
24+
/// ```swift
25+
/// let contract = EthereumContract(abi: [])
26+
/// contract.deploy(bytecode: smartContractBytecode)
27+
/// ```
28+
///
29+
/// ### Setting constructor arguments
30+
/// Some smart contracts expect input arguments for a constructor that is called on contract deployment.
31+
/// To set these input arguments you must provide `constructor` and `parameters`.
32+
/// Constructor can be statically created if you know upfront what are the input arguments and their exact order:
33+
///
34+
/// ```swift
35+
/// let inputArgsTypes: [ABI.Element.InOut] = [.init(name: "firstArgument", type: ABI.Element.ParameterType.string),
36+
/// .init(name: "secondArgument", type: ABI.Element.ParameterType.uint(bits: 256))]
37+
/// let constructor = ABI.Element.Constructor(inputs: inputArgsTypes, constant: false, payable: payable)
38+
/// let constructorArguments = ["This is the array of constructor arguments", 10_000] as [AnyObject]
39+
///
40+
/// contract.deploy(bytecode: smartContractBytecode,
41+
/// constructor: constructor,
42+
/// parameters: constructorArguments)
43+
/// ```
44+
///
45+
/// Alternatively, if you have ABI string that holds meta data about the constructor you can use it instead of creating constructor manually.
46+
/// But you must make sure the arguments for constructor call are of expected type in and correct order.
47+
/// Example of ABI string can be found in ``Web3/Utils/erc20ABI``.
48+
///
49+
/// ```swift
50+
/// let contract = EthereumContract(abiString)
51+
/// let constructorArguments = ["This is the array of constructor arguments", 10_000] as [AnyObject]
52+
///
53+
/// contract.deploy(bytecode: smartContractBytecode,
54+
/// constructor: contract.constructor,
55+
/// parameters: constructorArguments)
56+
/// ```
57+
///
58+
/// ⚠️ If you pass in only constructor or only parameters - it will have no effect on the final transaction object.
59+
/// Also, you have an option to set any extra bytes at the end of ``CodableTransaction/data`` attribute.
60+
/// Alternatively you can encode constructor parameters outside of the deploy function and only set `extraData` to pass in these
61+
/// parameters:
62+
///
63+
/// ```swift
64+
/// // `encodeParameters` call returns `Data?`. Check it for nullability before calling `deploy`
65+
/// // function to create `CodableTransaction`.
66+
/// let encodedConstructorArguments = someConstructor.encodeParameters(arrayOfInputArguments)
67+
/// constructor.deploy(bytecode: smartContractBytecode, extraData: encodedConstructorArguments)
68+
/// ```
1469
public protocol ContractProtocol {
1570
/// Address of the referenced smart contract. Can be set later, e.g. if the contract is deploying and address is not yet known.
1671
var address: EthereumAddress? {get set}
@@ -55,76 +110,19 @@ public protocol ContractProtocol {
55110
/// new Solidity keywords, types etc. that are not yet supported, etc.
56111
init(_ abiString: String, at: EthereumAddress?) throws
57112

58-
/// Creates a smart contract deployment transaction.
59-
///
60-
/// ## How to
61-
/// To create a smart contract deployment transaction there is only one requirement - `bytecode`.
62-
/// That is the compiled smart contract that is ready to be executed by EVM, or eWASM if that is a Serenity.
63-
/// Creating a transaction is as simple as:
64-
///
65-
/// ```swift
66-
/// contractInstance.deploy(bytecode: smartContractBytecode)
67-
/// ```
68-
///
69-
/// One of the default implementations of `ContractProtocol` is ``EthereumContract``.
70-
/// ```swift
71-
/// let contract = EthereumContract(abi: [])
72-
/// contract.deploy(bytecode: smartContractBytecode)
73-
/// ```
74-
///
75-
/// ### Setting constructor arguments
76-
/// Some smart contracts expect input arguments for a constructor that is called on contract deployment.
77-
/// To set these input arguments you must provide `constructor` and `parameters`.
78-
/// Constructor can be statically created if you know upfront what are the input arguments and their exact order:
79-
///
80-
/// ```swift
81-
/// let inputArgsTypes: [ABI.Element.InOut] = [.init(name: "firstArgument", type: ABI.Element.ParameterType.string),
82-
/// .init(name: "secondArgument", type: ABI.Element.ParameterType.uint(bits: 256))]
83-
/// let constructor = ABI.Element.Constructor(inputs: inputArgsTypes, constant: false, payable: payable)
84-
/// let constructorArguments = ["This is the array of constructor arguments", 10_000] as [AnyObject]
85-
///
86-
/// contract.deploy(bytecode: smartContractBytecode,
87-
/// constructor: constructor,
88-
/// parameters: constructorArguments)
89-
/// ```
90-
///
91-
/// Alternatively, if you have ABI string that holds meta data about the constructor you can use it instead of creating constructor manually.
92-
/// But you must make sure the arguments for constructor call are of expected type in and correct order.
93-
/// Example of ABI string can be found in ``Web3/Utils/erc20ABI``.
94-
///
95-
/// ```swift
96-
/// let contract = EthereumContract(abiString)
97-
/// let constructorArguments = ["This is the array of constructor arguments", 10_000] as [AnyObject]
98-
///
99-
/// contract.deploy(bytecode: smartContractBytecode,
100-
/// constructor: contract.constructor,
101-
/// parameters: constructorArguments)
102-
/// ```
103-
///
104-
/// ⚠️ If you pass in only constructor or only parameters - it will have no effect on the final transaction object.
105-
/// Also, you have an option to set any extra bytes at the end of ``EthereumTransaction/data`` attribute.
106-
/// Alternatively you can encode constructor parameters outside of the deploy function and only set `extraData` to pass in these
107-
/// parameters:
108-
///
109-
/// ```swift
110-
/// // `encodeParameters` call returns `Data?`. Check it for nullability before calling `deploy`
111-
/// // function to create `EthereumTransaction`.
112-
/// let encodedConstructorArguments = someConstructor.encodeParameters(arrayOfInputArguments)
113-
/// constructor.deploy(bytecode: smartContractBytecode, extraData: encodedConstructorArguments)
114-
/// ```
113+
/// Prepare transaction data for smart contract deployment transaction.
115114
///
116115
/// - Parameters:
117116
/// - bytecode: bytecode to deploy.
118117
/// - constructor: constructor of the smart contract bytecode is related to. Used to encode `parameters`.
119118
/// - parameters: parameters for `constructor`.
120119
/// - extraData: any extra data. It can be encoded input arguments for a constuctor but then you should set `constructor` and
121120
/// `parameters` to be `nil`.
122-
/// - Returns: transaction if given `parameters` were successfully encoded in a `constructor`. If any or both are `nil`
123-
/// then no encoding will take place and a transaction with `bytecode + extraData` will be returned.
121+
/// - Returns: Encoded data for a given parameters, which is should be assigned to ``CodableTransaction.data`` property
124122
func deploy(bytecode: Data,
125123
constructor: ABI.Element.Constructor?,
126124
parameters: [AnyObject]?,
127-
extraData: Data?) -> EthereumTransaction?
125+
extraData: Data?) -> Data?
128126

129127
/// Creates function call transaction with data set as `method` encoded with given `parameters`.
130128
/// The `method` must be part of the ABI used to init this contract.
@@ -136,7 +134,7 @@ public protocol ContractProtocol {
136134
/// - parameters: method input arguments;
137135
/// - extraData: additional data to append at the end of `transaction.data` field;
138136
/// - Returns: transaction object if `method` was found and `parameters` were successfully encoded.
139-
func method(_ method: String, parameters: [AnyObject], extraData: Data?) -> EthereumTransaction?
137+
func method(_ method: String, parameters: [AnyObject], extraData: Data?) -> Data?
140138

141139
/// Decode output data of a function.
142140
/// - Parameters:
@@ -188,7 +186,7 @@ extension ContractProtocol {
188186
func deploy(_ bytecode: Data,
189187
constructor: ABI.Element.Constructor? = nil,
190188
parameters: [AnyObject]? = nil,
191-
extraData: Data? = nil) -> EthereumTransaction? {
189+
extraData: Data? = nil) -> Data? {
192190
deploy(bytecode: bytecode,
193191
constructor: constructor,
194192
parameters: parameters,
@@ -201,7 +199,7 @@ extension ContractProtocol {
201199
/// See ``ContractProtocol/method(_:parameters:extraData:)`` for details.
202200
func method(_ method: String = "fallback",
203201
parameters: [AnyObject]? = nil,
204-
extraData: Data? = nil) -> EthereumTransaction? {
202+
extraData: Data? = nil) -> Data? {
205203
self.method(method, parameters: parameters ?? [], extraData: extraData)
206204
}
207205

@@ -220,15 +218,15 @@ extension DefaultContractProtocol {
220218
public func deploy(bytecode: Data,
221219
constructor: ABI.Element.Constructor?,
222220
parameters: [AnyObject]?,
223-
extraData: Data?) -> EthereumTransaction? {
221+
extraData: Data?) -> Data? {
224222
var fullData = bytecode
225223

226224
if let constructor = constructor,
227225
let parameters = parameters,
228226
!parameters.isEmpty {
229227
guard constructor.inputs.count == parameters.count,
230-
let encodedData = constructor.encodeParameters(parameters)
231-
else {
228+
// FIXME: This should be zipped, because Arrays don't guarantee it's elements order
229+
let encodedData = constructor.encodeParameters(parameters) else {
232230
NSLog("Constructor encoding will fail as the number of input arguments doesn't match the number of given arguments.")
233231
return nil
234232
}
@@ -240,18 +238,15 @@ extension DefaultContractProtocol {
240238
}
241239

242240
// MARK: Writing Data flow
243-
return EthereumTransaction(to: .contractDeploymentAddress(),
244-
value: BigUInt(0),
245-
data: fullData,
246-
parameters: .init(gasLimit: BigUInt(0), gasPrice: BigUInt(0)))
241+
return fullData
247242
}
248243

249244
/// Call given contract method with given parameters
250245
/// - Parameters:
251246
/// - method: Method to call
252247
/// - parameters: Parameters to pass to method call
253248
/// - extraData: Any additional data that needs to be encoded
254-
/// - Returns: preset EthereumTransaction with filled date
249+
/// - Returns: preset CodableTransaction with filled date
255250
///
256251
/// Returned transaction have filled following priperties:
257252
/// - to: contractAddress
@@ -260,14 +255,10 @@ extension DefaultContractProtocol {
260255
/// - params: EthereumParameters with no contract method call encoded data.
261256
public func method(_ method: String,
262257
parameters: [AnyObject],
263-
extraData: Data?) -> EthereumTransaction? {
264-
guard let to = self.address else { return nil }
265-
266-
let params = EthereumParameters(gasLimit: BigUInt(0), gasPrice: BigUInt(0))
267-
258+
extraData: Data?) -> Data? {
268259
// MARK: - Encoding ABI Data flow
269260
if method == "fallback" {
270-
return EthereumTransaction(to: to, value: BigUInt(0), data: extraData ?? Data(), parameters: params)
261+
return extraData ?? Data()
271262
}
272263

273264
let method = Data.fromHex(method) == nil ? method : method.addHexPrefix().lowercased()
@@ -282,9 +273,7 @@ extension DefaultContractProtocol {
282273
}
283274

284275
// MARK: - Encoding ABI Data flow
285-
// return filled EthereumTransaction, which is could be sent iterate with a contract.
286-
// But no gas related data here yet.
287-
return EthereumTransaction(to: to, value: BigUInt(0), data: encodedData, parameters: params)
276+
return encodedData
288277
}
289278

290279
public func parseEvent(_ eventLog: EventLog) -> (eventName: String?, eventData: [String: Any]?) {

Sources/web3swift/Contract/EthereumContract.swift renamed to Sources/Core/Contract/EthereumContract.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
import Foundation
77
import BigInt
8-
import Core
98

109
/// Default representation of a smart contract. Created out of an array of ``ABI/Element`` which could be functions, events,
1110
/// constructor, errors and optional ``EthereumAddress`` that could be set later.

Sources/web3swift/EthereumABI/ABIDecoding.swift renamed to Sources/Core/EthereumABI/ABIDecoding.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
import Foundation
77
import BigInt
8-
import Core
98

109
public struct ABIDecoder { }
1110

Sources/web3swift/EthereumABI/ABIElements.swift renamed to Sources/Core/EthereumABI/ABIElements.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
import Foundation
77
import BigInt
8-
import Core
98

109
public extension ABI {
1110
struct Input: Decodable {
@@ -195,6 +194,7 @@ extension ABI.Element {
195194
extension ABI.Element.Constructor {
196195
public func encodeParameters(_ parameters: [AnyObject]) -> Data? {
197196
guard parameters.count == inputs.count else { return nil }
197+
// FIXME: This should be zipped, because Arrays don't guarantee it's elements order
198198
return ABIEncoder.encode(types: inputs, values: parameters)
199199
}
200200
}
@@ -262,7 +262,7 @@ extension ABI.Element {
262262

263263
extension ABI.Element.Function {
264264
public func decodeInputData(_ rawData: Data) -> [String: Any]? {
265-
return web3swift.decodeInputData(rawData, methodEncoding: methodEncoding, inputs: inputs)
265+
return Core.decodeInputData(rawData, methodEncoding: methodEncoding, inputs: inputs)
266266
}
267267

268268
public func decodeReturnData(_ data: Data) -> [String: Any]? {
@@ -337,7 +337,7 @@ extension ABI.Element.Function {
337337

338338
extension ABI.Element.Constructor {
339339
public func decodeInputData(_ rawData: Data) -> [String: Any]? {
340-
return web3swift.decodeInputData(rawData, inputs: inputs)
340+
return Core.decodeInputData(rawData, inputs: inputs)
341341
}
342342
}
343343

0 commit comments

Comments
 (0)