Interact with STRATO using API calls from command line

Further instructions assume you have STRATO accessible on localhost domain. For Docker Toolbox you have to use Docker VM IP address instead (usually 192.168.99.100)

To upload and invoke Smart Contracts, one needs to first generate a public address.

REST API

Users

  • Get all Users

    To get all users, we use the /users endpoint.

    $ curl "http://localhost/bloc/v2.1/users"
    ** Sample Response **
    [
    "admin"
    ]
    
  • Create a new user

    To create a new user we simply post the username and password to the user endpoint. The response is the user's new public address.

    $ curl -X POST "http://localhost/bloc/v2.1/users/testUser?faucet=true" -H  "accept: application/json;charset=utf-8" -H  "content-type: application/json;charset=utf-8" -d "\"password\""
    ** Sample Response **
    badf39b2f81bf6be824e7314e72701318485587e
    
  • Transfer Ether between users

    We've now generated two addresses - let's transfer value from admin to testUser.

    $ curl -X POST "http://localhost/bloc/v2.1/users/testUser/a8c3d953fb4d89d2aeb0be71aecb614feb786ae8/send" -H  "accept: application/json;charset=utf-8" -H  "content-type: application/json;charset=utf-8" -d "{  \"toAddress\": \"00000000000000000000000000000000deadbeef\",  \"value\": \"10\",  \"password\": \"password\",  \"txParams\": {    \"gasLimit\": 123,    \"gasPrice\": 345,    \"nonce\": 9876  }}"
    ** SAMPLE RESPONSE **
    {
      "hash": "75234522a097bfa09cf01675fc5584b9f76efa3674f27b0914c1f96aa5587407",
      "gasLimit": "123",
      "codeOrData": "",
      "gasPrice": "345",
      "to": "00000000000000000000000000000000deadbeef",
      "value": "10000000000000000000",
      "from": "a8c3d953fb4d89d2aeb0be71aecb614feb786ae8",
      "r": "feb5ad19abd43b9a49386570df330a69b42e30f9f66fb491f419010a7f8c1289",
      "s": "1b7b4b1761921924ecbef3254bc2945d28e11a248fa1ad01a763cb460150c428",
      "v": "1b",
      "nonce": "9876"
    }
    

Note: 'testUser' refers to the address of the user . The "value" in the transaction response from the server is much larger than the 10 we passed as a parameter. This is because the server response with the smallest unit of ETHER which is WEI, 1ETH * (10^-18)

Contracts

Note: Currently, bloc supports v3.6 for the Solidity compiler, which makes some of the new version of Contracts incompatible with the older version.

  • Deploy a contract

    We've learned how to send value from one user to another. We can deploy our first smart contract just as easily, but first let's look at the source code.

    contract SimpleStorage {
      uint storedData;
      function set(uint x) { storedData = x; }
      function get() returns (uint retVal) { return storedData; }
    }
    

    Above is a basic contract called SimpleStorage. It is written in Solidity, the most popular high level language that compiles to EVM bytecode. The contract has a global variable called storedData, and a getter and setter for it. We can upload the contract as follows.

    $ curl -X POST "http://localhost/bloc/v2.1/users/testUser/b47f921627827d386a427d2368677127bc5f90fd/contract" -H  "accept: application/json;charset=utf-8" -H  "content-type: application/json;charset=utf-8" -d "{  \"value\": \"10\",  \"password\": \"password\",  \"contract\": \"SimpleStorage\",  \"src\": \"contract SimpleStorage { uint storedData; function set(uint x) { storedData = x; } function get() returns (uint retVal) { return storedData; } }\"}"
    ** SAMPLE RESPONSE **
    dca5bd846d09eaf943344c9bc068ee758ebb2021
    

    The response is the address of the newly created contract.

  • Bootstrapping the Contract.

Since the contract is now deployed, we can view the Bootstrapped rendition of the Contract compiled. adding the html extension View a scaffolded UI that can call the contracts methods with the .html extension.

http://localhost/bloc/v2.1/contracts/SimpleStorage/dca5bd846d09eaf943344c9bc068ee758ebb2021.html

The automatically generated HTML Contract page contains all the fields and methods contained by the contract. All contract methods can be invoked directly by using the textfields and buttons on the webpage. For more details, Visit API Documentation

  • Contract Invocation

    With our contract deployed, let's call the set function and save some data on the blockchain! We'll call the method "set" with the parameter "x" set to "7". These are passed as post parameters

    $ curl -X POST "http://localhost/bloc/v2.1/users/testUser/b47f921627827d386a427d2368677127bc5f90fd/contract/SimpleStorage/dca5bd846d09eaf943344c9bc068ee758ebb2021/call" -H  "accept: application/json;charset=utf-8" -H  "content-type: application/json;charset=utf-8" -d "{  \"password\": \"password\",  \"method\": \"get\",  \"args\": {},  \"value\": 0}"
    ** SAMPLE RESPONSE **
    {
      "returns": [
        "0"
      ]
    }
    

    The return value is the return value of the Solidity method, which in this case isn't present.

  • Contract State

    We didn't see the change in contract state reflected in the response above. How can we introspect into contract states? We use the /state route.

    $ curl -X GET "http://localhost/bloc/v2.1/contracts/SimpleStorage/dca5bd846d09eaf943344c9bc068ee758ebb2021/state" -H  "accept: application/json;charset=utf-8"
    ** SAMPLE RESPONSE **
    {
      "get": "function () returns (UInt256)",
      "set": "function (UInt256) returns ()",
      "storedData": "0"
    }
    

    The /state route is the workhorse that drives applications - in most cases UIs are just views of the data available at the /state route.

Note we did not need to invoke the getter function in SimpleStorage to obtain its state. We'll see a use for getter functions in the next section.

  • Multiple Contracts

    Uploading multiple contracts requires an additional parameter indicating which contract is to be uploaded.

    Consider the simple source file:

    contract Consumer { InfoFeed feed; uint global;

      function setFeed(address addr) {
          feed = InfoFeed(addr);
      }
    
      function callFeed() {
          global=feed.info();
      }
    

    }

    contract InfoFeed { function info() returns (uint ret) { return 42; } }

    We separately upload these contracts by passing the contract to upload as a parameter:

    $ curl --data-urlencode "contract=Consumer" --data-urlencode "password=securePassword" --data-urlencode "src=contract Consumer { InfoFeed feed; uint global; function setFeed(address addr) { feed = InfoFeed(addr);} function callFeed() { global=feed.info();}} contract InfoFeed { function info() returns (uint ret) {return 42; }}" http://localhost:8000/users/testUser/111dec89c25cbda1c12d67621ee3c10ddb8196bf/contract
    ** SAMPLE RESPONSE **
    e8ae999a084358bd3d2c11f70e20ae4104363eef
    

    and

    $ curl --data-urlencode "contract=InfoFeed" --data-urlencode "password=securePassword" --data-urlencode "src=contract Consumer { InfoFeed feed; uint global;  function setFeed(address addr) { feed = InfoFeed(addr);} function callFeed() { global=feed.info() } } contract InfoFeed { function info() returns (uint ret) { return 42; }" http://localhost:8000/users/testUser/111dec89c25cbda1c12d67621ee3c10ddb8196bf/contract
    ** SAMPLE RESPONSE **
    80aa9aa1482f36b1861b8580fa7c2953f6209466
    

    Next, let's register our instance of InfoFeed with Consumer.

    $ curl -H "Content-Type: application/json" -d '{"password":"securePassword","method":"setFeed","args":{"addr":"80aa9aa1482f36b1861b8580fa7c2953f6209466"},"value":0}' http://localhost:8000/users/testUser/111dec89c25cbda1c12d67621ee3c10ddb8196bf/contract/Consumer/e8ae999a084358bd3d2c11f70e20ae4104363eef/call
    ** SAMPLE RESPONSE **
    transaction returned: null
    

    To confirm the change, check the state route:

    $ curl http://localhost/bloc/v2.1/Consumer/e8ae999a084358bd3d2c11f70e20ae4104363eef/state
    {
      "setFeed":"function (Address) returns ()",
      "callFeed":"function () returns ()",
      "feed":"80aa9aa1482f36b1861b8580fa7c2953f6209466",
      "global":"0"
    }
    

    Note that feed has been succesfully registered. Finally, let's consume the feed:

    $ curl -H "Content-Type: application/json" -d '{"password":"securePassword","method":"callFeed","args":{},"value":0}' http://localhost:8000/users/testUser/111dec89c25cbda1c12d67621ee3c10ddb8196bf/contract/Consumer/e8ae999a084358bd3d2c11f70e20ae4104363eef/call
    ** SAMPLE RESPONSE **
    transaction returned: null
    

    Finally, we can check the state update:

    $ curl http://localhost/bloc/v2.1/contracts/Consumer/e8ae999a084358bd3d2c11f70e20ae4104363eef/state
    **SAMPLE RESPONE**
    {
      "setFeed": "function (Address) returns ()",
      "callFeed": "function () returns ()",
      "feed": "80aa9aa1482f36b1861b8580fa7c2953f6209466",
      "global": "42"
    }
    
  • Constructor Arguments

Solidity contracts support constructor arguments. Let's modify SimpleStorage to make use of a constructor.

    contract SimpleStorage {
      uint storedData;
      function SimpleStorage (uint constructorInt) { storedData = constructorInt; }
      function set(uint x) { storedData = x; }
      function get() returns (uint retVal) { return storedData; }
    }


Now, to upload SimpleStorage we use the earlier contract invocation