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

Support governance proposals/hotfixes in contractkit #1570

Closed
wants to merge 71 commits into from
Closed
Show file tree
Hide file tree
Changes from 56 commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
2811be4
Add toBuffer transformer to BaseWrapper
yorhodes Nov 3, 2019
0494f9d
Add Proposal and Transaction interaction to GovernanceWrapper
yorhodes Nov 3, 2019
7943754
Add propose function
yorhodes Nov 3, 2019
1a18c77
Add hotfix functions to Governance wrapper
yorhodes Nov 3, 2019
2e823a9
Add upvote function to Governance wrapper
yorhodes Nov 3, 2019
bb4629b
Add approve, vote, and execute functions to Governance wrapper
yorhodes Nov 3, 2019
808de6b
Add TODOs for using proxyCall and proxySend
yorhodes Nov 3, 2019
a589e82
Transition to using proxyCall
yorhodes Nov 4, 2019
03602a0
Add tests for propose
yorhodes Nov 4, 2019
08c0022
Add test stubs
yorhodes Nov 4, 2019
ef4c57a
Add transaction construction to test stubs
yorhodes Nov 4, 2019
74ee751
Fix hotfix tests
yorhodes Nov 5, 2019
8ab8896
Add revokeUpvote
yorhodes Nov 5, 2019
9051b02
Make test hotfix and proposal transaction results different
yorhodes Nov 5, 2019
f0a6413
Fix lesser and greater calcualtion
yorhodes Nov 5, 2019
a709598
Fix formatting
yorhodes Nov 5, 2019
57ef8c8
Remove proposal index input
yorhodes Nov 5, 2019
e866228
Remove proposal index from params
yorhodes Nov 5, 2019
90e6ee2
Add json transaction builder and tests
yorhodes Nov 6, 2019
f64bf8c
Fix proposal tests with locked gold
yorhodes Nov 7, 2019
7f0fdf1
Fix tests
yorhodes Nov 7, 2019
2d86caa
Add TransactionBuilder
yorhodes Nov 7, 2019
833ed19
Add map utilities to tx builder
yorhodes Nov 7, 2019
fc7ce7b
Add doc strings
yorhodes Nov 7, 2019
8c84218
Update tests to work with tx builder
yorhodes Nov 7, 2019
b45a333
Add validator registration for hotfix tests
yorhodes Nov 8, 2019
7417a81
Merge branch 'master' of github.com:celo-org/celo-monorepo into yorho…
yorhodes Nov 8, 2019
858a6bf
Add encoded prop to tx builder
yorhodes Nov 8, 2019
a38070d
Make concurrencyMap calls safer
yorhodes Nov 8, 2019
7a0290b
Fix tests
yorhodes Nov 8, 2019
9b59cd5
Address some PR comments
yorhodes Nov 9, 2019
5870fd5
Significant improvements to tx builder
yorhodes Nov 9, 2019
11ae01d
Updates to wrapper interfaces
yorhodes Nov 9, 2019
370b17d
Improve typings
yorhodes Nov 9, 2019
9c3afb2
Remove imports from wrapper to builder
yorhodes Nov 10, 2019
fbf7cbc
Implement json on PTXOProposal
yorhodes Nov 11, 2019
da2c8e7
Simplify proposal utilities
yorhodes Nov 11, 2019
bb8c4be
Fix lint
yorhodes Nov 11, 2019
f970ccd
Increase jest timeout
yorhodes Nov 11, 2019
c9ee368
Fix lint
yorhodes Nov 11, 2019
f2faa20
Merge hotfix and proposal utility
yorhodes Nov 12, 2019
14fe0bc
Dedupe address functions
yorhodes Nov 12, 2019
6b90778
Use expressive names for wrappers
yorhodes Nov 12, 2019
fc84210
Use lambdas in basewrapper functions
yorhodes Nov 12, 2019
0ebd845
Add numberLikeToFrac helper to base wrapper
yorhodes Nov 12, 2019
5e77364
Fix tslint disable
yorhodes Nov 12, 2019
ceb4e2a
Fix lint
yorhodes Nov 12, 2019
48a963e
improvements for toSolidityBytes
yorhodes Nov 12, 2019
e2454c4
Use block explorer parser in proposal utility
yorhodes Nov 12, 2019
98ad376
Make timeout test specific
yorhodes Nov 12, 2019
30a603e
Merge branch 'master' of github.com:celo-org/celo-monorepo into yorho…
yorhodes Nov 13, 2019
a59cf12
Remove static builder class
yorhodes Nov 13, 2019
63ed59d
Fix lint
yorhodes Nov 13, 2019
1327fa5
Fix contractkit explorer types
yorhodes Nov 14, 2019
1e133b2
Add doc strings and fix migration override
yorhodes Nov 14, 2019
b0c2c4f
Fix migration config merging
yorhodes Nov 14, 2019
3df97c6
Revert migration changes and disable validator dependent tests
yorhodes Nov 15, 2019
c6e58b2
Fix utils usage
yorhodes Nov 15, 2019
527718e
Fix explorer args
yorhodes Nov 15, 2019
9fed3f5
Merge branch 'master' of github.com:celo-org/celo-monorepo into yorho…
yorhodes Nov 15, 2019
fe00b39
Merge branch 'master' of github.com:celo-org/celo-monorepo into yorho…
yorhodes Nov 17, 2019
8f427cf
Fix lint
yorhodes Nov 17, 2019
96033e5
Cleanup
yorhodes Nov 17, 2019
2d768cd
Disable tests
yorhodes Nov 18, 2019
7373ad7
Further disable tests
yorhodes Nov 22, 2019
eed93e8
Address Nam's PR comments
yorhodes Nov 22, 2019
138308a
Improve utils with hexToBuffer
yorhodes Nov 22, 2019
6f3c771
Merge branch 'master' of github.com:celo-org/celo-monorepo into yorho…
yorhodes Nov 22, 2019
afb1428
Fix style in tests
yorhodes Nov 22, 2019
1e4716d
Updates to ProposalBuilder interface
yorhodes Nov 25, 2019
a1c3abb
Fix bugs
yorhodes Nov 26, 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
18 changes: 18 additions & 0 deletions packages/contractkit/src/explorer/base.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Address } from '@celo/utils/lib/address'
import { concurrentMap } from '@celo/utils/lib/async'
import { ABIDefinition } from 'web3/eth/abi'
import { Block, Transaction } from 'web3/eth/types'
import { AllContracts } from '../base'
import { ContractKit } from '../kit'

Expand All @@ -10,6 +11,23 @@ export interface ContractDetails {
jsonInterface: ABIDefinition[]
}

export interface CallDetails {
contract: string
function: string
parameters: Record<string, any>
args: any[]
yorhodes marked this conversation as resolved.
Show resolved Hide resolved
}

export interface ParsedTx {
callDetails: CallDetails
tx: Transaction
}

export interface ParsedBlock {
block: Block
parsedTx: ParsedTx[]
}

export async function obtainKitContractDetails(kit: ContractKit) {
return concurrentMap(5, AllContracts, async (celoContract) => {
const contract = await kit._web3Contracts.getContract(celoContract)
Expand Down
43 changes: 17 additions & 26 deletions packages/contractkit/src/explorer/block-explorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,14 @@ import { Address } from '@celo/utils/lib/address'
import abi, { ABIDefinition } from 'web3-eth-abi'
import { Block, Transaction } from 'web3/eth/types'
import { ContractKit } from '../kit'
import { ContractDetails, mapFromPairs, obtainKitContractDetails } from './base'

export interface CallDetails {
contract: string
function: string
parameters: Record<string, any>
}

export interface ParsedTx {
callDetails: CallDetails
tx: Transaction
}

export interface ParsedBlock {
block: Block
parsedTx: ParsedTx[]
}
import {
CallDetails,
ContractDetails,
mapFromPairs,
obtainKitContractDetails,
ParsedBlock,
ParsedTx,
} from './base'

interface ContractMapping {
details: ContractDetails
Expand Down Expand Up @@ -93,23 +84,23 @@ export class BlockExplorer {
return null
}

const parameters: Record<string, any> = abi.decodeParameters(
matchedAbi.inputs!,
encodedParameters
)
const parameters = abi.decodeParameters(matchedAbi.inputs!, encodedParameters)

// remove number & number keys
// build args from number keys
// remove number keys from parameters
const argKeys = Array.from(Array(parameters.__length__).keys())
delete parameters.__length__
Object.keys(parameters).forEach((key) => {
if (Number.parseInt(key, 10) >= 0) {
delete parameters[key]
}
const args = argKeys.map((argKey) => {
const arg = parameters[argKey]
delete parameters[argKey]
yorhodes marked this conversation as resolved.
Show resolved Hide resolved
return arg
yorhodes marked this conversation as resolved.
Show resolved Hide resolved
})

const callDetails: CallDetails = {
contract: contractMapping.details.name,
function: matchedAbi.name!,
parameters,
args,
}

return {
Expand Down
17 changes: 0 additions & 17 deletions packages/contractkit/src/explorer/log-explorer.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,9 @@
import { Address } from '@celo/utils/lib/address'
import abi, { ABIDefinition } from 'web3-eth-abi'
import { Block, Transaction } from 'web3/eth/types'
import { EventLog, Log, TransactionReceipt } from 'web3/types'
import { ContractKit } from '../kit'
import { ContractDetails, mapFromPairs, obtainKitContractDetails } from './base'

export interface CallDetails {
contract: string
function: string
parameters: Record<string, any>
}

export interface ParsedTx {
callDetails: CallDetails
tx: Transaction
}

export interface ParsedBlock {
block: Block
parsedTx: ParsedTx[]
}

interface ContractMapping {
details: ContractDetails
logMapping: Map<string, ABIDefinition>
Expand Down
1 change: 1 addition & 0 deletions packages/contractkit/src/governance/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './proposals'
96 changes: 96 additions & 0 deletions packages/contractkit/src/governance/proposals.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { concurrentMap } from '@celo/utils/lib/async'
import { keccak256 } from 'ethereumjs-util'
import Contract from 'web3/eth/contract'
import { Transaction, TransactionObject } from 'web3/eth/types'
import { AllContracts, CeloContract } from '../base'
import { obtainKitContractDetails } from '../explorer/base'
import { BlockExplorer } from '../explorer/block-explorer'
import { ContractKit } from '../kit'
import { CeloTransactionObject, valueToString } from '../wrappers/BaseWrapper'
import { Proposal, ProposalTransaction } from '../wrappers/Governance'

export interface ProposalTransactionJSON {
contract: CeloContract
function: string
args: any[]
value: string
}

export class ProposalUtility extends Proposal {
yorhodes marked this conversation as resolved.
Show resolved Hide resolved
constructor(transactions: ProposalTransaction[], private readonly kit: ContractKit) {
super(transactions)
}

static fromProposalAndKit(proposal: Proposal, kit: ContractKit) {
return new ProposalUtility(proposal.transactions, kit)
}

get hash(): Buffer {
const paramsEncoded = this.kit.web3.eth.abi.encodeParameters(
['uint256[]', 'address[]', 'bytes', 'uint256[]'],
yorhodes marked this conversation as resolved.
Show resolved Hide resolved
this.params
)
return keccak256(paramsEncoded) as Buffer
}

async json(): Promise<ProposalTransactionJSON[]> {
const contractDetails = await obtainKitContractDetails(this.kit)
const blockExplorer = new BlockExplorer(this.kit, contractDetails)

return concurrentMap(1, this.transactions, async (transaction) => {
const parsedTx = blockExplorer.tryParseTx(transaction as Transaction)
if (parsedTx == null) {
throw new Error(`Unable to parse ${transaction} with block explorer`)
}
return {
contract: parsedTx.callDetails.contract as CeloContract,
function: parsedTx.callDetails.function,
args: parsedTx.callDetails.args,
value: parsedTx.tx.value,
}
})
}
}

type ProposalTxParams = Pick<ProposalTransaction, 'to' | 'value'>
export function proposalTxFromWeb3Txo(
tx: TransactionObject<any>,
params: Required<ProposalTxParams>
): ProposalTransaction {
return {
value: params.value,
to: params.to,
input: tx.encodeABI(),
}
}

export function proposalTxFromCeloTxo(
tx: CeloTransactionObject<any>,
params: Partial<ProposalTxParams> = {}
) {
const to = tx.defaultParams && tx.defaultParams.to ? tx.defaultParams.to : params.to
const value = tx.defaultParams && tx.defaultParams.value ? tx.defaultParams.value : params.value
if (!to || !value) {
throw new Error("Transaction parameters 'to' and/or 'value' not provided")
}
return proposalTxFromWeb3Txo(tx.txo, { to, value: valueToString(value) })
}

export async function proposalTxFromJSONAndKit(tx: ProposalTransactionJSON, kit: ContractKit) {
yorhodes marked this conversation as resolved.
Show resolved Hide resolved
const contractName = tx.contract
if (!AllContracts.includes(contractName)) {
throw new Error(`Contract ${contractName} not found`)
}

const contract = await kit._web3Contracts.getContract(contractName)
const methodName = tx.function
const method = (contract.methods as Contract['methods'])[methodName]
if (!method) {
throw new Error(`Method ${methodName} not found on ${contractName}`)
}
const txo = method(tx.args)
if (!txo) {
throw new Error(`Arguments ${tx.args} did not match ${methodName} signature`)
}
return proposalTxFromWeb3Txo(txo, { to: contract._address, value: tx.value })
}
4 changes: 4 additions & 0 deletions packages/contractkit/src/test-utils/ganache-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ export function jsonRpcCall<O>(web3: Web3, method: string, params: any[]): Promi
)
})
}
export async function timeTravel(seconds: number, web3: Web3) {
await jsonRpcCall(web3, 'evm_increaseTime', [seconds])
await jsonRpcCall(web3, 'evm_mine', [])
}

export function evmRevert(web3: Web3, snapId: string): Promise<void> {
return jsonRpcCall(web3, 'evm_revert', [snapId])
Expand Down
43 changes: 41 additions & 2 deletions packages/contractkit/src/test-utils/migration-override.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,53 @@
{
"stableToken": {
"initialBalances": {
"addresses": ["0x5409ed021d9299bf6814279a6a1411a7e866a631"],
"values": ["10000000000000000000000"]
"addresses": [
"0x5409ED021D9299bf6814279A6A1411A7e866A631",
"0x6Ecbe1DB9EF729CBe972C83Fb886247691Fb6beb",
"0xE36Ea790bc9d7AB70C55260C66D52b1eca985f84",
"0xE834EC434DABA538cd1b9Fe1582052B880BD7e63",
"0x78dc5D2D739606d31509C31d654056A45185ECb6",
"0xA8dDa8d7F5310E4A9E24F8eBA77E091Ac264f872",
"0x06cEf8E666768cC40Cc78CF93d9611019dDcB628",
"0x4404ac8bd8F9618D27Ad2f1485AA1B2cFD82482D",
"0x7457d5E02197480Db681D3fdF256c7acA21bDc12",
"0x91c987bf62D25945dB517BDAa840A6c661374402"
],
"values": [
"50000000000000000000000",
"50000000000000000000000",
"50000000000000000000000",
"50000000000000000000000",
"50000000000000000000000",
"50000000000000000000000",
"50000000000000000000000",
"50000000000000000000000",
"50000000000000000000000",
"50000000000000000000000"
]
},
"oracles": [
"0x5409ED021D9299bf6814279A6A1411A7e866A631",
"0xE36Ea790bc9d7AB70C55260C66D52b1eca985f84",
"0x06cEf8E666768cC40Cc78CF93d9611019dDcB628",
"0x7457d5E02197480Db681D3fdF256c7acA21bDc12"
]
},
"validators": {
"validatorKeys": [
"0x83c6d2cc5ddcf9711a6d59b417dc20eb48afd58d45290099e5987e3d768f328f",
"0xbb2d3f7c9583780a7d3904a2f55d792707c345f21de1bacb2d389934d82796b2",
"0xb2fd4d29c1390b71b8795ae81196bfd60293adf99f9d32a0aff06288fcdac55f",
"0x23cb7121166b9a2f93ae0b7c05bde02eae50d64449b2cbb42bc84e9d38d6cc89"
]
},
"governance": {
"dequeueFrequency": 30,
"queueExpiry": 101,
"approvalStageDuration": 103,
"referendumStageDuration": 104,
"executionStageDuration": 105,
"concurrentProposals": 2,
"minDeposit": 1
}
}
28 changes: 14 additions & 14 deletions packages/contractkit/src/wrappers/Attestations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ import { ClaimTypes, IdentityMetadataWrapper } from '../identity'
import {
BaseWrapper,
proxyCall,
toBigNumber,
toNumber,
toTransactionObject,
tupleParser,
valueToBigNumber,
valueToInt,
} from './BaseWrapper'

const parseSignature = SignatureUtils.parseSignature

export interface AttestationStat {
Expand Down Expand Up @@ -68,11 +69,11 @@ interface GetCompletableAttestationsResponse {
}
function parseGetCompletableAttestations(response: GetCompletableAttestationsResponse) {
const metadataURLs = parseSolidityStringArray(
response[2].map(toNumber),
response[2].map(valueToInt),
(response[3] as unknown) as string
)

return zip3(response[0].map(toNumber), response[1], metadataURLs).map(
return zip3(response[0].map(valueToInt), response[1], metadataURLs).map(
([blockNumber, issuer, metadataURL]) => ({ blockNumber, issuer, metadataURL })
)
}
Expand All @@ -85,7 +86,7 @@ export class AttestationsWrapper extends BaseWrapper<Attestations> {
attestationExpiryBlocks = proxyCall(
this.contract.methods.attestationExpiryBlocks,
undefined,
toNumber
valueToInt
)

/**
Expand All @@ -96,13 +97,13 @@ export class AttestationsWrapper extends BaseWrapper<Attestations> {
attestationRequestFees = proxyCall(
this.contract.methods.attestationRequestFees,
undefined,
toBigNumber
valueToBigNumber
)

selectIssuersWaitBlocks = proxyCall(
this.contract.methods.selectIssuersWaitBlocks,
undefined,
toNumber
valueToInt
)

/**
Expand All @@ -114,8 +115,8 @@ export class AttestationsWrapper extends BaseWrapper<Attestations> {
this.contract.methods.getUnselectedRequest,
tupleParser(PhoneNumberUtils.getPhoneHash, (x: string) => x),
(res) => ({
blockNumber: toNumber(res[0]),
attestationsRequested: toNumber(res[1]),
blockNumber: valueToInt(res[0]),
attestationsRequested: valueToInt(res[1]),
attestationRequestFeeToken: res[2],
})
)
Expand Down Expand Up @@ -180,7 +181,7 @@ export class AttestationsWrapper extends BaseWrapper<Attestations> {
) => Promise<AttestationStat> = proxyCall(
this.contract.methods.getAttestationStats,
tupleParser(PhoneNumberUtils.getPhoneHash, stringIdentity),
(stat) => ({ completed: toNumber(stat[0]), total: toNumber(stat[1]) })
(stat) => ({ completed: valueToInt(stat[0]), total: valueToInt(stat[1]) })
)

/**
Expand Down Expand Up @@ -314,11 +315,10 @@ export class AttestationsWrapper extends BaseWrapper<Attestations> {
// Unfortunately can't be destructured
const stats = await this.contract.methods.batchGetAttestationStats(phoneNumberHashes).call()

const toNum = (n: string) => new BigNumber(n).toNumber()
const matches = stats[0].map(toNum)
const matches = stats[0].map(valueToInt)
const addresses = stats[1]
const completed = stats[2].map(toNum)
const total = stats[3].map(toNum)
const completed = stats[2].map(valueToInt)
const total = stats[3].map(valueToInt)
// Map of phone hash -> (Map of address -> AttestationStat)
const result: Record<string, Record<string, AttestationStat>> = {}

Expand Down
Loading