GetAccountMetadata()
Gets the account metadata for an IoTeX address.
Copy AccountMeta accountMeta;
ResultCode result = connection.api.wallets.getAccount("io1xkx7y9ygsa3dlmvzzyvv8zm6hd6rmskh4dawyu", accountMeta);
If result is SUCCESS
then the account metadata is be stored in accountMeta
The account metadata contains the following fields:
address : the IoTeX address
balance : the balance in RAU
pendingNonce : the account's pending nonce
isContract : true if the address is a contract
GetTransactionByHash()
Gets the data for a transfer given the transaction hash.
Copy ActionInfo_Transfer data;
ResultCode result = connection.api.wallets.getTransactionByHash("5444318f1a460c74d3e86918b640272d93d0b30e2bf2dc329dfd3faa636e52ec", data);
If result is SUCCESS
then the action data is stored in data
. The transfer action data contains the following fields:
Copy {
actHash
blkHash
timestamp
blkHeight
sender
gasFee
action {
senderPublicKey
signature
core
version
nonce
gasLimit
gasPrice
execution
amount
contract
data
}
}
Creating an account
We can create an account in the device from an existing private key, or generating a new private key.
From an existing private key
Copy const char pkString[] = <private_key>;
// Convert the privte key hex string byte array
uint8_t pkBytes[IOTEX_PRIVATE_KEY_SIZE];
signer.str2hex(pkString, pkBytes, IOTEX_SIGNATURE_SIZE);
Account account(pkBytes);
Generating a new private key
Copy // Generate a random private key
uint8_t pkBytes[IOTEX_PRIVATE_KEY_SIZE];
randomGenerator.fillRandom(pkBytes, sizeof(pkBytes));
// Create the account
Account account(pkBytes);
Getting account details
Now that the account is created, you can get the address in Ethereum or IoTeX format, and the public/private keys:
Copy // Create buffers for the account details
char publicKeyBuf[IOTEX_PUBLIC_KEY_C_STRING_SIZE] = {0};
char privateKeyBuf[IOTEX_PRIVATE_KEY_C_STRING_SIZE] = {0};
char ethAddressBuf[ETH_ADDRESS_C_STRING_SIZE] = {0};
char ioAddressBuf[IOTEX_ADDRESS_C_STRING_SIZE] = {0};
// Get the account details (ad hexadecimal strings)
account.getPublicKeyString(publicKeyBuf);
account.getPrivateKeyString(privateKeyBuf);
account.getEthereumAddress(ethAddressBuf);
account.getIotexAddress(ioAddressBuf);
Sending a transfer of IOTX
Sends a transfer of IOTX tokens
First create the account object:
Copy // Private key of the origin address
const char pkString[] = <private_key>;
// Destination IoTeX address
char destinationAddr[IOTEX_ADDRESS_C_STRING_SIZE] = <destination_address>;
// Convert the private key and address hex strings to byte arrays
uint8_t pkBytes[IOTEX_PRIVATE_KEY_SIZE];
signer.str2hex(pkString, pkBytes, IOTEX_SIGNATURE_SIZE);
// Create the account object
Account originAccount(pkBytes);
// Get the IoTeX address
char originIotexAddr[IOTEX_ADDRESS_C_STRING_SIZE] = "";
originAccount.getIotexAddress(originIotexAddr);
Then query the blockchain to get the account nonce:
Copy AccountMeta accMeta;
ResultCode result = connection.api.wallets.getAccount(originIotexAddr, accMeta);
IotexString nonceString = accMeta.pendingNonce;
uint64_t nonce = atoi(nonceString.c_str());
Now broadcast the transfer with the retrieved nonce:
Copy // Amount of RAU to transfer. Eg: 1 RAU
char amount[IOTEX_ADDRESS_C_STRING_SIZE] = "1";
// Send the transfer
uint8_t hash[IOTEX_HASH_SIZE] = {0};
result = originAccount.sendTokenTransferAction(connection, nonce, 20000000, "1000000000000", amount, destinationAddr, hash);
Signing a message
Signs a message.
First convert the private key to a byte array:
Copy const char pkString[] = <private_key>;
uint8_t pkBytes[IOTEX_PRIVATE_KEY_SIZE];
signer.str2hex(pkString, pkBytes, IOTEX_SIGNATURE_SIZE);
Now sign the message
Copy // Message to sign as a byte array
const uint8_t message[] = { 0xab, 0xcd };
uint8_t signature[IOTEX_SIGNATURE_SIZE] = {0};
signer.signMessage(message, sizeof(message), pkBytes, signature);
The signature is stored as a byte array in signature.
Storing the private key to persistent memory in the device
You can store the private key in the EEPROM or flash memory of your Arduino device, or in a text file in Linux.
First convert the private key to a byte array:
Copy const char pkString[] = <private_key>;
uint8_t pkBytes[IOTEX_PRIVATE_KEY_SIZE];
signer.str2hex(pkString, pkBytes, IOTEX_SIGNATURE_SIZE);
First initialize the storage module (not needed for Nano33 IoT or Linux):
Copy // The number of bytes we want to use for the EEPROM
// This is passed to EEPROM.begin()
// Should be at least IOTEX_PRIVATE_KEY_SIZE
uint32_t eepromSize = IOTEX_PRIVATE_KEY_SIZE;
storage.Initialize(eepromSize);
Now store the private key:
Copy // Specify any address number between 0 and (eepromSize - IOTEX_PRIVATE_KEY_SIZE).
// This is the EEPROM address where the private key is stored.
// There needs to be suficcient space between eepromAddress and eepromSize to store the whole private key (at least IOTEX_PRIVATE_KEY_SIZE bytes)
const uint32_t eepromAddress = 0;
ResultCode result = storage.savePrivateKey(eepromAddress, pkBytes);
You can also read the private key that is stored in the device:
Copy result = storage.readPrivateKey(eepromAddress, pkBytes);
Sending a XRC20 token transfer
First convert the private key to a byte array:
Copy const char pkString[] = <private_key>;
uint8_t pkBytes[IOTEX_PRIVATE_KEY_SIZE];
signer.str2hex(pkString, pkBytes, IOTEX_SIGNATURE_SIZE);
Similarly, convert the destination address to a byte array:
Copy const char destAddrString[] = "0x5840bf8e5d3f5b66EE52B9b933bDAC9682E386D0";
uint8_t destAddrBytes[ETH_ADDRESS_SIZE];
signer.str2hex(destAddrString, destAddrBytes, ETH_ADDRESS_SIZE);
Generate the contract call data:
Copy // Amount to transfer
uint64_t value = 1000000000000000000;
uint8_t data[IOTEX_CONTRACT_ENCODED_TRANSFER_SIZE] = {0};
Xrc20Contract::generateCallDataForTransfer(destAddrBytes, value, data);
char callData[IOTEX_CONTRACT_ENCODED_TRANSFER_SIZE * 2 + 1] = {0};
signer.hex2str(data, IOTEX_CONTRACT_ENCODED_TRANSFER_SIZE, callData, sizeof(callData));
Create the account object and get the account metadata in order to obtain the nonce:
Copy Account originAccount(pkBytes);
AccountMeta accMeta;
char originIotexAddr[IOTEX_ADDRESS_STRLEN] = {0};
originAccount.getIotexAddress(originIotexAddr);
connection.api.wallets.getAccount(originIotexAddr, accMeta);
int nonce = atoi(accMeta.pendingNonce.c_str());
Broadcast the XRC20 token transfer
Copy // The token address. Eg: VITA token
const char tokenAddress[] = "io1hp6y4eqr90j7tmul4w2wa8pm7wx462hq0mg4tw";
uint8_t hash[IOTEX_HASH_SIZE] = {0};
ResultCode result = originAccount.sendExecutionAction(connection, atoi(accMeta.pendingNonce.c_str()), 20000000, "1000000000000", "0", tokenAddress, callData, hash);
Calling a contract function
This example shows how to call a contract function using the addData function of the contract with address io1n49gavyahsukdvvxxandkxephdx93n3atcrqur
as an example. You can find the contract ABI here .
First convert the private key to a byte array:
Copy const char pkString[] = <private_key>;
uint8_t pkBytes[IOTEX_PRIVATE_KEY_SIZE];
signer.str2hex(pkString, pkBytes, IOTEX_SIGNATURE_SIZE);
Create the account object and get the account metadata in order to obtain the nonce:
Copy Account originAccount(pk);
AccountMeta accMeta;
char originIotexAddr[IOTEX_ADDRESS_C_STRING_SIZE] = "";
originAccount.getIotexAddress(originIotexAddr);
ResultCode result = connection.api.wallets.getAccount(originIotexAddr, accMeta);
int nonce = atoi(accMeta.pendingNonce.c_str());
Create the function call parameters:
Copy ParameterValue paramImei = MakeParamString(imei);
ParameterValue paramData = MakeParamBytes(data, sizeof(data), true);
ParameterValue paramSig = MakeParamBytes(signature, sizeof(signature), true);
Create the dictionary that contain the parameters and their values:
Copy ParameterValuesDictionary params;
params.AddParameter("imei", paramImei);
params.AddParameter("data", paramData);
params.AddParameter("signature", paramSig);
Create the contract object:
Copy // The contract abi as a serialized json string
String abi = <contract_abi_json_string>;
Contract contract(abi);
Generate the call data:
Copy String callData = "";
contract.generateCallData("addData", params, callData);
Broadcast the contract execution action
Copy uint8_t hash[IOTEX_HASH_SIZE] = {0};
result = originAccount.sendExecutionAction(connection, nonce, 20000000, "1000000000000", "0", contractAddress, callData, hash);