Examples
EOSIO SDK for Swift contains an extensive set of functionality beyond the basics required for transactions. The code snippets below show how to use some of this extended functionality. It is important to note that these are simply example snippets and may not work the way you expect if you just copy and paste them into a method.
One common mistake is to allow the transaction or one of the providers to go out of scope, resulting in an error in the return closure when the server replies to the transaction request. If you are seeing "self does not exist" errors when trying to send transactions or RPC calls, check to make sure that your objects are being held properly.
Note: For clarity, these examples use the Softkey Signature Provider, which is NOT recommended for production use!
Basic Transaction Examples
Submitting a Transaction
Basic submission of a transaction is shown in the main README.md file at the top level of the repository. Please see the Basic Usage example for details.
How to Transfer an EOSIO Token
The Basic Usage example in the top level README.md file is an example of transferring an EOSIO token. Please see that example for details.
Extended Transaction Examples
Retrieving Action Return Values From Transactions
This snippet calls a transaction that returns a 32-bit integer value. The user is required to know the correct type that the action returns in order to cast successfully. Each action will contain its return value, if the server provided one.
let url = URL(string: "https://my.example.blockchain")!
rpcProvider = EosioRpcProvider(endpoint: url)
transaction.rpcProvider = rpcProvider
transaction.serializationProvider = EosioAbieosSerializationProvider()
transaction.signatureProvider = try EosioSoftkeySignatureProvider(privateKeys: ["YourPrivateKey"])
let action = try EosioTransaction.Action(
account: EosioName("returnvalue"),
name: EosioName("actionresret"),
authorization: [EosioTransaction.Action.Authorization(
actor: EosioName("bob"),
permission: EosioName("active"))
],
data: [String: Any]()
)
transaction.add(action: action)
transaction.signAndBroadcast { result in
switch result {
case .success:
print("Transaction successful, action return value is: \(String(describing: action.returnValue))")
let returnValue = action.returnValue as? Int32
case .failure(let error):
print("Transaction failed, error: \(error)")
}
}
Accessing Extended Fields in Transaction Responses
Using EosioTransaction.signAndBroadcast()
provides an easy way to sign and submit transactions, but it returns a limited amount of information. If you need to get additional information back from the blockchain, you must use sendTransactionBase()
from EosioRpcProvider
to submit the transaction after it is signed. The process is much the same as a normal flow but instead of calling signAndBroadcast()
, use sign()
instead and load the results into an EosioRpcSendTransactionRequest
to be sent to the blockchain. Afterward, the full response is available and can be decoded. A small subset of fields are shown in the example below.
transaction = EosioTransaction()
let url = URL(string: "https://my.test.blockchain")!
rpcProvider = EosioRpcProvider(endpoint: url)
transaction.rpcProvider = rpcProvider
transaction.serializationProvider = EosioAbieosSerializationProvider()
do {
transaction.signatureProvider = try EosioSoftkeySignatureProvider(privateKeys: ["MyTestKey"])
let action = try EosioTransaction.Action(
account: EosioName("eosio.token"),
name: EosioName("transfer"),
authorization: [EosioTransaction.Action.Authorization(
actor: EosioName("bob"),
permission: EosioName("active"))
],
data: Transfer(from: EosioName("bob"),
to: EosioName("alice"),
quantity: "42.0000 SYS",
memo: "This is only a test")
)
transaction.add(action: action)
transaction.sign { result in
switch result {
case .success:
guard let serializedTransaction = self.transaction.serializedTransaction?.hexEncodedString(),
let signatures = self.transaction.signatures else {
print("Error, could not find signatures or serialized transaction.")
return
}
let requestParameters = EosioRpcSendTransactionRequest(signatures: signatures,
compression: 0,
packedContextFreeData: "",
packedTrx: serializedTransaction)
self.rpcProvider.sendTransactionBase(requestParameters: requestParameters) { response in
switch response {
case .success(let sentResponse):
let transactionId = sentResponse.transactionId
if let sentTransactionResponse = sentResponse as? EosioRpcTransactionResponse {
if let processed = sentTransactionResponse.processed as [String: Any]?,
let receipt = processed["receipt"] as? [String: Any],
let status = receipt["status"] as? String {
// Work with values
} else {
print("Should be able to find processed.receipt.status.")
}
} else {
print("Concrete response type should be EosioRpcTransactionResponse.")
}
case .failure(let err):
print("\(err.description)")
}
}
case .failure(let error):
print("Transaction failed, error: \(error)")
}
}
} catch (let error) {
print("Handle this error: \(error.localizedDescription)")
}
Extended RPC Call Examples
Get Account Information
This snippet retrieves information for an account on the blockchain. There are several layers of response to unpack if all information is desired. Some portions of the response are not fully unmarshalled, either due to size or because the responses can vary in structure. These are returned as general [String: Any]
Swift objects. The NODEOS Reference is helpful for decoding the parts of responses that are not fully unmarshalled.
let url = URL(string: "https://my.example.blockchain")!
rpcProvider = EosioRpcProvider(endpoint: url)
let requestParameters = EosioRpcAccountRequest(accountName: "cryptkeeper")
rpcProvider.getAccount(requestParameters: requestParameters) { response in
switch response {
case .success(let eosioRpcAccountResponse):
guard let response = eosioRpcAccountResponse else {
// Handle condition
return
}
let accountname = response.accountName
let ramQuota = response.ramQuota.value
guard let permissions = response.permissions else {
// Handle Condition
return
}
guard let activePermission = permissions.filter({$0.permName == "active"}).first else {
print("Cannot find Active permission in permissions structure of the account")
return
}
guard activePermission.parent == "owner" else {
print("Active Key does not have proper parent.")
return
}
guard let keysAndWeight = activePermission.requiredAuth.keys.first else {
print("Cannot find key in keys structure of the account")
return
}
let key = keysAndWeight.key
guard let firstPermission = activePermission.requiredAuth.accounts.first else {
print("Can't find permission in keys structure of the account")
return
}
let actor = firstPermission.permission.actor
let permission = firstPermission.permission.permission
let waitSec = activePermission.requiredAuth.waits.first?.waitSec.value
guard let dict = eosioRpcAccountResponse.totalResources as? [String: Any] else {
print("Could not find total resources as [String: Any].")
return
}
let owner = dict["owner"] as? String
let rambytes = dict["ram_bytes"] as? UInt64
case .failure(let err):
print(err.description)
XCTFail("Failed get_account")
}
expect.fulfill()
}
Retrieving Values from KV Tables
This snippet retrieves values from a KV table defined by a contract on the server. The example below is requesting the values from the contract "todo" in the table named "todo". It is querying the index named "uuid" for the value "bf581bee-9f2c-447b-94ad-78e4984b6f51". The encoding type of the indexValue being supplied is ".string". Other supported encoding types can be found in the full documentation in this repo at README.
let url = URL(string: "https://my.example.blockchain")!
rpcProvider = EosioRpcProvider(endpoint: url)
let tablesRequest = EosioRpcKvTableRowsRequest(code: "todo",
table: "todo",
indexName: "uuid",
encodeType: .string,
json: true,
indexValue: "bf581bee-9f2c-447b-94ad-78e4984b6f51")
rpcProvider.getKvTableRows(requestParameters: tablesRequest) { result in
switch result {
case .failure(let error):
print("Failed getKvTableRows call: \(error.localizedDescription)")
case .success(let response):
// Iterate through rows. They will either be serialized strings if json equaled false
// or they will be [String: Any] representations of the returned JSON objects if
// json equaled true in the request.
response.rows.foreach { row in
// Work with each row.
if let entry: [String: Any] = row as? [String: Any] {
let accountName = entry["account_name"] as? String ?? ""
let firstName = entry["first_name"] as? String ?? ""
let lastName = entry["last_name"] as? String ?? ""
} else {
// Would check for serialized string.
}
}
}
}