Skip to content

Latest commit

 

History

History
270 lines (225 loc) · 15.8 KB

working-with-js.md

File metadata and controls

270 lines (225 loc) · 15.8 KB

Using JavaScript Library

echojs-lib library is the recommended means for communication with Echo network in JavaScript & TypeScript.

Documentation on the library can be found in the docs section of https://github.com/echoprotocol/echojs-lib/tree/master/docs.

Below is an example of working with Echo network using echojs-lib for an ERC20 token contract deployment and calling.

Pre-requisites:

  • A private key of an account with positive balance in ECHO
  • WebSocket access to a running Echo node

Initialization

The library can be installed using npm:

npm i echojs-lib

Then you need to initialize a connection to a node and import your private key:

const { default: echo, PrivateKey, constants } = require('echojs-lib');

const privateKey = PrivateKey.fromWif(YOUR_PRIVATE_KEY_WIF);

const connect = async () => {
    await echo.connect('ws://127.0.0.1:9000');
};

connect().then(async () => {
    //    the rest of the code below should be used here.
});

Contract Deployment

To deploy a contract, you need to build an operation, sign and send it:

const bytecode = '608060405261271060025534801561001657600080fd5b506127106000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055503373ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6127106040518082815260200191505060405180910390a3610d8e806100d36000396000f30060806040526004361061008e576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063095ea7b31461009357806318160ddd146100f857806323b872dd1461012357806339509351146101a857806370a082311461020d578063a457c2d714610264578063a9059cbb146102c9578063dd62ed3e1461032e575b600080fd5b34801561009f57600080fd5b506100de600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506103a5565b604051808215151515815260200191505060405180910390f35b34801561010457600080fd5b5061010d6103bc565b6040518082815260200191505060405180910390f35b34801561012f57600080fd5b5061018e600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506103c6565b604051808215151515815260200191505060405180910390f35b3480156101b457600080fd5b506101f3600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610477565b604051808215151515815260200191505060405180910390f35b34801561021957600080fd5b5061024e600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061051c565b6040518082815260200191505060405180910390f35b34801561027057600080fd5b506102af600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610564565b604051808215151515815260200191505060405180910390f35b3480156102d557600080fd5b50610314600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610609565b604051808215151515815260200191505060405180910390f35b34801561033a57600080fd5b5061038f600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610620565b6040518082815260200191505060405180910390f35b60006103b23384846106a7565b6001905092915050565b6000600254905090565b60006103d3848484610928565b61046c843361046785600160008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610c4e90919063ffffffff16565b6106a7565b600190509392505050565b6000610512338461050d85600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610cd890919063ffffffff16565b6106a7565b6001905092915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60006105ff33846105fa85600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610c4e90919063ffffffff16565b6106a7565b6001905092915050565b6000610616338484610928565b6001905092915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614151515610772576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260248152602001807f45524332303a20617070726f76652066726f6d20746865207a65726f2061646481526020017f726573730000000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415151561083d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001807f45524332303a20617070726f766520746f20746865207a65726f20616464726581526020017f737300000000000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040518082815260200191505060405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141515156109f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001807f45524332303a207472616e736665722066726f6d20746865207a65726f20616481526020017f647265737300000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614151515610abe576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260238152602001807f45524332303a207472616e7366657220746f20746865207a65726f206164647281526020017f657373000000000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b610b0f816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610c4e90919063ffffffff16565b6000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610ba2816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610cd890919063ffffffff16565b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a3505050565b600080838311151515610cc9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525060200191505060405180910390fd5b82840390508091505092915050565b6000808284019050838110151515610d58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b80915050929150505600a165627a7a723058209db49b546872ac269ed6ee5bd01a2644ad7a12d7abf648300c0afd08ef5a483d0029';

const options = {
    fee: { // optional, default fee asset: 1.3.0, amount: will be calculated
        asset_id: '1.3.0'
    },
    registrar: '1.2.1334',
    value: { asset_id: '1.3.0', amount: 0 }, // transfer asset to contract
    code: bytecode,
    eth_accuracy: false,
};

const result = await echo
    .createTransaction()
    .addOperation(constants.OPERATIONS_IDS.CREATE_CONTRACT, options)
    .addSigner(privateKey)
    .broadcast();

console.log(result);

result variable will have the following value:

[
  {
    "id": "a8354a7d57505a5197bf12a18c7c057c08305919",
    "block_num": 661562,
    "trx_num": 0,
    "trx": {
      "ref_block_num": 6200,
      "ref_block_prefix": 1131830036,
      "expiration": "2019-07-23T22:50:51",
      "operations": [
        [
          40,
          {
            "fee": {
              "amount": 1116,
              "asset_id": "1.3.0"
            },
            "registrar": "1.2.1334",
            "value": {
              "amount": 0,
              "asset_id": "1.3.0"
            },
            "code": "608060405261<...>d08ef5a483d0029",
            "eth_accuracy": false,
            "extensions": []
          }
        ]
      ],
      "extensions": [],
      "signatures": [
        "1bcd1d<...>f16a0f"
      ],
      "signed_with_echorand_key": false,
      "operation_results": [
        [
          1,
          "1.12.726"
        ]
      ]
    }
  }
]

ID 1.12.721 in operation_results array defines the operation execution result ID. An object with said ID stores the information about the deployed contract. api.getObject(objectId) method can be used to get said object.

const object = await echo.api.getObject('1.12.726');
console.log(object);
{
  "id": "1.15.726",
  "type": "evm",
  "contracts_id": [
    "1.11.352"
  ],
  "extensions": []
}

The first element of the contracts_id array is the contract ID. Contract ID is used to call it.

Call contract

There are two types of contract calls - a call without changing the contract's state (to receive values of variables and methods) and a call that would change the contract's state (sending a transaction).

Get ERC20 Token Balance

Fetching an account's balance in token doesn't require a transaction, hence the callContractNoChangingState(contractId, accountId, assetId, bytecode) method is used:

const balance = await echo.api.callContractNoChangingState('1.11.352', '1.2.1334', '1.3.0', '70a082310000000000000000000000000000000000000000000000000000000000000536');
console.log(parseInt(balance, 16)); // 10000

The last argument in the method is the hash of the contract's called method and the argument joined with the arguments that were passed along with the call. In this case 70a08231 is the hash of balanceOf(address) method, and 0000000000000000000000000000000000000000000000000000000000000536 is the "address" (derived from account ID), the balance of which we need are trying to get (zeroes are added to increase the size of the address to 32 bytes). This address belongs to Echo account 1.2.1334. More information on converting the IDs to address formats can be found in EVM. Introduction .

Transfer ERC20 Token

Token transfer is an operation that requires a transaction.

const contractId = '1.11.352';
const accountSender = '1.2.1334';
const method = 'a9059cbb';
const methodParameters = '00000000000000000000000000000000000000000000000000000000000005370000000000000000000000000000000000000000000000000000000000000010';

const options = {
    fee: { // optional, default fee asset: 1.3.0, amount: will be calculated
        asset_id: '1.3.0'
    },
    registrar: accountSender,
    value: { // if method mark as payable you can transfer asset, if not set amount to 0
        asset_id: '1.3.0',
        amount: 0,
    },
    code: method + methodParameters,
    callee: contractId,
};

const result = await echo
    .createTransaction()
    .addOperation(constants.OPERATIONS_IDS.CALL_CONTRACT, options)
    .addSigner(privateKey)
    .broadcast();

console.log(result);

When this method is executed, a transaction will be sent to Echo network. result variable will have the following value:

[
  {
    "id": "d4c8ff190f74add76696e344a6db0f5e9f561272",
    "block_num": 661760,
    "trx_num": 0,
    "trx": {
      "ref_block_num": 6398,
      "ref_block_prefix": 4048465865,
      "expiration": "2019-07-23T23:00:53",
      "operations": [
        [
          41,
          {
            "fee": {
              "amount": 151,
              "asset_id": "1.3.0"
            },
            "registrar": "1.2.1334",
            "value": {
              "amount": 0,
              "asset_id": "1.3.0"
            },
            "code": "a9059cbb00000000000000000000000000000000000000000000000000000000000005370000000000000000000000000000000000000000000000000000000000000010",
            "callee": "1.11.352",
            "extensions": []
          }
        ]
      ],
      "extensions": [],
      "signatures": [
        "911ca1ed144a68948a3d47fb5d00bc667c70373b69c4a77776af2b12daf7ad33a4bea7d65b397fc2a4ef9da600d2cb873cba2550c56cf9ff598234108875350f"
      ],
      "signed_with_echorand_key": false,
      "operation_results": [
        [
          1,
          "1.12.727"
        ]
      ]
    }
  }
]

As a result of the transfer, the contract calls an event Transfer(address indexed from, address indexed to, uint256 value); event. The logs can be viewed via getContractResult method, and adding operation execution result ID to argument:

const result = await echo.api.getContractResult('1.12.727');
console.log(result);
[
  0,
  {
    "exec_res": {
      "excepted": "None",
      "new_address": "0000000000000000000000000000000000000000",
      "output": "0000000000000000000000000000000000000000000000000000000000000001",
      "code_deposit": "None",
      "gas_for_deposit": 0,
      "deposit_size": 0
    },
    "tr_receipt": {
      "status_code": 1,
      "gas_used": 50133,
      "bloom": "00000000000000002000000000000000800040000000010000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000008000000000004000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000002000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
      "log": [
        {
          "address": "0100000000000000000000000000000000000160",
          "log": [
            "ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
            "0000000000000000000000000000000000000000000000000000000000000536",
            "0000000000000000000000000000000000000000000000000000000000000537"
          ],
          "data": "0000000000000000000000000000000000000000000000000000000000000010"
        }
      ]
    }
  }
]

This contract call changes an account's token balance. The change in balance can be checked via balanceOf method:

const balance = await echo.api.callContractNoChangingState('1.11.352', '1.2.1334', '1.3.0', '70a082310000000000000000000000000000000000000000000000000000000000000536');
console.log(parseInt(balance, 16)); // 9984