Skip to content

Commit

Permalink
Merge branch 'master' into martinvol/wallet-automatic-country
Browse files Browse the repository at this point in the history
  • Loading branch information
martinvol authored Oct 15, 2019
2 parents 91e1b04 + 35b9cd2 commit cf552fd
Show file tree
Hide file tree
Showing 11 changed files with 297 additions and 39 deletions.
3 changes: 3 additions & 0 deletions packages/celotool/src/e2e-tests/transfer_tests.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// tslint:disable-next-line: no-reference (Required to make this work w/ ts-node)
/// <reference path="../../../contractkit/types/web3.d.ts" />

import { CeloContract, CeloToken, ContractKit, newKit, newKitFromWeb3 } from '@celo/contractkit'
import { TransactionResult } from '@celo/contractkit/lib/utils/tx-result'
import { toFixed } from '@celo/utils/lib/fixidity'
Expand Down
4 changes: 2 additions & 2 deletions packages/celotool/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"@google-cloud/monitoring": ["types/monitoring"]
}
},
"include": ["src/"],
"include": ["src", "../contractkit/types"],
"exclude": ["node_modules/"],
"references": [{ "path": "../utils" }]
"references": [{ "path": "../utils" }, { "path": "../contractkit" }]
}
29 changes: 23 additions & 6 deletions packages/cli/src/commands/validatorgroup/member.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,32 @@ export default class ValidatorGroupRegister extends BaseCommand {
...BaseCommand.flags,
from: Flags.address({ required: true, description: "ValidatorGroup's address" }),
accept: flags.boolean({
exclusive: ['remove'],
exclusive: ['remove', 'reorder'],
description: 'Accept a validator whose affiliation is already set to the group',
}),
remove: flags.boolean({
exclusive: ['accept'],
exclusive: ['accept', 'reorder'],
description: 'Remove a validator from the members list',
}),
reorder: flags.integer({
exclusive: ['accept', 'remove'],
description: 'Reorder a validator within the members list',
}),
}

static args: IArg[] = [Args.address('validatorAddress', { description: "Validator's address" })]

static examples = [
'member --accept 0x97f7333c51897469e8d98e7af8653aab468050a3 ',
'member --remove 0x47e172f6cfb6c7d01c1574fa3e2be7cc73269d95',
'member --reorder 3 0x47e172f6cfb6c7d01c1574fa3e2be7cc73269d95',
]

async run() {
const res = this.parse(ValidatorGroupRegister)

if (!(res.flags.accept || res.flags.remove)) {
this.error(`Specify action: --accept or --remove`)
if (!(res.flags.accept || res.flags.remove || res.flags.reorder)) {
this.error(`Specify action: --accept, --remove or --reorder`)
return
}

Expand All @@ -40,8 +45,20 @@ export default class ValidatorGroupRegister extends BaseCommand {

if (res.flags.accept) {
await displaySendTx('addMember', validators.addMember((res.args as any).validatorAddress))
} else {
await displaySendTx('addMember', validators.removeMember((res.args as any).validatorAddress))
} else if (res.flags.remove) {
await displaySendTx(
'removeMember',
validators.removeMember((res.args as any).validatorAddress)
)
} else if (res.flags.reorder != null) {
await displaySendTx(
'reorderMember',
await validators.reorderMember(
res.flags.from,
(res.args as any).validatorAddress,
res.flags.reorder
)
)
}
}
}
6 changes: 5 additions & 1 deletion packages/cli/src/utils/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ import Table from 'cli-table'
import { cli } from 'cli-ux'
import { Tx } from 'web3/eth/types'

export async function displaySendTx<A>(name: string, txObj: CeloTransactionObject<A>, tx?: Tx) {
export async function displaySendTx<A>(
name: string,
txObj: CeloTransactionObject<A>,
tx?: Omit<Tx, 'data'>
) {
cli.action.start(`Sending Transaction: ${name}`)
const txResult = await txObj.send(tx)

Expand Down
4 changes: 2 additions & 2 deletions packages/cli/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
"esModuleInterop": true,
"target": "es6"
},
"include": ["src"],
"references": [{ "path": "../utils" }]
"include": ["src", "../contractkit/types"],
"references": [{ "path": "../utils" }, { "path": "../contractkit" }]
}
8 changes: 4 additions & 4 deletions packages/contractkit/src/wrappers/Attestations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import {
proxySend,
toBigNumber,
toNumber,
toTransactionObject,
tupleParser,
wrapSend,
} from './BaseWrapper'
const parseSignature = SignatureUtils.parseSignature

Expand Down Expand Up @@ -206,7 +206,7 @@ export class AttestationsWrapper extends BaseWrapper<Attestations> {
const phoneHash = PhoneNumberUtils.getPhoneHash(phoneNumber)
const expectedSourceMessage = attestationMessageToSign(phoneHash, account)
const { r, s, v } = parseSignature(expectedSourceMessage, code, issuer.toLowerCase())
return wrapSend(this.kit, this.contract.methods.complete(phoneHash, v, r, s))
return toTransactionObject(this.kit, this.contract.methods.complete(phoneHash, v, r, s))
}

/**
Expand Down Expand Up @@ -305,7 +305,7 @@ export class AttestationsWrapper extends BaseWrapper<Attestations> {
async request(phoneNumber: string, attestationsRequested: number, token: CeloToken) {
const phoneHash = PhoneNumberUtils.getPhoneHash(phoneNumber)
const tokenAddress = await this.kit.registry.addressFor(token)
return wrapSend(
return toTransactionObject(
this.kit,
this.contract.methods.request(phoneHash, attestationsRequested, tokenAddress)
)
Expand All @@ -332,7 +332,7 @@ export class AttestationsWrapper extends BaseWrapper<Attestations> {
Buffer.from(phoneNumber, 'utf8')
).toString('hex')

return wrapSend(
return toTransactionObject(
this.kit,
this.contract.methods.reveal(
PhoneNumberUtils.getPhoneHash(phoneNumber),
Expand Down
41 changes: 24 additions & 17 deletions packages/contractkit/src/wrappers/BaseWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,6 @@ export abstract class BaseWrapper<T extends Contract> {
}
}

export interface CeloTransactionObject<O> {
/** web3 native TransactionObject. Normally not used */
txo: TransactionObject<O>
/** send the transaction to the chain */
send(params?: Omit<Tx, 'data'>): Promise<TransactionResult>
/** send the transaction and waits for the receipt */
sendAndWaitForReceipt(params?: Omit<Tx, 'data'>): Promise<TransactionReceipt>
}

/** Parse string -> BigNumber */
export function toBigNumber(input: string) {
return new BigNumber(input)
Expand Down Expand Up @@ -205,18 +196,34 @@ export function proxySend<InputArgs extends any[], ParsedInputArgs extends any[]
if (sendArgs.length === 2) {
const methodFn = sendArgs[0]
const preParse = sendArgs[1]
return (...args: InputArgs) => wrapSend(kit, methodFn(...preParse(...args)))
return (...args: InputArgs) => toTransactionObject(kit, methodFn(...preParse(...args)))
} else {
const methodFn = sendArgs[0]
return (...args: InputArgs) => wrapSend(kit, methodFn(...args))
return (...args: InputArgs) => toTransactionObject(kit, methodFn(...args))
}
}

export function wrapSend<O>(kit: ContractKit, txo: TransactionObject<O>): CeloTransactionObject<O> {
return {
send: (params?: Omit<Tx, 'data'>) => kit.sendTransactionObject(txo, params),
txo,
sendAndWaitForReceipt: (params?: Omit<Tx, 'data'>) =>
kit.sendTransactionObject(txo, params).then((result) => result.waitReceipt()),
export function toTransactionObject<O>(
kit: ContractKit,
txo: TransactionObject<O>,
defaultParams?: Omit<Tx, 'data'>
): CeloTransactionObject<O> {
return new CeloTransactionObject(kit, txo, defaultParams)
}

export class CeloTransactionObject<O> {
constructor(
private kit: ContractKit,
readonly txo: TransactionObject<O>,
readonly defaultParams?: Omit<Tx, 'data'>
) {}

/** send the transaction to the chain */
send = (params?: Omit<Tx, 'data'>): Promise<TransactionResult> => {
return this.kit.sendTransactionObject(this.txo, { ...this.defaultParams, ...params })
}

/** send the transaction and waits for the receipt */
sendAndWaitForReceipt = (params?: Omit<Tx, 'data'>): Promise<TransactionReceipt> =>
this.send(params).then((result) => result.waitReceipt())
}
19 changes: 17 additions & 2 deletions packages/contractkit/src/wrappers/LockedGold.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
proxyCall,
proxySend,
toBigNumber,
wrapSend,
toTransactionObject,
} from '../wrappers/BaseWrapper'

export interface VotingDetails {
Expand Down Expand Up @@ -117,6 +117,21 @@ export class LockedGoldWrapper extends BaseWrapper<LockedGold> {
*/
isVoting = proxyCall(this.contract.methods.isVoting)

/**
* Check if an account already exists.
* @param account The address of the account
* @return Returns `true` if account exists. Returns `false` otherwise.
* In particular it will return `false` if a delegate with given address exists.
*/
isAccount = proxyCall(this.contract.methods.isAccount)

/**
* Check if a delegate already exists.
* @param account The address of the delegate
* @return Returns `true` if delegate exists. Returns `false` otherwise.
*/
isDelegate = proxyCall(this.contract.methods.isDelegate)

/**
* Query maximum notice period.
* @returns Current maximum notice period.
Expand Down Expand Up @@ -226,7 +241,7 @@ export class LockedGoldWrapper extends BaseWrapper<LockedGold> {
role: Roles
): Promise<CeloTransactionObject<void>> {
const sig = await this.getParsedSignatureOfAddress(account, delegate)
return wrapSend(
return toTransactionObject(
this.kit,
this.contract.methods.delegateRole(role, delegate, sig.v, sig.r, sig.s)
)
Expand Down
139 changes: 139 additions & 0 deletions packages/contractkit/src/wrappers/Validators.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import Web3 from 'web3'
import { newKitFromWeb3 } from '../kit'
import { testWithGanache } from '../test-utils/ganache-test'
import { LockedGoldWrapper } from './LockedGold'
import { ValidatorsWrapper } from './Validators'

/*
TEST NOTES:
- In migrations: The only account that has cUSD is accounts[0]
*/

const minLockedGoldValue = Web3.utils.toWei('100', 'ether') // 1 gold
const minLockedGoldNoticePeriod = 120 * 24 * 60 * 60 // 120 days

// A random 64 byte hex string.
const publicKey =
'ea0733ad275e2b9e05541341a97ee82678c58932464fad26164657a111a7e37a9fa0300266fb90e2135a1f1512350cb4e985488a88809b14e3cbe415e76e82b2'
const blsPublicKey =
'4d23d8cd06f30b1fa7cf368e2f5399ab04bb6846c682f493a98a607d3dfb7e53a712bb79b475c57b0ac2785460f91301'
const blsPoP =
'9d3e1d8f49f6b0d8e9a03d80ca07b1d24cf1cc0557bdcc04f5e17a46e35d02d0d411d956dbd5d2d2464eebd7b74ae30005d223780d785d2abc5644fac7ac29fb0e302bdc80c81a5d45018b68b1045068a4b3a4861c93037685fd0d252d740501'

const publicKeysData = '0x' + publicKey + blsPublicKey + blsPoP

testWithGanache('Validators Wrapper', (web3) => {
const kit = newKitFromWeb3(web3)
let accounts: string[] = []
let validators: ValidatorsWrapper
let lockedGold: LockedGoldWrapper

const registerAccountWithCommitment = async (account: string) => {
// console.log('isAccount', )
// console.log('isDelegate', await lockedGold.isDelegate(account))

if (!(await lockedGold.isAccount(account))) {
await lockedGold.createAccount().sendAndWaitForReceipt({ from: account })
}
await lockedGold
.newCommitment(minLockedGoldNoticePeriod)
.sendAndWaitForReceipt({ from: account, value: minLockedGoldValue })
}

beforeAll(async () => {
accounts = await web3.eth.getAccounts()
validators = await kit.contracts.getValidators()
lockedGold = await kit.contracts.getLockedGold()
})

const setupGroup = async (groupAccount: string) => {
await registerAccountWithCommitment(groupAccount)
await validators
.registerValidatorGroup('thegroup', 'The Group', 'thegroup.com', [minLockedGoldNoticePeriod])
.sendAndWaitForReceipt({ from: groupAccount })
}

const setupValidator = async (validatorAccount: string) => {
await registerAccountWithCommitment(validatorAccount)
// set account1 as the validator
await validators
.registerValidator(
'goodoldvalidator',
'Good old validator',
'goodold.com',
// @ts-ignore
publicKeysData,
[minLockedGoldNoticePeriod]
)
.sendAndWaitForReceipt({ from: validatorAccount })
}

test('SBAT registerValidatorGroup', async () => {
const groupAccount = accounts[0]
await setupGroup(groupAccount)
await expect(validators.isValidatorGroup(groupAccount)).resolves.toBe(true)
})

test('SBAT registerValidator', async () => {
const validatorAccount = accounts[1]
await setupValidator(validatorAccount)
await expect(validators.isValidator(validatorAccount)).resolves.toBe(true)
})

test('SBAT addMember', async () => {
const groupAccount = accounts[0]
const validatorAccount = accounts[1]
await setupGroup(groupAccount)
await setupValidator(validatorAccount)
await validators.affiliate(groupAccount).sendAndWaitForReceipt({ from: validatorAccount })
await validators.addMember(validatorAccount).sendAndWaitForReceipt({ from: groupAccount })

const members = await validators.getValidatorGroup(groupAccount).then((group) => group.members)
expect(members).toContain(validatorAccount)
})

describe('SBAT reorderMember', () => {
let groupAccount: string, validator1: string, validator2: string

beforeEach(async () => {
groupAccount = accounts[0]
await setupGroup(groupAccount)

validator1 = accounts[1]
validator2 = accounts[2]

for (const validator of [validator1, validator2]) {
await setupValidator(validator)
await validators.affiliate(groupAccount).sendAndWaitForReceipt({ from: validator })
await validators.addMember(validator).sendAndWaitForReceipt({ from: groupAccount })
}

const members = await validators
.getValidatorGroup(groupAccount)
.then((group) => group.members)
expect(members).toEqual([validator1, validator2])
})

test('move last to first', async () => {
await validators
.reorderMember(groupAccount, validator2, 0)
.then((x) => x.sendAndWaitForReceipt())

const membersAfter = await validators
.getValidatorGroup(groupAccount)
.then((group) => group.members)
expect(membersAfter).toEqual([validator2, validator1])
})

test('move first to last', async () => {
await validators
.reorderMember(groupAccount, validator1, 1)
.then((x) => x.sendAndWaitForReceipt())

const membersAfter = await validators
.getValidatorGroup(groupAccount)
.then((group) => group.members)
expect(membersAfter).toEqual([validator2, validator1])
})
})
})
Loading

0 comments on commit cf552fd

Please sign in to comment.