Skip to content

Commit e245dde

Browse files
Merge branch 'develop' into feature/erc777
2 parents b29bdcb + 6fc89ea commit e245dde

File tree

4 files changed

+203
-64
lines changed

4 files changed

+203
-64
lines changed

web3swift.xcodeproj/project.pbxproj

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@
212212
E228BED021A4C89F0085268C /* Web3Legacy+Eth.swift in Sources */ = {isa = PBXBuildFile; fileRef = E228BEC921A4C89E0085268C /* Web3Legacy+Eth.swift */; };
213213
E228BED121A4C89F0085268C /* Web3Legacy+Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = E228BECA21A4C89F0085268C /* Web3Legacy+Instance.swift */; };
214214
E228BED221A4C89F0085268C /* Web3Legacy+Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = E228BECA21A4C89F0085268C /* Web3Legacy+Instance.swift */; };
215+
E279C9EF21C46A140081695F /* Web3+ERC165.swift in Sources */ = {isa = PBXBuildFile; fileRef = E279C9EE21C46A140081695F /* Web3+ERC165.swift */; };
215216
E2DCA653218C875100F94FBA /* web3swift_ENS_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81A7B2782143C978004CD2C7 /* web3swift_ENS_Tests.swift */; };
216217
E2DCA654218C879900F94FBA /* ENS.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2E668CD214F8A7B00C3CC2D /* ENS.swift */; };
217218
E2DCA655218C879900F94FBA /* ENSResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = B219DC162154F3EE0035BF94 /* ENSResolver.swift */; };
@@ -393,6 +394,7 @@
393394
E23B5ADC20EA685D00DC7F32 /* web3swift_EIP67_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = web3swift_EIP67_Tests.swift; sourceTree = "<group>"; };
394395
E23B5AE020EA695400DC7F32 /* web3swift_rinkeby_personalSignature_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = web3swift_rinkeby_personalSignature_Tests.swift; sourceTree = "<group>"; };
395396
E23B5AE220EA69B900DC7F32 /* web3swift_numberFormattingUtil_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = web3swift_numberFormattingUtil_Tests.swift; sourceTree = "<group>"; };
397+
E279C9EE21C46A140081695F /* Web3+ERC165.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Web3+ERC165.swift"; sourceTree = "<group>"; };
396398
E2C590752152835400FF53D3 /* JSONRPCrequestDispatcher+ObjC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "JSONRPCrequestDispatcher+ObjC.swift"; sourceTree = "<group>"; };
397399
E2E94C5F217788E0005F54A0 /* Web3+ERC721.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Web3+ERC721.swift"; sourceTree = "<group>"; };
398400
FB43EC035C593F9E5A3644B6 /* Pods-web3swift-macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-web3swift-macOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-web3swift-macOS/Pods-web3swift-macOS.debug.xcconfig"; sourceTree = "<group>"; };
@@ -614,6 +616,7 @@
614616
isa = PBXGroup;
615617
children = (
616618
9196A68921B9F0B100852ED0 /* ERC777 */,
619+
E279C9ED21C3F2970081695F /* ERC165 */,
617620
E2E94C5E2177886C005F54A0 /* ERC721 */,
618621
8159C50621343ED300197B91 /* ERC20 */,
619622
);
@@ -957,6 +960,14 @@
957960
path = Classes;
958961
sourceTree = "<group>";
959962
};
963+
E279C9ED21C3F2970081695F /* ERC165 */ = {
964+
isa = PBXGroup;
965+
children = (
966+
E279C9EE21C46A140081695F /* Web3+ERC165.swift */,
967+
);
968+
path = ERC165;
969+
sourceTree = "<group>";
970+
};
960971
E2E94C5E2177886C005F54A0 /* ERC721 */ = {
961972
isa = PBXGroup;
962973
children = (
@@ -1263,6 +1274,7 @@
12631274
81A1823720D6E2BB0016741F /* Promise+Web3+Eth+GetBlockByHash.swift in Sources */,
12641275
81909D51218DAEC0007D2AE5 /* Promise+Web3+Personal+CreateAccount.swift in Sources */,
12651276
818D16CF204D42910084D2A4 /* Web3+EventParser.swift in Sources */,
1277+
E279C9EF21C46A140081695F /* Web3+ERC165.swift in Sources */,
12661278
81C5DA282072E18200424CD6 /* NativeTypesEncoding+Extensions.swift in Sources */,
12671279
8123E1C7200CBAC200B6D3AB /* Dictionary+Extension.swift in Sources */,
12681280
E228BE7421A4492B0085268C /* Promise+Web3Legacy+Eth+Call.swift in Sources */,
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//
2+
// Web3+ERC165.swift
3+
// web3swift-iOS
4+
//
5+
// Created by Anton Grigorev on 15/12/2018.
6+
// Copyright © 2018 The Matter Inc. All rights reserved.
7+
//
8+
9+
import Foundation
10+
import BigInt
11+
import PromiseKit
12+
import EthereumAddress
13+
14+
protocol IERC165 {
15+
16+
func supportsInterface(interfaceID: [UInt8]) throws -> Bool
17+
18+
}

web3swift/PrecompiledContracts/ERC20/Web3+ERC20.swift

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,19 @@ import BigInt
99
import EthereumAddress
1010
import PromiseKit
1111

12+
protocol IERC20 {
13+
func getBalance(account: EthereumAddress) throws -> BigUInt
14+
func getAllowance(originalOwner: EthereumAddress, delegate: EthereumAddress) throws -> BigUInt
15+
func transfer(from: EthereumAddress, to: EthereumAddress, amount: String) throws -> WriteTransaction
16+
func transferFrom(from: EthereumAddress, to: EthereumAddress, originalOwner: EthereumAddress, amount: String) throws -> WriteTransaction
17+
func setAllowance(from: EthereumAddress, to: EthereumAddress, newAmount: String) throws -> WriteTransaction
18+
func approve(from: EthereumAddress, spender: EthereumAddress, amount: String) throws -> WriteTransaction
19+
}
20+
1221
// This namespace contains functions to work with ERC20 tokens.
1322
// variables are lazyly evaluated or global token information (name, ticker, total supply)
1423
// can be imperatively read and saved
15-
public class ERC20 {
24+
public class ERC20: IERC20 {
1625

1726
@available(*, deprecated, renamed: "transactionOptions")
1827
public var options: Web3Options = .init()
@@ -99,7 +108,7 @@ public class ERC20 {
99108
}.wait()
100109
}
101110

102-
func getBalance(account: EthereumAddress) throws -> BigUInt{
111+
public func getBalance(account: EthereumAddress) throws -> BigUInt {
103112
let contract = self.contract
104113
var transactionOptions = TransactionOptions()
105114
transactionOptions.callOnBlock = .latest
@@ -185,5 +194,26 @@ public class ERC20 {
185194
return tx
186195
}
187196

197+
public func approve(from: EthereumAddress, spender: EthereumAddress, amount: String) throws -> WriteTransaction {
198+
let contract = self.contract
199+
var basicOptions = TransactionOptions()
200+
basicOptions.from = from
201+
basicOptions.callOnBlock = .latest
202+
203+
// get the decimals manually
204+
let callResult = try contract.read("decimals", transactionOptions: basicOptions)!.call()
205+
var decimals = BigUInt(0)
206+
guard let dec = callResult["0"], let decTyped = dec as? BigUInt else {
207+
throw Web3Error.inputError(desc: "Contract may be not ERC20 compatible, can not get decimals")}
208+
decimals = decTyped
209+
210+
let intDecimals = Int(decimals)
211+
guard let value = Web3.Utils.parseToBigUInt(amount, decimals: intDecimals) else {
212+
throw Web3Error.inputError(desc: "Can not parse inputted amount")
213+
}
214+
215+
let tx = contract.write("approve", parameters: [spender, value] as [AnyObject], transactionOptions: basicOptions)!
216+
return tx
217+
}
188218

189219
}

web3swift/PrecompiledContracts/ERC721/Web3+ERC721.swift

Lines changed: 141 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,52 @@ import BigInt
99
import PromiseKit
1010
import EthereumAddress
1111

12+
protocol IERC721 {
13+
14+
func getBalance(account: EthereumAddress) throws -> BigUInt
15+
16+
func getOwner(tokenId: BigUInt) throws -> EthereumAddress
17+
18+
func transferFrom(from: EthereumAddress, to: EthereumAddress, originalOwner: EthereumAddress, tokenId: BigUInt) throws -> WriteTransaction
19+
20+
func transfer(from: EthereumAddress, to: EthereumAddress, tokenId: BigUInt) throws -> WriteTransaction
21+
22+
func approve(from: EthereumAddress, approved: EthereumAddress, tokenId: BigUInt) throws -> WriteTransaction
23+
24+
func setApprovalForAll(from: EthereumAddress, operator user: EthereumAddress, approved: Bool) throws -> WriteTransaction
25+
26+
func getApproved(tokenId: BigUInt) throws -> EthereumAddress
27+
28+
func isApprovedForAll(owner: EthereumAddress, operator user: EthereumAddress) throws -> Bool
29+
}
30+
31+
protocol IERC721Metadata {
32+
33+
func name() throws -> String
34+
35+
func symbol() throws -> String
36+
37+
func tokenURI(tokenId: BigUInt) throws -> String
38+
39+
}
40+
41+
protocol IERC721Enumerable {
42+
43+
func totalSupply() throws -> BigUInt
44+
45+
func tokenByIndex(index: BigUInt) throws -> BigUInt
46+
47+
func tokenOfOwnerByIndex(owner: EthereumAddress, index: BigUInt) throws -> BigUInt
48+
}
49+
1250
// This namespace contains functions to work with ERC721 tokens.
1351
// can be imperatively read and saved
14-
public class ERC721 {
52+
public class ERC721: IERC721 {
1553

1654
@available(*, deprecated, renamed: "transactionOptions")
1755
public var options: Web3Options = .init()
1856

19-
private var _name: String? = nil
20-
private var _symbol: String? = nil
2157
private var _tokenId: BigUInt? = nil
22-
private var _tokenURI: String? = nil
2358
private var _hasReadProperties: Bool = false
2459

2560
public var transactionOptions: TransactionOptions
@@ -42,22 +77,6 @@ public class ERC721 {
4277
self.transactionOptions = mergedOptions
4378
}
4479

45-
public var name: String {
46-
self.readProperties()
47-
if self._name != nil {
48-
return self._name!
49-
}
50-
return ""
51-
}
52-
53-
public var symbol: String {
54-
self.readProperties()
55-
if self._symbol != nil {
56-
return self._symbol!
57-
}
58-
return ""
59-
}
60-
6180
public var tokenId: BigUInt {
6281
self.readProperties()
6382
if self._tokenId != nil {
@@ -66,14 +85,6 @@ public class ERC721 {
6685
return 0
6786
}
6887

69-
public var tokenURI: String {
70-
self.readProperties()
71-
if self._tokenURI != nil {
72-
return self._tokenURI!
73-
}
74-
return ""
75-
}
76-
7788
public func readProperties() {
7889
if self._hasReadProperties {
7990
return
@@ -82,33 +93,16 @@ public class ERC721 {
8293
guard contract.contract.address != nil else {return}
8394
var transactionOptions = TransactionOptions.defaultOptions
8495
transactionOptions.callOnBlock = .latest
85-
guard let namePromise = contract.read("name", parameters: [] as [AnyObject], extraData: Data(), transactionOptions: transactionOptions)?.callPromise() else {return}
86-
87-
guard let symbolPromise = contract.read("symbol", parameters: [] as [AnyObject], extraData: Data(), transactionOptions: transactionOptions)?.callPromise() else {return}
8896

8997
guard let tokenIdPromise = contract.read("tokenId", parameters: [] as [AnyObject], extraData: Data(), transactionOptions: transactionOptions)?.callPromise() else {return}
9098

91-
guard let tokenURIpromise = contract.read("tokenURI", parameters: [] as [AnyObject], extraData: Data(), transactionOptions: transactionOptions)?.callPromise() else {return}
92-
93-
let allPromises = [namePromise, symbolPromise, tokenIdPromise, tokenURIpromise]
99+
let allPromises = [tokenIdPromise]
94100
let queue = self.web3.requestDispatcher.queue
95101
when(resolved: allPromises).map(on: queue) { (resolvedPromises) -> Void in
96-
guard case .fulfilled(let nameResult) = resolvedPromises[0] else {return}
97-
guard let name = nameResult["0"] as? String else {return}
98-
self._name = name
99-
100-
guard case .fulfilled(let symbolResult) = resolvedPromises[1] else {return}
101-
guard let symbol = symbolResult["0"] as? String else {return}
102-
self._symbol = symbol
103-
104-
guard case .fulfilled(let tokenIdResult) = resolvedPromises[2] else {return}
102+
guard case .fulfilled(let tokenIdResult) = resolvedPromises[0] else {return}
105103
guard let tokenId = tokenIdResult["0"] as? BigUInt else {return}
106104
self._tokenId = tokenId
107105

108-
guard case .fulfilled(let tokenURIresult) = resolvedPromises[3] else {return}
109-
guard let uri = tokenURIresult["0"] as? String else {return}
110-
self._tokenURI = uri
111-
112106
self._hasReadProperties = true
113107
}.wait()
114108
}
@@ -122,7 +116,7 @@ public class ERC721 {
122116
return res
123117
}
124118

125-
public func getOwner(tokenId: BigUInt) throws -> EthereumAddress{
119+
public func getOwner(tokenId: BigUInt) throws -> EthereumAddress {
126120
let contract = self.contract
127121
var transactionOptions = TransactionOptions()
128122
transactionOptions.callOnBlock = .latest
@@ -140,6 +134,66 @@ public class ERC721 {
140134
return res
141135
}
142136

137+
public func transfer(from: EthereumAddress, to: EthereumAddress, tokenId: BigUInt) throws -> WriteTransaction {
138+
let contract = self.contract
139+
var basicOptions = TransactionOptions()
140+
basicOptions.from = from
141+
basicOptions.to = self.address
142+
143+
let tx = contract.write("transfer", parameters: [to, tokenId] as [AnyObject], transactionOptions: basicOptions)!
144+
return tx
145+
}
146+
147+
public func transferFrom(from: EthereumAddress, to: EthereumAddress, originalOwner: EthereumAddress, tokenId: BigUInt) throws -> WriteTransaction {
148+
let contract = self.contract
149+
var basicOptions = TransactionOptions()
150+
basicOptions.from = from
151+
basicOptions.to = self.address
152+
153+
let tx = contract.write("transferFrom", parameters: [originalOwner, to, tokenId] as [AnyObject], transactionOptions: basicOptions)!
154+
return tx
155+
}
156+
157+
public func approve(from: EthereumAddress, approved: EthereumAddress, tokenId: BigUInt) throws -> WriteTransaction {
158+
let contract = self.contract
159+
var basicOptions = TransactionOptions()
160+
basicOptions.from = from
161+
162+
let tx = contract.write("approve", parameters: [approved, tokenId] as [AnyObject], transactionOptions: basicOptions)!
163+
return tx
164+
}
165+
166+
public func setApprovalForAll(from: EthereumAddress, operator user: EthereumAddress, approved: Bool) throws -> WriteTransaction {
167+
let contract = self.contract
168+
var basicOptions = TransactionOptions()
169+
basicOptions.from = from
170+
171+
let tx = contract.write("setApprovalForAll", parameters: [user, approved] as [AnyObject], transactionOptions: basicOptions)!
172+
return tx
173+
}
174+
175+
public func isApprovedForAll(owner: EthereumAddress, operator user: EthereumAddress) throws -> Bool {
176+
let contract = self.contract
177+
var basicOptions = TransactionOptions()
178+
basicOptions.callOnBlock = .latest
179+
let result = try contract.read("isApprovedForAll", parameters: [owner, user] as [AnyObject], extraData: Data(), transactionOptions: self.transactionOptions)!.call(transactionOptions: transactionOptions)
180+
guard let res = result["0"] as? Bool else {throw Web3Error.processingError(desc: "Failed to get result of expected type from the Ethereum node")}
181+
return res
182+
}
183+
184+
}
185+
186+
extension ERC721: IERC721Enumerable {
187+
188+
public func totalSupply() throws -> BigUInt {
189+
let contract = self.contract
190+
var transactionOptions = TransactionOptions()
191+
transactionOptions.callOnBlock = .latest
192+
let result = try contract.read("totalSupply", parameters: [AnyObject](), extraData: Data(), transactionOptions: self.transactionOptions)!.call(transactionOptions: transactionOptions)
193+
guard let res = result["0"] as? BigUInt else {throw Web3Error.processingError(desc: "Failed to get result of expected type from the Ethereum node")}
194+
return res
195+
}
196+
143197
public func tokenByIndex(index: BigUInt) throws -> BigUInt {
144198
let contract = self.contract
145199
var transactionOptions = TransactionOptions()
@@ -158,24 +212,49 @@ public class ERC721 {
158212
return res
159213
}
160214

161-
public func transfer(from: EthereumAddress, to: EthereumAddress, tokenId: BigUInt) throws -> WriteTransaction {
215+
}
216+
217+
extension ERC721: IERC721Metadata {
218+
219+
public func name() throws -> String {
162220
let contract = self.contract
163-
var basicOptions = TransactionOptions()
164-
basicOptions.from = from
165-
basicOptions.to = self.address
166-
167-
let tx = contract.write("transfer", parameters: [to, tokenId] as [AnyObject], transactionOptions: basicOptions)!
168-
return tx
221+
var transactionOptions = TransactionOptions()
222+
transactionOptions.callOnBlock = .latest
223+
let result = try contract.read("name", parameters: [AnyObject](), extraData: Data(), transactionOptions: self.transactionOptions)!.call(transactionOptions: transactionOptions)
224+
guard let res = result["0"] as? String else {throw Web3Error.processingError(desc: "Failed to get result of expected type from the Ethereum node")}
225+
return res
169226
}
170227

171-
public func transferFrom(from: EthereumAddress, to: EthereumAddress, originalOwner: EthereumAddress, tokenId: BigUInt) throws -> WriteTransaction {
228+
public func symbol() throws -> String {
172229
let contract = self.contract
173-
var basicOptions = TransactionOptions()
174-
basicOptions.from = from
175-
basicOptions.to = self.address
176-
177-
let tx = contract.write("transferFrom", parameters: [originalOwner, to, tokenId] as [AnyObject], transactionOptions: basicOptions)!
178-
return tx
230+
var transactionOptions = TransactionOptions()
231+
transactionOptions.callOnBlock = .latest
232+
let result = try contract.read("symbol", parameters: [AnyObject](), extraData: Data(), transactionOptions: self.transactionOptions)!.call(transactionOptions: transactionOptions)
233+
guard let res = result["0"] as? String else {throw Web3Error.processingError(desc: "Failed to get result of expected type from the Ethereum node")}
234+
return res
235+
}
236+
237+
public func tokenURI(tokenId: BigUInt) throws -> String {
238+
let contract = self.contract
239+
var transactionOptions = TransactionOptions()
240+
transactionOptions.callOnBlock = .latest
241+
let result = try contract.read("tokenId", parameters: [tokenId] as [AnyObject], extraData: Data(), transactionOptions: self.transactionOptions)!.call(transactionOptions: transactionOptions)
242+
guard let res = result["0"] as? String else {throw Web3Error.processingError(desc: "Failed to get result of expected type from the Ethereum node")}
243+
return res
244+
}
245+
246+
}
247+
248+
extension ERC721: IERC165 {
249+
250+
public func supportsInterface(interfaceID: [UInt8]) throws -> Bool {
251+
let contract = self.contract
252+
var transactionOptions = TransactionOptions()
253+
transactionOptions.callOnBlock = .latest
254+
transactionOptions.gasLimit = .manual(30000)
255+
let result = try contract.read("supportsInterface", parameters: [interfaceID] as [AnyObject], extraData: Data(), transactionOptions: self.transactionOptions)!.call(transactionOptions: transactionOptions)
256+
guard let res = result["0"] as? Bool else {throw Web3Error.processingError(desc: "Failed to get result of expected type from the Ethereum node")}
257+
return res
179258
}
180259

181260
}

0 commit comments

Comments
 (0)