pocket-ios-eth
是一个符合 PocketPlugin
接口的 Ethereum 插件,适用于 Pocket iOS SDK。使用 web3.swift
和 Cryptoswift
进行核心加密和与 Ethereum 相关的功能。符合 Pocket API 规范。
安装
需要在您的 Podfile 中安装以下 pod
pod 'SwiftKeychainWrapper', :git => '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="">[email protected]:jrendel/SwiftKeychainWrapper.git', :branch => 'develop', :commit => '77f73c354d695d976bcf1437fc9fbcea981aa2b4'
pod 'Pocket', :git => 'https://github.com/pokt-network/pocket-ios-eth.git', :branch => 'master'
准备工作
Pocket Network 为测试提供了一个在 Rinkeby 运行的节点。 https://ethereum.pokt.network
为了轻松设置,请按照以下步骤操作
1- 在您的 appDelegate
中导入 Pocket
和 PocketEth
2- 将 Configuration
协议添加到类中:class AppDelegate: UIResponder, UIApplicationDelegate, Configuration, {
3- 使用节点 URL 实现 nodeURL
:var nodeURL: URL { get { return URL.init(string: "https://ethereum.pokt.network")! } }
子网络
目前Pocket团队提供 https://ethereum.pokt.network
端点,该端点支持主网和Rinkeby测试网,以下为对应的 subnetwork
标识符
1
代表主网,4
代表Rinkeby
功能
创建钱包
public static func createWallet(subnetwork: String, data: [AnyHashable : Any]?) throws -> Wallet
钱包创建主要使用web3库和 SECP256k1.generatePrivateKey
函数,并将私钥保存到设备上的keystore中。开发者无需担心加密、存储或从设备中检索钱包。
示例如 BANANO Quest
let wallet = try PocketEth.createWallet(subnetwork: subnetwork, data: nil)
if try wallet.save(passphrase: walletPassphrase) == false {
throw PlayerPersistenceError.walletCreationError
}
导入钱包
public static func importWallet(subnetwork: String, privateKey: String, address: String?, data: [AnyHashable : Any]?) throws -> Wallet
导入钱包时,用户必须传入其明文私钥。
创建交易
public static func createTransaction(wallet: Wallet, params: [AnyHashable : Any]) throws -> Transaction
创建以太坊交易需要以下参数
nonce
:每次在账户上创建交易时递增的计数器。您可以使用eth_getTransactionCount
查询获取当前交易计数。gasPrice
:以wei计价的交易价格gasLimit
:以wei计价的交易最大 gas 数量to
:接收交易公共地址value
(可选):在交易中发送的 ETH 数量data
(可选):例如在智能合约上调用函数的 ABI 数据可以通过数据字段发送
通过将此作为 params
字典传入,以太坊插件抽象了开发者为创建交易所面临的所有困难,并返回一个简单的 Transaction
对象。例如,在 BANANO Quest 中创建任务的事务
定义合约函数ABI
let functionABI = "{\"constant\":false,\"inputs\":[{\"name\":\"_tokenAddress\",\"type\":\"address\"},{\"name\":\"_name\",\"type\":\"string\"},{\"name\":\"_hint\",\"type\":\"string\"},{\"name\":\"_maxWinners\",\"type\":\"uint256\"},{\"name\":\"_merkleRoot\",\"type\":\"bytes32\"},{\"name\":\"_merkleBody\",\"type\":\"string\"},{\"name\":\"_metadata\",\"type\":\"string\"}],\"name\":\"createQuest\",\"outputs\":[],\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"function\"}"
定义参数
var functionParameters = [AnyObject]()
functionParameters.append(tokenAddress as AnyObject)
functionParameters.append(questName.description as AnyObject)
functionParameters.append(hint.description as AnyObject)
functionParameters.append(maxWinners as AnyObject)
functionParameters.append(merkleRoot as AnyObject)
functionParameters.append(merkleBody as AnyObject)
functionParameters.append(metadata as AnyObject)
let txParams = [
"from": wallet.address,
"nonce": BigUInt.init(transactionCount),
"to": tavernAddress,
"value": BigUInt.init(ethPrizeWei),
"chainID": AppConfiguration.chainID,
"gasLimit": BigUInt.init(2000000),
"gasPrice": BigUInt.init(1000000000),
"data": [
"abi": functionABI,
"params": functionParameters
] as [AnyHashable: Any]
] as [AnyHashable: Any]
创建交易
guard let transaction = try? PocketEth.createTransaction(wallet: wallet, params: txParams) else {
self.error = PocketPluginError.transactionCreationError("Error creating transaction")
self.finish()
return
}
发送交易
Pocket.shared.sendTransaction(transaction: transaction) { (transactionResponse, error) in
if error != nil {
self.error = error
self.finish()
return
}
解析交易哈希响应
guard let txHash = transactionResponse?.hash else {
self.error = UploadQuestOperationError.invalidTxHash
self.finish()
return
}
self.txHash = txHash
self.finish()
创建查询
public static func createQuery(subnetwork: String, params: [AnyHashable: Any], decoder: [AnyHashable: Any]?) throws -> Query
要为以太坊创建一个Pocket查询,你需要为你要进行的特定JSON RPC调用提供subnetwork
和params
。为了创建一个查询,有两种类型的参数:
rpcMethod
:你要调用的智能合约方法的名称rpcParams
:你要调用的智能合约方法的输入
decoder
字典允许开发者指定读取请求的返回类型。
以下是一个示例,展示如何创建一个getBalance
查询并使用Pocket获取账户的余额。
let params = [
"rpcMethod": "eth_getBalance",
"rpcParams": [address, "latest"]
] as [AnyHashable: Any]
guard let query = try? PocketEth.createQuery(params: params, decoder: nil) else {
self.error = PocketPluginError.queryCreationError("Error creating query")
self.finish()
return
}
Pocket.shared.executeQuery(query: query) { (queryResponse, error) in
if error != nil {
self.error = error
self.finish()
return
}
为智能合约中的常量创建查询略为复杂,因为你需要提供你调用方法的ABI接口、functionParameters
和decoder
。以下是从BANANO Quest获取任务列表的一个示例。
创建交易
var tx = [AnyHashable: Any]()
创建ABI
let functionABI = "{\"constant\":true,\"inputs\":[{\"name\":\"_tokenAddress\",\"type\":\"address\"},{\"name\":\"_questIndex\",\"type\":\"uint256\"}],\"name\":\"getQuest\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"},{\"name\":\"\",\"type\":\"uint256\"},{\"name\":\"\",\"type\":\"string\"},{\"name\":\"\",\"type\":\"string\"},{\"name\":\"\",\"type\":\"bytes32\"},{\"name\":\"\",\"type\":\"string\"},{\"name\":\"\",\"type\":\"uint256\"},{\"name\":\"\",\"type\":\"string\"},{\"name\":\"\",\"type\":\"bool\"},{\"name\":\"\",\"type\":\"uint256\"},{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}"
传入地址和索引
let functionParameters = [tokenAddress, questIndex] as [AnyObject]
编码ABI和参数
guard let data = try? PocketEth.encodeFunction(functionABI: functionABI, parameters: functionParameters).toHexString() else {
self.error = PocketPluginError.queryCreationError("Error creating query")
self.finish()
return
}
为以太坊交易添加参数
tx["to"] = tavernAddress
tx["data"] = "0x" + data
tx["from"] = self.playerAddress
创建最终以太坊查询的参数
let params = [
"rpcMethod": "eth_call",
"rpcParams": [tx, "latest"]
] as [AnyHashable: Any]
创建解码器
let decoder = [
"returnTypes": ["address", "uint256", "string", "string", "bytes32", "string", "uint256", "string", "bool", "uint256", "uint256"]
] as [AnyHashable : Any]
创建查询对象
guard let query = try? PocketEth.createQuery(params: params, decoder: decoder) else {
self.error = PocketPluginError.queryCreationError("Error creating query")
self.finish()
return
}
执行查询
Pocket.shared.executeQuery(query: query) { (queryResponse, error) in
if error != nil {
self.error = error
self.finish()
return
}
获取并解析响应
guard let questArr = queryResponse?.result?.value() as? [JSON] else {
self.error = DownloadQuestOperationError.questParsing
self.finish()
return
}
let creator = questArr[0].value() as? String ?? ""
let index = questArr[1].value() as? String ?? "0"
let name = questArr[2].value() as? String ?? ""
let hint = questArr[3].value() as? String ?? ""
let merkleRoot = questArr[4].value() as? String ?? ""
let merkleBody = questArr[5].value() as? String ?? ""
let maxWinners = questArr[6].value() as? String ?? "0"
let metadata = questArr[7].value() as? String ?? ""
let valid = questArr[8].value() as? Bool ?? false
let winnersAmount = questArr[9].value() as? String ?? "0"
let claimersAmount = questArr[10].value() as? String ?? "0"
self.questDict = [
"creator": creator,
"index": index,
"name": name,
"hint": hint,
"merkleRoot": merkleRoot,
"merkleBody": merkleBody,
"maxWinners": maxWinners,
"metadata": metadata,
"valid": valid,
"winnersAmount": winnersAmount,
"claimersAmount": claimersAmount
] as [AnyHashable: Any]
self.finish()