Nayms Smart contracts.
NOTE: the old version of the contracts used to deploy the v1 pilots can be found via the v1_post_audit tag.
Install the package:
npm install @nayms/contracts
The package exposes the following properties:
contracts- the key contracts (see below)rawContracts- ABIs of all Solidity contracts in the repoaddresses- contents ofdeployedAddresses.jsonevents- ABIs for events to listen forreleaseConfig- the contents ofreleaseConfig.json, this is used to keep track of the build number inVersionInfo.sol.extractEventsFromAbis()- given an array of contract ABIs, this will extract the event ABIs within.keccak256()- keccak256 hash functionROLES- role constantsROLEGROUPS- rolegroup constantsSETTINGS- settings constants
The key contracts are:
ACL (IACL.sol)- Interface for our access control system. We have a single global ACL for our platform.AccessControl (AccessControl.sol)- Interface for obtaining ACL context info from deployed contracts.EntityDeployer (IEntityDeployer.sol)- Interface for the entity deployer. We have a single global deployer for our platform.Entity (IEntity.sol)- Interface for interacting with entities.ERC20 (IERC20.sol)- Interface for interacting with ERC-20 contracts.EtherToken (IEtherToken.sol)- Interface for interacting with wrapped ETH token contract. We have a single global instance for our platform.Market (IMarket.sol)- Interface for interacting with our MakerOTC matching market. We have a single global instance for our platform.Policy (IPolicy.sol)- Interface for interacting with policies.Settings (ISettings.sol)- Interface for global settings. We have a single global settings instance for our platform.
The Nayms company entity and its address can be obtained via Settings.getAddress(SETTINGS.NAYMS_ENTITY).
An architectural overview can be found in docs/architecture.md.
Architectural Decision Records (ADRs) can be found in docs/adr.
const ethers = require('ethers')
const { parseLog } = require('ethereum-event-logs')
const { contracts, addresses, events } = require('@nayms/contracts')
const mnemonic = '<mnemonic pass phrase>'
const init = async () => {
const provider = new ethers.providers.InfuraProvider('rinkeby', '<infura token>')
const wallet = ethers.Wallet.fromMnemonic(mnemonic).connect(provider)
const deployer = new ethers.Contract(
// '4' is Rinkeby (see https://chainid.network/chains/)
addresses.EntityDeployer['4'].address,
contracts.EntityDeployer.abi,
wallet
)
// deploy a new Entity
const tx = await deployer.deploy({
gasPrice: '0x3B9ACA00', // 1,000,000,000
gasLimit: '0x2DC6C0', // 1,500,000
})
console.log(`Tx hash: ${tx.hash}`)
const receipt = await provider.waitForTransaction(tx.hash)
const [ newEntityEvent ] = parseLog(receipt.logs, [ events.NewEntity ])
const { args: { entity } } = newEntityEvent
console.log(`New entity deployed at: ${entity}`)
}
init().catch(err => {
console.error(err)
process.exit(-1)
})To deploy and use the contracts on your local chain please clone this repository and run the following deployment commands:
yarn compile
yarn deploy:local
# The addresses at which the contract are deployed will be output in the terminal.Requirements:
- Node.js 14.16.0+
- Yarn 1.22.10+ (use
npm i -g yarnonce Node.js is installed)
Install dependencies:
yarnInitialize git submodules (for maker-otc trading engine):
git submodule init
git submodule updateFirst, run the dev network in a separate terminal:
yarn devnetCompile the contracts:
yarn compileSetup release config:
yarn setup-release-config-for-localNow deploy the contracts to it:
yarn deploy:localNow you can run the tests:
yarn testTo run a single test:
yarn hardhat test ./test/testName.jsYou can use the admin dapp to interact with your locally deployed contracts.
First let's build it:
yarn build-admin-dappThen open Metamask in your browser and configure it to use our custom mnemonic and pointing to http://localhost:8545 as a Custom RPC endpoint (Note: you may already have a "Localhost 8545" entry in your Metamask network list, in which ase you don't need to add a new one).
Once done, start a lightweight HTTP server to serve up the admin dapp:
npx serve ./dappVisit the URL shown in the output and enjoy.
NOTE: Rinkeby/Mainnet deployments are done using Nayms wallet 2, i.e. the second wallet generated from the Nayms company mnemonic - 0xfcE918c07BD4c900941500A6632deB24bA7897Ce. Also note that we use a dedicated Infura endpoint for smart contracts deployments (find it in 1password).
Set up the env vars:
export MNEMONIC="..."
export INFURA_KEY="..."To upgrade existing Rinkeby contracts:
yarn setup-release-config-for-rinkeby
yarn deploy:rinkebyFor mainnet:
yarn setup-release-config-for-mainnet
yarn deploy:mainnetBy default all deployments are upgrade-only, meaning that the ACL, Settings and other such contracts won't get deployed - instead the existing addresses from deployedAddresses.json will be used. Existing Entity and Policy contracts will be upgraded to the latest implementations.
Fresh deployments
To deploy a fresh set of contracts and update deployedAddresses.json, edit releaseConfig.json and add the following keys before running the deploy command:
{
...
"freshDeployment": true,
"extractDeployedAddresses": true,
...
}The deployedAddresses.json file will be modified once complete. Remember to commit this into Git and push since it contains the addresses of the newly deployed ACL, Settings, etc.
The release branch
Pushing to the release branch will result in a Rinkeby deployment (upgrade-only) as well as the admin dapp being deployed.
Known issues
When deploying to public networks, if deployment fails with a "transaction underpriced" error then it means there are pending transactions for the deployment account - you need to wait for these to complete before trying again.
- We use
block.timestamp (now)in the code. We assume this is safe to do since our timescales occur across days and months rather than seconds, see https://medium.com/@phillipgoldberg/smart-contract-best-practices-revisited-block-number-vs-timestamp-648905104323