Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setup oracle account, Add CLI commands to report oracle values #1394

Closed
wants to merge 67 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
76d9eea
sketch of some tests
yerdua Oct 8, 2019
f3bb54a
Fix and add a test for a bug that prevented the most recent oracle
yerdua Oct 10, 2019
1f39bf5
add new account type for oracle
yerdua Sep 30, 2019
a985430
whitelist oracle account in the migration
yerdua Oct 2, 2019
93ecc51
try to get the migration to do the right thing
yerdua Sep 30, 2019
e896e0d
adding to oracle wrapper
yerdua Oct 7, 2019
37bb712
remove some console.log
yerdua Oct 7, 2019
1dfba9f
wip
mcortesi Oct 7, 2019
711daca
more experimentation to get things to work
yerdua Oct 8, 2019
badcb62
add report function to sorted oracles wrapper
yerdua Oct 11, 2019
c3d9c6c
Merge branch 'master' into yerdua/price-oracle-with-brownian-motion
yerdua Oct 14, 2019
7f775ed
try to figure out what this 'fix' is actually doing
yerdua Oct 14, 2019
7d2ea2e
flesh out the sorted oracles wrapper and tests
yerdua Oct 17, 2019
2c4a2ea
stop hardcoding oracles in stabletoken migration. make network config…
yerdua Oct 17, 2019
55b9999
use new contract kit version in cli
yerdua Oct 18, 2019
fcede62
Merge branch 'master' into yerdua/price-oracle-with-brownian-motion
yerdua Oct 18, 2019
44cf9a7
pull all the contractkit work out of #1394
yerdua Oct 18, 2019
5d45823
Merge branch 'master' into yerdua/sorted-oracles-wrapper-contractkit
yerdua Oct 18, 2019
e5fee87
don't need to use ts-ignore if you fill an empty block with a comment
yerdua Oct 18, 2019
86c1a57
start with an empty array for priceOracleAccounts just to have this c…
yerdua Oct 18, 2019
1459059
I don't know how versioning works
yerdua Oct 21, 2019
c9054dc
bump version of contractkit
yerdua Oct 21, 2019
234ce6f
bumping the version isn't necessary
yerdua Oct 21, 2019
a66ad18
Merge branch 'yerdua/sorted-oracles-wrapper-contractkit' into yerdua/…
yerdua Oct 21, 2019
e63721d
cleanup messy merge
yerdua Oct 21, 2019
a7d27b0
pass in the oracle address to report from, rather than relying on kit…
yerdua Oct 21, 2019
0aa7fd3
tests that the numerator/denominator division happens
yerdua Oct 21, 2019
60992ab
simplify test expectations - use expected string values
yerdua Oct 21, 2019
9ec4eb4
Merge branch 'yerdua/sorted-oracles-wrapper-contractkit' into yerdua/…
yerdua Oct 21, 2019
8104395
cleanup some accidental changes
yerdua Oct 21, 2019
f905bed
remove hardcoded test address
yerdua Oct 22, 2019
219d992
Merge branch 'master' into yerdua/price-oracle-with-brownian-motion
yerdua Oct 22, 2019
203875c
Merge branch 'master' into yerdua/sorted-oracles-wrapper-contractkit
yerdua Oct 22, 2019
dbf985e
Merge branch 'yerdua/sorted-oracles-wrapper-contractkit' into yerdua/…
yerdua Oct 22, 2019
0434e81
Merge branch 'master' into yerdua/sorted-oracles-wrapper-contractkit
yerdua Oct 22, 2019
97ca105
Merge branch 'master' into yerdua/price-oracle-with-brownian-motion
yerdua Oct 22, 2019
3077458
Merge branch 'master' into yerdua/sorted-oracles-wrapper-contractkit
yerdua Oct 22, 2019
be794b1
numRates can just be a number, rather than a BigNumber
yerdua Oct 22, 2019
61da582
Merge branch 'yerdua/sorted-oracles-wrapper-contractkit' into yerdua/…
yerdua Oct 22, 2019
3b11ca6
Merge branch 'master' into yerdua/price-oracle-with-brownian-motion
yerdua Oct 23, 2019
e033ad8
use more recent celo-blockchain/geth commit
yerdua Oct 23, 2019
41bb953
add cli command to report oracle values
yerdua Oct 23, 2019
0f33f0b
Merge branch 'master' into yerdua/price-oracle-with-brownian-motion
yerdua Oct 23, 2019
32b2076
undo modification of old exchange rates file
yerdua Oct 23, 2019
bb5f3c4
Merge branch 'master' into yerdua/price-oracle-with-brownian-motion
yerdua Oct 24, 2019
b369e5d
go back to numerator + denominator for report command. add a command …
yerdua Oct 25, 2019
66c1ef6
Merge branch 'master' into yerdua/price-oracle-with-brownian-motion
yerdua Oct 25, 2019
8a7f1fc
Merge branch 'master' into yerdua/price-oracle-with-brownian-motion
yerdua Oct 25, 2019
9e4a35c
add bash script to report exchange rates from a csv
yerdua Oct 25, 2019
c5503de
Merge branch 'master' into yerdua/price-oracle-with-brownian-motion
yerdua Oct 28, 2019
5b0c405
report script in python because it's faster, especially for later tim…
yerdua Oct 28, 2019
9a71081
Merge branch 'master' into yerdua/price-oracle-with-brownian-motion
yerdua Oct 31, 2019
735f127
Merge branch 'master' into yerdua/price-oracle-with-brownian-motion
yerdua Oct 31, 2019
9387cb5
Merge branch 'master' into yerdua/price-oracle-with-brownian-motion
yerdua Nov 1, 2019
8655b66
this shouldn't live here
yerdua Nov 1, 2019
650f41a
Merge branch 'master' into yerdua/price-oracle-with-brownian-motion
yerdua Nov 4, 2019
ffa3dd6
Merge branch 'master' into yerdua/price-oracle-with-brownian-motion
yerdua Nov 4, 2019
99d2bd1
fix issues in cli commands. add celotool command because cli hangs fo…
yerdua Nov 7, 2019
d927e93
Merge branch 'master' into yerdua/price-oracle-with-brownian-motion
yerdua Nov 7, 2019
cb21e7d
Merge branch 'master' into yerdua/price-oracle-with-brownian-motion
Nov 8, 2019
3e77289
run command within cluster
Nov 12, 2019
8189da8
get host ip dynamically
yerdua Nov 12, 2019
83cda5f
Merge branch 'master' into yerdua/price-oracle-with-brownian-motion
yerdua Nov 13, 2019
b4479c0
Merge branch 'master' into yerdua/price-oracle-with-brownian-motion
yerdua Nov 14, 2019
d3790ac
close the web3 connection in cli, even if local accounts have been added
yerdua Nov 14, 2019
f31a604
command to add local-signing accounts to the cli
yerdua Nov 14, 2019
94d7bb2
update cli docs
yerdua Nov 14, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/celotool/src/cmds/deploy/initial/contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export const handler = async (argv: InitialArgv) => {
() => '60000000000000000000000'
), // 60k Celo Dollars
},
oracles: getAddressesFor(AccountType.PRICE_ORACLE, mnemonic, 1),
},
})

Expand Down
99 changes: 99 additions & 0 deletions packages/celotool/src/cmds/report_oracle_value.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { CeloContract, CeloToken, newKit } from '@celo/contractkit'
import BigNumber from 'bignumber.js'
import { switchToClusterFromEnv } from 'src/lib/cluster'
import { addCeloEnvMiddleware, CeloEnvArgv, envVar, fetchEnv } from 'src/lib/env-utils'
import { AccountType, generatePrivateKey, privateKeyToAddress } from 'src/lib/generate_utils'
import { portForwardAnd } from 'src/lib/port_forward'
import * as yargs from 'yargs'

export const command = 'report-oracle-value'

interface ReportOracleValueArgv extends CeloEnvArgv {
token: string
price: number
// oracleAccount: string
runWithPortForward: boolean
}

export const builder = (argv: yargs.Argv) => {
return addCeloEnvMiddleware(argv)
.option('token', {
type: 'string',
description: 'Celo Token in which to report the price of 1 Celo Gold',
default: 'StableToken',
})
.option('price', {
type: 'number',
description: 'The price of 1 Celo Gold in the specified token (float values allowed)',
demand: 'Please specify the price of 1 Celo Gold',
})
.option('runWithPortForward', {
type: 'boolean',
description:
'Specify whether this command should be run port-forwarded, or is running within the cluster. Default is true',
default: true,
})
}

export const handler = async (argv: ReportOracleValueArgv) => {
if (argv.runWithPortForward) {
await switchToClusterFromEnv(false)

try {
await portForwardAnd(argv.celoEnv, reportCmd.bind(null, argv))
console.info('finished with the portforwarding???')
} catch (error) {
console.error(`Unable to report value of ${argv.token}`)
console.error(error.error)
process.exit(1)
}
} else {
try {
await reportCmd(argv)
} catch (error) {
console.error(`Unable to report value of ${argv.token}`)
console.error(error.error)
process.exit(1)
}
}
process.exit()
}

async function reportCmd(argv: ReportOracleValueArgv) {
let token: CeloToken
if (argv.token === CeloContract.StableToken) {
token = CeloContract.StableToken
} else {
console.error(`${argv.token} is not a valid token to report upon`)
process.exit(1)
return
}

let numerator = new BigNumber(argv.price)
let denominator = new BigNumber(1)

if (numerator.decimalPlaces() > 0) {
denominator = new BigNumber(10).pow(numerator.decimalPlaces())
numerator = numerator.multipliedBy(denominator)
}

const hostEnvVar = `${argv.celoEnv.toUpperCase()}_SERVICE_0_TCP_SERVICE_HOST`
const kit = newKit(`http://${fetchEnv(hostEnvVar)}:8545`)
const mnemonic = fetchEnv(envVar.MNEMONIC)
// TODO: switch this to the right account type after deploying testnet
// Or, don't hardcode this at all.
const oracleKey = generatePrivateKey(mnemonic, AccountType.ATTESTATION, 0)
kit.addAccount(oracleKey)
const oracleAddress = privateKeyToAddress(oracleKey)

const sortedOracles = await kit.contracts.getSortedOracles()
const tx = await sortedOracles.report(
token,
numerator.toNumber(),
denominator.toNumber(),
oracleAddress
)

await tx.sendAndWaitForReceipt()
console.info(`Reported the price of ${argv.price} ${argv.token} for 1 Celo Gold`)
}
6 changes: 5 additions & 1 deletion packages/celotool/src/lib/generate_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export enum AccountType {
BOOTNODE = 3,
FAUCET = 4,
ATTESTATION = 5,
PRICE_ORACLE = 6,
}

export enum ConsensusType {
Expand All @@ -47,6 +48,7 @@ export const MNEMONIC_ACCOUNT_TYPE_CHOICES = [
'bootnode',
'faucet',
'attestation',
'price_oracle',
]

export const add0x = (str: string) => {
Expand Down Expand Up @@ -143,11 +145,13 @@ export const generateGenesisFromEnv = (enablePetersburg: boolean = true) => {
// Assing DEFAULT ammount of gold to 2 faucet accounts
const faucetAddresses = getStrippedAddressesFor(AccountType.FAUCET, mnemonic, 2)

const oracleAddress = getStrippedAddressesFor(AccountType.PRICE_ORACLE, mnemonic, 1)

return generateGenesis({
validators,
consensusType,
blockTime,
initialAccounts: faucetAddresses,
initialAccounts: faucetAddresses.concat(oracleAddress),
epoch,
chainId,
requestTimeout,
Expand Down
14 changes: 12 additions & 2 deletions packages/cli/src/base.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { ContractKit, newKitFromWeb3 } from '@celo/contractkit'
import { CeloProvider, ContractKit, newKitFromWeb3 } from '@celo/contractkit'
import { Command, flags } from '@oclif/command'
import Web3 from 'web3'
import { getNodeUrl } from './utils/config'
import { injectDebugProvider } from './utils/eth-debug-provider'
import { requireNodeIsSynced } from './utils/helpers'
import { addKeysToKit } from './utils/local_accounts'

export abstract class BaseCommand extends Command {
static flags = {
Expand Down Expand Up @@ -46,6 +47,7 @@ export abstract class BaseCommand extends Command {
if (this.requireSynced) {
await requireNodeIsSynced(this.web3)
}
addKeysToKit(this.kit, this.config.configDir)
}

// TODO(yorke): implement log(msg) switch on logLevel with chalk colored output
Expand All @@ -59,8 +61,16 @@ export abstract class BaseCommand extends Command {

finally(arg: Error | undefined): Promise<any> {
try {
// Close the web3 connection or the CLI hangs forever.
// If local-signing accounts are added, the debug wrapper is itself wrapped
// with a CeloProvider. This class has a stop() function that handles closing
// the connection for underlying providers
if (this.web3.currentProvider instanceof CeloProvider) {
const celoProvider = this.web3.currentProvider as CeloProvider
celoProvider.stop()
}

if (this._originalProvider && this._originalProvider.hasOwnProperty('connection')) {
// Close the web3 connection or the CLI hangs forever.
const connection = this._originalProvider.connection
if (connection.hasOwnProperty('_connection')) {
connection._connection.close()
Expand Down
31 changes: 31 additions & 0 deletions packages/cli/src/commands/localaccounts/add.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { cli } from 'cli-ux'
import * as fs from 'fs-extra'
// import * as path from 'path'
import { BaseCommand } from '../../base'
import { addPrivateKeyToConfig } from '../../utils/local_accounts'

export default class AddLocalAccount extends BaseCommand {
static description = 'Add a private key to locally sign transactions from an account'

static args = [
{
name: 'keyPath',
required: true,
description: 'Private key to add',
},
]

async run() {
const res = this.parse(AddLocalAccount)
try {
const absolutePath = fs.realpathSync(res.args.keyPath)
const key = fs.readFileSync(absolutePath).toString()
this.kit.addAccount(key)

addPrivateKeyToConfig(this.config.configDir, absolutePath)
} catch (error) {
cli.info('Failed to add private key')
cli.error(error)
}
}
}
33 changes: 33 additions & 0 deletions packages/cli/src/commands/oracle/rates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { CeloContract } from '@celo/contractkit'
import { cli } from 'cli-ux'
import { BaseCommand } from '../../base'

export default class GetRates extends BaseCommand {
static description = 'Get the current set oracle-reported rates for the given token'

static flags = {
...BaseCommand.flags,
}

static args = [
{
name: 'token',
required: true,
description: 'Token to get the rates for',
options: [CeloContract.StableToken],
},
]

static example = ['rates StableToken']

async run() {
const res = this.parse(GetRates)
const sortedOracles = await this.kit.contracts.getSortedOracles()

const rates = await sortedOracles.getRates(res.args.token)
cli.table(rates, {
address: {},
rate: { get: (r) => r.rate.toNumber() },
})
}
}
64 changes: 64 additions & 0 deletions packages/cli/src/commands/oracle/report.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { CeloContract } from '@celo/contractkit'
import { flags } from '@oclif/command'
import BigNumber from 'bignumber.js'
import { BaseCommand } from '../../base'
import { displaySendTx } from '../../utils/cli'
import { Flags } from '../../utils/command'

export default class ReportPrice extends BaseCommand {
static description =
'Report the price of Celo Gold in a specified token (currently just Celo Dollar, aka: "StableToken")'

static args = [
{
name: 'token',
required: true,
description: 'Token to report on',
options: [CeloContract.StableToken],
},
]
static flags = {
...BaseCommand.flags,
from: Flags.address({ required: true, description: 'Address of the oracle account' }),
numerator: flags.string({
required: true,
description: 'Amount of the specified token equal to the amount of cGLD in the denominator',
}),
denominator: flags.string({
required: false,
description: 'Amount of cGLD equal to the numerator. Defaults to 1 if left blank',
}),
}

static example = [
'report --token StableToken --numerator 1.02 --from 0x8c349AAc7065a35B7166f2659d6C35D75A3893C1',
'report --token StableToken --numerator 102 --denominator 100 --from 0x8c349AAc7065a35B7166f2659d6C35D75A3893C1',
]

async run() {
const res = this.parse(ReportPrice)
const sortedOracles = await this.kit.contracts.getSortedOracles()
let numerator = new BigNumber(res.flags.numerator)
let denominator = new BigNumber(res.flags.denominator || 1)
if (numerator.decimalPlaces() > 0) {
const multiplier = new BigNumber(10).pow(numerator.decimalPlaces()).toNumber()
numerator = numerator.multipliedBy(multiplier)
denominator = denominator.multipliedBy(multiplier)
}

await displaySendTx(
'sortedOracles.report',
await sortedOracles.report(
res.args.token,
numerator.toNumber(),
denominator.toNumber(),
res.flags.from
)
)
this.log(
`Reported oracle value of ${numerator.div(denominator).toNumber()} ${
res.args.token
} for 1 CeloGold`
)
}
}
42 changes: 42 additions & 0 deletions packages/cli/src/utils/local_accounts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { ContractKit } from '@celo/contractkit'
import * as fs from 'fs-extra'
import * as path from 'path'

export interface CeloLocalKeys {
files: string[]
}

const keyFileList = 'keys.json'

export const defaultKeyList: CeloLocalKeys = {
files: [],
}

export function keyListPath(configDir: string) {
return path.join(configDir, keyFileList)
}

export function addKeysToKit(kit: ContractKit, configDir: string) {
const keyPaths = readKeyList(configDir)

for (const kp of keyPaths.files) {
if (fs.pathExistsSync(kp)) {
kit.addAccount(fs.readFileSync(kp).toString())
} else {
console.error(`no key found at ${kp}, skipping...`)
}
}
}

export function readKeyList(configDir: string): CeloLocalKeys {
if (fs.pathExistsSync(keyListPath(configDir))) {
return fs.readJSONSync(keyListPath(configDir))
} else {
return defaultKeyList
}
}

export function addPrivateKeyToConfig(configDir: string, keyPath: string) {
const existingFiles = readKeyList(configDir).files
fs.writeJSONSync(keyListPath(configDir), { files: existingFiles.concat(keyPath) })
}
1 change: 1 addition & 0 deletions packages/contractkit/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Web3 from 'web3'
export { Address, AllContracts, CeloContract, CeloToken, NULL_ADDRESS } from './base'
export { IdentityMetadataWrapper } from './identity'
export * from './kit'
export { CeloProvider } from './providers/celo-provider'
export { CeloTransactionObject } from './wrappers/BaseWrapper'

/**
Expand Down
19 changes: 19 additions & 0 deletions packages/docs/command-line-interface/localaccounts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
description: Add a private key to locally sign transactions from an account
---

## Commands

### Add

Add a private key to locally sign transactions from an account

```
USAGE
$ celocli localaccounts:add KEYPATH

ARGUMENTS
KEYPATH Private key to add
```

_See code: [packages/cli/src/commands/localaccounts/add.ts](https://github.com/celo-org/celo-monorepo/tree/master/packages/cli/src/commands/localaccounts/add.ts)_
Loading