Skip to content

Commit

Permalink
add topup test case
Browse files Browse the repository at this point in the history
  • Loading branch information
yuetloo committed Jan 27, 2024
1 parent aff548d commit 6db892e
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 48 deletions.
11 changes: 10 additions & 1 deletion contracts/cli/addRecipients.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* HARDHAT_NETWORK=localhost yarn ts-node clr/addRecipients.ts <ClrFund address>
*
*/
import { getEventArg } from '@clrfund/common'
import { program } from 'commander'
import { ethers } from 'hardhat'

Expand All @@ -29,7 +30,7 @@ async function main(args: any) {
)

let numAdded = 0
for (let i = 6; i < 10; i++) {
for (let i = 1; i < 3; i++) {
const recipient = recipients[i]
const recipientAddress = recipient?.address || signer.address
const addRecipientTx = await recipientRegistry.addRecipient(
Expand All @@ -44,6 +45,14 @@ async function main(args: any) {
const receipt = await addRecipientTx.wait()
if (receipt.status === 1) {
numAdded++

const recipientIndex = await getEventArg(
addRecipientTx,
recipientRegistry,
'RecipientAdded',
'_index'
)
console.log('Added recipient index', recipientIndex)
} else {
console.log('Failed to add recipient', i)
}
Expand Down
58 changes: 32 additions & 26 deletions contracts/cli/claim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,26 @@ import { JSONFile } from '../utils/JSONFile'
import { ethers } from 'hardhat'
import { program } from 'commander'
import { isPathExist } from '../utils/misc'
import { Contract, getNumber } from 'ethers'
import { getNumber } from 'ethers'

program
.description('Claim funnds for test recipients')
.requiredOption(
'-f --funding-round <fundingRoundAddress>',
'-f, --funding-round <fundingRoundAddress>',
'The funding round contract address'
)
.requiredOption('-t --tally-file <file>', 'The tally file')
.requiredOption('-r, --recipient-index <index>', 'The recipient index')
.requiredOption('-t, --tally-file <file>', 'The tally file')
.option('-a, --amount <amount>', 'The expected claim amount to verify')
.parse()

async function main(args: any) {
const { fundingRound, tallyFile } = args
const [, , recipient0, recipient1, recipient2] = await ethers.getSigners()
const { fundingRound, tallyFile, recipientIndex, amount } = args
console.log('recipientIndex', recipientIndex)

if (!isPathExist(tallyFile)) {
throw new Error(`Path ${tallyFile} does not exist`)
}

const tally = JSONFile.read(tallyFile)

const fundingRoundContract = await ethers.getContractAt(
Expand All @@ -47,26 +48,31 @@ async function main(args: any) {
)

// Claim funds
const recipients = [recipient0, recipient1, recipient2]
for (const recipientIndex of [1, 2]) {
const recipientClaimData = getRecipientClaimData(
recipientIndex,
recipientTreeDepth,
tally
)
const fundingRoundAsRecipient = fundingRoundContract.connect(
recipients[recipientIndex]
) as Contract
const claimTx = await fundingRoundAsRecipient.claimFunds(
...recipientClaimData
)
const claimedAmount = await getEventArg(
claimTx,
fundingRoundAsRecipient,
'FundsClaimed',
'_amount'
)
console.log(`Recipient ${recipientIndex} claimed ${claimedAmount} tokens.`)
const recipientClaimData = getRecipientClaimData(
getNumber(recipientIndex),
recipientTreeDepth,
tally
)
const claimTx = await fundingRoundContract.claimFunds(...recipientClaimData)
const receipt = await claimTx.wait()
if (receipt.status !== 1) {
throw new Error('Failed claimFunds()')
}
const claimedAmount = await getEventArg(
claimTx,
fundingRoundContract,
'FundsClaimed',
'_amount'
)

console.log(
`Recipient ${recipientIndex} claimed ${claimedAmount} tokens. Gas used: ${receipt.gasUsed}`
)

if (amount) {
if (BigInt(claimedAmount) !== BigInt(amount)) {
throw new Error(`Expected claim amount ${amount} got ${claimedAmount}`)
}
}
}

Expand Down
45 changes: 35 additions & 10 deletions contracts/cli/contribute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { program } from 'commander'
import { ethers } from 'hardhat'
import { isPathExist } from '../utils/misc'
import type { FundingRound, ERC20 } from '../typechain-types'
import { BaseContract } from 'ethers'

program
.description('Contribute to a funding round')
Expand All @@ -36,7 +37,10 @@ async function main(args: any) {
state.fundingRound
)
const tokenAddress = await fundingRound.nativeToken()
const token = await ethers.getContractAt('AnyOldERC20Token', tokenAddress)
const token = (await ethers.getContractAt(
'AnyOldERC20Token',
tokenAddress
)) as BaseContract as ERC20
const maciAddress = await fundingRound.maci()
const maci = await ethers.getContractAt('MACI', maciAddress)

Expand All @@ -47,11 +51,22 @@ async function main(args: any) {
const contributorAddress = await contributor.getAddress()

// transfer token to contributor first
await token.transfer(contributorAddress, contributionAmount)
const tx = await token.transfer(contributorAddress, contributionAmount)
const transferReciept = await tx.wait()
if (transferReciept?.status !== 1) {
throw new Error('Failed token.transfer()')
}

const contributorKeypair = new Keypair()
const tokenAsContributor = token.connect(contributor) as ERC20
await tokenAsContributor.approve(fundingRound.target, contributionAmount)
const approveTx = await tokenAsContributor.approve(
fundingRound.target,
contributionAmount
)
const approveReceipt = await approveTx.wait()
if (approveReceipt?.status !== 1) {
throw new Error('Failed token.approve()')
}

const fundingRoundAsContributor = fundingRound.connect(
contributor
Expand All @@ -60,27 +75,37 @@ async function main(args: any) {
contributorKeypair.pubKey.asContractParam(),
contributionAmount
)
const receipt = await contributionTx.wait()
if (receipt?.status !== 1) {
throw new Error('Failed contribute()')
}

const stateIndex = await getEventArg(
contributionTx,
maci,
'SignUp',
'_stateIndex'
)
const voiceCredits = await getEventArg(
const amount = await getEventArg(
contributionTx,
maci,
'SignUp',
'_voiceCreditBalance'
fundingRound,
'Contribution',
'_amount'
)
console.log('saving states')

console.log('saving states with amount', amount)
state.contributors[contributorAddress] = {
privKey: contributorKeypair.privKey.serialize(),
pubKey: contributorKeypair.pubKey.serialize(),
stateIndex: parseInt(stateIndex),
voiceCredits: voiceCredits.toString(),
amount: amount.toString(),
}

const totalGasUsed =
transferReciept.gasUsed + approveReceipt.gasUsed + receipt.gasUsed
console.log(
`Contributor ${contributorAddress} registered. State index: ${stateIndex}. Voice credits: ${voiceCredits.toString()}.`
`Contributor ${contributorAddress} registered. State index: ${stateIndex}. Contribution: ${amount}}. ` +
`Gas used: ${totalGasUsed}`
)
}

Expand Down
43 changes: 34 additions & 9 deletions contracts/cli/vote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@ import { ethers } from 'hardhat'
import { program } from 'commander'
import dotenv from 'dotenv'
import { isPathExist } from '../utils/misc'
import { AbiCoder } from 'ethers'
import { FundingRound } from '../typechain-types'

dotenv.config()

const abiCoder = new AbiCoder()
program
.description('Cast votes for test users')
.argument('stateFile', 'The file to store the state information')
Expand All @@ -45,10 +48,17 @@ async function main(args: any) {
const state = JSONFile.read(stateFile)
const coordinatorKeyPair = new Keypair(PrivKey.deserialize(coordinatorMacisk))

const fundingRound = await ethers.getContractAt(
'FundingRound',
state.fundingRound
)

const pollId = state.pollId
for (const contributor of [contributor1, contributor2]) {
const contributorAddress = await contributor.getAddress()
const contributorData = state.contributors[contributorAddress]
const address = await contributor.getAddress()
const contributorData = state.contributors[address]
const data = abiCoder.encode(['address'], [address])
const voiceCredits = await fundingRound.getVoiceCredits(address, data)
const contributorKeyPair = new Keypair(
PrivKey.deserialize(contributorData.privKey)
)
Expand All @@ -71,9 +81,10 @@ async function main(args: any) {
messages.push(message)
encPubKeys.push(encPubKey)
nonce += 1

// Vote
for (const recipientIndex of [1, 2]) {
const votes = BigInt(contributorData.voiceCredits) / BigInt(4)
const votes = voiceCredits / BigInt(2)
const [message, encPubKey] = createMessage(
contributorData.stateIndex,
newContributorKeypair,
Expand All @@ -87,19 +98,33 @@ async function main(args: any) {
messages.push(message)
encPubKeys.push(encPubKey)
nonce += 1
console.log(
`Contributor ${address} votes ${votes} for recipient ${recipientIndex}`
)
}

const fundingRoundAsContributor = await ethers.getContractAt(
'FundingRound',
state.fundingRound,
const fundingRoundAsContributor = fundingRound.connect(
contributor
)
await fundingRoundAsContributor.submitMessageBatch(
) as FundingRound

const tx = await fundingRoundAsContributor.submitMessageBatch(
messages.reverse().map((msg) => msg.asContractParam()),
encPubKeys.reverse().map((key) => key.asContractParam())
)
console.log(`Contributor ${contributorAddress} voted.`)
const receipt = await tx.wait()
if (receipt?.status !== 1) {
throw new Error('Failed submitMessageBatch()')
}
console.log('Gas used:', receipt.gasUsed)

state.contributors[address].privKey =
newContributorKeypair.privKey.serialize()
state.contributors[address].pubKey =
newContributorKeypair.pubKey.serialize()
}

// Update state file with new key
JSONFile.update(stateFile, state)
}

main(program.args)
Expand Down
16 changes: 15 additions & 1 deletion contracts/sh/runScriptTests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ yarn ts-node cli/addRecipients.ts "${CLRFUND}"
yarn ts-node cli/contribute.ts ${STATE_FILE}
yarn ts-node cli/vote.ts ${STATE_FILE}

yarn ts-node cli/topup.ts ${STATE_FILE}
yarn ts-node cli/vote.ts ${STATE_FILE}

yarn ts-node cli/timeTravel.ts ${ROUND_DURATION}

# run the tally script
Expand All @@ -72,5 +75,16 @@ yarn ts-node cli/finalize.ts --clrfund "${CLRFUND}" --tally-file ${TALLY_FILE}

# claim funds
FUNDING_ROUND=$(extract 'fundingRound')
yarn ts-node cli/claim.ts --funding-round "${FUNDING_ROUND}" --tally-file ${TALLY_FILE}

# amount should be 3200000000000000000 but there's rounding error in division by
# voice credit factor and sqrt for the vote weight
yarn ts-node cli/claim.ts --funding-round "${FUNDING_ROUND}" \
--recipient-index 1 \
--amount 3199999999999999999 \
--tally-file ${TALLY_FILE}

yarn ts-node cli/claim.ts --funding-round "${FUNDING_ROUND}" \
--recipient-index 2 \
--amount 3199999999999999999 \
--tally-file ${TALLY_FILE}

2 changes: 1 addition & 1 deletion contracts/utils/JSONFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export class JSONFile {
} catch {
state = {}
}
fs.writeFileSync(path, JSON.stringify({ ...state, ...data }, null, 2))
fs.writeFileSync(path, JSON.stringify({ ...state, ...data }, replacer, 2))
}

/**
Expand Down

0 comments on commit 6db892e

Please sign in to comment.