This typescript repository contains all the server code used by the RIF Relay System.
This project works as a dependency as well as a stand-alone project.
- Node version 16.x
- RSKj Running Node.
- Note: To work properly with this server in Regtest, please use the RSKj configuration that can be found here.
- RIF Relay Contracts deployed
Just run npm install
to install all dependencies.
To start the relay server, you first need a configuration file. This is loaded using node-config package from ./config
folder.
We prepared some defaults for testnet and mainnet, however to run it locally, or to use custom settings, you'd need to create a new file in ./config
and prepend
NODE_ENV=<config_file_name>
to the execution command.
File ./config/default.json5 contains all configuration properties and their descriptions.
./config/default.json5
// config/default.json5
// TODO: add descriptions in comments
// This file should not be aimed at any specific environment, but rather contain configuration defaults that are not likely to cause issues if left undefined in an override
{
/*
Server
*/
app: {
url: "http://127.0.0.1", // URL where the relay server will be deployed, it could be localhost or the IP of the host machine.
port: 8090, // port where the relay server will be hosted.
devMode: false, // indicates to the server if we are in development mode or not.
customReplenish: false, // set if the server uses a custom replenish function or not.
logLevel: 4 /* The log level for the relay server. Available levels:
{
TRACE: 0;
DEBUG: 1;
INFO: 2;
WARN: 3;
ERROR: 4;
SILENT: 5;
}
*/,
workdir: ".", // path to the folder where the server will store the database and all its data.
readyTimeout: 30000,
checkInterval: 10000,
disableSponsoredTx: false,
/* It's the fee that the fee collector will take from the execution of
transfer() or transferFrom() functions.
- This value should be expressed as a fraction, i.e. 0.1 means 10% of the value being transfered
and 0.01 means 1% of the value being transfered.
- This value has priority over gasFeePercentage. If transferFeePercentage is properly configured and the execution
is a tranfer or transferFrom, gasFeePercentage will be ignored even if transferFeePercentage = 0.
- Negative values disable this fee.
*/
transferFeePercentage: -1,
/* Sets the fee value (%) that the worker will take from all transactions
based on the total amount of gas used.
- Under certain conditions, this value will be ignored. See transferFeePercentage above to know more about it.
- the fee will be added to the estimated gas and required in the transaction amount.
- the percentage is represented as a fraction (1 = 100%) string to allow for very low or high percentages
- fractions exceeding the number of decimals of that of the native currency will be rounded up
*/
gasFeePercentage: 0,
/* It's a fixed fee that the feeCollector takes from all the operations regardless of their
nature (deploy, relay, transfer, transferFrom, etc.). For example, if fixedUsdFee = 1.5, every transaction
will pay an additional fee of 1.5USD.
- This fee is not exclusive. If gasFeePercentage or transferFeePercentage is configured, fixedUsdFee will be
an additional fee, so the total amount will be initialGasEstimation + gasFee (or transferFee) + fixedFee.
*/
fixedUsdFee: 0,
sponsoredDestinations: [],
requestMinValidSeconds: 43200,
},
/*
Blockchain node
*/
blockchain: {
rskNodeUrl: "http://127.0.0.1:4444", // RSK node endpoint URL, where the RSK node is located.
gasPriceFactor: 1,
alertedBlockDelay: 0,
minAlertedDelayMS: 0,
maxAlertedDelayMS: 0,
registrationBlockRate: 0,
workerMinBalance: 0.001e18, // 0.001 RBTC
workerTargetBalance: 0.003e18, // 0.003 RBTC
managerMinBalance: 0.001e18, // 0.001 RBTC
managerMinStake: 1, // 1 wei
managerTargetBalance: 0.003e18, // 0.003 RBTC
minHubWithdrawalBalance: 0.001e18, // 0.001 RBTC
refreshStateTimeoutBlocks: 5,
pendingTransactionTimeoutBlocks: 30, // around 5 minutes with 10 seconds block times.
successfulRoundsForReady: 3, // successful mined blocks to become ready after exception.
confirmationsNeeded: 12,
retryGasPriceFactor: 1.2, // gas price factor used to calculate the gas on the server, you can leave it as 1
defaultGasLimit: 500000,
maxGasPrice: 100000000000,
estimateGasFactor: 1.2,
initialBlockToScan: 1, // the first block to scan to look for events
maxBlockRange: 1000 // the maximum amount of blocks to include while requesting events
},
/*
Relay contracts addresses
*/
contracts: {
relayHubAddress: "0x0000000000000000000000000000000000000000", // relay hub contract address, you can retrieve this from the contract summary.
relayVerifierAddress: "0x0000000000000000000000000000000000000000", // relay verifier contract address, you can retrieve this from the contract summary.
deployVerifierAddress: "0x0000000000000000000000000000000000000000", // deploy verifier contract address, you can retrieve this from the contract summary.
feesReceiver: "0x0000000000000000000000000000000000000000",
trustedVerifiers: [],
},
register: {
stake: "0.01", // amount of stake to set up
funds: "0.02", // amount of funds to set up
mnemonic: "", // mnemonic to use for unlocking the account parameter; DO NOT STORE IT HERE, use REGISTER_MNEMONIC as env variable.
privateKey: "", // private key to retrieve the account address from; DO NOT STORE IT HERE, use REGISTER_PRIVATE_KEY as env variable.
relayHub: "",
gasPrice: 60000000,
unstakeDelay: 1000,
},
}
Keep in mind, that the if
local
configuration exists, it WILL OVERWRITE any other configuration files loaded using NODE_ENV.Also note that
development
is the default NODE_ENV value. The following depicts the order in which the node-config library merges configuration, starting from the least to the most specific config:
flowchart TD;
default.json5 --> |$NODE_ENV value| development.json5
development.json5 --> |if local exists| local.json5
local.json5 --> |for specified values only| custom-environment-variables.json
Consult the node-config file load order documentation for more details about config load order.
Some of these options will be overrideable using environment variables defined in ./config/custom-environment-variables.json file.
./config/custom-environment-variables.json
// config/custom-environment-variables.json
{
"register": {
"stake": "REGISTER_STAKE",
"funds": "REGISTER_FUNDS",
"mnemonic": "REGISTER_MNEMONIC",
"privateKey": "REGISTER_PRIVATE_KEY",
"hub": "REGISTER_HUB_ADDRESS",
"gasPrice": "REGISTER_GAS_PRICE",
"unstakeDelay": "REGISTER_UNSTAKE_DELAY"
}
}
Keep in mind that neither
mnemonic
orprivateKey
are intended to be set in the file directly and doing it can lead to security issues. Please refer to the server registration section for further details.
To use these overrides, you'd prepend an environment variable, e.g.:
REGISTER_UNSTAKE_DELAY=2000 REGISTER_GAS_PRICE=1000000 npm run register
Depending on your preferred configuration, start the server with:
# to use with local instance
npm run start # This will use development.json5 first, if one exists
# to use for testnet deployment
NODE_ENV=testnet npm run start
# to use for mainnet deployment
NODE_ENV=mainnet npm run start
# or your own
NODE_ENV=ferko_mrkvicka npm run start
You can browse the getAddr
endpoint (e.g. by doing curl
to http://localhost:8090/getaddr
) to verify the server is running correctly as well as visualize some useful information:
{
"relayWorkerAddress": "0xe722143177fe9c7c58057dc3d98d87f6c414dc95",
"relayManagerAddress": "0xe0820002dfaa69cbf8add6a738171e8eb0a5ee54",
"relayHubAddress": "0x38bebd507aBC3D76B10d61f5C95668e1240D087F",
"minGasPrice": "6000000000",
"chainId": "31",
"networkId": "31",
"ready": false,
"version": "2.0.1"
}
If it's the first time the server is run, some logs will state that the server isn't ready and that some values are wrong. This is expected, you just need to register the server on the relay hub in order for it to be usable by the clients.
Once the relay server is up, you need to register it in order for it to be usable. The ./config/default.json5
config file contains configuration definitions for this too. You can either store them in your own config, or override them with environment variables.
# to use with local instance
NODE_ENV=local npm run register
# to use for testnet deployment
NODE_ENV=testnet npm run register
# to use for mainnet deployment
NODE_ENV=mainnet npm run register
# or your own env
NODE_ENV=ferko_mrkvicka npm run register
After this you will see several log entries indicating the registration progress. After a little while, look for this entry in the relay server execution terminal to make sure that the server is ready:
Relayer state: READY
Keep in mind that there are different ways to specify the keys during the registration steps.
- If nothing is specified, the register scrips tries to retrieve the signer from the RPC accounts configured in the node; this method is enabled for development purposes only (Regtest)
- The user could use either a private key or a mnemonic using the custom environment variable method hence by specifying
REGISTER_PRIVATE_KEY
orREGISTER_MNEMONIC
as environment variables (e.g.:REGISTER_PRIVATE_KEY="0xabc123" npm run register
orREGISTER_MNEMONIC="word1 word2 etc..." npm run register
).
You can run the server as a Docker container. Docker and Docker compose should be installed and an RSK Node should be running. After modifying the config-file as indicated here, an additional modification should be made in the same file as follows:
For Mac users:
// in your config override file
rskNodeUrl: "http://host.docker.internal:4444",
For Linux users:
// in your config override file
rskNodeUrl: "http://172.17.0.1:4444",
In both cases, edit your local hosts file to make the address above resolve as 127.0.0.1.
Then run:
NODE_ENV=<name> docker-compose build && NODE_ENV=<name> docker-compose up
After that, you need to login into the running container docker exec -it <container_name> bash
. To get the container name, you need to run docker-compose ps
in the project folder. Once you logged in the running container, you need to run the register command:
<VARIABLE_LIST> node dist/commands/Register.js
where VARIABLE_LIST
can contains any of the variables defined in the override section.
Please remember that, in oder to properly register the server, you need to specify at least the following environment variables:
- REGISTER_MNEMONIC or REGISTER_PRIVATE_KEY.
Clone this repository inside your project's root folder and use the npm link
mechanism (https://docs.npmjs.com/cli/v8/commands/npm-link) to add it to your project.
Make your modifications and then run npm run dist
to validate them.
When you are done with your changes, you can publish them by creating a distributable version.
The relay server scripts define three testing strategies:
test:unit
- runs one-off unit tests within the./test/unit/
directorytest:integration
- runs one-off integration tests within the./test/integration
directorytdd
- runs unit tests in watch mode. Watches all ts files in the project
In addition, the TRACE_LOG=true
environment variable may be used to use the trace log level in the tests ;]
. This will print a lot of logs from the codebase.
We use husky to check linters and code styles on commits, if you commit your changes and the commit fails on lint or prettier checks you can use these command to check and fix the errors before trying to commit again:
npm run lint
to check linter bugsnpm run lint:fix
to fix linter bugsnpm run prettier
to check code-style errorsnpm run prettier:fix
to fix code-style errors
- Create a new release with the new version (remember to update
package.json
).