It can be very easy to send a simple transaction (transfer some CFX to another address), all you need is from, to, value and from's privateKey.
const { Conflux,Drip } =require('js-conflux-sdk');constPRIVATE_KEY='0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'; // sender private keyconstRECEIVER_ADDRESS='cfxtest:aaawgvnhveawgvnhveawgvnhveawgvnhvey1umfzwp';asyncfunctionmain() {constconflux=newConflux({ url:'https://test.confluxrpc.com', networkId:1, });constsender=conflux.wallet.addPrivateKey(PRIVATE_KEY); // add private to local walletconsttransactionHash=awaitconflux.cfx.sendTransaction({ from:sender.address,// account address or instance which added into conflux.wallet to:RECEIVER_ADDRESS,// receiver address value:Drip.fromCFX(0.1),// 0.1 CFX = 100000000000000000 Drip });console.log(transactionHash); // suggest store transactionHash in disk !!!// 0x22e5ffefe4da995ebcb2847762b7acb1c03fd17c9ab010272965fa63c9590d6e// that it, the transaction has been sended, after it was pack and executed your CFX will be transfer to the target account}main();
Normally if everything is well, the tx will be executed is at most 20s, then you can get it's receipt through hash
If the transaction receipt's outcomeStatus is 0, congratulate you have send a transaction successfully.
Note: before sending transaction, you should add an account to wallet with conflux.wallet.addPrivateKey(PRIVATE_KEY)
Transaction's stage
After sending, a transaction could be in several different states, here is a detail explanation of transaction life cycle.
You can get a transaction's state by it's status or it's receipt's outcomeStatus
null The tx has not mined or executed
0 Tx execute success
1 Tx execute failed
Only after a transaction executed, you can get it's receipt. The receipt.outcomeStatus may have two value:
0 Tx execute success
1 Tx execute failed
Correspond to transaction stages, the SDK has provide several advanced sendTransaction usage:
const { Conflux,Drip } =require('js-conflux-sdk');constPRIVATE_KEY='0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'; // sender private keyconstADDRESS='cfxtest:aaawgvnhveawgvnhveawgvnhveawgvnhvey1umfzwp';asyncfunctionmain() {constconflux=newConflux({ url:'https://test.confluxrpc.com', networkId:1, });constsender=conflux.wallet.addPrivateKey(PRIVATE_KEY);constpendingTransaction=conflux.cfx.sendTransaction({ from:sender.address,// account address or instance which added into conflux.wallet to:ADDRESS,// receiver address value:Drip.fromCFX(0.1),// 0.1 CFX = 100000000000000000 Drip }); // NOTE: without await, transaction not send yetconsttransactionHash=await pendingTransaction; // send and await endpoint return transaction hashconsole.log(transactionHash);// usually wait about 2 secondsconstpackedTransaction=awaitpendingTransaction.get(); // await endpoint packed transactionconsole.log(packedTransaction); // `blockHash` might still be `null`// usually wait about 5 secondsconstminedTransaction=awaitpendingTransaction.mined(); // await transaction minedconsole.log(minedTransaction); // already have `blockHash`// usually wait about 10 secondsconstexecutedReceipt=awaitpendingTransaction.executed(); // await transaction executedconsole.log(executedReceipt); // if `outcomeStatus` equal 0, return receipt, else throw error// usually wait about 50 secondsconstconfirmedReceipt=awaitpendingTransaction.confirmed(); // await transaction confirmedconsole.log(confirmedReceipt); // usually same as executedReceipt, but transaction block risk is <= 1e-8}main();
Note: the mined, executed, confirmed methods maybe will take a long time, even will be timeout.
Send transaction complete
Besides from, to, value there are several other fields could be filled with:
nonce: optional, the nonce of a transaction to keep the order of your sending transactions, increase one by one. If missing, the result of cfx_getNextNonce will be automatically filled in and it works for general scenarios. Some cases, like sending a lot of transactions in a short period. It's recommended to maintain the nonce on your own.
gasPrice: optional, the price in Drip that you would like to pay for each gas consumed. If missing, the result of cfx_gasPrice will be automatically filled in, which is the median of recent transactions.
gas: optional, the max gas you would like to use in the transaction. After the end of transaction processing, the unused gas will be refunded if used_gas >= gas * 0.75. If missing, the result of cfx_estimateGasAndCollateral will be automatically filled in and it works for general scenarios.
to: the receiver of the transaction, could be a personal account(start with 1) or contract(start with 8). Leave a null here to deploy a contract.
value: the value (in Drip) to be transferred.
storageLimit: optional, the max storage (in Byte) you would like to collateralize in the transaction. If missing, the result of cfx_estimateGasAndCollateral will be automatically filled in and it works for general senarios.
epochHeight: optional, a transaction is can be verified only in epochs in the range [epochHeight - 10000, epochHeight + 10000], so it's a timeout mechanism. If missing, the result of cfx_epochNumber will be automatically filled in and it works for general scenarios.
data: optional, it's either an attached message of a transaction or a function signature of a contract call. If missing, a null will be filled into it.
chainId: optional, it used for dealing with a hard fork or preventing a transaction replay attack. If missing SDK will get it from RPC.
from: The sender account(with private key) to sign the transaction.
Compare with ethereum Conflux transaction have three new field: storageLimit, epochHeight, chainId
const { Conflux,Drip } =require('js-conflux-sdk');constPRIVATE_KEY='0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'; // sender private keyconstADDRESS='cfxtest:aaawgvnhveawgvnhveawgvnhveawgvnhvey1umfzwp';asyncfunctionmain() {constconflux=newConflux({ url:'https://test.confluxrpc.com', networkId:1, });constaccount=conflux.wallet.addPrivateKey(PRIVATE_KEY); // create account instance and add to walletconstestimate=awaitconflux.cfx.estimateGasAndCollateral({ to, value });conststatus=awaitconflux.cfx.getStatus();consttransactionHash=awaitconflux.cfx.sendTransaction({ from:account.address,// sender address which added into conflux.wallet to:ADDRESS,// receiver address value:Drip.fromCFX(0.1),// 0.1 CFX = 100000000000000000 Drip data:null, gas:estimate.gasUsed, storageLimit:0, chainId:status.chainId, nonce:awaitconflux.getNextNonce(account.address), gasPrice:awaitconflux.getGasPrice(), epochHeight:awaitconflux.getEpochNumber(), }); console.log(transactionHash);}main();
How much gas and storageLimit a transaction need
If you are just transfer CFX, the gas should be 21000, if you are interact with a contract it's a little complicated. Normally you can estimate it by call estimateGasAndCollateral.
constconflux=newConflux({ url:'https://test.confluxrpc.com', logger: console,// for debug defaultGasPrice:1, networkId:1,});
gasPrice
When sending transaction if you specify the gasPrice it will be used, if not it will try to use cfx.defaultGasPrice you can specify it when you initiallize the cfx object.
If both gasPrice and defaultGasPrice is not specified, the SDK will fill the result of getGasPrice() to it.
Currently set the gasPrice to 1 Drip will enough to send most transactions.
gas
First you can specify the tx.gas, if you don't it will use the result of estimateGasAndCollateral.gasUsed.
storageLimit
Same as gas you can specify storageLimit when you send transaction (unit is Byte), if not
SendRawTransaction
The sendTransaction will get from's privateKey from wallet, use it sign transaction and invoke sendRawTransaction method, if you have a raw transaction you can use it directly. the sendRawTransaction method also can use get, mined, executed, confirmed method.
If your transaction always pending in the pool, normally you have use a incorrect nonce or your balance is not enough. You can get the transaction info by it's hash, and check it's nonce with your account's nonce, and check your balance is enough to cover the value + gasPrice * gas + storageLimit.
Why my transaction failed?
If your transaction is failed, you can find reason in below ways:
Is your balance is enough cover your tx: check value, gas, storageLimit
Is your gas is enough, is your storageLimit enough
Check receipt's txExecErrorMsg for detail error message
How to send a transaction with a note
If you want send a transaction with a note, you can specify it through data, the tricky is you need convert your message to a hex string.
const { Conflux,format } =require('js-conflux-sdk');constPRIVATE_KEY='0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'; // sender private keyasyncfunctionmain() {constconflux=newConflux({ url:'https://test.confluxrpc.com', networkId:1, });constaccount=conflux.wallet.addPrivateKey(PRIVATE_KEY); // create account instance and add to walletconsttransactionHash=awaitconflux.cfx.sendTransaction({ from:account.address, to:account.address,// if data is not contract bytecode, must have `to` address data:format.bytes('Hello World') });console.log(transactionHash); }main()