-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add Token Deployment Script This patch adds saddle scripts to deploy, verify and match a cToken from a JSON configuration passed in on the command line. The goal is to make life very easy for deployment, specifically with builds from release versions of the Compound Protocol. Note: this does not _force_ developers to use release versions, but it means that developers can choose to deploy from versions of Compound that were audited. I've added significant usage notes to the README. * Add Docker Builds This patch adds Docker builds to our CI pipeline. This is the last step in letting the community run verified deployments. Every time a commit is pushed, an image and built and pushed to Docker Hub tagged with the commit (and if the commit is tagged, that will be included as a tag for Docker Hub as well).
- Loading branch information
Showing
11 changed files
with
560 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,4 +35,6 @@ junit.xml | |
.build | ||
.last_confs | ||
.git | ||
script/certora | ||
script/certora | ||
.saddle_history | ||
.circleci |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,4 +37,5 @@ scenario/.tscache | |
tests/scenarios/ | ||
junit.xml | ||
.build | ||
.last_confs | ||
.last_confs | ||
.saddle_history |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
let { loadConf } = require('./support/tokenConfig'); | ||
|
||
function printUsage() { | ||
console.log(` | ||
usage: npx saddle script token:deploy {tokenConfig} | ||
note: pass VERIFY=true and ETHERSCAN_API_KEY=<api key> to verify contract on Etherscan | ||
example: | ||
npx saddle -n rinkeby script token:deploy '{ | ||
"underlying": "0x577D296678535e4903D59A4C929B718e1D575e0A", | ||
"comptroller": "$Comptroller", | ||
"interestRateModel": "$Base200bps_Slope3000bps", | ||
"initialExchangeRateMantissa": "2.0e18", | ||
"name": "Compound Kyber Network Crystal", | ||
"symbol": "cKNC", | ||
"decimals": "8", | ||
"admin": "$Timelock" | ||
}' | ||
`); | ||
} | ||
|
||
function sleep(timeout) { | ||
return new Promise((resolve, reject) => { | ||
setTimeout(() => { | ||
resolve(); | ||
}, timeout); | ||
}); | ||
} | ||
|
||
(async function() { | ||
if (args.length !== 1) { | ||
return printUsage(); | ||
} | ||
|
||
let conf = loadConf(args[0], addresses); | ||
if (!conf) { | ||
return printUsage(); | ||
} | ||
|
||
console.log(`Deploying cToken with ${JSON.stringify(conf)}`); | ||
|
||
let deployArgs = [conf.underlying, conf.comptroller, conf.interestRateModel, conf.initialExchangeRateMantissa.toString(), conf.name, conf.symbol, conf.decimals, conf.admin]; | ||
let contract = await saddle.deploy('CErc20Immutable', deployArgs); | ||
|
||
console.log(`Deployed contract to ${contract._address}`); | ||
|
||
if (env['VERIFY']) { | ||
const etherscanApiKey = env['ETHERSCAN_API_KEY']; | ||
if (etherscanApiKey === undefined || etherscanApiKey.length === 0) { | ||
throw new Error(`ETHERSCAN_API_KEY must be set if using VERIFY flag...`); | ||
} | ||
|
||
console.log(`Sleeping for 30 seconds then verifying contract on Etherscan...`); | ||
await sleep(30000); // Give Etherscan time to learn about contract | ||
console.log(`Now verifying contract on Etherscan...`); | ||
|
||
await saddle.verify(etherscanApiKey, contract._address, 'CErc20Immutable', deployArgs, 0); | ||
console.log(`Contract verified at https://${network}.etherscan.io/address/${contract._address}`); | ||
} | ||
|
||
return { | ||
...conf, | ||
address: contract._address | ||
}; | ||
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
let { loadAddress, loadConf } = require('./support/tokenConfig'); | ||
|
||
function printUsage() { | ||
console.log(` | ||
usage: npx saddle script token:match address {tokenConfig} | ||
This checks to see if the deployed byte-code matches this version of the Compound Protocol. | ||
example: | ||
npx saddle -n rinkeby script token:match 0x19B674715cD20626415C738400FDd0d32D6809B6 '{ | ||
"underlying": "0x577D296678535e4903D59A4C929B718e1D575e0A", | ||
"comptroller": "$Comptroller", | ||
"interestRateModel": "$Base200bps_Slope3000bps", | ||
"initialExchangeRateMantissa": "2.0e18", | ||
"name": "Compound Kyber Network Crystal", | ||
"symbol": "cKNC", | ||
"decimals": "8", | ||
"admin": "$Timelock" | ||
}' | ||
`); | ||
} | ||
|
||
(async function() { | ||
if (args.length !== 2) { | ||
return printUsage(); | ||
} | ||
|
||
let address = loadAddress(args[0], addresses); | ||
let conf = loadConf(args[1], addresses); | ||
if (!conf) { | ||
return printUsage(); | ||
} | ||
|
||
console.log(`Matching cToken at ${address} with ${JSON.stringify(conf)}`); | ||
|
||
let deployArgs = [conf.underlying, conf.comptroller, conf.interestRateModel, conf.initialExchangeRateMantissa.toString(), conf.name, conf.symbol, conf.decimals, conf.admin]; | ||
|
||
await saddle.match(address, 'CErc20Immutable', deployArgs); | ||
|
||
return { | ||
...conf, | ||
address | ||
}; | ||
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
|
||
function getRaw(config, key, required=true) { | ||
let value = config[key]; | ||
if (!value) { | ||
throw new Error(`Config missing required key \`${key}\``); | ||
} | ||
return value; | ||
} | ||
|
||
function getString(config, key, required=true) { | ||
let value = getRaw(config, key, required); | ||
if (value === "" && required) { | ||
throw new Error(`Config missing required key \`${key}\``); | ||
} | ||
return value || ""; | ||
} | ||
|
||
function loadAddress(value, addresses, errorMessage=null) { | ||
if (value.startsWith("$")) { | ||
let contract = value.slice(1,); | ||
let address = addresses[contract]; | ||
if (!address) { | ||
throw new Error(`Cannot find deploy address for \`${contract}\``); | ||
} | ||
return address; | ||
} else if (value.startsWith("0x")) { | ||
return value; | ||
} else { | ||
throw new Error(errorMessage || `Invalid address \`${value}\``); | ||
} | ||
} | ||
|
||
function getAddress(addresses, config, key, required=true) { | ||
let value = getString(config, key, required); | ||
return loadAddress( | ||
value, | ||
addresses, | ||
`Invalid address for \`${key}\`=${value}`, | ||
required | ||
); | ||
} | ||
|
||
function getNumber(config, key, required=true) { | ||
let value = getRaw(config, key, required); | ||
let result = Number(value); | ||
if (Number.isNaN(result)) { | ||
throw new Error(`Invalid number for \`${key}\`=${value}`); | ||
} else { | ||
return Number(result); | ||
} | ||
} | ||
|
||
function loadConf(configArg, addresses) { | ||
let config; | ||
if (!configArg) { | ||
return null; | ||
} | ||
|
||
try { | ||
config = JSON.parse(configArg) | ||
} catch (e) { | ||
console.log(); | ||
console.error(e); | ||
return null; | ||
} | ||
const conf = { | ||
underlying: getAddress(addresses, config, 'underlying'), | ||
comptroller: getAddress(addresses, config, 'comptroller'), | ||
interestRateModel: getAddress(addresses, config, 'interestRateModel'), | ||
initialExchangeRateMantissa: getNumber(config, 'initialExchangeRateMantissa'), | ||
name: getString(config, 'name'), | ||
symbol: getString(config, 'symbol'), | ||
decimals: getNumber(config, 'decimals'), | ||
admin: getAddress(addresses, config, 'admin'), | ||
}; | ||
|
||
return conf; | ||
} | ||
|
||
module.exports = { | ||
loadAddress, | ||
loadConf | ||
}; |
Oops, something went wrong.