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

Fix invite script by moving to contractkit #1645

Merged
merged 6 commits into from
Nov 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions packages/celotool/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
/lib/
.tmp

twilio-config.js
32 changes: 22 additions & 10 deletions packages/celotool/src/cmds/account/faucet.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { downloadArtifacts } from 'src/lib/artifacts'
import { switchToClusterFromEnv } from 'src/lib/cluster'
/* tslint:disable no-console */
import { newKit } from '@celo/contractkit'
import { convertToContractDecimals } from 'src/lib/contract-utils'
import { portForwardAnd } from 'src/lib/port_forward'
import { execCmd, validateAccountAddress } from 'src/lib/utils'
import { validateAccountAddress } from 'src/lib/utils'
import * as yargs from 'yargs'
import { AccountArgv } from '../account'

Expand All @@ -28,18 +29,29 @@ export const builder = (argv: yargs.Argv) => {
}

export const handler = async (argv: FaucetArgv) => {
await switchToClusterFromEnv()
const address = argv.account

const cb = async () => {
await execCmd(
// TODO(yerdua): reimplement the protocol transfer script here, using
// the SDK + Web3 when the SDK can be built for multiple environments
`yarn --cwd ../protocol run transfer -n ${argv.celoEnv} -a ${argv.account} -d 10 -g 10`
)
const kit = newKit('http://localhost:8545')
const account = (await kit.web3.eth.getAccounts())[0]
console.log(`Using account: ${account}`)
kit.defaultAccount = account

const [goldToken, stableToken] = await Promise.all([
kit.contracts.getGoldToken(),
kit.contracts.getStableToken(),
])
const goldAmount = (await convertToContractDecimals(1, goldToken)).toString()
const stableTokenAmount = (await convertToContractDecimals(10, stableToken)).toString()

console.log(`Fauceting ${goldAmount} Gold and ${stableTokenAmount} StableToken to ${address}`)
await Promise.all([
goldToken.transfer(address, goldAmount).sendAndWaitForReceipt(),
stableToken.transfer(address, stableTokenAmount).sendAndWaitForReceipt(),
])
}

try {
await downloadArtifacts(argv.celoEnv)
await portForwardAnd(argv.celoEnv, cb)
} catch (error) {
console.error(`Unable to faucet ${argv.account} on ${argv.celoEnv}`)
Expand Down
109 changes: 84 additions & 25 deletions packages/celotool/src/cmds/account/invite.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
/* tslint:disable no-console */
import { downloadArtifacts } from 'src/lib/artifacts'
import { switchToClusterFromEnv } from 'src/lib/cluster'
import { newKit } from '@celo/contractkit'
import { BigNumber } from 'bignumber.js'
import { convertToContractDecimals } from 'src/lib/contract-utils'
import { portForwardAnd } from 'src/lib/port_forward'
import { execCmd } from 'src/lib/utils'
import twilio from 'twilio'
import { Argv } from 'yargs'
import { AccountArgv } from '../account'

Expand All @@ -12,39 +14,96 @@ export const describe = 'command for sending an invite code to a phone number'

interface InviteArgv extends AccountArgv {
phone: string
fast: boolean
}

export const builder = (yargs: Argv) => {
return yargs
.option('phone', {
type: 'string',
description: 'Phone number to send invite code,',
demand: 'Please specify phone number to send invite code',
})
.option('fast', {
type: 'boolean',
default: false,
description: "Don't download artifacts, use this for repeated invocations",
demand: 'Please specify phone number to send invite code',
})
return yargs.option('phone', {
type: 'string',
description: 'Phone number to send invite code,',
demand: 'Please specify phone number to send invite code',
})
}

export const handler = async (argv: InviteArgv) => {
console.log(`Sending invitation code to ${argv.phone}`)
const phone = argv.phone

console.log(`Sending invitation code to ${phone}`)

// This key is only present in celo-testnet
await execCmd('gcloud config set project celo-testnet')
cmcewen marked this conversation as resolved.
Show resolved Hide resolved
await execCmd(
'gcloud kms decrypt --ciphertext-file=twilio-config.enc --plaintext-file=twilio-config.js \
--key=github-key --keyring=celo-keyring --location=global'
)
const cb = async () => {
await execCmd(
`yarn --cwd ../protocol run invite -n ${argv.celoEnv} -p ${argv.phone} -f ${argv.fast}`
const kit = newKit('http://localhost:8545')
const account = (await kit.web3.eth.getAccounts())[0]
console.log(`Using account: ${account}`)
kit.defaultAccount = account

// TODO(asa): This number was made up
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feels dangerous but I guess it's been working for us

const attestationGasAmount = new BigNumber(10000000)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty sure we can cut this and the gold related parts too

// TODO: this default gas price might not be accurate
const gasPrice = 100000000000

const temporaryWalletAccount = await kit.web3.eth.accounts.create()
const temporaryAddress = temporaryWalletAccount.address
// Buffer.from doesn't expect a 0x for hex input
const privateKeyHex = temporaryWalletAccount.privateKey.substring(2)
const inviteCode = Buffer.from(privateKeyHex, 'hex').toString('base64')

const [goldToken, stableToken, attestations, escrow] = await Promise.all([
kit.contracts.getGoldToken(),
kit.contracts.getStableToken(),
kit.contracts.getAttestations(),
kit.contracts.getEscrow(),
])
const attestationFee = new BigNumber(
await attestations.attestationRequestFees(stableToken.address)
)
const goldAmount = attestationGasAmount.times(gasPrice).toString()
const stableTokenInviteAmount = attestationFee.times(10).toString()
const stableTokenEscrowAmount = (await convertToContractDecimals(5, stableToken)).toString()

const phoneHash: string = kit.web3.utils.soliditySha3({
type: 'string',
value: phone,
})

await stableToken.approve(escrow.address, stableTokenEscrowAmount).sendAndWaitForReceipt()
const expirySeconds = 60 * 60 * 24 * 5 // 5 days

console.log(
`Transferring ${goldAmount} Gold, ${stableTokenInviteAmount} StableToken, and escrowing ${stableTokenEscrowAmount} StableToken`
)
await Promise.all([
// TODO: remove if no one is paying for gas with gold
goldToken.transfer(temporaryAddress, goldAmount).sendAndWaitForReceipt(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, i think your comment is right. The invite doesn't actually need to send gold.

stableToken.transfer(temporaryAddress, stableTokenInviteAmount).sendAndWaitForReceipt(),
escrow
.transfer(
phoneHash,
stableToken.address,
stableTokenEscrowAmount,
expirySeconds,
temporaryAddress,
0
)
.sendAndWaitForReceipt(),
])
console.log(`Temp address: ${temporaryAddress}`)
console.log(`Invite code: ${inviteCode}`)
const messageText = `Hi! I would like to invite you to join the Celo payments network. Your invite code is: ${inviteCode}`
console.log('Sending SMS...')
const twilioConfig = require('twilio-config')
const twilioClient = twilio(twilioConfig.sid, twilioConfig.authToken)
await twilioClient.messages.create({
body: messageText,
from: twilioConfig.phoneNumber,
to: argv.phone,
})
}
try {
if (argv.fast) {
console.log(`Fast mode is on, cluster won't be switched, artifacts won't be downloaded`)
} else {
console.log(`Fast mode is off, artifacts will be downloaded`)
await switchToClusterFromEnv(false)
await downloadArtifacts(argv.celoEnv)
}
await portForwardAnd(argv.celoEnv, cb)
} catch (error) {
console.error(`Unable to send invitation code to ${argv.phone}`)
Expand Down
12 changes: 12 additions & 0 deletions packages/celotool/src/lib/contract-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { GoldTokenWrapper } from '@celo/contractkit/lib/wrappers/GoldTokenWrapper'
import { StableTokenWrapper } from '@celo/contractkit/lib/wrappers/StableTokenWrapper'
import { BigNumber } from 'bignumber.js'

export async function convertToContractDecimals(
value: number | BigNumber,
contract: StableTokenWrapper | GoldTokenWrapper
) {
const decimals = new BigNumber(await contract.decimals())
const one = new BigNumber(10).pow(decimals.toNumber())
return one.times(value)
}
Binary file added packages/celotool/twilio-config.enc
Binary file not shown.
11 changes: 6 additions & 5 deletions packages/contractkit/src/contract-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { AccountsWrapper } from './wrappers/Accounts'
import { AttestationsWrapper } from './wrappers/Attestations'
import { BlockchainParametersWrapper } from './wrappers/BlockchainParameters'
import { ElectionWrapper } from './wrappers/Election'
import { EscrowWrapper } from './wrappers/Escrow'
import { ExchangeWrapper } from './wrappers/Exchange'
import { GasPriceMinimumWrapper } from './wrappers/GasPriceMinimum'
import { GoldTokenWrapper } from './wrappers/GoldTokenWrapper'
Expand All @@ -19,7 +20,7 @@ const WrapperFactories = {
[CeloContract.Attestations]: AttestationsWrapper,
[CeloContract.BlockchainParameters]: BlockchainParametersWrapper,
[CeloContract.Election]: ElectionWrapper,
// [CeloContract.Escrow]: EscrowWrapper,
[CeloContract.Escrow]: EscrowWrapper,
[CeloContract.Exchange]: ExchangeWrapper,
// [CeloContract.GasCurrencyWhitelist]: GasCurrencyWhitelistWrapper,
[CeloContract.GasPriceMinimum]: GasPriceMinimumWrapper,
Expand All @@ -43,7 +44,7 @@ interface WrapperCacheMap {
[CeloContract.Attestations]?: AttestationsWrapper
[CeloContract.BlockchainParameters]?: BlockchainParametersWrapper
[CeloContract.Election]?: ElectionWrapper
// [CeloContract.Escrow]?: EscrowWrapper,
[CeloContract.Escrow]?: EscrowWrapper
[CeloContract.Exchange]?: ExchangeWrapper
// [CeloContract.GasCurrencyWhitelist]?: GasCurrencyWhitelistWrapper,
[CeloContract.GasPriceMinimum]?: GasPriceMinimumWrapper
Expand Down Expand Up @@ -82,9 +83,9 @@ export class WrapperCache {
getElection() {
return this.getContract(CeloContract.Election)
}
// getEscrow() {
// return this.getWrapper(CeloContract.Escrow, newEscrow)
// }
getEscrow() {
return this.getContract(CeloContract.Escrow)
}
getExchange() {
return this.getContract(CeloContract.Exchange)
}
Expand Down
23 changes: 23 additions & 0 deletions packages/contractkit/src/wrappers/Escrow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Escrow } from '../generated/types/Escrow'
import { BaseWrapper, proxyCall, proxySend } from './BaseWrapper'

/**
* Contract for handling reserve for stable currencies
*/
export class EscrowWrapper extends BaseWrapper<Escrow> {
escrowedPayments = proxyCall(this.contract.methods.escrowedPayments)

receivedPaymentIds = proxyCall(this.contract.methods.receivedPaymentIds)

sentPaymentIds = proxyCall(this.contract.methods.sentPaymentIds)

getReceivedPaymentIds = proxyCall(this.contract.methods.sentPaymentIds)

getSentPaymentId = proxyCall(this.contract.methods.sentPaymentIds)

transfer = proxySend(this.kit, this.contract.methods.transfer)

withdraw = proxySend(this.kit, this.contract.methods.withdraw)

revoke = proxySend(this.kit, this.contract.methods.revoke)
}