navbar

exchangeratesapi exchangeratesapi Oracle Docs

pragma solidity ^0.5.0;

import "./OracleAPI.sol";

/**
 * @title Example contract using exchangeratesapi oracle
 * @author TruSource
 * @notice Example contract using exchangeratesapi oracle
 * @dev Demonstrates usage of OracleAPI and building queryParams
 */
contract Example is OracleAPI {
    event LogResult(bytes32 queryId, Oracle.Oracle.Operations operationId, uint256 statusCode, string result);

    constructor(address resolverAddress) public OracleAPI (resolverAddress) public {}

    /**
     * @notice Make getHistory query
     * @dev Make getHistory query, queryId is returned to be used to handle query result
     */
    function getHistory() external {
        Buffer.buffer memory optionalQueryParams = createBuffer();

        // Optional
        addString(optionalQueryParams, "end_at", "2018-09-01");
        addString(optionalQueryParams, "start_at", "2018-01-01");
        addString(optionalQueryParams, "symbols", "ILS,JPY");

        trusource_getHistory(optionalQueryParams);
    }

    /**
     * @dev Handle query result using queryId, operationId and statusCode
     * @param queryId unique id for query
     * @param operationId id for operation
     * @param statusCode HTTP response status code
     * @param result query result
     */
    function trusource_callback(
        bytes32 queryId,
        Oracle.Oracle.Operations operationId,
        uint256 statusCode,
        string calldata result
    ) external checkAddress checkQueryId(queryId) {
        if (operationId == Oracle.Oracle.Operations.getHistory) {
            emit LogResult(queryId, operationId, statusCode, result);
            return;
        }
    }
}

exchangeratesapi have partnered with TruSource to provide users with data on the Ethereum blockchain. Users can access data from exchangeratesapi endpoints detailed in these docs by signing up for exchangeratesapi via the TruSource website.

Dependencies

Before starting ensure the following requirements are met.

Example Project

To start, clone the exchangeratesapi example truffle project. Alternatively use the exchangeratesapi truffle box, ensure you are in a new and empty directory and run the following

truffle unbox TruSource/exchangeratesapi-exchangeratesapi

Looking at the project, the contract, Example.sol, demonstrates the usage of the operations exposed by the oracleAPI.sol. A reduced version of Example.sol is shown on the right, the getHistory function uses the getHistory operation by calling the trusource_getHistory function defined in OracleAPI.sol.

Do it Yourself

When writing a contract that uses the exchangeratesapi oracle, several important conditions have to be met.

Firstly, the contract should inherit the OracleAPI.

contract Example is OracleAPI

The constructor should accept a resolver address argument which is passed to the base contract using a OracleAPI modifier.

constructor(address resolverAddress) OracleAPI (resolverAddress) public {}

The contract must then implement a trusource_callback method.

function trusource_callback(bytes32 queryId, Oracle.Oracle.Operations operationId, uint256 statusCode, string calldata result) external checkAddress checkQueryId(queryId)

The implementation should use the checkAddress and checkQueryId(queryId) modifiers.

Callback Function

The trusource_callback method is called by TruSource, with the query return passed as one of the arguments.

trusource_callback(bytes32 queryId, Oracle.Oracle.Operations operationId, uint256 statusCode, string calldata result) external checkAddress checkQueryId(queryId)

Parameter Description
queryId Unique id to identify each query
operationId Unique id to identify each operation
statusCode HTTP status code
result API call response as string

Optional Query Parameters

/**
 * @notice Make getHistory query
 * @dev Make getHistory query, queryId is returned to be used to handle query result
 */
function getHistory() external {
    Buffer.buffer memory optionalQueryParams = createBuffer();

    // Optional
    addString(optionalQueryParams, "end_at", "2018-09-01");
    addString(optionalQueryParams, "start_at", "2018-01-01");
    addString(optionalQueryParams, "symbols", "ILS,JPY");

    trusource_getHistory(optionalQueryParams);
}

Some operations will allow for optional query parameters. Mutable byte buffers are used and query parameter keys and values are CBOR encoded using the solidity-cborutils library.

Use the addString or addUInt helpers to construct the query parameter buffer.

For example, lets assume the getHistory operation allows optional query parameters. To construct the query parameters ?end_at=2018-09-01&start_at=2018-01-01&symbols=ILS,JPY, first initialise a buffer variable.

Buffer.buffer memory queryParams = createBuffer();

Then add the keys and values.

addString(queryParams, "end_at", "2018-09-01");

addString(queryParams, "start_at", "2018-01-01");

addString(queryParams, "symbols", "ILS,JPY");

Options String

An options string can be passed along with a call to every operation. The format of the string is as follows

identifier/options

The following identifiers are currently supported.

identifier Description
json Parse json response
fixedNum reformat floating point return as fixed number

Multiple options can be specified. For example, both response parsing and a fixed number response:

json/parse.json.response/fixedNum/4

Response Parsing

Example response

{
  "posts": [
    {
      "id": 1,
      "title": "hello",
      "rating": 4.75
    }
  ],
  "profile": {
    "name": "typicode"
  }
}

This is useful when an operation returns a json response and a single value is required in the contract. Take the example response on the right as an example.

Assuming the title of the first post is required, the option string would be constructed as

json/posts.0.title

Fixed point number response

Solidity does not yet support floating point numbers, fixed point number representations are commonly used instead within smart contracts. When constructing the string pass an integer to represent decimal multiplier.

For example, if the following options string was used for the example response (4.75)

json/posts.0.rating/fixedNum/2

The response would be "475". The parseInt can then be used to parse the string as a uint256.

Local Testing

The exchangeratesapi example and any user projects using the exchangeratesapi oracle can be tested locally with a local server that can mimic the TruSource servers that will fetch and respond with data to contracts running on local ganache blockchains.

  1. Start an Ethereum client. We will use ganache-cli.

    npx ganache-cli

    Note: the client needs to support WebSockets (do not use truffle develop for this reason).

    For other options, see Truffle - Choosing an Ethereum client.

  2. Migrate the smart contracts, in a 2nd terminal

    truffle migrate

  3. Start the TruSource local server. It will listen for events, fetch and return data to requesting contracts.

    npm start

  4. Using the provided Truffle script ./server/calls.js, call functions in Example.sol. This will execute a set of contracts calls, testing each operation with provided example arguments. In a 3rd terminal

    truffle exec server/calls.js

Network Testing

ropsten migrations

const yourContract = artifacts.require("yourContract");

module.exports = (deployer, network) => {
  if (network === "ropsten") {
    const resolverAddress = "0x0e20f5f1919435e3ac1d83b2ee03b5b2ea8ca2c1";
    deployer.deploy(yourContract, resolverAddress);
  }
};
network Resolver Address Oracle Address
ropsten 0x0e20f5f1919435e3ac1d83b2ee03b5b2ea8ca2c1 0xbefbe2cca474145b29608f4f7ed860c916ede27a

The exchangeratesapi oracle is currently deployed on the networks shown in the table.

To use the exchangeratesapi oracle on a given network, you must deploy your contract and provide the resolver address as a constructor argument.

For all contract calls that make a call to the exchangeratesapi oracle, Trusource will make a call to the trusource_callback function in your contract with the result.

The truffle migrations for ropsten is demonstrated.

To deploy your contract to a live network, update the migrations as shown, a do the following within the exchangeratesapi truffle box:

  1. Uncomment line 4 to 12 in truffle-config.js.

  2. Set the SEED_PHRASE (mnemonic) and ETHEREUM_RPC_URL environment variables in .env.

  3. Migrate the contracts.

    truffle migrate --network <network-name>

  4. Whitelist the contract that will call the exchangeratesapi API at trusource.io.

Operations

getHistory

/**
 * @notice Make getHistory query
 * @dev Make getHistory query, queryId is returned to be used to handle query result
 */
function getHistory() external {
    Buffer.buffer memory optionalQueryParams = createBuffer();

    // Optional
    addString(optionalQueryParams, "end_at", "2018-09-01");
    addString(optionalQueryParams, "start_at", "2018-01-01");
    addString(optionalQueryParams, "symbols", "ILS,JPY");

    trusource_getHistory(optionalQueryParams);
}

OracleAPI Method

trusource_getHistory()

trusource_getHistory(string memory options)

trusource_getHistory(Buffer.buffer memory optionalQueryParams)

trusource_getHistory(Buffer.buffer memory optionalQueryParams, string memory options)

Operation Query Parameters

Optional query parameters need to be CBOR encoded and be passed as a bytes array. See optional query parameters for more details.

Parameter Required
end_at false
start_at false
symbols false

Options

An options string can be provided, see options string for more details.

getLatest

/**
 * @notice Make getLatest query
 * @dev Make getLatest query, queryId is returned to be used to handle query result
 */
function getLatest() external {
    Buffer.buffer memory optionalQueryParams = createBuffer();

    // Optional
    addString(optionalQueryParams, "symbols", "USD,GBP");

    trusource_getLatest(optionalQueryParams);
}

OracleAPI Method

trusource_getLatest()

trusource_getLatest(string memory options)

trusource_getLatest(Buffer.buffer memory optionalQueryParams)

trusource_getLatest(Buffer.buffer memory optionalQueryParams, string memory options)

Operation Query Parameters

Optional query parameters need to be CBOR encoded and be passed as a bytes array. See optional query parameters for more details.

Parameter Required
symbols false

Options

An options string can be provided, see options string for more details.

OracleAPI

Helper functions enabling the use of optional query parameters for some operations and response parsing are provided.

addInt

CBOR encode a string key and uint value pair and add to buffer.

addUint(Buffer.buffer memory param, string memory key, string memory value)

Parameter Description
param buffer object to which the encoded key and value will be added to
key query parameter key of type string
value query parameter value of type uint

addString

CBOR encode a string key and string value pair and add to buffer.

addString(Buffer.buffer memory param, string memory key, string memory value)

Parameter Description
param buffer object to which the encoded key and value will be added to
key query parameter key of type string
value query parameter value of type string

parseInt

Parse a the string response within trusource_callback as uint256.

parseInt(string memory str)

Parameter Description
str string representation of uint

createBuffer

Initialises and returns buffer set to defaultBufferSize of 256.

createBuffer()