-
Notifications
You must be signed in to change notification settings - Fork 443
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #104 from matterinc/develop
recent changes
- Loading branch information
Showing
755 changed files
with
123,630 additions
and
11,822 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,307 @@ | ||
|
||
# web3swift 2.0 Migration Guide | ||
|
||
web3swift 2.0 is the latest major release of web3swift by Matter, Swift implementation of web3.js functionality for iOS and macOS. Following Semantic Versioning conventions, 2.0 introduces major release API-breaking changes. | ||
|
||
This guide is provided in order to ease the transition of existing applications using web3swift 1.x to the latest APIs, as well as explain the design and structure of new and updated functionality. | ||
|
||
- [Requirements](#requirements) | ||
- [Benefits of Upgrading](#benefits-of-upgrading) | ||
- [Follow naming convention](#follow-naming-convention) | ||
- [New pods](#new-pods) | ||
- [Breaking API Changes](#breaking-api-changes) | ||
- [Setting Transaction Options](#setting-transaction-options) | ||
- [Preparing transaction](#preparing-transaction) | ||
- [For sending Ether](#for-sending-ether) | ||
- [For sending ERC20](#for-sending-erc20) | ||
- [For sending to contract](#for-sending-to-contract) | ||
- [Send transaction](#send-transaction) | ||
- [For sending ether or tokens to wallets and contracts](#for-sending-ether-or-tokens-to-wallets-and-contracts) | ||
- [For calling contract methods](#for-calling-contract-methods) | ||
- [Get balance](#get-balance) | ||
- [Get Ether balance](#get-ether-balance) | ||
- [Get ERC20 balance](#get-erc20-balance) | ||
- [Chain state](#chain-state) | ||
- [Get Block number](#get-block-number) | ||
|
||
## Requirements | ||
|
||
- iOS 9.0+, macOS 10.11.0+ | ||
- Xcode 10.0+ | ||
- Swift 4.0+ | ||
|
||
## Benefits of Upgrading | ||
|
||
- **Complete Swift 4 Compatibility:** includes the full adoption of the new [API Design Guidelines](https://swift.org/documentation/api-design-guidelines/). | ||
- **Separate libraries: EthereumAddress, EthereumABI:** Since there are several Matter products uses this classes, we've decided make them separate and turn in Pods. | ||
- **New class: TransactionOptions:** "Web3Options" is no longer used, instead new class introduced: "TransactionOptions" used to specify gas price, limit, nonce policy, value. | ||
- **New classes: Write Transaction & Read Transaction:** "TransactionIntermediate" is no longer used, instead two new classes introduced: "ReadTransaction" and "WriteTransaction", that have a variable "transactionOptions" used to specify gas price, limit, nonce policy, value | ||
- **WKWebView with injected "web3" provider:** create a simple DApps' browser with "web3" provider onboard. | ||
- **Add or remove "middleware":** that intercepts, modifies and even cancel transaction workflow on stages "before assembly" (before obtaining nonce, gas price, etc), "after assembly" (when nonce and gas price is set for transaction) and "before submission" (right before transaction is either signed locally and is sent as raw, or just send to remote node). | ||
- **Hooks and event loops functionality:** easy monitor properties in web3. | ||
- **New errors handling:** more 'try-catch' less optionals for errors handling. | ||
- **Removed "Result" framework:** usage of "Result" framework was removed due to large amount if name conflicts, now functions throw instead of returning "Result" wrapper. | ||
|
||
--- | ||
|
||
## Follow naming convention | ||
|
||
Now you have to do "import Web3swift" (capitalization!) instead of "import web3swift" to follow naming convention. | ||
|
||
## New pods | ||
|
||
Now EthereumAddress and Ethereum ABI are separate projects. Use "import EthereumAddress" and "import Ethereum ABI" everywhere you use them. | ||
|
||
## Breaking API Changes | ||
|
||
web3swift 2.0 has fully adopted all the new Swift 4 changes and conventions, including the new [API Design Guidelines](https://swift.org/documentation/api-design-guidelines/). Because of this, almost every API in web3swift has been modified in some way. We can't possibly document every single change, so we're going to attempt to identify the most important API changes to help you through those sometimes less than helpful compiler errors. | ||
|
||
### Setting Transaction Options | ||
|
||
Since setting transaction options is the most important operation for building transaction in web3swift, here are some examples of web3swift 1.x building transaction options compared to their new equivalents in web3swift 2.0. | ||
|
||
```swift | ||
// web3swift 1.0 | ||
var options = Web3Options() | ||
options.gasLimit = BigUInt(0) | ||
options.gasPrice = BigUInt(0) | ||
options.value = BigUInt(0) | ||
options.to = EthereumAddress("<Reciever address>")! | ||
options.from = EthereumAddress("<Sender address>")! | ||
|
||
// web3swift 2.0 | ||
var options = TransactionOptions() | ||
options.callOnBlock = .pending // or .latest / or .exactBlockNumber(BigUInt) | ||
options.nonce = .pending // or .latest / or .manual(BigUInt) | ||
options.gasLimit = .automatic // or .manual(BigUInt) / or .limited(BigUInt) / or .withMargin(Double) | ||
options.gasPrice = .automatic // or .manual(BigUInt) / or .withMargin(Double) | ||
options.to = EthereumAddress("<Reciever address>")! | ||
options.from = EthereumAddress("<Sender address>")! | ||
``` | ||
|
||
### Preparing transaction | ||
|
||
In web3swift 1.0 you specified transactions for Ether, ERC20 and to contract in different, inconvenient and unobvious ways. From 2.0 on it became more convenient and obvious. | ||
|
||
#### For sending Ether | ||
|
||
```swift | ||
// web3swift 1.0 | ||
guard let destinationEthAddress = EthereumAddress(destinationAddressString) else {return} | ||
guard let amount = Web3.Utils.parseToBigUInt(amountString, units: .eth) else {return} | ||
guard let selectedKey = KeysService().selectedWallet()?.address else {return} | ||
let web3 = web3swift.web3(provider: InfuraProvider(Networks.Mainnet)!) //or any other network | ||
web3.addKeystoreManager(KeysService().keystoreManager()) | ||
let ethAddressFrom = EthereumAddress(selectedKey) | ||
var options = Web3Options.defaultOptions() | ||
options.from = ethAddressFrom | ||
options.value = BigUInt(amount) | ||
guard let contract = web3.contract(Web3.Utils.coldWalletABI, at: destinationEthAddress) else {return} | ||
guard let estimatedGas = contract.method(options: options)?.estimateGas(options: nil).value else {return} | ||
options.gasLimit = estimatedGas | ||
guard let gasPrice = web3.eth.getGasPrice().value else {return} | ||
options.gasPrice = gasPrice | ||
guard let transaction = contract.method(options: options) else {return} | ||
return transaction | ||
|
||
// web3swift 2.0 | ||
guard let destinationEthAddress = EthereumAddress(destinationAddressString) else {return} | ||
guard let amount = Web3.Utils.parseToBigUInt(amountString, units: .eth) else {return} | ||
guard let selectedKey = KeysService().selectedWallet()?.address else {return} | ||
let web3 = Web3.InfuraMainnetWeb3() //or any other network | ||
web3.addKeystoreManager(KeysService().keystoreManager()) | ||
guard let ethAddressFrom = EthereumAddress(selectedKey) else {return} | ||
guard let contract = web3.contract(Web3.Utils.coldWalletABI, at: destinationEthAddress, abiVersion: 2) else {return} | ||
guard let writeTX = contract.write("fallback") else {return} | ||
writeTX.transactionOptions.from = ethAddressFrom | ||
writeTX.transactionOptions.value = value | ||
return writeTX | ||
``` | ||
|
||
#### For sending ERC20 | ||
|
||
```swift | ||
// web3swift 1.0 | ||
guard let destinationEthAddress = EthereumAddress(destinationAddressString) else {return} | ||
guard let amount = Web3.Utils.parseToBigUInt(amountString, units: .eth) else {return} | ||
let web3 = web3swift.web3(provider: InfuraProvider(Networks.Mainnet)!) //or any other network | ||
web3.addKeystoreManager(KeysService().keystoreManager()) | ||
let contract = self.contract(for: token, web3: web3) | ||
var options = Web3Options.defaultOptions() | ||
guard let tokenAddress = EthereumAddress(token), | ||
let fromAddress = Web3SwiftService.currentAddress, | ||
let intermediate = web3.eth.sendERC20tokensWithNaturalUnits(tokenAddress: tokenAddress, | ||
from: fromAddress, | ||
to: destinationEthAddress, | ||
amount: amountString) else {return} | ||
//MARK: - Just to check that everything is all right | ||
guard let _ = contract?.method(options: options)?.estimateGas(options: options).value else {return} | ||
guard let gasPrice = web3.eth.getGasPrice().value else {return} | ||
options.from = Web3SwiftService.currentAddress | ||
options.gasPrice = gasPrice | ||
options.value = 0 | ||
options.to = EthereumAddress(token) | ||
let parameters = [destinationEthAddress, amount] as [Any] | ||
guard let transaction = contract?.method("transfer", | ||
parameters: parameters as [AnyObject], | ||
options: options) else {return} | ||
return transaction | ||
|
||
// web3swift 2.0 | ||
guard let contractAddress = EthereumAddress(contractAddressString) else {return} | ||
guard let amount = Web3.Utils.parseToBigUInt(amountString, units: .eth) else {return} | ||
guard let selectedKey = KeysService().selectedWallet()?.address else {return} | ||
let web3 = Web3.InfuraMainnetWeb3() //or any other network | ||
web3.addKeystoreManager(KeysService().keystoreManager()) | ||
guard let ethAddressFrom = EthereumAddress(selectedKey) else {return} | ||
guard let contract = web3.contract(Web3.Utils.erc20ABI, at: contractAddress, abiVersion: 2) else {return} | ||
guard let writeTX = contract.write("transfer") else {return} | ||
writeTX.transactionOptions.from = ethAddressFrom | ||
writeTX.transactionOptions.value = value | ||
return writeTX | ||
``` | ||
|
||
#### For sending to contract | ||
|
||
```swift | ||
// web3swift 1.0 | ||
let wallet = TransactionsService.keyservice.selectedWallet() | ||
guard let address = wallet?.address else {return} | ||
guard let ethAddressFrom = EthereumAddress(address) else {return} | ||
guard let ethContractAddress = EthereumAddress(contractAddress) else {return} | ||
let web3 = Web3.InfuraMainnetWeb3() //or any other web | ||
web3.addKeystoreManager(TransactionsService.keyservice.keystoreManager()) | ||
var options = predefinedOptions ?? Web3Options.defaultOptions() | ||
options.from = ethAddressFrom | ||
options.to = ethContractAddress | ||
options.value = options.value ?? 0 | ||
guard let contract = web3.contract(contractAbi, | ||
at: ethContractAddress, | ||
abiVersion: 2) else {return} | ||
guard let gasPrice = web3.eth.getGasPrice().value else {return} | ||
options.gasPrice = predefinedOptions?.gasPrice ?? gasPrice | ||
guard let transaction = contract.method(method, | ||
parameters: data, | ||
options: options) else {return} | ||
guard case .success(let estimate) = transaction.estimateGas(options: options) else {return} | ||
print("estimated cost: \(estimate)") | ||
return transaction | ||
|
||
// web3swift 2.0 | ||
guard let contractAddress = EthereumAddress(contractAddressString) else {return} | ||
guard let amount = Web3.Utils.parseToBigUInt(amountString, units: .eth) else {return} | ||
guard let selectedKey = KeysService().selectedWallet()?.address else {return} | ||
let web3 = Web3.InfuraMainnetWeb3() //or any other network | ||
web3.addKeystoreManager(KeysService().keystoreManager()) | ||
guard let ethAddressFrom = EthereumAddress(selectedKey) else {return} | ||
guard let contract = web3.contract(contractAbi, at: contractAddress, abiVersion: 2) else {return} | ||
guard let writeTX = contract.write(method, | ||
parameters: parameters, | ||
extraData: data, | ||
transactionOptions: predefinedOptions) else {return} | ||
writeTX.transactionOptions.from = ethAddressFrom | ||
writeTX.transactionOptions.value = value | ||
return writeTX | ||
``` | ||
|
||
### Send transaction | ||
|
||
In web3swift 1.0 you specified sending operations with only value and to contract in different, inconvenient and unobvious ways. From 2.0 on you can use two methods: Send to send ether or tokens and Call for calling contract methods. | ||
|
||
#### For sending ether or tokens to wallets and contracts | ||
|
||
```swift | ||
// web3swift 1.0 | ||
let result = transaction.send(password: <your password>, | ||
options: options) | ||
if let error = result.error {return} | ||
guard let value = result.value else {return} | ||
return value | ||
|
||
// web3swift 2.0 | ||
let options = options ?? transaction.transactionOptions | ||
guard let result = password == nil ? | ||
try? transaction.send() : | ||
try? transaction.send(password: <your password>, transactionOptions: options) else {return} | ||
return result | ||
``` | ||
|
||
#### For calling contract methods | ||
|
||
```swift | ||
// web3swift 1.0 | ||
let result = transaction.send(password: <your password>, | ||
options: transaction.options) | ||
if let error = result.error {return} | ||
guard let value = result.value else {return} | ||
return value | ||
|
||
// web3swift 2.0 | ||
let options = options ?? transaction.transactionOptions | ||
guard let result = try? transaction.call(transactionOptions: options) else {return} | ||
return result | ||
``` | ||
|
||
### Get balance | ||
|
||
### Get Ether balance | ||
|
||
```swift | ||
// web3swift 1.0 | ||
let address = EthereumAddress("<Address>")! | ||
let web3Main = Web3.InfuraMainnetWeb3() | ||
let balanceResult = web3Main.eth.getBalance(address) | ||
guard case .success(let balance) = balanceResult else {return} | ||
let balanceString = Web3.Utils.formatToEthereumUnits(balance, toUnits: .eth, decimals: 3) | ||
|
||
// web3swift 2.0 | ||
let address = EthereumAddress("<Address>")! | ||
let web3Main = Web3.InfuraMainnetWeb3() | ||
let balance = try web3.eth.getBalance(address: address) | ||
let balanceString = Web3.Utils.formatToEthereumUnits(balance, toUnits: .eth, decimals: 3) | ||
``` | ||
|
||
### Get ERC20 balance | ||
|
||
```swift | ||
// web3swift 1.0 | ||
let contractAddress = EthereumAddress("<Contract ddress>")! // w3s token on Ethereum mainnet | ||
let contract = web3.contract(Web3.Utils.erc20ABI, at: contractAddress, abiVersion: 2)! // utilize precompiled ERC20 ABI for your concenience | ||
guard let w3sBalanceResult = contract.method("balanceOf", | ||
parameters: [coldWalletAddress] as [AnyObject], | ||
options: options)?.call(options: nil) else {return} // encode parameters for transaction | ||
guard case .success(let w3sBalance) = w3sBalanceResult, let bal = w3sBalance["0"] as? BigUInt else {return} // w3sBalance is [String: Any], and parameters are enumerated as "0", "1", etc in order of being returned. If returned parameter has a name in ABI, it is also duplicated | ||
|
||
// web3swift 2.0 | ||
let contractAddress = EthereumAddress("<Contract address>")! // w3s token on Ethereum mainnet | ||
let contract = web3.contract(Web3.Utils.erc20ABI, at: contractAddress, abiVersion: 2) // utilize precompiled ERC20 ABI for your concenience | ||
let userAddress = EthereumAddress("<address>")! | ||
guard let readTX = contract?.read("balanceOf", parameters: [addressOfUser] as [AnyObject]) else {return} | ||
readTX.transactionOptions.from = EthereumAddress("<address>")! | ||
let tokenBalance = try readTX.callPromise().wait() | ||
guard let balance = tokenBalance["0"] as? BigUInt else {return} | ||
``` | ||
|
||
### Chain state | ||
|
||
### Get Block number | ||
|
||
```swift | ||
// web3swift 1.0 | ||
let web3 = WalletWeb3Factory.web3() | ||
let res = web3.eth.getBlockNumber() | ||
switch res { | ||
case .failure(let error): | ||
return error | ||
case .success(let number): | ||
return number | ||
} | ||
|
||
// web3swift 2.0 | ||
do { | ||
let number = try web3.eth.getBlockNumber() | ||
return number | ||
} catch let error { | ||
return error | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
platform :ios, '12.0' | ||
|
||
target 'web3swiftBrowser' do | ||
use_frameworks! | ||
pod 'web3swift', :path => '../../' | ||
pod "WKBridge" | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
PODS: | ||
- BigInt (3.1.0): | ||
- SipHash (~> 1.2) | ||
- CryptoSwift (0.13.0) | ||
- EthereumABI (1.1.1): | ||
- BigInt (~> 3.1) | ||
- CryptoSwift (~> 0.13) | ||
- EthereumAddress (~> 1.0.0) | ||
- EthereumAddress (1.0.0): | ||
- CryptoSwift (~> 0.13) | ||
- PromiseKit (6.5.2): | ||
- PromiseKit/CorePromise (= 6.5.2) | ||
- PromiseKit/Foundation (= 6.5.2) | ||
- PromiseKit/UIKit (= 6.5.2) | ||
- PromiseKit/CorePromise (6.5.2) | ||
- PromiseKit/Foundation (6.5.2): | ||
- PromiseKit/CorePromise | ||
- PromiseKit/UIKit (6.5.2): | ||
- PromiseKit/CorePromise | ||
- scrypt (2.0): | ||
- CryptoSwift (~> 0.11) | ||
- secp256k1_swift (1.0.3) | ||
- SipHash (1.2.2) | ||
- SwiftRLP (1.2): | ||
- BigInt (~> 3.1) | ||
- web3swift (2.0.1): | ||
- BigInt (~> 3.1) | ||
- CryptoSwift (~> 0.13) | ||
- EthereumABI (~> 1.1.1) | ||
- EthereumAddress (~> 1.0.0) | ||
- PromiseKit (~> 6.3) | ||
- scrypt (~> 2.0) | ||
- secp256k1_swift (~> 1.0.3) | ||
- SwiftRLP (~> 1.1) | ||
- WKBridge (0.2.4) | ||
|
||
DEPENDENCIES: | ||
- web3swift (from `../../`) | ||
- WKBridge | ||
|
||
SPEC REPOS: | ||
https://github.com/cocoapods/specs.git: | ||
- BigInt | ||
- CryptoSwift | ||
- EthereumABI | ||
- EthereumAddress | ||
- PromiseKit | ||
- scrypt | ||
- secp256k1_swift | ||
- SipHash | ||
- SwiftRLP | ||
- WKBridge | ||
|
||
EXTERNAL SOURCES: | ||
web3swift: | ||
:path: "../../" | ||
|
||
SPEC CHECKSUMS: | ||
BigInt: 76b5dfdfa3e2e478d4ffdf161aeede5502e2742f | ||
CryptoSwift: 16e78bebf567bad1c87b2d58f6547f25b74c31aa | ||
EthereumABI: f040f5429e5a4366d028c88b88d9441e137593af | ||
EthereumAddress: f476e1320dca3a0024431e713ede7a09c7eb7796 | ||
PromiseKit: 27c1601bfb73405871b805bcb8cf7e55c4dad3db | ||
scrypt: 3fe5b1a3b0976f97cd87488673a8f7c65708cc84 | ||
secp256k1_swift: 4fc5c4b2d2c6d21ee8ccb868cdc92da12f38bed9 | ||
SipHash: fad90a4683e420c52ef28063063dbbce248ea6d4 | ||
SwiftRLP: 98a02b2210128353ca02e4c2f4d83e2a9796db4f | ||
web3swift: aadc7a9b0c3b0384227eff181e39ba24ebfcd76c | ||
WKBridge: 677fc36b9a9e4a80b6f9c4e915480d8fd91f5ad5 | ||
|
||
PODFILE CHECKSUM: ed17f63e9fc4feec3b3d9d88971f86da22d55a1f | ||
|
||
COCOAPODS: 1.6.0.beta.2 |
Oops, something went wrong.