@reality.eth/contracts
Version:
Collection of smart contracts for the Realitio fact verification platform
462 lines (395 loc) • 15.1 kB
JavaScript
const fs = require('fs');
const ethers = require('ethers');
const project_base = './../';
const build_dir = './../truffle/build/contracts/';
const rc = require('../index.js');
const { join } = require('path');
const chain_configs = require('./../generated/chains.json');
let secrets_dir = join(__dirname, '../secrets');
if (process.env.SECRETS) {
secrets_dir = process.env.SECRETS;
}
const deployed_at = null;
// const deployed_at = '0x33aa365a53a4c9ba777fb5f450901a8eef73f0a9'; //mainnet gno
// const deployed_at = '0xc79e58D0a23ea0eDBDD2dBc96d16e65f696BfFc8'; // rinkeby test
var undef;
const defaultConfigs = {
//maxFeePerGas: 610000000000,
//maxPriorityFeePerGas: 10000000000,
//gasPrice: 70000000000,
//gasPrice: 10000000000,
// gasPrice: 100000000,
// gasPrice: 10000, // optimism 1000000,
/// gasPrice: 5000000000,
//gasLimit: 6000000, // optimism 4500000
gasLimit: 4500000,
//etherscanApiKey: 'TPA4BFDDIH8Q7YBQ4JMGN6WDDRRPAV6G34'
//gasLimit: 155734867 // arbitrum
//gasLimit: 7000000
//gasLimit: 800035294
// gasLimit: 4291955938
}
const task = process.argv[2]
const version = process.argv[3]
const chain = process.argv[4]
const token_name = process.argv[5]
var arb_fee = process.argv[6]
var arbitrator_owner = process.argv[7]
var contract_type;
const chains = {
'mainnet': 1,
'ropsten': 3,
'rinkeby': 4,
'goerli': 5,
'ubiq': 8,
'optimism': 10,
'telosevm': 40,
'kovan': 42,
'bsc': 56,
'chapel': 97,
'sokol': 77,
'cheapeth': 777,
'gnosis': 100,
'scroll-alpha-testnet': 534353,
'polygon': 137,
'polygon-zkevm': 1101,
'holesky': 17000,
'mumbai': 80001,
'ava': 43114,
'arbitrum': 42161,
'arbitrum-rinkeby': 421611,
'arbitrum-goerli': 421613,
'arbitrum-sepolia': 421614,
'kovan-optimistic': 69,
'kintsugi': 1337702,
'sepolia': 11155111,
'backstopTestnet1': 88558801
}
const non_infura_chains = {
'gnosis': 'https://gnosis.oat.farm',
'scroll-alpha-testnet': 'https://alpha-rpc.scroll.io/l2',
'sokol': 'https://sokol.poa.network',
'bsc': 'https://bsc-dataseed.binance.org',
'chapel': 'https://bsc-testnet.public.blastapi.io',
'polygon': 'https://rpc-mainnet.maticvigil.com',
'polygon-zkevm': 'https://zkevm-rpc.com',
'ava': 'https://api.avax.network/ext/bc/C/rpc',
'arbitrum': 'https://arb1.arbitrum.io/rpc',
'arbitrum-rinkeby': 'https://rinkeby.arbitrum.io/rpc',
'arbitrum-goerli': 'https://goerli-rollup.arbitrum.io/rpc',
'arbitrum-sepolia': 'https://sepolia-rollup.arbitrum.io/rpc',
'ubiq': 'https://rpc.octano.dev',
'cheapeth': 'https://node.cheapeth.org/rpc',
'kovan-optimistic': 'https://kovan.optimism.io',
'optimism': 'https://mainnet.optimism.io',
'kintsugi': 'https://rpc.kintsugi.themerge.dev',
'mumbai': 'https://matic-mumbai.chainstacklabs.com',
'sepolia': 'https://sepolia.backstop.technology/', // 'https://rpc.sepolia.org',
'holesky': 'https://ethereum-holesky.publicnode.com',
'telosevm': 'https://mainnet.telos.net/evm',
'unichain': 'https://mainnet.unichain.org',
'base': 'https://mainnet.base.org',
'backstopTestnet1': 'https://testnet.rpc.backstop.technology'
}
function constructContractTemplate(contract_name) {
let abi;
try {
abi = JSON.parse(fs.readFileSync(project_base + '/abi/solc-0.4.25/'+contract_name+'.abi.json'));
} catch(e) {
try {
abi = JSON.parse(fs.readFileSync(project_base + '/abi/solc-0.8.6/'+contract_name+'.abi.json'));
} catch(e) {
abi = JSON.parse(fs.readFileSync(project_base + '/abi/solc-0.8.10/'+contract_name+'.abi.json'));
}
}
const bytecode = fs.readFileSync(project_base + '/bytecode/'+contract_name+'.bin', 'utf8').replace(/\n/, '');
//console.log('bytecode', bytecode);
return {
"abi": abi,
"contractName": contract_name,
"bytecode": bytecode
};
}
function usage_error(msg) {
msg = msg + "\n";
msg += "Usage: node deploy.js <RealityETH|Arbitrator|ERC20|Factory> <version> <chain_name> <token_name> [<dispute_fee>] [<arbitrator_owner>]";
throw msg;
}
const isNumeric = (string) => /^[+-]?\d+(\.\d+)?$/.test(string)
let chain_id;
// Predefined chains (old method)
if (chain in chains) {
chain_id = chains[chain];
// Get the chain from the chain config
} else {
for (const c in chain_configs) {
const cn = chain_configs[c].chainName.toLowerCase().replace(' ', '-');
if (cn == chain) {
chain_id = c;
break;
}
if (chain_configs[c].network_name) {
const cn2 = chain_configs[c].network_name.toLowerCase();
if (cn2 == chain) {
chain_id = c;
break;
}
}
}
}
if (!chain_id) {
usage_error("Network unknown");
}
if (token_name == undef) {
usage_error("token_name not supplied");
}
var token_address;
const token_info = rc.tokenConfig(token_name, chain_id);
if (!token_info) {
usage_error("token not found, please configure it first");
}
console.log('token', token_info);
if (isERC20()) {
token_address = token_info.address;
}
if (arb_fee == undef) {
arb_fee = "0xde0b6b3a76400000";
}
if (arbitrator_owner == undef) {
arbitrator_owner = "0xdd8a989e5e89ad23ed2f91c6f106aea678a1a3d0";
}
const priv = fs.readFileSync(secrets_dir + '/' + chain + '.sec', 'utf8').replace(/\n/, '')
ensure_chain_directory_exists(chain_id, token_name);
if (task == 'RealityETH') {
deployRealityETH();
} else if (task == 'Arbitrator') {
deployArbitrator();
} else if (task == 'ERC20') {
deployERC20();
} else if (task == 'Factory') {
deployFactory();
}
function ensure_chain_directory_exists(chain, token) {
const dir = project_base + '/chains/deployments/' + chain+ '/' + token;
if (!fs.existsSync(dir)) {
console.log('creating directory for token', chain, token, dir);
fs.mkdirSync(dir, {
recursive: true
});
}
const dir2 = project_base + '/chains/factories/' + chain;
if (!fs.existsSync(dir2)) {
console.log('creating directory for factories', chain, dir);
fs.mkdirSync(dir2, {
recursive: true
});
}
return true;
}
function store_deployed_contract(template, chain_id, token_name, out_json) {
const file = project_base + '/chains/deployments/' + chain_id + '/' + token_name + '/' + template + '.json';
fs.writeFileSync(file, JSON.stringify(out_json, null, 4));
console.log('wrote file', file);
}
function store_deployed_factory_contract(template, chain_id, out_json) {
const file = project_base + '/chains/factories/' + chain_id + '/' + template + '.json';
fs.writeFileSync(file, JSON.stringify(out_json, null, 4));
console.log('wrote file', file);
}
function provider_for_chain() {
if (non_infura_chains[chain]) {
console.log('Using chain', non_infura_chains[chain]);
return new ethers.providers.JsonRpcProvider(non_infura_chains[chain]);
} else {
if (chains[chain]) {
console.log('Using infura on chain', chain);
return new ethers.providers.InfuraProvider(chain);
} else {
const chain_config = chain_configs[chain_id];
const hostedRPC = chain_config.hostedRPC;
console.log('Using RPC', hostedRPC);
return new ethers.providers.JsonRpcProvider(chain_config.hostedRPC);
}
}
}
function isERC20() {
return (!token_info.is_native);
}
function realityETHName() {
let tmpl = isERC20() ? 'RealityETH_ERC20' : 'RealityETH';
tmpl = tmpl + '-' + version;
return tmpl;
}
async function waitForGas(provider) {
if (!defaultConfigs.maxFeePerGas) {
return true;
}
// console.log('in waitForGas');
const sleep = (milliseconds) => {
return new Promise(resolve => setTimeout(resolve, milliseconds))
}
const f = await provider.getFeeData()
console.log('fee', f)
throw new Error();
return;
if (f.gasPrice.gt(ethers.BigNumber.from(defaultConfigs.maxFeePerGas))) {
console.log('Gas is too expensive, got', f.gasPrice.toString(), 'but you will only pay ', defaultConfigs.maxFeePerGas, ', retrying...')
await sleep(2000);
await waitForGas(provider);
}
return true;
}
async function deployRealityETH() {
var tmpl = realityETHName();
var txt = 'deploying reality.eth';
txt = txt + ' [template '+tmpl+']';
const provider = provider_for_chain();
const t = constructContractTemplate(tmpl);
const signer = new ethers.Wallet(priv, provider);
const confac = new ethers.ContractFactory(t.abi, t.bytecode, signer);
// console.log(signer);
txt = txt + ' (from address ' + signer.address + ')';
console.log(txt);
await waitForGas(provider);
if (deployed_at) {
console.log('using preconfigured address', deployed_at);
const inst = new ethers.Contract(deployed_at, t.abi, provider);
conninst = inst.connect(signer);
// console.log('depres', depres);
const settings = {
"address": deployed_at,
"block": 0, // fill this in by hand from the earlier tx
"token_address": token_address,
"notes": null,
"arbitrators": {}
}
//console.log('result was', result);
store_deployed_contract(tmpl, chain_id, token_name, settings);
if (isERC20()) {
console.log('Setting token')
conninst.setToken(token_address);
}
} else {
confac.deploy(defaultConfigs).then(function(result) {
const txid = result.deployTransaction.hash;
const address = result.address;
console.log('storing address', address);
console.log('deploying at address with tx ', txid);
result.deployed().then(function(depres) {
// console.log('depres', depres);
const settings = {
"address": address,
"block": depres.provider._lastBlockNumber,
"token_address": token_address,
"notes": null,
"arbitrators": {}
}
//console.log('result was', result);
store_deployed_contract(tmpl, chain_id, token_name, settings);
if (isERC20()) {
console.log('Setting token')
result.setToken(token_address);
}
});
});
}
}
function deployArbitrator() {
const rc_conf = rc.realityETHConfig(chain_id, token_name, version);
console.log('using reality.eth config', rc_conf);
if (rc_conf.token_address != token_address) {
throw new Error('Reality.eth contract does not seem to use the token address you specified');
}
var tmpl = 'Arbitrator';
var rc_file = project_base + '/chains/deployments/' + chain_id + '/' + token_name + '/' + tmpl + '.json';
const timer = ms => new Promise( res => setTimeout(res, ms));
const provider = provider_for_chain();
const t = constructContractTemplate('Arbitrator');
const signer = new ethers.Wallet(priv, provider);
const confac = new ethers.ContractFactory(t.abi, t.bytecode, signer);
confac.deploy(defaultConfigs).then(function(result) {
const txid = result.deployTransaction.hash;
const address = result.address;
console.log('storing address', address);
console.log('deploying at address with tx ', txid);
result.deployed().then(function(depres) {
// console.log('depres', depres);
const settings = {
"address": address,
"block": depres.provider._lastBlockNumber,
"reality_eth_address": rc_conf.address
}
console.log('storing address', address);
store_deployed_contract('Arbitrator', chain_id, token_name, settings);
console.log('doing setRealitio');
result.setRealitio(rc_conf.address).then(function() {
console.log('done setRealitio');
return timer(9000);
}).then(function() {
console.log('doing setDisputeFee');
return result.setDisputeFee(arb_fee);
}).then(function() {
console.log('done setDisputeFee');
return timer(9000);
}).then(function() {
if (arbitrator_owner) {
result.transferOwnership(arbitrator_owner);
}
});
});
});
}
function deployERC20() {
console.log('deploying an erc20 token', token_name);
const provider = provider_for_chain();
const t = constructContractTemplate('ERC20');
const signer = new ethers.Wallet(priv, provider);
const confac = new ethers.ContractFactory(t.abi, t.bytecode, signer);
confac.deploy(defaultConfigs).then(function(result) {
const txid = result.deployTransaction.hash;
const address = result.address;
console.log('storing address', address);
console.log('deploying at address with tx ', txid);
result.deployed().then(function(depres) {
// console.log('depres', depres);
const settings = {
"address": address,
"block": depres.provider._lastBlockNumber
}
console.log('storing address', address);
store_deployed_contract(template, chain_id, token_name, settings);
});
//result.setToken(token_address);
//result.setToken(result.contractAddress);
});
}
async function deployFactory() {
const config = rc.realityETHConfig(chain_id, token_name, version);
const lib = config.address;
var tmpl = realityETHName();
var txt = 'deploying reality.eth factory [library '+lib+']';
const provider = provider_for_chain();
const t = constructContractTemplate('RealityETH_ERC20_Factory');
const signer = new ethers.Wallet(priv, provider);
const confac = new ethers.ContractFactory(t.abi, t.bytecode, signer);
// console.log(signer);
txt = txt + ' (from address ' + signer.address + ')';
console.log(txt);
await waitForGas(provider);
confac.deploy(lib, defaultConfigs).then(function(result) {
const txid = result.deployTransaction.hash;
const address = result.address;
console.log('storing address', address);
console.log('deploying at address with tx ', txid);
result.deployed().then(function(depres) {
// console.log('depres', depres);
const settings = {
"address": address,
"block": depres.provider._lastBlockNumber,
"library_address": lib,
}
//console.log('result was', result);
store_deployed_factory_contract(tmpl, chain_id, settings);
});
});
}