Web3Swift智能合约工具类封装

·  阅读 2807
Web3Swift智能合约工具类封装

前言:什么是智能合约?

智能合约,是一段写在区块链上的代码,一旦某个事件触发合约中的条款,代码即自动执行。也就是说,满足条件就执行,不需要人为操控。

web3Swift

web3Swift是一个纯粹而快速以太坊Web3库 github.com/skywinder/w…

在使用之前,请先Cocoapods集成web3swift

 pod 'web3swift' #web3智能合约
复制代码

Web3SwiftUtils

  • 相信很多接触刚智能合约开发和合约API调用的iOSer会遇到很多问题或踩坑,本工具类主要实现了Etherum、Binance、Polygon、ERC20平行链等,智能合约常用业务调用及主要方法封装;

主要方法调用

调用智能合约

    /// 操作智能合约
    /// - Parameters:
    ///   - method: 方法名称
    ///   - params: 参数
    ///   - config: options配置
    ///   - closure: tx结果信息
    private func callContractService(_ abiType: CSContractAbiType = .erc20, methodName: String, callType: CSContractCallType, params: [AnyObject] = [AnyObject](), config: CSContractConfig, closure: @escaping (CSContractTransResult)->Void) {

        if let object = config.modelToJSONObject() {
            print("Contract call config:\(object)\n")
            print("Contract call params:\(params)\n")
            print("Contract call rpc:\(self.network.ipUrl)\n")
        }

        let transResult = CSContractTransResult()

        // key
        guard let privateKey = config.privateKey else { return }

        let formattedKey = privateKey.trimmingCharacters(in: .whitespacesAndNewlines)
        let dataKey = Data.fromHex(formattedKey)!
        let keystore = try! EthereumKeystoreV3(privateKey: dataKey, password: password)

        let keystoreManager = KeystoreManager([keystore! as EthereumKeystoreV3])

        /// web3
        let endpoint = URL(string: contractURL)!
        guard let web333 = try? Web3.new(endpoint) else {
            return
        }

        web333.addKeystoreManager(keystoreManager)
        web3Manager = web333

        // 合约方法名称
        let contractMethod = methodName

        // ABI资源
        var contractABI = Web3.Utils.erc20ABI
        switch abiType {
        case .erc20:
            contractABI = Web3.Utils.erc20ABI

        default:
            let abiName = fetchAbiType(type: abiType)
            contractABI = String.fileContractABI(resName: abiName)
        }

        // 合约地址
        let ethContractAddress = EthereumAddress(config.contractAddress!)
        let abiVersion = 2 // Contract ABI version
        guard let contract = web333.contract(contractABI, at: ethContractAddress, abiVersion: abiVersion) else {
            return
        }

        var options = TransactionOptions.defaultOptions
        // 我的地址
        if let from = config.from, let walletAddress = EthereumAddress(from) {
            options.from = walletAddress
        }

        // 接收地址
        if let to = config.to, let toAddress = EthereumAddress(to) {
            options.to = toAddress
        }

        var decimals = BigUInt(18)
        // get the decimals manually
        if let callResult = try? contract.read("decimals", transactionOptions: options)?.call() {
            guard let dec = callResult["0"], let decTyped = dec as? BigUInt else {
                return
            }
            decimals = decTyped
        }

        let intDecimals = Int(decimals)
        if let amount = config.amount {
             options.value = Web3.Utils.parseToBigUInt(amount, decimals: intDecimals)
        }

        if let gasLimit = config.gasLimit {
            options.gasLimit = .manual(BigUInt("\(gasLimit)")!)
        }else {
            options.gasLimit = .automatic
        }

        if let gasPrice = config.gasPrice {
            if let gwei = Web3.Utils.parseToBigUInt(gasPrice, units: .Gwei) {
                options.gasPrice = .manual(gwei)
            }else {
                options.gasPrice = .automatic
            }
        }
        else {
            options.gasPrice = .automatic
        }

        let extraData: Data = Data() // Extra data for contract method

        if (callType == .write) {
            guard let tx = contract.write(contractMethod,
                                          parameters: params,
                                          extraData: extraData,
                                          transactionOptions: options) else {

                // callback
                closure(transResult)
                return
            }

            print("Transaction methodName:\(methodName)\n")
            print("Transaction description:\(tx.transaction.description)\n")

            if let result = try? tx.call() {
                transResult.callData = result
                print("Transaction callData:\(result)")

                if let etherAddress = result["0"] as? EthereumAddress {
                    print("Transaction _link:\(etherAddress.address)")
                    transResult.linkAddress = etherAddress.address
                }
            }

            txSendCallResult(tx, config: config) { result in
                transResult.transHash = result?.hash ?? ""
                transResult.transDesc = result?.transaction.description ?? ""
            }
        }else {
            guard let tx = contract.read(contractMethod,
                                         parameters: params,
                                         extraData: extraData,
                                         transactionOptions: options) else {

                // callback
                closure(transResult)
                return

            }

            print("Transaction methodName:\(methodName)\n")
            print("Transaction description:\(tx.transaction.description)\n")

            if let result = try? tx.call() {
                transResult.callData = result
                if let tokenWei = result["0"] as? BigUInt {
                    transResult.callStatus = tokenWei > 0
                    transResult.approvedAmount = "\(tokenWei)"
                }else if let status = result["0"] as? Bool {
                    if (config.symbol == "BNB" || config.symbol == "ETH" || config.symbol == "MATIC") {
                        transResult.callStatus = true
                    }else {
                        transResult.callStatus = status
                    }
                }
                print("Transaction callData:\(result)")
            }
        }
        
        // callback
        closure(transResult)
    }
复制代码

获取合约Transaction结果

private func txSendCallResult(_ tx: WriteTransaction, options: TransactionOptions? = nil, config: CSContractConfig, completion: @escaping (TransactionSendingResult?)->Void) {
        // Get transaction result
        do {
            let result = try tx.send(password: password, transactionOptions: options)
            completion(result)

            print("Transaction hash:\(result.hash)\n")
            print("Transaction desc:\(result.transaction.description)\n")
        } catch {
            completion(nil)
            let transactionErr = "\(error)"
            showMessage(message: transactionErr, config: config)
        }
     }
复制代码

代币授权

    func tokenApprove() {
        let config = CSContractConfig()
        config.abiType = .erc20;
        config.privateKey = "your privateKey"
        config.from = "your walletAddress";
        config.approveAmount = "1000000000000";
        config.contractAddress = "contract address"
        config.symbol = "token symbol"

        CSContractManager.shared.callContract(method: "approve", params: [], config: config) { result in
            if (result.transHash.length > 0 && result.callData.count > 0) {
                print("Token approve success")
            }else {
                print("Token approve fail")
            }
        }
    }
复制代码

代币发送

    func sendToken() {
        let config = CSContractConfig()
        config.abiType = .erc20;
        config.privateKey = "your privateKey"
        config.from = "your walletAddress";
        config.contractAddress = "contract address"
        config.symbol = "token symbol"
        config.gasLimit = kBaseGasLimit;
        
        let targetAddress = "target address"
        CSContractManager.shared.sendToken(config: config, amount: "10", toAdds: targetAddress) { result  in
            if (result.transHash.length > 0) {
                print("Token send success")
            }else {
                print("Token send fail")
            }
        }
    }
复制代码

查询代币信息

    func queryToken() {
        let tokenAddress = ""
        guard let token = CSContractManager.shared.querySocialToken(address: tokenAddress) else {
            return
        }
        
        print("Token Name:\(token.name)\n")
        print("Token Symbol:\(token.symbol)\n")
        print("Token decimals:\(token.decimals)\n")
    }
复制代码

查询当前钱包账户余额

    func queryAccountBalance () {
        let myWalletAddress = "your walletAddress";
        let balance = CSContractManager.shared.getAccountBalance(address: myWalletAddress)
        print("Your account balance:\(balance)")
    }
复制代码

具体功能使用,可以下载源码了解;

github.com/developerje… 如果对您有一些帮助请麻烦给个Star,谢谢。

分类:
iOS
标签:
收藏成功!
已添加到「」, 点击更改