Web3Swift.io 0.0.4

Web3Swift.io 0.0.4

Anton NazarovTimofey SoloninVadim Koleoshkin维护。



 
依赖项
SwiftyJSON~> 4.3
secp256k1.swift~> 0.1
CryptoSwift~> 1.0
BigInt~> 5.0
 

  • Timofey Solonin 和 Vadim Koleoshkin

Version Code coverage CI Status License Follow on Twitter Join Telegram

安装

CocoaPods

Web3 可通过 CocoaPods 提供。要安装它,只需将以下行添加到您的 Podfile

pod 'Web3Swift.io'

发送以太币

从一个具有私钥 0x1636e10756e62baabddd4364010444205f1216bdb1644ff8f776f6e2982aa9f5 的账户向在主网上地址为 0x79d2c50Ba0cA4a2C6F8D65eBa1358bEfc1cFD403 的账户发送一些 wei

import Web3Swift

let sender: PrivateKey = EthPrivateKey(
    hex: "0x1636e10756e62baabddd4364010444205f1216bdb1644ff8f776f6e2982aa9f5"
)

let recipient: BytesScalar = EthAddress(
    hex: "0x79d2c50Ba0cA4a2C6F8D65eBa1358bEfc1cFD403"
)

let network: Network = InfuraNetwork(
    chain: "mainnet",
    apiKey: "0c4d6dc730244b4185a6bde26f981bff"
)

let amount: BytesScalar = EthNumber(
    hex: "0xde0b6b3a7640000" // 10^18 in hex that represents 1 ETH
)

let response = try SendRawTransactionProcedure(
    network: network,
    transactionBytes: EthDirectTransactionBytes(
        network: network,
        senderKey: sender,
        recipientAddress: recipient,
        weiAmount: amount
    )
).call()

//If Ethereum network accepts the transaction, you could get transaction hash from the response. Otherwise, library will throw `DescribedError`
print(response["result"].string ?? "Something went wrong")

如果您想指定 gas 价格或 gas 数量,请查看 EthDirectTransactionBytes.swift

要发送 ether 而不是 wei

let ethAmount = 1.1

try SendRawTransactionProcedure(
    ...,
    weiAmount: EthToWei(
        amount: ethAmount
    )
).call()

处理 ERC-20 代币

向地址发送代币

为了发送一些ERC-20代币,例如OmiseGO,我们需要获取智能合约地址。OMG代币由以下智能合约管理:0xd26114cd6EE289AccF82350c8d8487fedB8A0C07。在这个例子中,我们从具有私钥0x1636e10756e62baabddd4364010444205f1216bdb1644ff8f776f6e2982aa9f5的账户向主网上的地址0x79d2c50Ba0cA4a2C6F8D65eBa1358bEfc1cFD403发送代币。

import Web3Swift

let network: Network = InfuraNetwork(
    chain: "mainnet", apiKey: "0c4d6dc730244b4185a6bde26f981bff"
)

let sender: PrivateKey = EthPrivateKey(
    hex: "0x1636e10756e62baabddd4364010444205f1216bdb1644ff8f776f6e2982aa9f5"
)

let recipient: BytesScalar = EthAddress(
    hex: "0x79d2c50Ba0cA4a2C6F8D65eBa1358bEfc1cFD403"
)

let token: BytesScalar = EthAddress(
    hex: "0xd26114cd6EE289AccF82350c8d8487fedB8A0C07"
)

let amount: BytesScalar = EthNumber(
    hex: "0xde0b6b3a7640000" // 10^18 in hex that represents 1 OMG token
)

let response = try SendRawTransactionProcedure(
    network: network,
    transactionBytes: EthContractCallBytes(
        network: network,
        senderKey: sender,
        contractAddress: token,
        weiAmount: EthNumber(
            hex: "0x00" //We do not need to provide ethers to not payable functions.
        ),
        functionCall: EncodedABIFunction(
            signature: SimpleString(
                string: "transfer(address,uint256)"
            ),
            parameters: [
                ABIAddress(
                    address: recipient
                ),
                ABIUnsignedNumber(
                    origin: amount
                )
            ]
        )
    )
).call()

//If Ethereum network accepts the transaction, you could get transaction hash from the response. Otherwise, library will throw `DescribedError`
print(response["result"].string ?? "Something went wrong")

只需编码另一个EncodedABIFunction,就可以快速处理其他ERC-20功能。

向地址发送委托代币

以下是编码transferFrom(from,to,value)函数的示例

EncodedABIFunction(
    signature: SimpleString(
        string: "transferFrom(address,address,uint256)"
    ),
    parameters: [
        ABIAddress(
            address: EthAddress(
                hex: "0xFBb1b73C4f0BDa4f67dcA266ce6Ef42f520fBB98"
            )
        ),
        ABIAddress(
            address: EthAddress(
                hex: "0x79d2c50Ba0cA4a2C6F8D65eBa1358bEfc1cFD403"
            )
        ),
        ABIUnsignedNumber(
            origin: EthNumber(
                hex: "0x01"
            )
        )
    ]
)

包括更高级的编码示例,可放置在Example/Tests/ABI

检查地址余额

不需要发送交易即可从智能合约中读取数据。以下是通过调用智能合约函数balanceOf(owner)来检查地址余额的示例。

let balance = try HexAsDecimalString(
    hex: EthContractCall(
        network: InfuraNetwork(
            chain: "mainnet", apiKey: "0c4d6dc730244b4185a6bde26f981bff"
        ),
        contractAddress: EthAddress(
            hex: "0xd26114cd6EE289AccF82350c8d8487fedB8A0C07" //OmiseGO token contract
        ),
        functionCall: EncodedABIFunction(
            signature: SimpleString(
                string: "balanceOf(address)"
            ),
            parameters: [
                ABIAddress(
                    address: EthAddress(
                        hex: "0xFBb1b73C4f0BDa4f67dcA266ce6Ef42f520fBB98" //Bittrex
                    )
                )
            ]
        )
    )
).value()

print(balance) // 13098857909137917398909558 is 13 098 857.909137917398909558 OMG tokens

签名

import CryptoSwift

// Add your private key
let privateKey = EthPrivateKey(
        hex: "YOUR_PRIVATE_KEY"
)

// Form the bytes for your message
// In our example we sign null Ethereum address
let messageBytes = try! EthAddress(
        hex: "0x0000000000000000000000000000000000000000"
).value().bytes

// Create a message
// Don't forget that some services may expect
// a message with Ethereum prefix as here
let message = ConcatenatedBytes(
        bytes: [
            //Ethereum prefix
            UTF8StringBytes(
                    string: SimpleString(
                            string: "\u{19}Ethereum Signed Message:\n32"
                    )
            ),
            //message
            Keccak256Bytes(
                    origin: SimpleBytes(
                            bytes:
                    )
            )
        ]
)

// Use your custom hash function if needed
let hashFunction = SHA3(variant: .keccak256).calculate

// Create the signature
// Calculations are performed in a lazy way
// so you don't have to worry about performance
let signature = SECP256k1Signature(
        privateKey: privateKey,
        message: message,
        hashFunction: hashFunction
)

// Now you can retrieve all the parameters
// of the signature or use it for the signing with web3
let r = PrefixedHexString(
        bytes: try! signature.r()
)
let s = PrefixedHexString(
        bytes: try! signature.s()
)
let v = try! signature.recoverID().value() + 27

获取交易信息

获取信息

获取最新或以前交易的结果是在与DApps交互开发中最常见的任务之一。有双边JSON-RPC方法获取基本和附加的交易信息。第一个是eth_getTransactionByHash示例),第二个是eth_getTransactionReceipt示例)。你可以使用以下库示例从以太坊区块链获取所需信息。

import Web3Swift
import SwiftyJSON

let transactionHash = BytesFromHexString(
    hex: "0x5798fbc45e3b63832abc4984b0f3574a13545f415dd672cd8540cd71f735db56"
)

let network = InfuraNetwork(
    chain: "mainnet",
    apiKey: "0c4d6dc730244b4185a6bde26f981bff"
)

let basicInfo: JSON = try TransactionProcedure(
    network: network,
    transactionHash: transactionHash
).call()

let advancedInfo: JSON = try TransactionReceiptProcedure(
    network: network,
    transactionHash: transactionHash
).call()

print(basicInfo["result"].dictionary ?? "Something went wrong")
/**
[
    "blockNumber": 0x196666,
    "value": 0x0,
    "v": 0x1b,
    "input":0x612e45a3000000000000000000000000b656b2a9c3b2416437a811e07466ca712f5a5b5a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000093a80000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000116c6f6e656c792c20736f206c6f6e656c7900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,
    "hash": 0x5798fbc45e3b63832abc4984b0f3574a13545f415dd672cd8540cd71f735db56,
    "to": 0xbb9bc244d798123fde783fcc1c72d3bb8c189413,
    "transactionIndex": 0x7,
    "gasPrice": 0x4a817c800,
    "r": 0xd92d67e4a982c45c78c1260fc2f644ed78483e2bf7d6151aab9ea40a8e172472,
    "nonce": 0x0,
    "blockHash": 0x1f716531f40858da4d4b08269f571f9f22c7b8bd921764e8bdf9cb2e0508efa1,
    "from": 0xb656b2a9c3b2416437a811e07466ca712f5a5b5a,
    "s": 0x6ee7e259e4f13378cf167bb980659520a7e5897643a2642586f246c6de5367d6,
    "gas": 0x4c449
]
*/

print(advancedInfo["result"].dictionary ?? "Something went wrong")

/**
[
    "root": 0xee69c77c73cd53b90e928e786b1c7f5b743a36dccd877128cf1dce7b46980a97,
    "blockNumber": 0x196666,
    "transactionIndex": 0x7,
    "transactionHash": 0x5798fbc45e3b63832abc4984b0f3574a13545f415dd672cd8540cd71f735db56,
    "blockHash": 0x1f716531f40858da4d4b08269f571f9f22c7b8bd921764e8bdf9cb2e0508efa1,
    "from": 0xb656b2a9c3b2416437a811e07466ca712f5a5b5a,
    "contractAddress": null,
    "logsBloom": 0x00000000000000020000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000200000000000000000000800000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000,
    "to": 0xbb9bc244d798123fde783fcc1c72d3bb8c189413,
    "logs": [
        {
            "blockNumber" : "0x196666",
            "topics" : [
                "0x5790de2c279e58269b93b12828f56fd5f2bc8ad15e61ce08572585c81a38756f",
                "0x000000000000000000000000000000000000000000000000000000000000003b"
            ],
            "data" : "0x000000000000000000000000b656b2a9c3b2416437a811e07466ca712f5a5b5a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000116c6f6e656c792c20736f206c6f6e656c79000000000000000000000000000000",
            "logIndex" : "0x5",
            "transactionHash" : "0x5798fbc45e3b63832abc4984b0f3574a13545f415dd672cd8540cd71f735db56",
            "removed" : false,
            "address" : "0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
            "blockHash" : "0x1f716531f40858da4d4b08269f571f9f22c7b8bd921764e8bdf9cb2e0508efa1",
            "transactionIndex" : "0x7"
        }
    ],
    "gasUsed": 0x33da9,
    "cumulativeGasUsed": 0xf98e3
]
*/

注意:库仍在开发中。针对所有RPC结构的领域级别对象将在计划中。

解析交易

在获取信息后,您可以透明地将其转换为合适对象。

// Get the number of the block in which the transaction occurred
let block = try HexAsDecimalString(
    hex: EthNumber(
        hex: basicInfo["result"]["blockNumber"].stringValue
    )   
).value()

print(block)
// 1664614

// Get the recipient of the transaction
let recipient = try EthAddress(
    hex: basicInfo["result"]["to"].stringValue
).value().toHexString()

print(recipient)
// bb9bc244d798123fde783fcc1c72d3bb8c189413

// Get the transaction fee in WEI
let gasPrice = EthNumber(
    hex: basicInfo["result"]["gasPrice"].stringValue
)

let gasUsed = EthNumber(
    hex: advancedInfo["result"]["gasUsed"].stringValue
)

let fee = try HexAsDecimalString(
    hex: gasPrice * gasUsed
).value()

print(fee)
// 4247860000000000 WEI = 0,00424786 ETH

解析交易输入数据

通过了解其ABI或数据传递给它时使用的数据类型,您可以轻松解析任何交易的输入。

// Parse the transaction input parameters
/*
    newProposal(
        [0] address _recipient,
        [1] uint256 _amount,
        [2] string _description,
        [3] bytes _transactionData,
        [4] uint256 _debatingPeriod,
        [5] bool _newCurator
    )
*/

// Prepare the transaction's input for parsing - trim the signature of the executed function
let input = ABIMessage(
    message: TrimmedPrefixString(
        string: SimpleString{
            basicInfo["result"]["input"].stringValue
        },
        prefix: SimpleString{
            "0x612e45a3"
        }
    )
)

// Get the recipient's address
let abiRecipient = try DecodedABIAddress(
    abiMessage: input,
    index: 0
).value().toHexString()

print(abiRecipient)
// b656b2a9c3b2416437a811e07466ca712f5a5b5a

// Get the description string
let description = try DecodedABIString(
    abiMessage: input,
    index: 2
).value()

print(description)
// lonely, so lonely

// Get the debating period number
let debatingPeriod = try HexAsDecimalString(
    hex: DecodedABINumber(
        abiMessage: input,
        index: 4
    )
).value()

print(debatingPeriod)
// 604800

// Get the boolean flag
let flag = try DecodedABIBoolean(
    abiMessage: input,
    index: 5
).value()

print(flag)
// true

作者

许可

Web3Swift遵循Apache License 2.0。有关更多信息,请参阅LICENSE文件。