1.0.22 • Published 5 years ago

@vidy-dev/ethereum-connect v1.0.22

Weekly downloads
4
License
MIT
Repository
github
Last release
5 years ago

ethereum-connect

Quick connection to ethereum nodes, including RPC configuration and internal service detection.

connecting

To create a connection with default settings, use:

const ethereumConnect = require('@vidy-dev/ethereum-connect')
const connection = await ethereumConnect()

Connection configuration is inferred from environmental context and, optionally, a config/{environment}.js config file readable with the config module. Alternatively, configurations can be overridden by providing an options argument, like:

const ethereumConnect = require('@vidy-dev/ethereum-connect')
const connection = await ethereumConnect({logging: true, rpc: {port: 1337}})

caching

Usage of ethereumConnect as an object constructor will create a fresh connection every time it is called; it is the user's responsibility to manage the transfer of this connection object between uses.

Alternatively, the module provides connection caching based on input arguments:

const ethereumConnect = require('@vidy-dev/ethereum-connect')
const connection1 = await ethereumConnect.getConnection({logging: true})
...
const connection2 = await ethereumConnect.getConnection({logging: true})

In this example, both connection1 and connection2 refer to the same object. If the input configuration is meaningfully changed, a new connection would be returned instead. This allows different files or function invocations to use the same connection (saving time and remote calls) so long as they share configuration arguments. ethereumConnect.reset() clears this cache.

config / options

The environment configuration file is checked for these keys:

{
  "ethereum": {
    "contracts": [],
    "logging": false,
    "rpc": {
      "address": "www.google.com",
      "port": 8545
    }
  }
}

when provided as function arguments, the same format may be used, or the subobject named ethereum.

ethereum node

ethereumConnect automates the complexity of discovering the Vidy backend ethereum service domain name, connecting to the load balancer, testing the connection, etc. To this end, functions that create connections (the constructor ethereumConnect() and caching ethereumConnect.getConnection() function) will raise exceptions if an active Ethereum node cannot be found.

The ethereum node location can be specified as the rpc.address and rpc.port options. If the address is omitted, the normal discovery process will be used; if the port is omitted, 8545 is the default.

ethereum node address discovery

ethereumConnect is intended for three use cases:

  1. The service is running on the Google Cloud backend, in a project using our ethereum-node load balancing service.
  2. The service is running on a developer's local workstation, with an active port-tunnelling connection to the ethereum middleman (see the ethereum-tools repo).
  3. The service is running on an instance with an active ethereum node.

To handle the first case, Google's metadata domain names are queried for the current project and zone; from these, the associated ethereum-node fully-qualified-domain-name can be determined. This address is sent a simple RPC request (net_version) to confirm that it is active and accepting RPC connections. If the connection fails, ethereumConnect reverts to the default region us-central1 and tries again. If both fail, a connection to localhost is connected.

The first of these three connection attempts to succeed is the one used for the connection. If none succeed, the connection attempt fails and an exception will be thrown.

contracts

Solidity smart contracts, as build output .json files, can be discovered and loaded by the connection. Contracts loaded by it will be wrapped in the truffle-contract interface and preconfigured with a default account for transaction signing. See the truffle-contract implementation or other examples for usage of the contracts themselves, once loaded.

Contract discovery allows users to specify contracts without their fully scoped module paths. For example, if the VidyCoin contract is included in your project (with npm install @vidy-dev/ethereum-vidycoin) you can reference it directly with await connection.getContract('@vidy-dev/ethereum-vidycoin/build/contracts/VidyCoin.json') -- but it could also be located with simpler queries, such as await connection.getContract('ethereum-vidycoin/VidyCoin.json') or even await connection.getContract('VidyCoin'). It is an error (an exception will be thrown) to request a contract that cannot be found, or a query string that is ambiguous (discovers multiple contracts).

As a security measure, contracts located in your project's node_modules paths will only be discoverable if they exist in the @vidy-dev scope (this prevents 3rd party libraries from attacking by providing conflicting contract definitions). However, if you need custom contracts that are not provided by modules in that scope, their directories can be specified with the ethereum.contracts config option.

connections

Connections created by ethereumConnect provide these functions:

await connection.getConfig(): provides the fully populated configuration object, combining environment configuration, construction options, node discovery, and default values.

await connection.getWeb3(): provides the ethereum web3 instance used for the connection, preconfigured with a default account for transaction signing. Useful for any web3 operation: checking block numbers, sync status, account balances, etc.

await connection.getContractFinder(): provides the internal helper used to locate Solidity contracts when getContract() or createContract is used.

await connection.getContract(contract): discovers, loads, and configures a truffle-contract instance for the specified contract, which is a string or file path uniquely identifying a discoverable contract .json file. To save time, the output is cached; multiple calls with the same input query will retrieve exactly the same contract instance (you should not rely on this caching for any reason other than efficiency; e.g. you should not build code on the assumption that the same instance is provided every time).

await connection.createContract(contract): identical to getContract, except no caching is done; a fresh truffle-contract instance is provided with each call.

example

Below is a short usage example, taken from the KYC reference implementation. The specific functions supported by the contract itself are contract-dependent.

'use strict';

const web3 = require('../lib/web3');
const ethereumConnect = require('@vidy-dev/ethereum-connect')

exports.isOnWhitelist = async function(req, res) {
  try {
    // get a connection (cached; only the first call is expensive)
    const connection = await ethereumConnect.getConnection();
    // get a contract interface for the public whitelist (cached)
    const PublicICOWhitelist = await connection.getContract('PublicIcoWhitelist');
    // get an interface for the instance deployed on this ethereum network
    const publicIcoWhitelist = await PublicICOWhitelist.deployed();
    // query whether the given address is on the whitelist
    const result = await publicIcoWhitelist.whitelist.call(req.params.address);
    if (!result) {
      res.status(404).send({address: `address ${req.params.address} is not on the whitelist`, success: false});
    } else {
      res.json({success:result});
    }
  } catch (err) {
    console.log(err);
    res.status(500).send({success:false, message: err.message})
  }
};

exports.addToWhitelist = async function(req, res) {
  try {
    // get a connection (cached; only the first call is expensive)
    const connection = await ethereumConnect.getConnection();
    // get a contract interface for the public whitelist (cached)
    const PublicICOWhitelist = await connection.getContract('PublicIcoWhitelist');
    // get an interface for the instance deployed on this ethereum network
    const publicIcoWhitelist = await PublicICOWhitelist.deployed();
    // make the change on the Ethereum blockchain through the contract interface
    await publicIcoWhitelist.addAddressToWhitelist(req.params.address);
    res.json({"success":true});
  } catch (err) {
    console.log(err);
    res.status(500).send({success:false, message: err.message})
  }
};
1.0.22

5 years ago

1.0.21

5 years ago

1.0.20

5 years ago

1.0.19

5 years ago

1.0.18

5 years ago

1.0.17

5 years ago

1.0.16

5 years ago

1.0.15

5 years ago

1.0.14

5 years ago

1.0.13

5 years ago

1.0.12

5 years ago

1.0.11

5 years ago

1.0.10

5 years ago

1.0.9

5 years ago

1.0.8

5 years ago

1.0.7

5 years ago

1.0.6

6 years ago

1.0.5

6 years ago

1.0.4

6 years ago

1.0.3

6 years ago

1.0.2

6 years ago

1.0.1

6 years ago

1.0.0

6 years ago