From 7464b05f185e45aae957156b1c4d4063c308b240 Mon Sep 17 00:00:00 2001 From: BaldyAsh Date: Fri, 15 Mar 2019 10:18:28 +0300 Subject: [PATCH 1/6] added st20 and security token classes, tested them --- web3swift.xcodeproj/project.pbxproj | 24 + .../PrecompiledContracts/ST20/Web3+ST20.swift | 314 ++++++++++++ .../ST20/Web3+SecurityToken.swift | 473 ++++++++++++++++++ web3swift/Web3/Classes/Web3+Utils.swift | 5 + ...web3swift_ST20AndSecurityToken_Tests.swift | 55 ++ 5 files changed, 871 insertions(+) create mode 100644 web3swift/PrecompiledContracts/ST20/Web3+ST20.swift create mode 100644 web3swift/PrecompiledContracts/ST20/Web3+SecurityToken.swift create mode 100644 web3swiftTests/web3swift_ST20AndSecurityToken_Tests.swift diff --git a/web3swift.xcodeproj/project.pbxproj b/web3swift.xcodeproj/project.pbxproj index 2ebdfddd4..fcad911f6 100755 --- a/web3swift.xcodeproj/project.pbxproj +++ b/web3swift.xcodeproj/project.pbxproj @@ -10,6 +10,7 @@ 00E5FE8220EA3FF40030E0D6 /* web3swift_infura_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00E5FE8120EA3FF40030E0D6 /* web3swift_infura_Tests.swift */; }; 13AE5971A972F5B55FA6FB69 /* libPods-web3swift-iOS_Tests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8349531F1984454E50389370 /* libPods-web3swift-iOS_Tests.a */; }; 1CD91B341FD769A6007BFB45 /* web3swift_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1CD91AFC1FD76910007BFB45 /* web3swift_iOS.framework */; }; + 3A0CD5E9223B865000D0A4FE /* web3swift_ST20AndSecurityToken_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A0CD5E8223B865000D0A4FE /* web3swift_ST20AndSecurityToken_Tests.swift */; }; 3AC1E7CB222D6A8C004F43D8 /* Web3+BrowserFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81C0FCF8204456E600D82FAF /* Web3+BrowserFunctions.swift */; }; 3AC1E7CC222D6A99004F43D8 /* Web3+ERC1376.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F8083521CB142000B6BF15 /* Web3+ERC1376.swift */; }; 3AC1E7CD222D6A99004F43D8 /* Web3+ERC1155.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F8083221CB0EF300B6BF15 /* Web3+ERC1155.swift */; }; @@ -25,6 +26,10 @@ 3AC1E7D7222D6A99004F43D8 /* Web3+ERC777.swift in Sources */ = {isa = PBXBuildFile; fileRef = E279C9F421C47B4A0081695F /* Web3+ERC777.swift */; }; 3AC1E7D8222D6A99004F43D8 /* Web3+ERC165.swift in Sources */ = {isa = PBXBuildFile; fileRef = E279C9EE21C46A140081695F /* Web3+ERC165.swift */; }; 3AC1E7D9222D6AA0004F43D8 /* Web3+BrowserFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81C0FCF8204456E600D82FAF /* Web3+BrowserFunctions.swift */; }; + 3AC3BD7D222EA70500656EC7 /* Web3+ST20.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AC3BD7C222EA70500656EC7 /* Web3+ST20.swift */; }; + 3AC3BD7E222EA70500656EC7 /* Web3+ST20.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AC3BD7C222EA70500656EC7 /* Web3+ST20.swift */; }; + 3AC3BD80222EC6C900656EC7 /* Web3+SecurityToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AC3BD7F222EC6C900656EC7 /* Web3+SecurityToken.swift */; }; + 3AC3BD81222EC6C900656EC7 /* Web3+SecurityToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AC3BD7F222EC6C900656EC7 /* Web3+SecurityToken.swift */; }; 4194811B203630530065A83B /* Web3+HttpProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 817EBB142004FE4200E02EAA /* Web3+HttpProvider.swift */; }; 4194811E203630530065A83B /* Web3.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81DDECCE1FDF004E0063684A /* Web3.swift */; }; 4194811F203630530065A83B /* Web3+Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 818ABD5A1FE95F8F002657BB /* Web3+Instance.swift */; }; @@ -252,6 +257,9 @@ 2B8FEFF3962166E1BEADC886 /* Pods_web3swift_ios.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_web3swift_ios.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 342700493511FEB189700D13 /* Pods-web3swift-iOS_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-web3swift-iOS_Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-web3swift-iOS_Tests/Pods-web3swift-iOS_Tests.debug.xcconfig"; sourceTree = ""; }; 391A0D2EF42488E5C8AB2F71 /* Pods_web3swift_osx_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_web3swift_osx_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 3A0CD5E8223B865000D0A4FE /* web3swift_ST20AndSecurityToken_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = web3swift_ST20AndSecurityToken_Tests.swift; sourceTree = ""; }; + 3AC3BD7C222EA70500656EC7 /* Web3+ST20.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Web3+ST20.swift"; sourceTree = ""; }; + 3AC3BD7F222EC6C900656EC7 /* Web3+SecurityToken.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Web3+SecurityToken.swift"; sourceTree = ""; }; 417715D420362916005C3E16 /* web3swift_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = web3swift_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 419481432036338A0065A83B /* Pods_web3swift_osx.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Pods_web3swift_osx.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4EFFCB6D208552F2008165FE /* web3swift_local_node_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = web3swift_local_node_Tests.swift; sourceTree = ""; }; @@ -479,6 +487,7 @@ children = ( 81909D4E21887658007D2AE5 /* web3swift_Eventloop_Tests.swift */, 81A7B2892143DF1D004CD2C7 /* web3swift_EIP681_Tests.swift */, + 3A0CD5E8223B865000D0A4FE /* web3swift_ST20AndSecurityToken_Tests.swift */, 81A7B2782143C978004CD2C7 /* web3swift_ENS_Tests.swift */, 8159C50D2135901700197B91 /* web3swift_ERC20_Class_Tests.swift */, 81FECD5D211AEFCE006DA367 /* web3swift_ObjC_Tests.swift */, @@ -501,6 +510,15 @@ path = web3swiftTests; sourceTree = ""; }; + 3AC3BD7B222EA6EF00656EC7 /* ST20 */ = { + isa = PBXGroup; + children = ( + 3AC3BD7C222EA70500656EC7 /* Web3+ST20.swift */, + 3AC3BD7F222EC6C900656EC7 /* Web3+SecurityToken.swift */, + ); + path = ST20; + sourceTree = ""; + }; 78D101CC419F27D142F6E9AE /* Frameworks */ = { isa = PBXGroup; children = ( @@ -604,6 +622,7 @@ 8159C50921343EF900197B91 /* PrecompiledContracts */ = { isa = PBXGroup; children = ( + 3AC3BD7B222EA6EF00656EC7 /* ST20 */, E2F8083421CB140E00B6BF15 /* ERC1376 */, E2F8083121CB0ED400B6BF15 /* ERC1155 */, E2F8082E21CB095A00B6BF15 /* ERC721x */, @@ -1235,6 +1254,7 @@ 81DDECCF1FDF004E0063684A /* Web3.swift in Sources */, 81A1823420D6E1FD0016741F /* Promise+Web3+Eth+GetBlockByNumber.swift in Sources */, 81A1822820D678BF0016741F /* Promise+Web3+Eth+GetAccounts.swift in Sources */, + 3AC3BD80222EC6C900656EC7 /* Web3+SecurityToken.swift in Sources */, E2F8081F21CA90BA00B6BF15 /* Web3+ERC1410.swift in Sources */, 81A7B2512143C3A8004CD2C7 /* NameHash.swift in Sources */, E2F8083021CB096D00B6BF15 /* Web3+ERC721x.swift in Sources */, @@ -1244,6 +1264,7 @@ E2F8082D21CB009A00B6BF15 /* Web3+ERC1633.swift in Sources */, 813FFF8D1FD82EEB006379A2 /* String+Extension.swift in Sources */, 81A1823120D68A110016741F /* Promise+Batching.swift in Sources */, + 3AC3BD7D222EA70500656EC7 /* Web3+ST20.swift in Sources */, 817EBB162004FE4200E02EAA /* Web3+HttpProvider.swift in Sources */, 8103BBCC2077B84400499769 /* PlainKeystore.swift in Sources */, 81DFB3FF210775320011DC85 /* Web3+Infura.swift in Sources */, @@ -1271,6 +1292,7 @@ 9196A68821B9EFF100852ED0 /* web3swift_EIP67_Tests.swift in Sources */, 9196A68721B9EFDA00852ED0 /* web3swift_EIP681_Tests.swift in Sources */, E2DCA653218C875100F94FBA /* web3swift_ENS_Tests.swift in Sources */, + 3A0CD5E9223B865000D0A4FE /* web3swift_ST20AndSecurityToken_Tests.swift in Sources */, 81909D292188504D007D2AE5 /* web3swift_AdvancedABIv2_Tests.swift in Sources */, 00E5FE8220EA3FF40030E0D6 /* web3swift_infura_Tests.swift in Sources */, 81909D2A21885067007D2AE5 /* web3swift_rinkeby_personalSignature_Tests.swift in Sources */, @@ -1356,6 +1378,7 @@ 81A1824320D7AA750016741F /* Promise+Web3+Eth+SendTransaction.swift in Sources */, 41948134203630530065A83B /* BIP39+WordLists.swift in Sources */, 41948135203630530065A83B /* EthereumKeystoreV3.swift in Sources */, + 3AC3BD81222EC6C900656EC7 /* Web3+SecurityToken.swift in Sources */, 41948136203630530065A83B /* KeystoreV3JSONStructure.swift in Sources */, 8116666420455E33008D8AD0 /* Web3+Wallet.swift in Sources */, 81909D2221884893007D2AE5 /* BigUInt+Extensions.swift in Sources */, @@ -1365,6 +1388,7 @@ 81A1823520D6E1FD0016741F /* Promise+Web3+Eth+GetBlockByNumber.swift in Sources */, 81A1822920D678BF0016741F /* Promise+Web3+Eth+GetAccounts.swift in Sources */, 81C5DA322074EC1E00424CD6 /* ContractProtocol.swift in Sources */, + 3AC3BD7E222EA70500656EC7 /* Web3+ST20.swift in Sources */, 81A1824C20D7DF1B0016741F /* Promise+Web3+Personal+UnlockAccount.swift in Sources */, 4194813B203630530065A83B /* NSRegularExpressionExtension.swift in Sources */, 81C0FD042044A8A700D82FAF /* Web3+Options.swift in Sources */, diff --git a/web3swift/PrecompiledContracts/ST20/Web3+ST20.swift b/web3swift/PrecompiledContracts/ST20/Web3+ST20.swift new file mode 100644 index 000000000..933dc32db --- /dev/null +++ b/web3swift/PrecompiledContracts/ST20/Web3+ST20.swift @@ -0,0 +1,314 @@ +// +// Web3+ST20.swift +// web3swift +// +// Created by Anton on 05/03/2019. +// Copyright © 2019 The Matter Inc. All rights reserved. +// + +import Foundation +import BigInt +import PromiseKit +import EthereumAddress + +//NPolymath Token Standard +protocol IST20: IERC20 { + // off-chain hash + func tokenDetails() throws -> [UInt32] + + //transfer, transferFrom must respect the result of verifyTransfer + func verifyTransfer(from: EthereumAddress, originalOwner: EthereumAddress, to: EthereumAddress, amount: String) throws -> WriteTransaction + + //used to create tokens + func mint(from: EthereumAddress, investor: EthereumAddress, amount: String) throws -> WriteTransaction + + //Burn function used to burn the securityToken + func burn(from: EthereumAddress, amount: String) throws -> WriteTransaction +} + +// This namespace contains functions to work with ST-20 tokens. +// can be imperatively read and saved +public class ST20: IST20 { + + private var _name: String? = nil + private var _symbol: String? = nil + private var _decimals: UInt8? = nil + + private var _hasReadProperties: Bool = false + + public var transactionOptions: TransactionOptions + public var web3: web3 + public var provider: Web3Provider + public var address: EthereumAddress + public var abi: String + + lazy var contract: web3.web3contract = { + let contract = self.web3.contract(self.abi, at: self.address, abiVersion: 2) + precondition(contract != nil) + return contract! + }() + + public init(web3: web3, provider: Web3Provider, address: EthereumAddress, abi: String = Web3.Utils.st20ABI) { + self.web3 = web3 + self.provider = provider + self.address = address + var mergedOptions = web3.transactionOptions + mergedOptions.to = address + self.abi = abi + self.transactionOptions = mergedOptions + } + + public var name: String { + self.readProperties() + if self._name != nil { + return self._name! + } + return "" + } + + public var symbol: String { + self.readProperties() + if self._symbol != nil { + return self._symbol! + } + return "" + } + + /// Must be 18! + public var decimals: UInt8 { + self.readProperties() + if self._decimals != nil { + return self._decimals! + } + return 18 + } + + public func readProperties() { + if self._hasReadProperties { + return + } + let contract = self.contract + guard contract.contract.address != nil else {return} + var transactionOptions = TransactionOptions.defaultOptions + transactionOptions.callOnBlock = .latest + guard let namePromise = contract.read("name", parameters: [] as [AnyObject], extraData: Data(), transactionOptions: transactionOptions)?.callPromise() else {return} + + guard let symbolPromise = contract.read("symbol", parameters: [] as [AnyObject], extraData: Data(), transactionOptions: transactionOptions)?.callPromise() else {return} + + guard let decimalPromise = contract.read("decimals", parameters: [] as [AnyObject], extraData: Data(), transactionOptions: transactionOptions)?.callPromise() else {return} + + let allPromises = [namePromise, symbolPromise, decimalPromise] + let queue = self.web3.requestDispatcher.queue + when(resolved: allPromises).map(on: queue) { (resolvedPromises) -> Void in + guard case .fulfilled(let nameResult) = resolvedPromises[0] else {return} + guard let name = nameResult["0"] as? String else {return} + self._name = name + + guard case .fulfilled(let symbolResult) = resolvedPromises[1] else {return} + guard let symbol = symbolResult["0"] as? String else {return} + self._symbol = symbol + + guard case .fulfilled(let decimalsResult) = resolvedPromises[2] else {return} + guard let decimals = decimalsResult["0"] as? BigUInt else {return} + self._decimals = UInt8(decimals) + + self._hasReadProperties = true + }.wait() + } + + func tokenDetails() throws -> [UInt32] { + let contract = self.contract + var transactionOptions = TransactionOptions() + transactionOptions.callOnBlock = .latest + let result = try contract.read("tokenDetails", parameters: [] as [AnyObject], extraData: Data(), transactionOptions: self.transactionOptions)!.call(transactionOptions: transactionOptions) + guard let res = result["0"] as? [UInt32] else {throw Web3Error.processingError(desc: "Failed to get result of expected type from the Ethereum node")} + return res + } + + func verifyTransfer(from: EthereumAddress, originalOwner: EthereumAddress, to: EthereumAddress, amount: String) throws -> WriteTransaction { + let contract = self.contract + var basicOptions = TransactionOptions() + basicOptions.from = from + basicOptions.to = self.address + basicOptions.callOnBlock = .latest + + // get the decimals manually + let callResult = try contract.read("decimals", transactionOptions: basicOptions)!.call() + var decimals = BigUInt(0) + guard let dec = callResult["0"], let decTyped = dec as? BigUInt else { + throw Web3Error.inputError(desc: "Contract may be not ERC20 compatible, can not get decimals")} + decimals = decTyped + + let intDecimals = Int(decimals) + guard let value = Web3.Utils.parseToBigUInt(amount, decimals: intDecimals) else { + throw Web3Error.inputError(desc: "Can not parse inputted amount") + } + + let tx = contract.write("verifyTransfer", parameters: [originalOwner, to, value] as [AnyObject], transactionOptions: basicOptions)! + return tx + } + + func mint(from: EthereumAddress, investor: EthereumAddress, amount: String) throws -> WriteTransaction { + let contract = self.contract + var basicOptions = TransactionOptions() + basicOptions.from = from + basicOptions.to = self.address + basicOptions.callOnBlock = .latest + + // get the decimals manually + let callResult = try contract.read("decimals", transactionOptions: basicOptions)!.call() + var decimals = BigUInt(0) + guard let dec = callResult["0"], let decTyped = dec as? BigUInt else { + throw Web3Error.inputError(desc: "Contract may be not ERC20 compatible, can not get decimals")} + decimals = decTyped + + let intDecimals = Int(decimals) + guard let value = Web3.Utils.parseToBigUInt(amount, decimals: intDecimals) else { + throw Web3Error.inputError(desc: "Can not parse inputted amount") + } + + let tx = contract.write("mint", parameters: [investor, value] as [AnyObject], transactionOptions: basicOptions)! + return tx + } + + public func burn(from: EthereumAddress, amount: String) throws -> WriteTransaction { + let contract = self.contract + var basicOptions = TransactionOptions() + basicOptions.from = from + basicOptions.to = self.address + basicOptions.callOnBlock = .latest + + // get the decimals manually + let callResult = try contract.read("decimals", transactionOptions: basicOptions)!.call() + var decimals = BigUInt(0) + guard let dec = callResult["0"], let decTyped = dec as? BigUInt else { + throw Web3Error.inputError(desc: "Contract may be not ERC20 compatible, can not get decimals")} + decimals = decTyped + + let intDecimals = Int(decimals) + guard let value = Web3.Utils.parseToBigUInt(amount, decimals: intDecimals) else { + throw Web3Error.inputError(desc: "Can not parse inputted amount") + } + let tx = contract.write("burn", parameters: [value] as [AnyObject], transactionOptions: basicOptions)! + return tx + } + + public func getBalance(account: EthereumAddress) throws -> BigUInt { + let contract = self.contract + var transactionOptions = TransactionOptions() + transactionOptions.callOnBlock = .latest + let result = try contract.read("balanceOf", parameters: [account] as [AnyObject], extraData: Data(), transactionOptions: self.transactionOptions)!.call(transactionOptions: transactionOptions) + guard let res = result["0"] as? BigUInt else {throw Web3Error.processingError(desc: "Failed to get result of expected type from the Ethereum node")} + return res + } + + public func getAllowance(originalOwner: EthereumAddress, delegate: EthereumAddress) throws -> BigUInt { + let contract = self.contract + var transactionOptions = TransactionOptions() + transactionOptions.callOnBlock = .latest + let result = try contract.read("allowance", parameters: [originalOwner, delegate] as [AnyObject], extraData: Data(), transactionOptions: self.transactionOptions)!.call(transactionOptions: transactionOptions) + guard let res = result["0"] as? BigUInt else {throw Web3Error.processingError(desc: "Failed to get result of expected type from the Ethereum node")} + return res + } + + public func transfer(from: EthereumAddress, to: EthereumAddress, amount: String) throws -> WriteTransaction { + let contract = self.contract + var basicOptions = TransactionOptions() + basicOptions.from = from + basicOptions.to = self.address + basicOptions.callOnBlock = .latest + + // get the decimals manually + let callResult = try contract.read("decimals", transactionOptions: basicOptions)!.call() + var decimals = BigUInt(0) + guard let dec = callResult["0"], let decTyped = dec as? BigUInt else { + throw Web3Error.inputError(desc: "Contract may be not ERC20 compatible, can not get decimals")} + decimals = decTyped + + let intDecimals = Int(decimals) + guard let value = Web3.Utils.parseToBigUInt(amount, decimals: intDecimals) else { + throw Web3Error.inputError(desc: "Can not parse inputted amount") + } + let tx = contract.write("transfer", parameters: [to, value] as [AnyObject], transactionOptions: basicOptions)! + return tx + } + + public func transferFrom(from: EthereumAddress, to: EthereumAddress, originalOwner: EthereumAddress, amount: String) throws -> WriteTransaction { + let contract = self.contract + var basicOptions = TransactionOptions() + basicOptions.from = from + basicOptions.to = self.address + basicOptions.callOnBlock = .latest + + // get the decimals manually + let callResult = try contract.read("decimals", transactionOptions: basicOptions)!.call() + var decimals = BigUInt(0) + guard let dec = callResult["0"], let decTyped = dec as? BigUInt else { + throw Web3Error.inputError(desc: "Contract may be not ERC20 compatible, can not get decimals")} + decimals = decTyped + + let intDecimals = Int(decimals) + guard let value = Web3.Utils.parseToBigUInt(amount, decimals: intDecimals) else { + throw Web3Error.inputError(desc: "Can not parse inputted amount") + } + + let tx = contract.write("transferFrom", parameters: [originalOwner, to, value] as [AnyObject], transactionOptions: basicOptions)! + return tx + } + + public func setAllowance(from: EthereumAddress, to: EthereumAddress, newAmount: String) throws -> WriteTransaction { + let contract = self.contract + var basicOptions = TransactionOptions() + basicOptions.from = from + basicOptions.to = self.address + basicOptions.callOnBlock = .latest + + // get the decimals manually + let callResult = try contract.read("decimals", transactionOptions: basicOptions)!.call() + var decimals = BigUInt(0) + guard let dec = callResult["0"], let decTyped = dec as? BigUInt else { + throw Web3Error.inputError(desc: "Contract may be not ERC20 compatible, can not get decimals")} + decimals = decTyped + + let intDecimals = Int(decimals) + guard let value = Web3.Utils.parseToBigUInt(newAmount, decimals: intDecimals) else { + throw Web3Error.inputError(desc: "Can not parse inputted amount") + } + + let tx = contract.write("setAllowance", parameters: [to, value] as [AnyObject], transactionOptions: basicOptions)! + return tx + } + + public func approve(from: EthereumAddress, spender: EthereumAddress, amount: String) throws -> WriteTransaction { + let contract = self.contract + var basicOptions = TransactionOptions() + basicOptions.from = from + basicOptions.to = self.address + basicOptions.callOnBlock = .latest + + // get the decimals manually + let callResult = try contract.read("decimals", transactionOptions: basicOptions)!.call() + var decimals = BigUInt(0) + guard let dec = callResult["0"], let decTyped = dec as? BigUInt else { + throw Web3Error.inputError(desc: "Contract may be not ERC20 compatible, can not get decimals")} + decimals = decTyped + + let intDecimals = Int(decimals) + guard let value = Web3.Utils.parseToBigUInt(amount, decimals: intDecimals) else { + throw Web3Error.inputError(desc: "Can not parse inputted amount") + } + + let tx = contract.write("approve", parameters: [spender, value] as [AnyObject], transactionOptions: basicOptions)! + return tx + } + + public func totalSupply() throws -> BigUInt { + let contract = self.contract + var transactionOptions = TransactionOptions() + transactionOptions.callOnBlock = .latest + let result = try contract.read("totalSupply", parameters: [AnyObject](), extraData: Data(), transactionOptions: self.transactionOptions)!.call(transactionOptions: transactionOptions) + guard let res = result["0"] as? BigUInt else {throw Web3Error.processingError(desc: "Failed to get result of expected type from the Ethereum node")} + return res + } + +} diff --git a/web3swift/PrecompiledContracts/ST20/Web3+SecurityToken.swift b/web3swift/PrecompiledContracts/ST20/Web3+SecurityToken.swift new file mode 100644 index 000000000..3a60b5ac1 --- /dev/null +++ b/web3swift/PrecompiledContracts/ST20/Web3+SecurityToken.swift @@ -0,0 +1,473 @@ +// +// Web3+SecurityToken.swift +// web3swift +// +// Created by Anton on 05/03/2019. +// Copyright © 2019 The Matter Inc. All rights reserved. +// + +import Foundation +import BigInt +import PromiseKit +import EthereumAddress + +//The Ownable contract has an owner address, and provides basic authorization control functions, this simplifies the implementation of "user permissions". +protocol IOwnable { + //Allows the current owner to relinquish control of the contract. + func renounceOwnership(from: EthereumAddress) throws -> WriteTransaction + + //Allows the current owner to transfer control of the contract to a newOwner. + func transferOwnership(from: EthereumAddress, newOwner: EthereumAddress) throws -> WriteTransaction +} + +//Security token interface +protocol ISecurityToken: IST20, IOwnable { + // Value of current checkpoint + func currentCheckpointId() throws -> BigUInt + + func getGranularity() throws -> BigUInt + + // Total number of non-zero token holders + func investorCount() throws -> BigUInt + + // List of token holders + func investors() throws -> [EthereumAddress] + + // Permissions this to a Permission module, which has a key of 1 + // If no Permission return false - note that IModule withPerm will allow ST owner all permissions anyway + // this allows individual modules to override this logic if needed (to not allow ST owner all permissions) + func checkPermission(delegate: EthereumAddress, module: EthereumAddress, perm: [UInt32]) throws -> Bool + + //returns module list for a module type + //params: + //- moduleType is which type of module we are trying to remove + //- moduleIndex is the index of the module within the chosen type + func getModule(moduleType: UInt8, moduleIndex: UInt8) throws -> ([UInt32], EthereumAddress) + + //returns module list for a module name - will return first match + //params: + //- moduleType is which type of module we are trying to remove + //- name is the name of the module within the chosen type + func getModuleByName(moduleType: UInt8, name: [UInt32]) throws -> ([UInt32], EthereumAddress) + + //Queries totalSupply as of a defined checkpoint + func totalSupplyAt(checkpointId: BigUInt) throws -> BigUInt + + //Queries balances as of a defined checkpoint + func balanceOfAt(investor: EthereumAddress, checkpointId: BigUInt) throws -> BigUInt + + //Creates a checkpoint that can be used to query historical balances / totalSuppy + func createCheckpoint(from: EthereumAddress) throws -> WriteTransaction + + //gets length of investors array + func getInvestorsLength() throws -> BigUInt +} + +public class SecurityToken: ISecurityToken { + + private var _name: String? = nil + private var _symbol: String? = nil + private var _decimals: UInt8? = nil + + private var _hasReadProperties: Bool = false + + public var transactionOptions: TransactionOptions + public var web3: web3 + public var provider: Web3Provider + public var address: EthereumAddress + public var abi: String + + lazy var contract: web3.web3contract = { + let contract = self.web3.contract(self.abi, at: self.address, abiVersion: 2) + precondition(contract != nil) + return contract! + }() + + public init(web3: web3, provider: Web3Provider, address: EthereumAddress, abi: String = Web3.Utils.st20ABI) { + self.web3 = web3 + self.provider = provider + self.address = address + var mergedOptions = web3.transactionOptions + mergedOptions.to = address + self.abi = abi + self.transactionOptions = mergedOptions + } + + public var name: String { + self.readProperties() + if self._name != nil { + return self._name! + } + return "" + } + + public var symbol: String { + self.readProperties() + if self._symbol != nil { + return self._symbol! + } + return "" + } + + /// Must be 18! + public var decimals: UInt8 { + self.readProperties() + if self._decimals != nil { + return self._decimals! + } + return 18 + } + + public func readProperties() { + if self._hasReadProperties { + return + } + let contract = self.contract + guard contract.contract.address != nil else {return} + var transactionOptions = TransactionOptions.defaultOptions + transactionOptions.callOnBlock = .latest + guard let namePromise = contract.read("name", parameters: [] as [AnyObject], extraData: Data(), transactionOptions: transactionOptions)?.callPromise() else {return} + + guard let symbolPromise = contract.read("symbol", parameters: [] as [AnyObject], extraData: Data(), transactionOptions: transactionOptions)?.callPromise() else {return} + + guard let decimalPromise = contract.read("decimals", parameters: [] as [AnyObject], extraData: Data(), transactionOptions: transactionOptions)?.callPromise() else {return} + + let allPromises = [namePromise, symbolPromise, decimalPromise] + let queue = self.web3.requestDispatcher.queue + when(resolved: allPromises).map(on: queue) { (resolvedPromises) -> Void in + guard case .fulfilled(let nameResult) = resolvedPromises[0] else {return} + guard let name = nameResult["0"] as? String else {return} + self._name = name + + guard case .fulfilled(let symbolResult) = resolvedPromises[1] else {return} + guard let symbol = symbolResult["0"] as? String else {return} + self._symbol = symbol + + guard case .fulfilled(let decimalsResult) = resolvedPromises[2] else {return} + guard let decimals = decimalsResult["0"] as? BigUInt else {return} + self._decimals = UInt8(decimals) + + self._hasReadProperties = true + }.wait() + } + + func tokenDetails() throws -> [UInt32] { + let contract = self.contract + var transactionOptions = TransactionOptions() + transactionOptions.callOnBlock = .latest + let result = try contract.read("tokenDetails", parameters: [] as [AnyObject], extraData: Data(), transactionOptions: self.transactionOptions)!.call(transactionOptions: transactionOptions) + guard let res = result["0"] as? [UInt32] else {throw Web3Error.processingError(desc: "Failed to get result of expected type from the Ethereum node")} + return res + } + + func verifyTransfer(from: EthereumAddress, originalOwner: EthereumAddress, to: EthereumAddress, amount: String) throws -> WriteTransaction { + let contract = self.contract + var basicOptions = TransactionOptions() + basicOptions.from = from + basicOptions.to = self.address + basicOptions.callOnBlock = .latest + + // get the decimals manually + let callResult = try contract.read("decimals", transactionOptions: basicOptions)!.call() + var decimals = BigUInt(0) + guard let dec = callResult["0"], let decTyped = dec as? BigUInt else { + throw Web3Error.inputError(desc: "Contract may be not ERC20 compatible, can not get decimals")} + decimals = decTyped + + let intDecimals = Int(decimals) + guard let value = Web3.Utils.parseToBigUInt(amount, decimals: intDecimals) else { + throw Web3Error.inputError(desc: "Can not parse inputted amount") + } + + let tx = contract.write("verifyTransfer", parameters: [originalOwner, to, value] as [AnyObject], transactionOptions: basicOptions)! + return tx + } + + func mint(from: EthereumAddress, investor: EthereumAddress, amount: String) throws -> WriteTransaction { + let contract = self.contract + var basicOptions = TransactionOptions() + basicOptions.from = from + basicOptions.to = self.address + basicOptions.callOnBlock = .latest + + // get the decimals manually + let callResult = try contract.read("decimals", transactionOptions: basicOptions)!.call() + var decimals = BigUInt(0) + guard let dec = callResult["0"], let decTyped = dec as? BigUInt else { + throw Web3Error.inputError(desc: "Contract may be not ERC20 compatible, can not get decimals")} + decimals = decTyped + + let intDecimals = Int(decimals) + guard let value = Web3.Utils.parseToBigUInt(amount, decimals: intDecimals) else { + throw Web3Error.inputError(desc: "Can not parse inputted amount") + } + + let tx = contract.write("mint", parameters: [investor, value] as [AnyObject], transactionOptions: basicOptions)! + return tx + } + + public func burn(from: EthereumAddress, amount: String) throws -> WriteTransaction { + let contract = self.contract + var basicOptions = TransactionOptions() + basicOptions.from = from + basicOptions.to = self.address + basicOptions.callOnBlock = .latest + + // get the decimals manually + let callResult = try contract.read("decimals", transactionOptions: basicOptions)!.call() + var decimals = BigUInt(0) + guard let dec = callResult["0"], let decTyped = dec as? BigUInt else { + throw Web3Error.inputError(desc: "Contract may be not ERC20 compatible, can not get decimals")} + decimals = decTyped + + let intDecimals = Int(decimals) + guard let value = Web3.Utils.parseToBigUInt(amount, decimals: intDecimals) else { + throw Web3Error.inputError(desc: "Can not parse inputted amount") + } + let tx = contract.write("burn", parameters: [value] as [AnyObject], transactionOptions: basicOptions)! + return tx + } + + public func getBalance(account: EthereumAddress) throws -> BigUInt { + let contract = self.contract + var transactionOptions = TransactionOptions() + transactionOptions.callOnBlock = .latest + let result = try contract.read("balanceOf", parameters: [account] as [AnyObject], extraData: Data(), transactionOptions: self.transactionOptions)!.call(transactionOptions: transactionOptions) + guard let res = result["0"] as? BigUInt else {throw Web3Error.processingError(desc: "Failed to get result of expected type from the Ethereum node")} + return res + } + + public func getAllowance(originalOwner: EthereumAddress, delegate: EthereumAddress) throws -> BigUInt { + let contract = self.contract + var transactionOptions = TransactionOptions() + transactionOptions.callOnBlock = .latest + let result = try contract.read("allowance", parameters: [originalOwner, delegate] as [AnyObject], extraData: Data(), transactionOptions: self.transactionOptions)!.call(transactionOptions: transactionOptions) + guard let res = result["0"] as? BigUInt else {throw Web3Error.processingError(desc: "Failed to get result of expected type from the Ethereum node")} + return res + } + + public func transfer(from: EthereumAddress, to: EthereumAddress, amount: String) throws -> WriteTransaction { + let contract = self.contract + var basicOptions = TransactionOptions() + basicOptions.from = from + basicOptions.to = self.address + basicOptions.callOnBlock = .latest + + // get the decimals manually + let callResult = try contract.read("decimals", transactionOptions: basicOptions)!.call() + var decimals = BigUInt(0) + guard let dec = callResult["0"], let decTyped = dec as? BigUInt else { + throw Web3Error.inputError(desc: "Contract may be not ERC20 compatible, can not get decimals")} + decimals = decTyped + + let intDecimals = Int(decimals) + guard let value = Web3.Utils.parseToBigUInt(amount, decimals: intDecimals) else { + throw Web3Error.inputError(desc: "Can not parse inputted amount") + } + let tx = contract.write("transfer", parameters: [to, value] as [AnyObject], transactionOptions: basicOptions)! + return tx + } + + public func transferFrom(from: EthereumAddress, to: EthereumAddress, originalOwner: EthereumAddress, amount: String) throws -> WriteTransaction { + let contract = self.contract + var basicOptions = TransactionOptions() + basicOptions.from = from + basicOptions.to = self.address + basicOptions.callOnBlock = .latest + + // get the decimals manually + let callResult = try contract.read("decimals", transactionOptions: basicOptions)!.call() + var decimals = BigUInt(0) + guard let dec = callResult["0"], let decTyped = dec as? BigUInt else { + throw Web3Error.inputError(desc: "Contract may be not ERC20 compatible, can not get decimals")} + decimals = decTyped + + let intDecimals = Int(decimals) + guard let value = Web3.Utils.parseToBigUInt(amount, decimals: intDecimals) else { + throw Web3Error.inputError(desc: "Can not parse inputted amount") + } + + let tx = contract.write("transferFrom", parameters: [originalOwner, to, value] as [AnyObject], transactionOptions: basicOptions)! + return tx + } + + public func setAllowance(from: EthereumAddress, to: EthereumAddress, newAmount: String) throws -> WriteTransaction { + let contract = self.contract + var basicOptions = TransactionOptions() + basicOptions.from = from + basicOptions.to = self.address + basicOptions.callOnBlock = .latest + + // get the decimals manually + let callResult = try contract.read("decimals", transactionOptions: basicOptions)!.call() + var decimals = BigUInt(0) + guard let dec = callResult["0"], let decTyped = dec as? BigUInt else { + throw Web3Error.inputError(desc: "Contract may be not ERC20 compatible, can not get decimals")} + decimals = decTyped + + let intDecimals = Int(decimals) + guard let value = Web3.Utils.parseToBigUInt(newAmount, decimals: intDecimals) else { + throw Web3Error.inputError(desc: "Can not parse inputted amount") + } + + let tx = contract.write("setAllowance", parameters: [to, value] as [AnyObject], transactionOptions: basicOptions)! + return tx + } + + public func approve(from: EthereumAddress, spender: EthereumAddress, amount: String) throws -> WriteTransaction { + let contract = self.contract + var basicOptions = TransactionOptions() + basicOptions.from = from + basicOptions.to = self.address + basicOptions.callOnBlock = .latest + + // get the decimals manually + let callResult = try contract.read("decimals", transactionOptions: basicOptions)!.call() + var decimals = BigUInt(0) + guard let dec = callResult["0"], let decTyped = dec as? BigUInt else { + throw Web3Error.inputError(desc: "Contract may be not ERC20 compatible, can not get decimals")} + decimals = decTyped + + let intDecimals = Int(decimals) + guard let value = Web3.Utils.parseToBigUInt(amount, decimals: intDecimals) else { + throw Web3Error.inputError(desc: "Can not parse inputted amount") + } + + let tx = contract.write("approve", parameters: [spender, value] as [AnyObject], transactionOptions: basicOptions)! + return tx + } + + public func totalSupply() throws -> BigUInt { + let contract = self.contract + var transactionOptions = TransactionOptions() + transactionOptions.callOnBlock = .latest + let result = try contract.read("totalSupply", parameters: [AnyObject](), extraData: Data(), transactionOptions: self.transactionOptions)!.call(transactionOptions: transactionOptions) + guard let res = result["0"] as? BigUInt else {throw Web3Error.processingError(desc: "Failed to get result of expected type from the Ethereum node")} + return res + } + + public func renounceOwnership(from: EthereumAddress) throws -> WriteTransaction { + let contract = self.contract + var basicOptions = TransactionOptions() + basicOptions.from = from + basicOptions.to = self.address + basicOptions.callOnBlock = .latest + + let tx = contract.write("renounceOwnership", parameters: [AnyObject](), transactionOptions: basicOptions)! + return tx + } + + public func transferOwnership(from: EthereumAddress, newOwner: EthereumAddress) throws -> WriteTransaction { + let contract = self.contract + var basicOptions = TransactionOptions() + basicOptions.from = from + basicOptions.to = self.address + basicOptions.callOnBlock = .latest + + let tx = contract.write("transferOwnership", parameters: [newOwner] as [AnyObject], transactionOptions: basicOptions)! + return tx + } + + public func currentCheckpointId() throws -> BigUInt { + let contract = self.contract + var transactionOptions = TransactionOptions() + transactionOptions.callOnBlock = .latest + let result = try contract.read("currentCheckpointId", parameters: [AnyObject](), extraData: Data(), transactionOptions: self.transactionOptions)!.call(transactionOptions: transactionOptions) + guard let res = result["0"] as? BigUInt else {throw Web3Error.processingError(desc: "Failed to get result of expected type from the Ethereum node")} + return res + } + + public func getGranularity() throws -> BigUInt { + let contract = self.contract + var transactionOptions = TransactionOptions() + transactionOptions.callOnBlock = .latest + let result = try contract.read("granularity", parameters: [AnyObject](), extraData: Data(), transactionOptions: self.transactionOptions)!.call(transactionOptions: transactionOptions) + guard let res = result["0"] as? BigUInt else {throw Web3Error.processingError(desc: "Failed to get result of expected type from the Ethereum node")} + return res + } + + public func investorCount() throws -> BigUInt { + let contract = self.contract + var transactionOptions = TransactionOptions() + transactionOptions.callOnBlock = .latest + let result = try contract.read("investorCount", parameters: [AnyObject](), extraData: Data(), transactionOptions: self.transactionOptions)!.call(transactionOptions: transactionOptions) + guard let res = result["0"] as? BigUInt else {throw Web3Error.processingError(desc: "Failed to get result of expected type from the Ethereum node")} + return res + } + + public func investors() throws -> [EthereumAddress] { + let contract = self.contract + var transactionOptions = TransactionOptions() + transactionOptions.callOnBlock = .latest + let result = try contract.read("investors", parameters: [AnyObject](), extraData: Data(), transactionOptions: self.transactionOptions)!.call(transactionOptions: transactionOptions) + guard let res = result["0"] as? [EthereumAddress] else {throw Web3Error.processingError(desc: "Failed to get result of expected type from the Ethereum node")} + return res + } + + public func checkPermission(delegate: EthereumAddress, module: EthereumAddress, perm: [UInt32]) throws -> Bool { + let contract = self.contract + var transactionOptions = TransactionOptions() + transactionOptions.callOnBlock = .latest + let result = try contract.read("checkPermission", parameters: [delegate, module, perm] as [AnyObject], extraData: Data(), transactionOptions: self.transactionOptions)!.call(transactionOptions: transactionOptions) + guard let res = result["0"] as? Bool else {throw Web3Error.processingError(desc: "Failed to get result of expected type from the Ethereum node")} + return res + } + + public func getModule(moduleType: UInt8, moduleIndex: UInt8) throws -> ([UInt32], EthereumAddress) { + let contract = self.contract + var transactionOptions = TransactionOptions() + transactionOptions.callOnBlock = .latest + let result = try contract.read("getModule", parameters: [moduleType, moduleIndex] as [AnyObject], extraData: Data(), transactionOptions: self.transactionOptions)!.call(transactionOptions: transactionOptions) + guard let moduleList = result["0"] as? [UInt32] else {throw Web3Error.processingError(desc: "Failed to get result of expected type from the Ethereum node")} + guard let moduleAddress = result["1"] as? EthereumAddress else {throw Web3Error.processingError(desc: "Failed to get result of expected type from the Ethereum node")} + return (moduleList, moduleAddress) + } + + public func getModuleByName(moduleType: UInt8, name: [UInt32]) throws -> ([UInt32], EthereumAddress) { + let contract = self.contract + var transactionOptions = TransactionOptions() + transactionOptions.callOnBlock = .latest + let result = try contract.read("getModuleByName", parameters: [moduleType, name] as [AnyObject], extraData: Data(), transactionOptions: self.transactionOptions)!.call(transactionOptions: transactionOptions) + guard let moduleList = result["0"] as? [UInt32] else {throw Web3Error.processingError(desc: "Failed to get result of expected type from the Ethereum node")} + guard let moduleAddress = result["1"] as? EthereumAddress else {throw Web3Error.processingError(desc: "Failed to get result of expected type from the Ethereum node")} + return (moduleList, moduleAddress) + } + + public func totalSupplyAt(checkpointId: BigUInt) throws -> BigUInt { + let contract = self.contract + var transactionOptions = TransactionOptions() + transactionOptions.callOnBlock = .latest + let result = try contract.read("totalSupplyAt", parameters: [checkpointId] as [AnyObject], extraData: Data(), transactionOptions: self.transactionOptions)!.call(transactionOptions: transactionOptions) + guard let res = result["0"] as? BigUInt else {throw Web3Error.processingError(desc: "Failed to get result of expected type from the Ethereum node")} + return res + } + + public func balanceOfAt(investor: EthereumAddress, checkpointId: BigUInt) throws -> BigUInt { + let contract = self.contract + var transactionOptions = TransactionOptions() + transactionOptions.callOnBlock = .latest + let result = try contract.read("balanceOfAt", parameters: [investor, checkpointId] as [AnyObject], extraData: Data(), transactionOptions: self.transactionOptions)!.call(transactionOptions: transactionOptions) + guard let res = result["0"] as? BigUInt else {throw Web3Error.processingError(desc: "Failed to get result of expected type from the Ethereum node")} + return res + } + + public func createCheckpoint(from: EthereumAddress) throws -> WriteTransaction { + let contract = self.contract + var basicOptions = TransactionOptions() + basicOptions.from = from + basicOptions.to = self.address + basicOptions.callOnBlock = .latest + + let tx = contract.write("createCheckpoint", parameters: [AnyObject](), transactionOptions: basicOptions)! + return tx + } + + public func getInvestorsLength() throws -> BigUInt { + let contract = self.contract + var transactionOptions = TransactionOptions() + transactionOptions.callOnBlock = .latest + let result = try contract.read("getInvestorsLength", parameters: [AnyObject](), extraData: Data(), transactionOptions: self.transactionOptions)!.call(transactionOptions: transactionOptions) + guard let res = result["0"] as? BigUInt else {throw Web3Error.processingError(desc: "Failed to get result of expected type from the Ethereum node")} + return res + } +} diff --git a/web3swift/Web3/Classes/Web3+Utils.swift b/web3swift/Web3/Classes/Web3+Utils.swift index ade6f7b48..9484c61b2 100755 --- a/web3swift/Web3/Classes/Web3+Utils.swift +++ b/web3swift/Web3/Classes/Web3+Utils.swift @@ -74,6 +74,11 @@ extension Web3.Utils { /// Precoded "cold wallet" (private key controlled) address. Basically - only a payable fallback function. public static var coldWalletABI = "[{\"payable\":true,\"type\":\"fallback\"}]" + /// Precoded ST20 contracts ABI. Output parameters are named for ease of use. + public static var st20ABI = """ +[{"constant":false,"inputs":[],"name":"freezeTransfers","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"investorListed","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_moduleType","type":"uint8"},{"name":"_moduleIndex","type":"uint8"}],"name":"removeModule","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"finishMintingSTO","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_granularity","type":"uint256"}],"name":"changeGranularity","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"finishedSTOMinting","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"tokenBurner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"tickerRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"unfreezeTransfers","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"securityTokenVersion","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"investors","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_investor","type":"address"},{"name":"_amount","type":"uint256"}],"name":"mint","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_value","type":"uint256"}],"name":"burn","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_moduleType","type":"uint8"},{"name":"_moduleIndex","type":"uint256"}],"name":"getModule","outputs":[{"name":"","type":"bytes32"},{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_investors","type":"address[]"},{"name":"_amounts","type":"uint256[]"}],"name":"mintMulti","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_investor","type":"address"},{"name":"_checkpointId","type":"uint256"}],"name":"balanceOfAt","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"currentCheckpointId","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"granularity","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_MODULES","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_moduleType","type":"uint8"},{"name":"_moduleIndex","type":"uint8"},{"name":"_budget","type":"uint256"}],"name":"changeModuleBudget","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"freeze","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STO_KEY","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_subtractedValue","type":"uint256"}],"name":"decreaseApproval","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"polyToken","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint8"},{"name":"","type":"uint256"}],"name":"modules","outputs":[{"name":"name","type":"bytes32"},{"name":"moduleAddress","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newTokenDetails","type":"string"}],"name":"updateTokenDetails","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"polymathRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"checkpointTotalSupply","outputs":[{"name":"checkpointId","type":"uint256"},{"name":"value","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_delegate","type":"address"},{"name":"_module","type":"address"},{"name":"_perm","type":"bytes32"}],"name":"checkPermission","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"TRANSFERMANAGER_KEY","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_checkpointId","type":"uint256"}],"name":"totalSupplyAt","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"verifyTransfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"finishedIssuerMinting","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_moduleType","type":"uint8"},{"name":"_name","type":"bytes32"}],"name":"getModuleByName","outputs":[{"name":"","type":"bytes32"},{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"finishMintingIssuer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"PERMISSIONMANAGER_KEY","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_tokenBurner","type":"address"}],"name":"setTokenBurner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"moduleRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"CHECKPOINT_KEY","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_start","type":"uint256"},{"name":"_iters","type":"uint256"}],"name":"pruneInvestors","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"securityTokenRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"tokenDetails","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_addedValue","type":"uint256"}],"name":"increaseApproval","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"investorCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInvestorsLength","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"updateFromRegistry","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_moduleFactory","type":"address"},{"name":"_data","type":"bytes"},{"name":"_maxCost","type":"uint256"},{"name":"_budget","type":"uint256"}],"name":"addModule","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"withdrawPoly","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"checkpointBalances","outputs":[{"name":"checkpointId","type":"uint256"},{"name":"value","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"createCheckpoint","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_name","type":"string"},{"name":"_symbol","type":"string"},{"name":"_decimals","type":"uint8"},{"name":"_granularity","type":"uint256"},{"name":"_tokenDetails","type":"string"},{"name":"_polymathRegistry","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_type","type":"uint8"},{"indexed":false,"name":"_name","type":"bytes32"},{"indexed":false,"name":"_moduleFactory","type":"address"},{"indexed":false,"name":"_module","type":"address"},{"indexed":false,"name":"_moduleCost","type":"uint256"},{"indexed":false,"name":"_budget","type":"uint256"},{"indexed":false,"name":"_timestamp","type":"uint256"}],"name":"LogModuleAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_oldDetails","type":"string"},{"indexed":false,"name":"_newDetails","type":"string"}],"name":"LogUpdateTokenDetails","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_oldGranularity","type":"uint256"},{"indexed":false,"name":"_newGranularity","type":"uint256"}],"name":"LogGranularityChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_type","type":"uint8"},{"indexed":false,"name":"_module","type":"address"},{"indexed":false,"name":"_timestamp","type":"uint256"}],"name":"LogModuleRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_moduleType","type":"uint8"},{"indexed":false,"name":"_module","type":"address"},{"indexed":false,"name":"_budget","type":"uint256"}],"name":"LogModuleBudgetChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_freeze","type":"bool"},{"indexed":false,"name":"_timestamp","type":"uint256"}],"name":"LogFreezeTransfers","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_checkpointId","type":"uint256"},{"indexed":false,"name":"_timestamp","type":"uint256"}],"name":"LogCheckpointCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_timestamp","type":"uint256"}],"name":"LogFinishMintingIssuer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_timestamp","type":"uint256"}],"name":"LogFinishMintingSTO","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_oldAddress","type":"address"},{"indexed":true,"name":"_newAddress","type":"address"}],"name":"LogChangeSTRAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"}],"name":"OwnershipRenounced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"Minted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_burner","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Burnt","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"}] +""" + /// TODO: - Need to make it right /// Precoded ERC888 contracts ABI. Output parameters are named for ease of use. public static var erc888ABI = "[{\"constant\":true,\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_spender\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"name\":\"\",\"type\":\"uint8\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"version\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"balance\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_spender\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"},{\"name\":\"_extraData\",\"type\":\"bytes\"}],\"name\":\"approveAndCall\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"},{\"name\":\"_spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"name\":\"remaining\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"inputs\":[{\"name\":\"_initialAmount\",\"type\":\"uint256\"},{\"name\":\"_tokenName\",\"type\":\"string\"},{\"name\":\"_decimalUnits\",\"type\":\"uint8\"},{\"name\":\"_tokenSymbol\",\"type\":\"string\"}],\"type\":\"constructor\"},{\"payable\":false,\"type\":\"fallback\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_spender\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},]" diff --git a/web3swiftTests/web3swift_ST20AndSecurityToken_Tests.swift b/web3swiftTests/web3swift_ST20AndSecurityToken_Tests.swift new file mode 100644 index 000000000..1b03fbae9 --- /dev/null +++ b/web3swiftTests/web3swift_ST20AndSecurityToken_Tests.swift @@ -0,0 +1,55 @@ +// +// web3swift_ST20_Tests.swift +// web3swift-iOS_Tests +// +// Created by Anton on 15/03/2019. +// Copyright © 2019 The Matter Inc. All rights reserved. +// + +import XCTest +import BigInt +import EthereumAddress + +@testable import web3swift_iOS + +class web3swift_ST20AndSecurityToken_Tests: XCTestCase { + + func testERC20TokenCreation() { + let web3 = Web3.new(URL(string: "https://kovan.infura.io")!)! + let w3sTokenAddress = EthereumAddress("0x2dD33957C90880bE4Ee9fd5F703110BDA2E579EC")! + let st20token = ST20.init(web3: web3, provider: web3.provider, address: w3sTokenAddress) + st20token.readProperties() + XCTAssert(st20token.symbol == "MIMI") + XCTAssert(st20token.name == "Mimi") + XCTAssert(st20token.decimals == 18) + } + + func testST20tokenBalanceAndAllowance() throws { + let web3 = Web3.new(URL(string: "https://kovan.infura.io")!)! + let w3sTokenAddress = EthereumAddress("0x2dD33957C90880bE4Ee9fd5F703110BDA2E579EC")! + let st20token = ST20.init(web3: web3, provider: web3.provider, address: w3sTokenAddress) + let userAddress = EthereumAddress("0xe22b8979739D724343bd002F9f432F5990879901")! + let balance = try st20token.getBalance(account: userAddress) + let allowance = try st20token.getAllowance(originalOwner: userAddress, delegate: userAddress) + XCTAssert(String(balance) == "0") + XCTAssert(allowance == 0) + } + + func testSecurityTokenInvestors() throws { + let web3 = Web3.new(URL(string: "https://kovan.infura.io")!)! + let w3sTokenAddress = EthereumAddress("0x2dD33957C90880bE4Ee9fd5F703110BDA2E579EC")! + let stoken = SecurityToken.init(web3: web3, provider: web3.provider, address: w3sTokenAddress) + let investorsCount = try stoken.investorCount() + let stringInvestorsCount = String(investorsCount) + XCTAssert(stringInvestorsCount == "0") + } + + func testSecurityTokenGranularity() throws { + let web3 = Web3.new(URL(string: "https://kovan.infura.io")!)! + let w3sTokenAddress = EthereumAddress("0x2dD33957C90880bE4Ee9fd5F703110BDA2E579EC")! + let stoken = SecurityToken.init(web3: web3, provider: web3.provider, address: w3sTokenAddress) + let granularity = try stoken.getGranularity() + let stringGranularity = String(granularity) + XCTAssert(stringGranularity == "1000000000000000000") + } +} From 0f8f5c84e562a05b47db0c6aa90defe8af072201 Mon Sep 17 00:00:00 2001 From: Lucas Cullen Date: Sat, 16 Mar 2019 14:39:33 +1000 Subject: [PATCH 2/6] Fix spelling --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1273727f3..bfbddba55 100755 --- a/README.md +++ b/README.md @@ -250,7 +250,7 @@ If you believe you have identified a security vulnerability with web3swift, you ## Donations -[The Matters](https://github.com/orgs/matterinc/people) are charged with open-sorсe and do not require money for using their web3swift lib. +[The Matters](https://github.com/orgs/matterinc/people) are charged with open-sourсe and do not require money for using their web3swift lib. We want to continue to do everything we can to move the needle forward. If you use any of our libraries for work, see if your employers would be interested in donating. Any amount you can donate today to help us reach our goal would be greatly appreciated. From 221b953af583b520387756e61a5a4f63176e2483 Mon Sep 17 00:00:00 2001 From: Scott Chou Date: Wed, 20 Mar 2019 18:45:39 +0800 Subject: [PATCH 3/6] let some functions public for customization --- web3swift/Promises/Classes/Promise+Batching.swift | 2 +- web3swift/Web3/Classes/Web3+JSONRPC.swift | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/web3swift/Promises/Classes/Promise+Batching.swift b/web3swift/Promises/Classes/Promise+Batching.swift index 982efa0e9..010b3cc02 100755 --- a/web3swift/Promises/Classes/Promise+Batching.swift +++ b/web3swift/Promises/Classes/Promise+Batching.swift @@ -16,7 +16,7 @@ public class JSONRPCrequestDispatcher { private var lockQueue: DispatchQueue private var batches: [Batch] = [Batch]() - init(provider: Web3Provider, queue: DispatchQueue, policy: DispatchPolicy) { + public init(provider: Web3Provider, queue: DispatchQueue, policy: DispatchPolicy) { self.provider = provider self.queue = queue self.policy = policy diff --git a/web3swift/Web3/Classes/Web3+JSONRPC.swift b/web3swift/Web3/Classes/Web3+JSONRPC.swift index 37d6d9a86..652c03132 100755 --- a/web3swift/Web3/Classes/Web3+JSONRPC.swift +++ b/web3swift/Web3/Classes/Web3+JSONRPC.swift @@ -24,10 +24,10 @@ public struct Counter { /// JSON RPC request structure for serialization and deserialization purposes. public struct JSONRPCrequest: Encodable { - var jsonrpc: String = "2.0" - var method: JSONRPCmethod? - var params: JSONRPCparams? - var id: UInt64 = Counter.increment() + public var jsonrpc: String = "2.0" + public var method: JSONRPCmethod? + public var params: JSONRPCparams? + public var id: UInt64 = Counter.increment() enum CodingKeys: String, CodingKey { case jsonrpc From c71fb3709bf2fc790f52ce51c5e154ec91fdd817 Mon Sep 17 00:00:00 2001 From: BaldyAsh Date: Tue, 26 Mar 2019 12:00:58 +0300 Subject: [PATCH 4/6] fixed podspec and project --- web3swift.podspec | 14 ++++++++------ web3swift.xcodeproj/project.pbxproj | 4 ---- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/web3swift.podspec b/web3swift.podspec index 1a7df8ca5..0c0865fde 100755 --- a/web3swift.podspec +++ b/web3swift.podspec @@ -1,33 +1,35 @@ Pod::Spec.new do |s| s.name = "web3swift" -s.version = "2.0.1" +s.version = "2.1.1" s.summary = "Web3 implementation in vanilla Swift for iOS ans macOS" s.description = <<-DESC Web3 implementation in vanilla Swift, intended for mobile developers of wallets, Dapps and Web3.0 DESC -s.homepage = "https://github.com/matterinc/web3swift" +s.homepage = "https://github.com/matter-labs/web3swift" s.license = 'Apache License 2.0' s.author = { "Alex Vlasov" => "alex.m.vlasov@gmail.com" } -s.source = { :git => 'https://github.com/matterinc/web3swift.git', :tag => s.version.to_s } +s.source = { :git => 'https://github.com/matter-labs/web3swift.git', :tag => s.version.to_s } s.social_media_url = 'https://twitter.com/shamatar' s.swift_version = '4.1' s.module_name = 'Web3swift' s.ios.deployment_target = "9.0" s.osx.deployment_target = "10.11" -s.source_files = "web3swift/{PrecompiledContracts,Promises,Web3,Contract,KeystoreManager,Transaction,Convenience}/Classes/*.{h,swift}", "web3swift/Utils/Classes/{EIP67Code, EIP681}.swift", "web3swift/HookedFunctions/Classes/*.swift", "web3swift/web3swift.h" +s.source_files = "web3swift/{Promises,HookedFunctions,Web3,Contract,KeystoreManager,Transaction,Convenience}/Classes/*.{h,swift}", "web3swift/Utils/Classes/{EIP67Code, EIP681, ENS, ENSResolver, NameHash}.swift", "web3swift/PrecompiledContracts/**/*.swift", "web3swift/web3swift.h" s.public_header_files = "web3swift/web3swift.h" s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } s.frameworks = 'CoreImage' +s.dependency 'scrypt', '~> 2.0' +s.dependency 'PromiseKit', '~> 6.4.1' s.dependency 'BigInt', '~> 3.1' s.dependency 'CryptoSwift', '~> 0.13' -s.dependency 'PromiseKit', '~> 6.3' -s.dependency 'scrypt', '~> 2.0' +s.dependency 'Result', '~> 4.0' s.dependency 'secp256k1_swift', '~> 1.0.3' s.dependency 'SwiftRLP', '~> 1.1' s.dependency 'EthereumAddress', '~> 1.0.0' s.dependency 'EthereumABI', '~> 1.1.1' + end diff --git a/web3swift.xcodeproj/project.pbxproj b/web3swift.xcodeproj/project.pbxproj index fcad911f6..5d4b3b77b 100755 --- a/web3swift.xcodeproj/project.pbxproj +++ b/web3swift.xcodeproj/project.pbxproj @@ -183,8 +183,6 @@ 81DFB400210775320011DC85 /* Web3+Infura.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81DFB3FE210775320011DC85 /* Web3+Infura.swift */; }; 81EB1E4B208173D7003BD47F /* Web3+Personal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81EB1E4A208173D7003BD47F /* Web3+Personal.swift */; }; 81EB1E4C208173D7003BD47F /* Web3+Personal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81EB1E4A208173D7003BD47F /* Web3+Personal.swift */; }; - 81ED4EA82190D922003E932E /* NonceMiddleware.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81ED4EA72190D922003E932E /* NonceMiddleware.swift */; }; - 81ED4EA92190D922003E932E /* NonceMiddleware.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81ED4EA72190D922003E932E /* NonceMiddleware.swift */; }; 81FA43F62044097100EE14D5 /* web3swift_macOS_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81FA43F52044097100EE14D5 /* web3swift_macOS_Tests.swift */; }; 81FA43F82044097100EE14D5 /* web3swift_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 417715D420362916005C3E16 /* web3swift_macOS.framework */; }; 81FB21FE207BB297007F9A83 /* EIP67Code.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81FB21F8207BA78B007F9A83 /* EIP67Code.swift */; }; @@ -1239,7 +1237,6 @@ 8160E5CE20B8245A0070070B /* IBAN.swift in Sources */, 81909D1521862D37007D2AE5 /* Web3+MutatingTransaction.swift in Sources */, 810B0F9C1FEC520500CF0DA2 /* Web3+Methods.swift in Sources */, - 81ED4EA82190D922003E932E /* NonceMiddleware.swift in Sources */, 81A1822520D678590016741F /* Promise+Web3+Eth+GetGasPrice.swift in Sources */, 8113DE7C1FD8514400CD8DF1 /* NSRegularExpressionExtension.swift in Sources */, E2F8082A21CAA07000B6BF15 /* Web3+ERC1643.swift in Sources */, @@ -1369,7 +1366,6 @@ 41948131203630530065A83B /* BIP32KeystoreJSONStructure.swift in Sources */, 41948132203630530065A83B /* BIP32HDNode.swift in Sources */, 81A7B2522143C3A8004CD2C7 /* NameHash.swift in Sources */, - 81ED4EA92190D922003E932E /* NonceMiddleware.swift in Sources */, 81A1824920D7DDA20016741F /* Promise+Web3+Personal+Sign.swift in Sources */, 81A1822620D678590016741F /* Promise+Web3+Eth+GetGasPrice.swift in Sources */, 81909D1621862D37007D2AE5 /* Web3+MutatingTransaction.swift in Sources */, From 17ce1467e9233f248baeec8d2bceea57229cc103 Mon Sep 17 00:00:00 2001 From: BaldyAsh Date: Tue, 26 Mar 2019 12:09:44 +0300 Subject: [PATCH 5/6] fixed proj --- web3swift.xcodeproj/project.pbxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web3swift.xcodeproj/project.pbxproj b/web3swift.xcodeproj/project.pbxproj index 5d4b3b77b..735085725 100755 --- a/web3swift.xcodeproj/project.pbxproj +++ b/web3swift.xcodeproj/project.pbxproj @@ -30,6 +30,8 @@ 3AC3BD7E222EA70500656EC7 /* Web3+ST20.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AC3BD7C222EA70500656EC7 /* Web3+ST20.swift */; }; 3AC3BD80222EC6C900656EC7 /* Web3+SecurityToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AC3BD7F222EC6C900656EC7 /* Web3+SecurityToken.swift */; }; 3AC3BD81222EC6C900656EC7 /* Web3+SecurityToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AC3BD7F222EC6C900656EC7 /* Web3+SecurityToken.swift */; }; + 3AE494F7224A23C300AB2972 /* NonceMiddleware.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81ED4EA72190D922003E932E /* NonceMiddleware.swift */; }; + 3AE494F8224A23CD00AB2972 /* NonceMiddleware.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81ED4EA72190D922003E932E /* NonceMiddleware.swift */; }; 4194811B203630530065A83B /* Web3+HttpProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 817EBB142004FE4200E02EAA /* Web3+HttpProvider.swift */; }; 4194811E203630530065A83B /* Web3.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81DDECCE1FDF004E0063684A /* Web3.swift */; }; 4194811F203630530065A83B /* Web3+Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 818ABD5A1FE95F8F002657BB /* Web3+Instance.swift */; }; @@ -1188,6 +1190,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 3AE494F7224A23C300AB2972 /* NonceMiddleware.swift in Sources */, 3AC1E7CB222D6A8C004F43D8 /* Web3+BrowserFunctions.swift in Sources */, E2DCA654218C879900F94FBA /* ENS.swift in Sources */, E2DCA655218C879900F94FBA /* ENSResolver.swift in Sources */, @@ -1311,6 +1314,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 3AE494F8224A23CD00AB2972 /* NonceMiddleware.swift in Sources */, 3AC1E7D9222D6AA0004F43D8 /* Web3+BrowserFunctions.swift in Sources */, 3AC1E7CC222D6A99004F43D8 /* Web3+ERC1376.swift in Sources */, 3AC1E7CD222D6A99004F43D8 /* Web3+ERC1155.swift in Sources */, From 2cdb1cbc4e99ad7de906ebdab1a8f15f5d83f2d3 Mon Sep 17 00:00:00 2001 From: BaldyAsh Date: Tue, 26 Mar 2019 12:31:50 +0300 Subject: [PATCH 6/6] project fix --- web3swift.xcodeproj/project.pbxproj | 4 -- .../web3swift_Eventloop_Tests.swift | 54 +++++++++---------- 2 files changed, 27 insertions(+), 31 deletions(-) diff --git a/web3swift.xcodeproj/project.pbxproj b/web3swift.xcodeproj/project.pbxproj index 735085725..5d4b3b77b 100755 --- a/web3swift.xcodeproj/project.pbxproj +++ b/web3swift.xcodeproj/project.pbxproj @@ -30,8 +30,6 @@ 3AC3BD7E222EA70500656EC7 /* Web3+ST20.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AC3BD7C222EA70500656EC7 /* Web3+ST20.swift */; }; 3AC3BD80222EC6C900656EC7 /* Web3+SecurityToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AC3BD7F222EC6C900656EC7 /* Web3+SecurityToken.swift */; }; 3AC3BD81222EC6C900656EC7 /* Web3+SecurityToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AC3BD7F222EC6C900656EC7 /* Web3+SecurityToken.swift */; }; - 3AE494F7224A23C300AB2972 /* NonceMiddleware.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81ED4EA72190D922003E932E /* NonceMiddleware.swift */; }; - 3AE494F8224A23CD00AB2972 /* NonceMiddleware.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81ED4EA72190D922003E932E /* NonceMiddleware.swift */; }; 4194811B203630530065A83B /* Web3+HttpProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 817EBB142004FE4200E02EAA /* Web3+HttpProvider.swift */; }; 4194811E203630530065A83B /* Web3.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81DDECCE1FDF004E0063684A /* Web3.swift */; }; 4194811F203630530065A83B /* Web3+Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 818ABD5A1FE95F8F002657BB /* Web3+Instance.swift */; }; @@ -1190,7 +1188,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 3AE494F7224A23C300AB2972 /* NonceMiddleware.swift in Sources */, 3AC1E7CB222D6A8C004F43D8 /* Web3+BrowserFunctions.swift in Sources */, E2DCA654218C879900F94FBA /* ENS.swift in Sources */, E2DCA655218C879900F94FBA /* ENSResolver.swift in Sources */, @@ -1314,7 +1311,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 3AE494F8224A23CD00AB2972 /* NonceMiddleware.swift in Sources */, 3AC1E7D9222D6AA0004F43D8 /* Web3+BrowserFunctions.swift in Sources */, 3AC1E7CC222D6A99004F43D8 /* Web3+ERC1376.swift in Sources */, 3AC1E7CD222D6A99004F43D8 /* Web3+ERC1155.swift in Sources */, diff --git a/web3swiftTests/web3swift_Eventloop_Tests.swift b/web3swiftTests/web3swift_Eventloop_Tests.swift index 6ca05f5ad..e54c44612 100644 --- a/web3swiftTests/web3swift_Eventloop_Tests.swift +++ b/web3swiftTests/web3swift_Eventloop_Tests.swift @@ -35,33 +35,33 @@ class web3swift_Eventloop_Tests: XCTestCase { waitForExpectations(timeout: 60, handler: nil) } - func testNonceMiddleware() { - let web3 = Web3.InfuraRinkebyWeb3() - let middleware = Web3.Utils.NonceMiddleware() - middleware.attach(web3) - - let sendToAddress = EthereumAddress("0xe22b8979739D724343bd002F9f432F5990879901")! - let ksData = getKeystoreData() - let tempKeystore = EthereumKeystoreV3(ksData!) - let keystoreManager = KeystoreManager([tempKeystore!]) - web3.addKeystoreManager(keystoreManager) - - var tx = web3.eth.sendETH(to: sendToAddress, amount: 1000) - tx!.transactionOptions.from = tempKeystore!.addresses!.first! - var result = try! tx!.send(password: "web3swift") - let newNonce = result.transaction.nonce - sleep(1) - let hookNewNonce = middleware.nonceLookups[tempKeystore!.addresses!.first!]! - XCTAssertEqual(newNonce, hookNewNonce) - - tx = web3.eth.sendETH(to: sendToAddress, amount: 1000) - tx!.transactionOptions.from = tempKeystore!.addresses!.first! - result = try! tx!.send(password: "web3swift") - sleep(1) - let newNonce2 = result.transaction.nonce - let hookNewNonce2 = middleware.nonceLookups[tempKeystore!.addresses!.first!]! - XCTAssert(newNonce2 == hookNewNonce2) - } +// func testNonceMiddleware() { +// let web3 = Web3.InfuraRinkebyWeb3() +// let middleware = Web3.Utils.NonceMiddleware() +// middleware.attach(web3) +// +// let sendToAddress = EthereumAddress("0xe22b8979739D724343bd002F9f432F5990879901")! +// let ksData = getKeystoreData() +// let tempKeystore = EthereumKeystoreV3(ksData!) +// let keystoreManager = KeystoreManager([tempKeystore!]) +// web3.addKeystoreManager(keystoreManager) +// +// var tx = web3.eth.sendETH(to: sendToAddress, amount: 1000) +// tx!.transactionOptions.from = tempKeystore!.addresses!.first! +// var result = try! tx!.send(password: "web3swift") +// let newNonce = result.transaction.nonce +// sleep(1) +// let hookNewNonce = middleware.nonceLookups[tempKeystore!.addresses!.first!]! +// XCTAssertEqual(newNonce, hookNewNonce) +// +// tx = web3.eth.sendETH(to: sendToAddress, amount: 1000) +// tx!.transactionOptions.from = tempKeystore!.addresses!.first! +// result = try! tx!.send(password: "web3swift") +// sleep(1) +// let newNonce2 = result.transaction.nonce +// let hookNewNonce2 = middleware.nonceLookups[tempKeystore!.addresses!.first!]! +// XCTAssert(newNonce2 == hookNewNonce2) +// } func getKeystoreData() -> Data? {