diff --git a/package.json b/package.json index ecabc60e0..3f394cf1c 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "private": true, "scripts": { "preinstall": "git config --global url.\"https://\".insteadOf ssh://", - "lint": "yarn lerna run lint && yarn run --silent lint:do-not-merge", + "lint": "yarn lerna run lint && yarn run lint:do-not-merge", "lint:do-not-merge": "git grep -E 'DO[ _]*NOT[ _]*MERGE';", "prettify": "yarn run prettier --config .prettierrc.js --write '**/*.+(ts|tsx|js|jsx|sol|java)'", "prettify:diff": "yarn run prettier --config .prettierrc.js --list-different '**/*.+(ts|tsx|js|jsx|sol|java)'", diff --git a/packages/cli/.eslintrc.js b/packages/cli/.eslintrc.js index 8cad82329..bfd2057be 100644 --- a/packages/cli/.eslintrc.js +++ b/packages/cli/.eslintrc.js @@ -1,6 +1,3 @@ module.exports = { extends: '../../.eslintrc.js', - // the releasegold folder is a symlink of releasecelo - // can't add a .eslintignore since it'd ignore the src folder - ignorePatterns: ['**/commands/releasegold/*'], } diff --git a/packages/cli/src/commands/releasegold/admin-revoke.test.ts b/packages/cli/src/commands/releasegold/admin-revoke.test.ts deleted file mode 100644 index 1371f2c64..000000000 --- a/packages/cli/src/commands/releasegold/admin-revoke.test.ts +++ /dev/null @@ -1,183 +0,0 @@ -import { newReleaseGold } from '@celo/abis/web3/ReleaseGold' -import { serializeSignature } from '@celo/base/lib/signatureUtils' -import { ContractKit, newKitFromWeb3 } from '@celo/contractkit' -import { AccountsWrapper } from '@celo/contractkit/lib/wrappers/Accounts' -import { GovernanceWrapper } from '@celo/contractkit/lib/wrappers/Governance' -import { ReleaseGoldWrapper } from '@celo/contractkit/lib/wrappers/ReleaseGold' -import { - getContractFromEvent, - NetworkConfig, - testWithGanache, - timeTravel, -} from '@celo/dev-utils/lib/ganache-test' -import Web3 from 'web3' -import { testLocally } from '../../test-utils/cliUtils' -import Approve from '../governance/approve' -import GovernanceUpvote from '../governance/upvote' -import GovernanceVote from '../governance/vote' -import AdminRevoke from './admin-revoke' -import Authorize from './authorize' -import CreateAccount from './create-account' -import LockedGold from './locked-gold' - -process.env.NO_SYNCCHECK = 'true' - -testWithGanache('releasegold:admin-revoke cmd', (web3: Web3) => { - let kit: ContractKit - let contractAddress: string - let releaseGoldWrapper: ReleaseGoldWrapper - let accounts: string[] - - beforeEach(async () => { - contractAddress = await getContractFromEvent( - 'ReleaseGoldInstanceCreated(address,address)', - web3, - { index: 1 } // revocable: true - ) - kit = newKitFromWeb3(web3) - releaseGoldWrapper = new ReleaseGoldWrapper( - kit.connection, - newReleaseGold(web3, contractAddress), - kit.contracts - ) - accounts = await web3.eth.getAccounts() - }) - - test('will revoke', async () => { - await testLocally(AdminRevoke, ['--contract', contractAddress, '--yesreally']) - const revokedContract = await getContractFromEvent( - 'ReleaseScheduleRevoked(uint256,uint256)', - web3 - ) - expect(revokedContract).toBe(contractAddress) - }) - - test('will rescue all cUSD balance', async () => { - const stableToken = await kit.contracts.getStableToken() - await stableToken.transfer(contractAddress, 100).send({ - from: accounts[0], - }) - await testLocally(AdminRevoke, ['--contract', contractAddress, '--yesreally']) - const balance = await stableToken.balanceOf(contractAddress) - expect(balance.isZero()).toBeTruthy() - }) - - test('will refund and finalize', async () => { - await testLocally(AdminRevoke, ['--contract', contractAddress, '--yesreally']) - const destroyedContract = await getContractFromEvent( - 'ReleaseGoldInstanceDestroyed(address,address)', - web3 - ) - expect(destroyedContract).toBe(contractAddress) - }) - - describe('#when account exists with locked celo', () => { - const value = '10' - - beforeEach(async () => { - await testLocally(CreateAccount, ['--contract', contractAddress]) - await testLocally(LockedGold, [ - '--contract', - contractAddress, - '--action', - 'lock', - '--value', - value, - '--yes', - ]) - }) - - test('will unlock all gold', async () => { - await testLocally(AdminRevoke, ['--contract', contractAddress, '--yesreally']) - const lockedGold = await kit.contracts.getLockedGold() - const lockedAmount = await lockedGold.getAccountTotalLockedGold(releaseGoldWrapper.address) - expect(lockedAmount.isZero()).toBeTruthy() - }) - - describe('#when account has authorized a vote signer', () => { - let voteSigner: string - let accountsWrapper: AccountsWrapper - - beforeEach(async () => { - voteSigner = accounts[2] - accountsWrapper = await kit.contracts.getAccounts() - const pop = await accountsWrapper.generateProofOfKeyPossession(contractAddress, voteSigner) - await testLocally(Authorize, [ - '--contract', - contractAddress, - '--role', - 'vote', - '--signer', - voteSigner, - '--signature', - serializeSignature(pop), - ]) - }) - - test('will rotate vote signer', async () => { - await testLocally(AdminRevoke, ['--contract', contractAddress, '--yesreally']) - const newVoteSigner = await accountsWrapper.getVoteSigner(contractAddress) - expect(newVoteSigner).not.toEqual(voteSigner) - }) - - describe('#when account has voted', () => { - let governance: GovernanceWrapper - - beforeEach(async () => { - // from vote.test.ts - const expConfig = NetworkConfig.governance - const minDeposit = web3.utils.toWei(expConfig.minDeposit.toString(), 'ether') - governance = await kit.contracts.getGovernance() - await governance - .propose([], 'URL') - .sendAndWaitForReceipt({ from: accounts[0], value: minDeposit }) - await timeTravel(expConfig.dequeueFrequency, web3) - await testLocally(Approve, ['--from', accounts[0], '--proposalID', '1', '--useMultiSig']) - await testLocally(GovernanceVote, [ - '--from', - voteSigner, - '--proposalID', - '1', - '--value', - 'Yes', - ]) - await governance - .propose([], 'URL') - .sendAndWaitForReceipt({ from: accounts[0], value: minDeposit }) - await governance - .propose([], 'URL') - .sendAndWaitForReceipt({ from: accounts[0], value: minDeposit }) - await testLocally(GovernanceUpvote, ['--from', voteSigner, '--proposalID', '3']) - - // const validators = await kit.contracts.getValidators() - // const groups = await validators.getRegisteredValidatorGroupsAddresses() - // await testLocally(ElectionVote, [ - // '--from', - // voteSigner, - // '--for', - // groups[0], - // '--value', - // value - // ]) - }) - - test('will revoke governance votes and upvotes', async () => { - const isVotingBefore = await governance.isVoting(contractAddress) - expect(isVotingBefore).toBeTruthy() - await testLocally(AdminRevoke, ['--contract', contractAddress, '--yesreally']) - const isVotingAfter = await governance.isVoting(contractAddress) - expect(isVotingAfter).toBeFalsy() - }) - - // test.only('will revoke election votes', async () => { - // const election = await kit.contracts.getElection() - // const votesBefore = await election.getTotalVotesByAccount(contractAddress) - // expect(votesBefore.isZero).toBeFalsy() - // await testLocally(AdminRevoke, ['--contract', contractAddress, '--yesreally']) - // const votesAfter = await election.getTotalVotesByAccount(contractAddress) - // expect(votesAfter.isZero()).toBeTruthy() - // }) - }) - }) - }) -}) diff --git a/packages/cli/src/commands/releasegold/admin-revoke.ts b/packages/cli/src/commands/releasegold/admin-revoke.ts deleted file mode 100644 index feeba6511..000000000 --- a/packages/cli/src/commands/releasegold/admin-revoke.ts +++ /dev/null @@ -1,146 +0,0 @@ -import { Flags } from '@oclif/core' - -import prompts from 'prompts' -import { displaySendTx, printValueMap } from '../../utils/cli' -import { ReleaseGoldBaseCommand } from '../../utils/release-gold-base' - -export default class AdminRevoke extends ReleaseGoldBaseCommand { - static hidden = true - - static description = 'Take all possible steps to revoke given contract instance.' - - static flags = { - ...ReleaseGoldBaseCommand.flags, - yesreally: Flags.boolean({ description: 'Override interactive prompt to confirm revocation' }), - } - - static args = {} - - static examples = ['admin-revoke --contract 0x5409ED021D9299bf6814279A6A1411A7e866A631'] - - async run() { - const kit = await this.getKit() - const { flags: _flags } = await this.parse(AdminRevoke) - const web3 = await this.getWeb3() - if (!_flags.yesreally) { - const response = await prompts({ - type: 'confirm', - name: 'confirmation', - message: 'Are you sure you want to revoke this contract? (y/n)', - }) - - if (!response.confirmation) { - console.info('Aborting due to user response') - process.exit(0) - } - } - - kit.defaultAccount = await this.releaseGoldWrapper.getReleaseOwner() - - const isRevoked = await this.releaseGoldWrapper.isRevoked() - if (!isRevoked) { - await displaySendTx( - 'releasegold: revokeBeneficiary', - this.releaseGoldWrapper.revokeBeneficiary(), - undefined, - 'ReleaseScheduleRevoked' - ) - } - - const accounts = await kit.contracts.getAccounts() - const contractAddress = await this.contractAddress() - const isAccount = await accounts.isAccount(contractAddress) - if (isAccount) { - // rotate vote signers - let voteSigner = await accounts.getVoteSigner(contractAddress) - if (voteSigner !== contractAddress) { - const password = 'bad_password' - voteSigner = await web3.eth.personal.newAccount(password) - await web3.eth.personal.unlockAccount(voteSigner, password, 1000) - const pop = await accounts.generateProofOfKeyPossession(contractAddress, voteSigner) - await displaySendTx( - 'accounts: rotateVoteSigner', - await this.releaseGoldWrapper.authorizeVoteSigner(voteSigner, pop), - undefined, - 'VoteSignerAuthorized' - ) - } - - const election = await kit.contracts.getElection() - const electionVotes = await election.getTotalVotesByAccount(contractAddress) - const isElectionVoting = electionVotes.isGreaterThan(0) - - // handle election votes - if (isElectionVoting) { - const txos = await this.releaseGoldWrapper.revokeAllVotesForAllGroups() - for (const txo of txos) { - await displaySendTx('election: revokeVotes', txo, { from: voteSigner }, [ - 'ValidatorGroupPendingVoteRevoked', - 'ValidatorGroupActiveVoteRevoked', - ]) - } - } - - const governance = await kit.contracts.getGovernance() - const isGovernanceVoting = await governance.isVoting(contractAddress) - - // handle governance votes - if (isGovernanceVoting) { - const isUpvoting = await governance.isUpvoting(contractAddress) - if (isUpvoting) { - await displaySendTx( - 'governance: revokeUpvote', - await governance.revokeUpvote(contractAddress), - { from: voteSigner }, - 'ProposalUpvoteRevoked' - ) - } - - const isVotingReferendum = await governance.isVotingReferendum(contractAddress) - if (isVotingReferendum) { - await displaySendTx( - 'governance: revokeVotes', - governance.revokeVotes(), - { from: voteSigner }, - 'ProposalVoteRevoked' - ) - } - } - - await displaySendTx( - 'releasegold: unlockAllGold', - await this.releaseGoldWrapper.unlockAllGold(), - undefined, - 'GoldUnlocked' - ) - } - - // rescue any cUSD balance - const stabletoken = await kit.contracts.getStableToken() - const cusdBalance = await stabletoken.balanceOf(contractAddress) - if (cusdBalance.isGreaterThan(0)) { - await displaySendTx( - 'releasegold: rescueCUSD', - this.releaseGoldWrapper.transfer(kit.defaultAccount, cusdBalance), - undefined, - 'Transfer' - ) - } - - // attempt to refund and finalize, surface pending withdrawals - const remainingLockedGold = await this.releaseGoldWrapper.getRemainingLockedBalance() - if (remainingLockedGold.isZero()) { - await displaySendTx( - 'releasegold: refundAndFinalize', - this.releaseGoldWrapper.refundAndFinalize(), - undefined, - 'ReleaseGoldInstanceDestroyed' - ) - } else { - console.log('Some celo is still locked, printing pending withdrawals...') - const lockedGold = await kit.contracts.getLockedGold() - const pendingWithdrawals = await lockedGold.getPendingWithdrawals(contractAddress) - pendingWithdrawals.forEach((w) => printValueMap(w)) - } - } -} diff --git a/packages/cli/src/commands/releasegold/authorize.test.ts b/packages/cli/src/commands/releasegold/authorize.test.ts deleted file mode 100644 index ba1cf0291..000000000 --- a/packages/cli/src/commands/releasegold/authorize.test.ts +++ /dev/null @@ -1,241 +0,0 @@ -import { newKitFromWeb3 } from '@celo/contractkit' -import { getContractFromEvent, testWithGanache } from '@celo/dev-utils/lib/ganache-test' -import { addressToPublicKey, serializeSignature } from '@celo/utils/lib/signatureUtils' -import Web3 from 'web3' -import { testLocally } from '../../test-utils/cliUtils' -import ValidatorRegister from '../validator/register' -import Authorize from './authorize' -import CreateAccount from './create-account' -import LockedGold from './locked-gold' - -process.env.NO_SYNCCHECK = 'true' - -testWithGanache('releasegold:authorize cmd', (web3: Web3) => { - let contractAddress: string - let kit: any - - beforeEach(async () => { - contractAddress = await getContractFromEvent( - 'ReleaseGoldInstanceCreated(address,address)', - web3 - ) - kit = newKitFromWeb3(web3) - await testLocally(CreateAccount, ['--contract', contractAddress]) - }) - - describe('can authorize account signers', () => { - let pop: any - let accounts: any - - beforeEach(async () => { - accounts = await web3.eth.getAccounts() - const accountsWrapper = await kit.contracts.getAccounts() - pop = await accountsWrapper.generateProofOfKeyPossession(contractAddress, accounts[1]) - }) - - test('can authorize account vote signer ', async () => { - await testLocally(Authorize, [ - '--contract', - contractAddress, - '--role', - 'vote', - '--signer', - accounts[1], - '--signature', - serializeSignature(pop), - ]) - }) - - test('can authorize account validator signer', async () => { - await testLocally(Authorize, [ - '--contract', - contractAddress, - '--role', - 'validator', - '--signer', - accounts[1], - '--signature', - serializeSignature(pop), - ]) - }) - - test('can authorize account attestation signer', async () => { - await testLocally(Authorize, [ - '--contract', - contractAddress, - '--role', - 'attestation', - '--signer', - accounts[1], - '--signature', - serializeSignature(pop), - ]) - }) - }) - - test('can register as a validator from an authorized signer', async () => { - const accounts = await web3.eth.getAccounts() - const accountsWrapper = await kit.contracts.getAccounts() - const signer = accounts[1] - const pop = await accountsWrapper.generateProofOfKeyPossession(contractAddress, signer) - const ecdsaPublicKey = await addressToPublicKey(signer, web3.eth.sign) - await testLocally(LockedGold, [ - '--contract', - contractAddress, - '--action', - 'lock', - '--value', - '10000000000000000000000', - '--yes', - ]) - await testLocally(Authorize, [ - '--contract', - contractAddress, - '--role', - 'validator', - '--signer', - signer, - '--signature', - serializeSignature(pop), - ]) - await testLocally(ValidatorRegister, [ - '--from', - signer, - '--ecdsaKey', - ecdsaPublicKey, - '--blsKey', - '0x4fa3f67fc913878b068d1fa1cdddc54913d3bf988dbe5a36a20fa888f20d4894c408a6773f3d7bde11154f2a3076b700d345a42fd25a0e5e83f4db5586ac7979ac2053cd95d8f2efd3e959571ceccaa743e02cf4be3f5d7aaddb0b06fc9aff00', - '--blsSignature', - '0xcdb77255037eb68897cd487fdd85388cbda448f617f874449d4b11588b0b7ad8ddc20d9bb450b513bb35664ea3923900', - '--yes', - ]) - }) - - test('can authorize signer with BLS keys after registering as validator', async () => { - const accounts = await web3.eth.getAccounts() - const accountsWrapper = await kit.contracts.getAccounts() - const signer = accounts[1] - const pop = await accountsWrapper.generateProofOfKeyPossession(contractAddress, signer) - const ecdsaPublicKey = await addressToPublicKey(signer, web3.eth.sign) - - const signerBLS = accounts[2] - const popBLS = await accountsWrapper.generateProofOfKeyPossession(contractAddress, signerBLS) - const newBlsPublicKey = web3.utils.randomHex(96) - const newBlsPoP = web3.utils.randomHex(48) - - await testLocally(LockedGold, [ - '--contract', - contractAddress, - '--action', - 'lock', - '--value', - '10000000000000000000000', - '--yes', - ]) - await testLocally(Authorize, [ - '--contract', - contractAddress, - '--role', - 'validator', - '--signer', - signer, - '--signature', - serializeSignature(pop), - ]) - await testLocally(ValidatorRegister, [ - '--from', - signer, - '--ecdsaKey', - ecdsaPublicKey, - '--blsKey', - '0x4fa3f67fc913878b068d1fa1cdddc54913d3bf988dbe5a36a20fa888f20d4894c408a6773f3d7bde11154f2a3076b700d345a42fd25a0e5e83f4db5586ac7979ac2053cd95d8f2efd3e959571ceccaa743e02cf4be3f5d7aaddb0b06fc9aff00', - '--blsSignature', - '0xcdb77255037eb68897cd487fdd85388cbda448f617f874449d4b11588b0b7ad8ddc20d9bb450b513bb35664ea3923900', - '--yes', - ]) - await testLocally(Authorize, [ - '--contract', - contractAddress, - '--role', - 'validator', - '--signer', - signerBLS, - '--signature', - serializeSignature(popBLS), - '--blsKey', - newBlsPublicKey, - '--blsPop', - newBlsPoP, - ]) - }) - - test('cannot authorize signer without BLS keys after registering as validator', async () => { - const accounts = await web3.eth.getAccounts() - const accountsWrapper = await kit.contracts.getAccounts() - const signer = accounts[1] - const pop = await accountsWrapper.generateProofOfKeyPossession(contractAddress, signer) - const ecdsaPublicKey = await addressToPublicKey(signer, web3.eth.sign) - - const signerNew = accounts[2] - const popNew = await accountsWrapper.generateProofOfKeyPossession(contractAddress, signerNew) - - await testLocally(LockedGold, [ - '--contract', - contractAddress, - '--action', - 'lock', - '--value', - '10000000000000000000000', - '--yes', - ]) - await testLocally(Authorize, [ - '--contract', - contractAddress, - '--role', - 'validator', - '--signer', - signer, - '--signature', - serializeSignature(pop), - ]) - await testLocally(ValidatorRegister, [ - '--from', - signer, - '--ecdsaKey', - ecdsaPublicKey, - '--blsKey', - '0x4fa3f67fc913878b068d1fa1cdddc54913d3bf988dbe5a36a20fa888f20d4894c408a6773f3d7bde11154f2a3076b700d345a42fd25a0e5e83f4db5586ac7979ac2053cd95d8f2efd3e959571ceccaa743e02cf4be3f5d7aaddb0b06fc9aff00', - '--blsSignature', - '0xcdb77255037eb68897cd487fdd85388cbda448f617f874449d4b11588b0b7ad8ddc20d9bb450b513bb35664ea3923900', - '--yes', - ]) - await expect( - testLocally(Authorize, [ - '--contract', - contractAddress, - '--role', - 'validator', - '--signer', - signerNew, - '--signature', - serializeSignature(popNew), - ]) - ).rejects.toThrow() - }) - - test('fails if contract is not registered as an account', async () => { - const accounts = await web3.eth.getAccounts() - await expect( - testLocally(Authorize, [ - '--contract', - contractAddress, - '--role', - 'validator', - '--signer', - accounts[1], - '--signature', - '0x1b9fca4bbb5bfb1dbe69ef1cddbd9b4202dcb6b134c5170611e1e36ecfa468d7b46c85328d504934fce6c2a1571603a50ae224d2b32685e84d4d1a1eebad8452eb', - ]) - ).rejects.toThrow() - }) -}) diff --git a/packages/cli/src/commands/releasegold/authorize.ts b/packages/cli/src/commands/releasegold/authorize.ts deleted file mode 100644 index 0367ce0e8..000000000 --- a/packages/cli/src/commands/releasegold/authorize.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { Flags as oclifFlags } from '@oclif/core' -import { newCheckBuilder } from '../../utils/checks' -import { displaySendTx } from '../../utils/cli' -import { CustomFlags } from '../../utils/command' -import { ReleaseGoldBaseCommand } from '../../utils/release-gold-base' -export default class Authorize extends ReleaseGoldBaseCommand { - static description = - 'Authorize an alternative key to be used for a given action (Vote, Validate, Attest) on behalf of the ReleaseGold instance contract.' - - static flags = { - ...ReleaseGoldBaseCommand.flags, - role: oclifFlags.string({ required: true, options: ['vote', 'validator', 'attestation'] }), - signer: CustomFlags.address({ - required: true, - description: 'The signer key that is to be used for voting through the ReleaseGold instance', - }), - signature: CustomFlags.proofOfPossession({ - description: 'Signature (a.k.a. proof-of-possession) of the signer key', - required: true, - }), - blsKey: CustomFlags.blsPublicKey({ - description: - 'The BLS public key that the validator is using for consensus, should pass proof of possession. 96 bytes.', - dependsOn: ['blsPop'], - }), - blsPop: CustomFlags.blsProofOfPossession({ - description: - 'The BLS public key proof-of-possession, which consists of a signature on the account address. 48 bytes.', - dependsOn: ['blsKey'], - }), - force: oclifFlags.boolean({ - description: - 'Allow rotation of validator ECDSA key without rotating the BLS key. Only intended for validators with a special reason to do so.', - default: false, - hidden: true, - }), - } - - static args = {} - - static examples = [ - 'authorize --contract 0x5409ED021D9299bf6814279A6A1411A7e866A631 --role vote --signer 0x6ecbe1db9ef729cbe972c83fb886247691fb6beb --signature 0x1b9fca4bbb5bfb1dbe69ef1cddbd9b4202dcb6b134c5170611e1e36ecfa468d7b46c85328d504934fce6c2a1571603a50ae224d2b32685e84d4d1a1eebad8452eb', - 'authorize --contract 0x5409ED021D9299bf6814279A6A1411A7e866A631 --role validator --signer 0x6ecbe1db9ef729cbe972c83fb886247691fb6beb --signature 0x1b9fca4bbb5bfb1dbe69ef1cddbd9b4202dcb6b134c5170611e1e36ecfa468d7b46c85328d504934fce6c2a1571603a50ae224d2b32685e84d4d1a1eebad8452eb --blsKey 0x4fa3f67fc913878b068d1fa1cdddc54913d3bf988dbe5a36a20fa888f20d4894c408a6773f3d7bde11154f2a3076b700d345a42fd25a0e5e83f4db5586ac7979ac2053cd95d8f2efd3e959571ceccaa743e02cf4be3f5d7aaddb0b06fc9aff00 --blsPop 0xcdb77255037eb68897cd487fdd85388cbda448f617f874449d4b11588b0b7ad8ddc20d9bb450b513bb35664ea3923900', - 'authorize --contract 0x5409ED021D9299bf6814279A6A1411A7e866A631 --role attestation --signer 0x6ecbe1db9ef729cbe972c83fb886247691fb6beb --signature 0x1b9fca4bbb5bfb1dbe69ef1cddbd9b4202dcb6b134c5170611e1e36ecfa468d7b46c85328d504934fce6c2a1571603a50ae224d2b32685e84d4d1a1eebad8452eb', - ] - - async run() { - const kit = await this.getKit() - // tslint:disable-next-line - const { flags } = await this.parse(Authorize) - - const role = flags.role - - // Check that the account is registered on-chain. - // Additionally, if the authorization is for a validator, the BLS key must be provided when the - // validator is already registered, and cannot be provided if the validator is not registered. - // (Because the BLS key is stored on the validator entry, which would not exist yet) - // Using the --force flag allows setting the ECDSA key on the validator without the BLS key. - const checker = newCheckBuilder(this).isAccount(this.releaseGoldWrapper.address) - if (flags.role === 'validator' && !flags.force) { - if (flags.blsKey && flags.blsPop) { - checker.isValidator(this.releaseGoldWrapper.address) - } else { - checker.isNotValidator(this.releaseGoldWrapper.address) - } - } - await checker.runChecks() - - const accounts = await kit.contracts.getAccounts() - const sig = accounts.parseSignatureOfAddress( - this.releaseGoldWrapper.address, - flags.signer, - flags.signature - ) - - const isRevoked = await this.releaseGoldWrapper.isRevoked() - kit.defaultAccount = isRevoked - ? await this.releaseGoldWrapper.getReleaseOwner() - : await this.releaseGoldWrapper.getBeneficiary() - let tx: any - if (role === 'vote') { - tx = await this.releaseGoldWrapper.authorizeVoteSigner(flags.signer, sig) - } else if (role === 'validator' && flags.blsKey && flags.blsPop) { - tx = await this.releaseGoldWrapper.authorizeValidatorSignerAndBls( - flags.signer, - sig, - flags.blsKey, - flags.blsPop - ) - } else if (role === 'validator') { - tx = await this.releaseGoldWrapper.authorizeValidatorSigner(flags.signer, sig) - } else if (role === 'attestation') { - tx = await this.releaseGoldWrapper.authorizeAttestationSigner(flags.signer, sig) - } else { - this.error('Invalid role provided') - return - } - await displaySendTx('authorize' + role + 'Tx', tx) - } -} diff --git a/packages/cli/src/commands/releasegold/create-account.ts b/packages/cli/src/commands/releasegold/create-account.ts deleted file mode 100644 index bb4f577a3..000000000 --- a/packages/cli/src/commands/releasegold/create-account.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { newCheckBuilder } from '../../utils/checks' -import { displaySendTx } from '../../utils/cli' -import { ReleaseGoldBaseCommand } from '../../utils/release-gold-base' -export default class CreateAccount extends ReleaseGoldBaseCommand { - static description = 'Creates a new account for the ReleaseGold instance' - - static flags = { - ...ReleaseGoldBaseCommand.flags, - } - - static args = {} - - static examples = ['create-account --contract 0x5409ED021D9299bf6814279A6A1411A7e866A631'] - - async run() { - const kit = await this.getKit() - const isRevoked = await this.releaseGoldWrapper.isRevoked() - await newCheckBuilder(this) - .isNotAccount(this.releaseGoldWrapper.address) - .addCheck('Contract is not revoked', () => !isRevoked) - .runChecks() - - kit.defaultAccount = await this.releaseGoldWrapper.getBeneficiary() - await displaySendTx('createAccount', this.releaseGoldWrapper.createAccount()) - } -} diff --git a/packages/cli/src/commands/releasegold/locked-gold.test.ts b/packages/cli/src/commands/releasegold/locked-gold.test.ts deleted file mode 100644 index 9dbd6d39a..000000000 --- a/packages/cli/src/commands/releasegold/locked-gold.test.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { newKitFromWeb3 } from '@celo/contractkit' -import { getContractFromEvent, testWithGanache } from '@celo/dev-utils/lib/ganache-test' -import Web3 from 'web3' -import { testLocally } from '../../test-utils/cliUtils' -import CreateAccount from './create-account' -import LockedGold from './locked-gold' - -process.env.NO_SYNCCHECK = 'true' - -testWithGanache('releasegold:locked-gold cmd', (web3: Web3) => { - let contractAddress: string - let kit: any - - beforeEach(async () => { - contractAddress = await getContractFromEvent( - 'ReleaseGoldInstanceCreated(address,address)', - web3 - ) - kit = newKitFromWeb3(web3) - await testLocally(CreateAccount, ['--contract', contractAddress]) - }) - - test('can lock celo with pending withdrawals', async () => { - const lockedGold = await kit.contracts.getLockedGold() - await testLocally(LockedGold, [ - '--contract', - contractAddress, - '--action', - 'lock', - '--value', - '100', - ]) - await testLocally(LockedGold, [ - '--contract', - contractAddress, - '--action', - 'unlock', - '--value', - '50', - ]) - await testLocally(LockedGold, [ - '--contract', - contractAddress, - '--action', - 'lock', - '--value', - '75', - ]) - await testLocally(LockedGold, [ - '--contract', - contractAddress, - '--action', - 'unlock', - '--value', - '50', - ]) - const pendingWithdrawalsTotalValue = await lockedGold.getPendingWithdrawalsTotalValue( - contractAddress - ) - await expect(pendingWithdrawalsTotalValue.toFixed()).toBe('50') - }) -}) diff --git a/packages/cli/src/commands/releasegold/locked-gold.ts b/packages/cli/src/commands/releasegold/locked-gold.ts deleted file mode 100644 index 7122b6d62..000000000 --- a/packages/cli/src/commands/releasegold/locked-gold.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { eqAddress } from '@celo/utils/lib/address' -import { Flags } from '@oclif/core' - -import BigNumber from 'bignumber.js' -import { newCheckBuilder } from '../../utils/checks' -import { binaryPrompt, displaySendTx } from '../../utils/cli' -import { CustomFlags } from '../../utils/command' -import { ReleaseGoldBaseCommand } from '../../utils/release-gold-base' - -export default class LockedGold extends ReleaseGoldBaseCommand { - static description = - 'Perform actions [lock, unlock, withdraw] on CELO that has been locked via the provided ReleaseGold contract.' - - static flags = { - ...ReleaseGoldBaseCommand.flags, - action: Flags.string({ - char: 'a', - options: ['lock', 'unlock', 'withdraw'], - description: "Action to perform on contract's celo", - required: true, - }), - value: CustomFlags.wei({ - required: true, - description: 'Amount of celo to perform `action` with', - }), - yes: Flags.boolean({ description: 'Answer yes to prompt' }), - } - - static examples = [ - 'locked-gold --contract 0xCcc8a47BE435F1590809337BB14081b256Ae26A8 --action lock --value 10000000000000000000000', - 'locked-gold --contract 0xCcc8a47BE435F1590809337BB14081b256Ae26A8 --action unlock --value 10000000000000000000000', - 'locked-gold --contract 0xCcc8a47BE435F1590809337BB14081b256Ae26A8 --action withdraw --value 10000000000000000000000', - ] - - async run() { - const kit = await this.getKit() - const { flags } = await this.parse(LockedGold) - const value = new BigNumber(flags.value) - const contractAddress = await this.contractAddress() - const checkBuilder = newCheckBuilder(this, contractAddress).isAccount(contractAddress) - const isRevoked = await this.releaseGoldWrapper.isRevoked() - const beneficiary = await this.releaseGoldWrapper.getBeneficiary() - const releaseOwner = await this.releaseGoldWrapper.getReleaseOwner() - const lockedGold = await kit.contracts.getLockedGold() - kit.defaultAccount = isRevoked ? releaseOwner : beneficiary - - if (flags.action === 'lock') { - // Must verify contract is account before checking pending withdrawals - await checkBuilder.addCheck('Is not revoked', () => !isRevoked).runChecks() - const pendingWithdrawalsValue = await lockedGold.getPendingWithdrawalsTotalValue( - contractAddress - ) - const relockValue = BigNumber.minimum(pendingWithdrawalsValue, value) - const lockValue = value.minus(relockValue) - await newCheckBuilder(this, contractAddress) - .hasEnoughCelo(contractAddress, lockValue) - .runChecks() - const txos = await this.releaseGoldWrapper.relockGold(relockValue) - for (const txo of txos) { - await displaySendTx('lockedGoldRelock', txo, { from: beneficiary }) - } - if (lockValue.gt(new BigNumber(0))) { - const accounts = await kit.contracts.getAccounts() - const totalValue = await this.releaseGoldWrapper.getRemainingUnlockedBalance() - const remaining = totalValue.minus(lockValue) - console.log('remaining', remaining.toFixed()) - if ( - !flags.yes && - remaining.lt(new BigNumber(2e18)) && - (eqAddress(await accounts.getVoteSigner(flags.contract), flags.contract) || - eqAddress(await accounts.getValidatorSigner(flags.contract), flags.contract)) - ) { - const check = await binaryPrompt( - `Only ${remaining.shiftedBy( - -18 - )} CELO would be left unlocked, you might not be able to fund your signers. Unlock anyway?`, - true - ) - if (!check) { - console.log('Cancelled') - return - } - } - await displaySendTx('lockedGoldLock', this.releaseGoldWrapper.lockGold(lockValue)) - } - } else if (flags.action === 'unlock') { - await checkBuilder.isNotVoting(contractAddress).hasEnoughLockedGoldToUnlock(value).runChecks() - await displaySendTx('lockedGoldUnlock', this.releaseGoldWrapper.unlockGold(flags.value)) - } else if (flags.action === 'withdraw') { - await checkBuilder.runChecks() - const currentTime = Math.round(new Date().getTime() / 1000) - let madeWithdrawal = false - while (!madeWithdrawal) { - const pendingWithdrawals = await lockedGold.getPendingWithdrawals(contractAddress) - for (let i = 0; i < pendingWithdrawals.length; i++) { - const pendingWithdrawal = pendingWithdrawals[i] - if (pendingWithdrawal.time.isLessThan(currentTime)) { - console.log( - `Found available pending withdrawal of value ${pendingWithdrawal.value.toFixed()}, withdrawing` - ) - await displaySendTx('lockedGoldWithdraw', this.releaseGoldWrapper.withdrawLockedGold(i)) - madeWithdrawal = true - } - } - } - const remainingPendingWithdrawals = await lockedGold.getPendingWithdrawals(contractAddress) - for (const pendingWithdrawal of remainingPendingWithdrawals) { - console.log( - `Pending withdrawal of value ${pendingWithdrawal.value.toFixed()} available for withdrawal in ${pendingWithdrawal.time - .minus(currentTime) - .toFixed()} seconds.` - ) - } - } - } -} diff --git a/packages/cli/src/commands/releasegold/refund-and-finalize.test.ts b/packages/cli/src/commands/releasegold/refund-and-finalize.test.ts deleted file mode 100644 index 0aa8611d5..000000000 --- a/packages/cli/src/commands/releasegold/refund-and-finalize.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { newReleaseGold } from '@celo/abis/web3/ReleaseGold' -import { ContractKit, newKitFromWeb3 } from '@celo/contractkit' -import { ReleaseGoldWrapper } from '@celo/contractkit/lib/wrappers/ReleaseGold' -import { getContractFromEvent, testWithGanache } from '@celo/dev-utils/lib/ganache-test' -import Web3 from 'web3' -import { testLocally } from '../../test-utils/cliUtils' -import RefundAndFinalize from './refund-and-finalize' -import Revoke from './revoke' -import Show from './show' - -process.env.NO_SYNCCHECK = 'true' - -testWithGanache('releasegold:refund-and-finalize cmd', (web3: Web3) => { - let contractAddress: any - let kit: ContractKit - - beforeEach(async () => { - contractAddress = await getContractFromEvent( - 'ReleaseGoldInstanceCreated(address,address)', - web3, - { index: 1 } // revocable = true - ) - kit = newKitFromWeb3(web3) - }) - - test('can refund celo', async () => { - await testLocally(Revoke, ['--contract', contractAddress, '--yesreally']) - const releaseGoldWrapper = new ReleaseGoldWrapper( - kit.connection, - newReleaseGold(web3, contractAddress), - kit.contracts - ) - const refundAddress = await releaseGoldWrapper.getRefundAddress() - const balanceBefore = await kit.getTotalBalance(refundAddress) - await testLocally(RefundAndFinalize, ['--contract', contractAddress]) - const balanceAfter = await kit.getTotalBalance(refundAddress) - expect(balanceBefore.CELO!.toNumber()).toBeLessThan(balanceAfter.CELO!.toNumber()) - }) - - test('can finalize the contract', async () => { - await testLocally(Revoke, ['--contract', contractAddress, '--yesreally']) - await testLocally(RefundAndFinalize, ['--contract', contractAddress]) - await expect(testLocally(Show, ['--contract', contractAddress])).rejects.toThrow() - }) -}) diff --git a/packages/cli/src/commands/releasegold/refund-and-finalize.ts b/packages/cli/src/commands/releasegold/refund-and-finalize.ts deleted file mode 100644 index b3322caa2..000000000 --- a/packages/cli/src/commands/releasegold/refund-and-finalize.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { newCheckBuilder } from '../../utils/checks' -import { displaySendTx } from '../../utils/cli' -import { ReleaseGoldBaseCommand } from '../../utils/release-gold-base' - -export default class RefundAndFinalize extends ReleaseGoldBaseCommand { - static description = - "Refund the given contract's balance to the appopriate parties and destroy the contact. Can only be called by the release owner of revocable ReleaseGold instances." - - static flags = { - ...ReleaseGoldBaseCommand.flags, - } - - static args = {} - - static examples = ['refund-and-finalize --contract 0x5409ED021D9299bf6814279A6A1411A7e866A631'] - - async run() { - const kit = await this.getKit() - const isRevoked = await this.releaseGoldWrapper.isRevoked() - const remainingLockedBalance = await this.releaseGoldWrapper.getRemainingLockedBalance() - - await newCheckBuilder(this) - .addCheck('Contract is revoked', () => isRevoked) - .addCheck('All contract celo is unlocked', () => remainingLockedBalance.eq(0)) - .runChecks() - - kit.defaultAccount = await this.releaseGoldWrapper.getReleaseOwner() - await displaySendTx('refundAndFinalize', await this.releaseGoldWrapper.refundAndFinalize()) - } -} diff --git a/packages/cli/src/commands/releasegold/revoke-votes.ts b/packages/cli/src/commands/releasegold/revoke-votes.ts deleted file mode 100644 index cadb004ac..000000000 --- a/packages/cli/src/commands/releasegold/revoke-votes.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { CeloTransactionObject } from '@celo/connect' -import { Flags } from '@oclif/core' -import BigNumber from 'bignumber.js' -import { newCheckBuilder } from '../../utils/checks' -import { displaySendTx } from '../../utils/cli' -import { CustomFlags } from '../../utils/command' -import { ReleaseGoldBaseCommand } from '../../utils/release-gold-base' - -export default class RevokeVotes extends ReleaseGoldBaseCommand { - static description = - "Revokes `votes` for the given contract's account from the given group's account" - - static flags = { - ...ReleaseGoldBaseCommand.flags, - group: CustomFlags.address({ - required: false, - exclusive: ['allGroups'], - description: 'Address of the group to revoke votes from', - }), - votes: Flags.string({ - required: false, - exclusive: ['allVotes', 'allGroups'], - description: 'The number of votes to revoke', - }), - allVotes: Flags.boolean({ - required: false, - exclusive: ['votes'], - description: 'Revoke all votes', - }), - allGroups: Flags.boolean({ - required: false, - exclusive: ['group', 'votes'], - description: 'Revoke all votes from all groups', - }), - } - - static examples = [ - 'revoke-votes --contract 0x47e172F6CfB6c7D01C1574fa3E2Be7CC73269D95 --group 0x5409ED021D9299bf6814279A6A1411A7e866A631 --votes 100', - 'revoke-votes --contract 0x47e172F6CfB6c7D01C1574fa3E2Be7CC73269D95 --allVotes --allGroups', - ] - - async run() { - const kit = await this.getKit() - // tslint:disable-next-line - const { flags } = await this.parse(RevokeVotes) - - await newCheckBuilder(this).isAccount(this.releaseGoldWrapper.address).runChecks() - - const isRevoked = await this.releaseGoldWrapper.isRevoked() - const beneficiary = await this.releaseGoldWrapper.getBeneficiary() - const releaseOwner = await this.releaseGoldWrapper.getReleaseOwner() - - kit.defaultAccount = isRevoked ? releaseOwner : beneficiary - - let txos: CeloTransactionObject[] - if (flags.allVotes && flags.allGroups) { - txos = await this.releaseGoldWrapper.revokeAllVotesForAllGroups() - } else if (flags.allVotes && flags.group) { - txos = await this.releaseGoldWrapper.revokeAllVotesForGroup(flags.group) - } else if (flags.votes && flags.group) { - txos = await this.releaseGoldWrapper.revokeValueFromVotes( - flags.group, - new BigNumber(flags.votes) - ) - } else { - throw new Error( - 'Must provide --votes amount and --group address or --allVotes --allGroups flags' - ) - } - - for (const txo of txos) { - await displaySendTx('revokeVotes', txo) - } - } -} diff --git a/packages/cli/src/commands/releasegold/revoke.ts b/packages/cli/src/commands/releasegold/revoke.ts deleted file mode 100644 index 469d48903..000000000 --- a/packages/cli/src/commands/releasegold/revoke.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { Flags } from '@oclif/core' -import prompts from 'prompts' -import { newCheckBuilder } from '../../utils/checks' -import { displaySendTx } from '../../utils/cli' -import { ReleaseGoldBaseCommand } from '../../utils/release-gold-base' -export default class Revoke extends ReleaseGoldBaseCommand { - static description = - 'Revoke the given contract instance. Once revoked, any Locked Gold can be unlocked by the release owner. The beneficiary will then be able to withdraw any released Gold that had yet to be withdrawn, and the remainder can be transferred by the release owner to the refund address. Note that not all ReleaseGold instances are revokable.' - - static flags = { - ...ReleaseGoldBaseCommand.flags, - yesreally: Flags.boolean({ description: 'Override prompt to set liquidity (be careful!)' }), - } - - static args = {} - - static examples = ['revoke --contract 0x5409ED021D9299bf6814279A6A1411A7e866A631'] - - async run() { - const kit = await this.getKit() - // tslint:disable-next-line - const { flags } = await this.parse(Revoke) - - const isRevoked = await this.releaseGoldWrapper.isRevoked() - const isRevocable = await this.releaseGoldWrapper.isRevocable() - - await newCheckBuilder(this) - .addCheck('Contract is not revoked', () => !isRevoked) - .addCheck('Contract is revocable', () => isRevocable) - .runChecks() - - if (!flags.yesreally) { - const response = await prompts({ - type: 'confirm', - name: 'confirmation', - message: 'Are you sure you want to revoke this contract? (y/n)', - }) - - if (!response.confirmation) { - console.info('Aborting due to user response') - process.exit(0) - } - } - - kit.defaultAccount = await this.releaseGoldWrapper.getReleaseOwner() - await displaySendTx('revokeReleasing', await this.releaseGoldWrapper.revokeReleasing()) - } -} diff --git a/packages/cli/src/commands/releasegold/set-account-wallet-address.ts b/packages/cli/src/commands/releasegold/set-account-wallet-address.ts deleted file mode 100644 index 2ac1059d1..000000000 --- a/packages/cli/src/commands/releasegold/set-account-wallet-address.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { Flags } from '@oclif/core' -import { newCheckBuilder } from '../../utils/checks' -import { displaySendTx } from '../../utils/cli' -import { CustomFlags } from '../../utils/command' -import { ReleaseGoldBaseCommand } from '../../utils/release-gold-base' - -export default class SetAccountWalletAddress extends ReleaseGoldBaseCommand { - static description = "Set the ReleaseGold contract account's wallet address" - - static flags = { - ...ReleaseGoldBaseCommand.flags, - walletAddress: CustomFlags.address({ - required: true, - description: - "Address of wallet to set for contract's account and signer of PoP. 0x0 if owner wants payers to contact them directly.", - }), - pop: Flags.string({ - required: false, - description: "ECDSA PoP for signer over contract's account", - }), - } - - static args = {} - - static examples = [ - 'set-account-wallet-address --contract 0x5409ED021D9299bf6814279A6A1411A7e866A631 --walletAddress 0xE36Ea790bc9d7AB70C55260C66D52b1eca985f84 --pop 0x1b3e611d05e46753c43444cdc55c2cc3d95c54da0eba2464a8cc8cb01bd57ae8bb3d82a0e293ca97e5813e7fb9b624127f42ef0871d025d8a56fe2f8f08117e25b', - ] - - async run() { - const kit = await this.getKit() - // tslint:disable-next-line - const { flags } = await this.parse(SetAccountWalletAddress) - const isRevoked = await this.releaseGoldWrapper.isRevoked() - - const checkBuilder = newCheckBuilder(this) - .isAccount(this.releaseGoldWrapper.address) - .addCheck('Contract is not revoked', () => !isRevoked) - - let sig: any - if (flags.walletAddress !== '0x0000000000000000000000000000000000000000') { - const accounts = await kit.contracts.getAccounts() - checkBuilder.addCheck( - 'Wallet address is provided and PoP is provided', - () => flags.pop !== undefined - ) - await checkBuilder.runChecks() - const pop = String(flags.pop) - sig = accounts.parseSignatureOfAddress( - this.releaseGoldWrapper.address, - flags.walletAddress, - pop - ) - } else { - await checkBuilder.runChecks() - sig = {} - sig.v = '0' - sig.r = '0x0' - sig.s = '0x0' - } - - kit.defaultAccount = await this.releaseGoldWrapper.getBeneficiary() - await displaySendTx( - 'setAccountWalletAddressTx', - this.releaseGoldWrapper.setAccountWalletAddress(flags.walletAddress, sig.v, sig.r, sig.s) - ) - } -} diff --git a/packages/cli/src/commands/releasegold/set-account.ts b/packages/cli/src/commands/releasegold/set-account.ts deleted file mode 100644 index 5d950eb3b..000000000 --- a/packages/cli/src/commands/releasegold/set-account.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { Flags } from '@oclif/core' -import { newCheckBuilder } from '../../utils/checks' -import { displaySendTx } from '../../utils/cli' -import { ReleaseGoldBaseCommand } from '../../utils/release-gold-base' -export default class SetAccount extends ReleaseGoldBaseCommand { - static description = - 'Set account properties of the ReleaseGold instance account such as name, data encryption key, and the metadata URL' - - static flags = { - ...ReleaseGoldBaseCommand.flags, - property: Flags.string({ - char: 'p', - options: ['name', 'dataEncryptionKey', 'metaURL'], - description: 'Property type to set', - required: true, - }), - value: Flags.string({ - char: 'v', - description: 'Property value to set', - required: true, - }), - } - - static args = {} - - static examples = [ - 'set-account --contract 0x5719118266779B58D0f9519383A4A27aA7b829E5 --property name --value mywallet', - 'set-account --contract 0x5719118266779B58D0f9519383A4A27aA7b829E5 --property dataEncryptionKey --value 0x041bb96e35f9f4b71ca8de561fff55a249ddf9d13ab582bdd09a09e75da68ae4cd0ab7038030f41b237498b4d76387ae878dc8d98fd6f6db2c15362d1a3bf11216', - 'set-account --contract 0x5719118266779B58D0f9519383A4A27aA7b829E5 --property metaURL --value www.test.com', - ] - - async run() { - const kit = await this.getKit() - // tslint:disable-next-line - const { flags } = await this.parse(SetAccount) - const isRevoked = await this.releaseGoldWrapper.isRevoked() - - await newCheckBuilder(this) - .isAccount(this.releaseGoldWrapper.address) - .addCheck('Contract is not revoked', () => !isRevoked) - .runChecks() - - let tx: any - if (flags.property === 'name') { - tx = this.releaseGoldWrapper.setAccountName(flags.value) - } else if (flags.property === 'dataEncryptionKey') { - tx = this.releaseGoldWrapper.setAccountDataEncryptionKey(flags.value) - } else if (flags.property === 'metaURL') { - tx = this.releaseGoldWrapper.setAccountMetadataURL(flags.value) - } else { - return this.error(`Invalid property provided`) - } - - kit.defaultAccount = await this.releaseGoldWrapper.getBeneficiary() - await displaySendTx('setAccount' + flags.property + 'Tx', tx) - } -} diff --git a/packages/cli/src/commands/releasegold/set-beneficiary.test.ts b/packages/cli/src/commands/releasegold/set-beneficiary.test.ts deleted file mode 100644 index 11710dd6f..000000000 --- a/packages/cli/src/commands/releasegold/set-beneficiary.test.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { newReleaseGold } from '@celo/abis/web3/ReleaseGold' -import { newKitFromWeb3 } from '@celo/contractkit' -import { ReleaseGoldWrapper } from '@celo/contractkit/lib/wrappers/ReleaseGold' -import { getContractFromEvent, testWithGanache } from '@celo/dev-utils/lib/ganache-test' -import Web3 from 'web3' -import { testLocally } from '../../test-utils/cliUtils' -import SetBeneficiary from './set-beneficiary' - -process.env.NO_SYNCCHECK = 'true' - -testWithGanache('releasegold:set-beneficiary cmd', (web3: Web3) => { - let contractAddress: any - let kit: any - let releaseGoldWrapper: ReleaseGoldWrapper - let releaseGoldMultiSig: any - let releaseOwner: string - let beneficiary: string - let newBeneficiary: string - let otherAccount: string - - beforeEach(async () => { - const accounts = await web3.eth.getAccounts() - releaseOwner = accounts[0] - newBeneficiary = accounts[2] - otherAccount = accounts[3] - contractAddress = await getContractFromEvent( - 'ReleaseGoldInstanceCreated(address,address)', - web3, - { index: 1 } // canValidate = false - ) - kit = newKitFromWeb3(web3) - releaseGoldWrapper = new ReleaseGoldWrapper( - kit.connection, - newReleaseGold(web3, contractAddress), - kit.contracts - ) - beneficiary = await releaseGoldWrapper.getBeneficiary() - const owner = await releaseGoldWrapper.getOwner() - releaseGoldMultiSig = await kit.contracts.getMultiSig(owner) - }) - - test('can change beneficiary', async () => { - // First submit the tx from the release owner (accounts[0]) - await testLocally(SetBeneficiary, [ - '--contract', - contractAddress, - '--from', - releaseOwner, - '--beneficiary', - newBeneficiary, - '--yesreally', - ]) - // The multisig tx should not confirm until both parties submit - expect(await releaseGoldWrapper.getBeneficiary()).toEqual(beneficiary) - await testLocally(SetBeneficiary, [ - '--contract', - contractAddress, - '--from', - beneficiary, - '--beneficiary', - newBeneficiary, - '--yesreally', - ]) - expect(await releaseGoldWrapper.getBeneficiary()).toEqual(newBeneficiary) - // It should also update the multisig owners - expect(await releaseGoldMultiSig.getOwners()).toEqual([releaseOwner, newBeneficiary]) - }) - - test('if called by a different account, it should fail', async () => { - await expect( - testLocally(SetBeneficiary, [ - '--contract', - contractAddress, - '--from', - otherAccount, - '--beneficiary', - newBeneficiary, - '--yesreally', - ]) - ).rejects.toThrow() - }) - - test('if the owners submit different txs, nothing on the ReleaseGold contract should change', async () => { - // ReleaseOwner tries to change the beneficiary to `newBeneficiary` while the beneficiary - // tries to change to `otherAccount`. Nothing should change on the RG contract. - await testLocally(SetBeneficiary, [ - '--contract', - contractAddress, - '--from', - releaseOwner, - '--beneficiary', - newBeneficiary, - '--yesreally', - ]) - await testLocally(SetBeneficiary, [ - '--contract', - contractAddress, - '--from', - beneficiary, - '--beneficiary', - otherAccount, - '--yesreally', - ]) - expect(await releaseGoldWrapper.getBeneficiary()).toEqual(beneficiary) - expect(await releaseGoldMultiSig.getOwners()).toEqual([releaseOwner, beneficiary]) - }) -}) diff --git a/packages/cli/src/commands/releasegold/set-beneficiary.ts b/packages/cli/src/commands/releasegold/set-beneficiary.ts deleted file mode 100644 index bd14c338c..000000000 --- a/packages/cli/src/commands/releasegold/set-beneficiary.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { Flags } from '@oclif/core' -import prompts from 'prompts' -import { newCheckBuilder } from '../../utils/checks' -import { displaySendTx } from '../../utils/cli' -import { CustomFlags } from '../../utils/command' -import { ReleaseGoldBaseCommand } from '../../utils/release-gold-base' - -export default class SetBeneficiary extends ReleaseGoldBaseCommand { - static description = - "Set the beneficiary of the ReleaseGold contract. This command is gated via a multi-sig, so this is expected to be called twice: once by the contract's beneficiary and once by the contract's releaseOwner. Once both addresses call this command with the same parameters, the tx will execute." - - static flags = { - ...ReleaseGoldBaseCommand.flags, - from: CustomFlags.address({ - required: true, - description: 'Address to submit multisig transaction from (one of the owners)', - }), - beneficiary: CustomFlags.address({ - required: true, - description: 'Address of the new beneficiary', - }), - yesreally: Flags.boolean({ - description: 'Override prompt to set new beneficiary (be careful!)', - }), - } - - static args = {} - - static examples = [ - 'set-beneficiary --contract 0x5409ED021D9299bf6814279A6A1411A7e866A631 --from 0xE36Ea790bc9d7AB70C55260C66D52b1eca985f84 --beneficiary 0x6Ecbe1DB9EF729CBe972C83Fb886247691Fb6beb', - ] - - async run() { - const kit = await this.getKit() - const { flags } = await this.parse(SetBeneficiary) - const newBeneficiary = flags.beneficiary as string - - const owner = await this.releaseGoldWrapper.getOwner() - const releaseGoldMultiSig = await kit.contracts.getMultiSig(owner) - - await newCheckBuilder(this) - .isMultiSigOwner(flags.from as string, releaseGoldMultiSig) - .runChecks() - - if (!flags.yesreally) { - const response = await prompts({ - type: 'confirm', - name: 'confirmation', - message: - "Are you sure you want to set a new beneficiary? This will forfeit the current beneficiary's controls. (y/n)", - }) - - if (!response.confirmation) { - console.info('Aborting due to user response') - process.exit(0) - } - } - - const currentBeneficiary = await this.releaseGoldWrapper.getBeneficiary() - const setBeneficiaryTx = this.releaseGoldWrapper.setBeneficiary(newBeneficiary) - const setBeneficiaryMultiSigTx = await releaseGoldMultiSig.submitOrConfirmTransaction( - await this.contractAddress(), - setBeneficiaryTx.txo - ) - await displaySendTx( - 'setBeneficiary', - setBeneficiaryMultiSigTx, - { from: flags.from as string }, - 'BeneficiarySet' - ) - const replaceOwnerTx = releaseGoldMultiSig.replaceOwner(currentBeneficiary, newBeneficiary) - const replaceOwnerMultiSigTx = await releaseGoldMultiSig.submitOrConfirmTransaction( - releaseGoldMultiSig.address, - replaceOwnerTx.txo - ) - await displaySendTx('replaceMultiSigOwner', replaceOwnerMultiSigTx, { from: flags.from }) - } -} diff --git a/packages/cli/src/commands/releasegold/set-can-expire.ts b/packages/cli/src/commands/releasegold/set-can-expire.ts deleted file mode 100644 index 504a1252c..000000000 --- a/packages/cli/src/commands/releasegold/set-can-expire.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { Flags } from '@oclif/core' -import prompts from 'prompts' -import { newCheckBuilder } from '../../utils/checks' -import { displaySendTx } from '../../utils/cli' -import { ReleaseGoldBaseCommand } from '../../utils/release-gold-base' - -export default class SetCanExpire extends ReleaseGoldBaseCommand { - static description = 'Set the canExpire flag for the given ReleaseGold contract' - - static expireOptions = ['true', 'false', 'True', 'False'] - - static flags = { - ...ReleaseGoldBaseCommand.flags, - value: Flags.option({ - options: SetCanExpire.expireOptions, - required: true, - description: 'canExpire value', - })(), - yesreally: Flags.boolean({ - description: 'Override prompt to set expiration flag (be careful!)', - }), - } - - static args = {} - - static examples = [ - 'set-can-expire --contract 0x5409ED021D9299bf6814279A6A1411A7e866A631 --value true', - ] - - async run() { - const kit = await this.getKit() - // tslint:disable-next-line - const { flags } = await this.parse(SetCanExpire) - const canExpire = flags.value === 'true' || flags.value === 'True' ? true : false - - await newCheckBuilder(this) - .addCheck('New expire value is different', async () => { - const revocationInfo = await this.releaseGoldWrapper.getRevocationInfo() - return revocationInfo.canExpire !== canExpire - }) - .runChecks() - - if (!flags.yesreally) { - const response = await prompts({ - type: 'confirm', - name: 'confirmation', - message: 'Are you sure you want to change the `canExpire` parameter? (y/n)', - }) - - if (!response.confirmation) { - console.info('Aborting due to user response') - process.exit(0) - } - } - - kit.defaultAccount = await this.releaseGoldWrapper.getBeneficiary() - await displaySendTx('setCanExpire', this.releaseGoldWrapper.setCanExpire(canExpire)) - } -} diff --git a/packages/cli/src/commands/releasegold/set-liquidity-provision.ts b/packages/cli/src/commands/releasegold/set-liquidity-provision.ts deleted file mode 100644 index c48b364dd..000000000 --- a/packages/cli/src/commands/releasegold/set-liquidity-provision.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { Flags } from '@oclif/core' -import prompts from 'prompts' -import { newCheckBuilder } from '../../utils/checks' -import { displaySendTx } from '../../utils/cli' -import { ReleaseGoldBaseCommand } from '../../utils/release-gold-base' -export default class SetLiquidityProvision extends ReleaseGoldBaseCommand { - static description = - 'Set the liquidity provision to true, allowing the beneficiary to withdraw released gold.' - - static flags = { - ...ReleaseGoldBaseCommand.flags, - yesreally: Flags.boolean({ description: 'Override prompt to set liquidity (be careful!)' }), - } - - static args = {} - - static examples = [ - 'set-liquidity-provision --contract 0x5409ED021D9299bf6814279A6A1411A7e866A631', - ] - - async run() { - const kit = await this.getKit() - // tslint:disable-next-line - const { flags } = await this.parse(SetLiquidityProvision) - - await newCheckBuilder(this) - .addCheck('The liquidity provision has not already been set', async () => { - const liquidityProvisionMet = await this.releaseGoldWrapper.getLiquidityProvisionMet() - return !liquidityProvisionMet - }) - .runChecks() - - if (!flags.yesreally) { - const response = await prompts({ - type: 'confirm', - name: 'confirmation', - message: 'Are you sure you want to enable the liquidity provision? (y/n)', - }) - - if (!response.confirmation) { - console.info('Aborting due to user response') - process.exit(0) - } - } - - kit.defaultAccount = await this.releaseGoldWrapper.getReleaseOwner() - await displaySendTx('setLiquidityProvision', this.releaseGoldWrapper.setLiquidityProvision()) - } -} diff --git a/packages/cli/src/commands/releasegold/set-max-distribution.ts b/packages/cli/src/commands/releasegold/set-max-distribution.ts deleted file mode 100644 index 05b0db555..000000000 --- a/packages/cli/src/commands/releasegold/set-max-distribution.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { Flags } from '@oclif/core' -import prompts from 'prompts' -import { newCheckBuilder } from '../../utils/checks' -import { displaySendTx } from '../../utils/cli' -import { ReleaseGoldBaseCommand } from '../../utils/release-gold-base' -export default class SetMaxDistribution extends ReleaseGoldBaseCommand { - static description = 'Set the maximum distribution of celo for the given contract' - - static flags = { - ...ReleaseGoldBaseCommand.flags, - distributionRatio: Flags.string({ - required: true, - description: - 'Amount in range [0, 1000] (3 significant figures) indicating % of total balance available for distribution.', - }), - yesreally: Flags.boolean({ - description: 'Override prompt to set new maximum distribution (be careful!)', - }), - } - - static args = {} - - static examples = [ - 'set-max-distribution --contract 0x5409ED021D9299bf6814279A6A1411A7e866A631 --distributionRatio 1000', - ] - - async run() { - const kit = await this.getKit() - // tslint:disable-next-line - const { flags } = await this.parse(SetMaxDistribution) - const distributionRatio = Number(flags.distributionRatio) - - await newCheckBuilder(this) - .addCheck( - 'Distribution ratio must be within [0, 1000]', - () => distributionRatio >= 0 && distributionRatio <= 1000 - ) - .runChecks() - - if (!flags.yesreally) { - const response = await prompts({ - type: 'confirm', - name: 'confirmation', - message: - 'Are you sure you want to set the new maximum distribution ratio to ' + - distributionRatio + - '? (y/n)', - }) - - if (!response.confirmation) { - console.info('Aborting due to user response') - process.exit(0) - } - } - - kit.defaultAccount = await this.releaseGoldWrapper.getReleaseOwner() - await displaySendTx( - 'setMaxDistribution', - this.releaseGoldWrapper.setMaxDistribution(distributionRatio) - ) - } -} diff --git a/packages/cli/src/commands/releasegold/show.ts b/packages/cli/src/commands/releasegold/show.ts deleted file mode 100644 index c9301e309..000000000 --- a/packages/cli/src/commands/releasegold/show.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { printValueMapRecursive } from '../../utils/cli' -import { ReleaseGoldBaseCommand } from '../../utils/release-gold-base' - -export default class Show extends ReleaseGoldBaseCommand { - static description = 'Show info on a ReleaseGold instance contract.' - - static flags = { - ...ReleaseGoldBaseCommand.flags, - } - - static examples = ['show --contract 0x47e172F6CfB6c7D01C1574fa3E2Be7CC73269D95'] - - async run() { - const kit = await this.getKit() - const balanceStateData = { - totalWithdrawn: await this.releaseGoldWrapper.getTotalWithdrawn(), - maxDistribution: await this.releaseGoldWrapper.getMaxDistribution(), - totalBalance: await this.releaseGoldWrapper.getTotalBalance(), - remainingTotalBalance: await this.releaseGoldWrapper.getRemainingTotalBalance(), - remainingUnlockedBalance: await this.releaseGoldWrapper.getRemainingUnlockedBalance(), - remainingLockedBalance: await this.releaseGoldWrapper.getRemainingLockedBalance(), - currentReleasedTotalAmount: await this.releaseGoldWrapper.getCurrentReleasedTotalAmount(), - } - const accounts = await kit.contracts.getAccounts() - const isAccount = await accounts.isAccount(this.releaseGoldWrapper.address) - const authorizedSigners = isAccount - ? { - voter: await accounts.getVoteSigner(this.releaseGoldWrapper.address), - validator: await accounts.getValidatorSigner(this.releaseGoldWrapper.address), - attestations: await accounts.getAttestationSigner(this.releaseGoldWrapper.address), - } - : { voter: null, validator: null, attestations: null } - const releaseGoldInfo = { - releaseGoldWrapperAddress: this.releaseGoldWrapper.address, - beneficiary: await this.releaseGoldWrapper.getBeneficiary(), - authorizedSigners, - releaseOwner: await this.releaseGoldWrapper.getReleaseOwner(), - owner: await this.releaseGoldWrapper.getOwner(), - refundAddress: await this.releaseGoldWrapper.getRefundAddress(), - liquidityProvisionMet: await this.releaseGoldWrapper.getLiquidityProvisionMet(), - canValidate: await this.releaseGoldWrapper.getCanValidate(), - canVote: await this.releaseGoldWrapper.getCanVote(), - releaseSchedule: await this.releaseGoldWrapper.getHumanReadableReleaseSchedule(), - isRevoked: await this.releaseGoldWrapper.isRevoked(), - revokedStateData: await this.releaseGoldWrapper.getRevocationInfo(), - balanceStateData: balanceStateData, - } - printValueMapRecursive(releaseGoldInfo) - } -} diff --git a/packages/cli/src/commands/releasegold/transfer-dollars.test.ts b/packages/cli/src/commands/releasegold/transfer-dollars.test.ts deleted file mode 100644 index 560101ce2..000000000 --- a/packages/cli/src/commands/releasegold/transfer-dollars.test.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { ContractKit, newKitFromWeb3 } from '@celo/contractkit' -import { getContractFromEvent, testWithGanache } from '@celo/dev-utils/lib/ganache-test' -import Web3 from 'web3' -import { testLocally } from '../../test-utils/cliUtils' -import Register from '../account/register' -import TransferDollars from '../transfer/dollars' -import CreateAccount from './create-account' -import RGTransferDollars from './transfer-dollars' - -process.env.NO_SYNCCHECK = 'true' - -// Lots of commands, sometimes times out -jest.setTimeout(15000) - -testWithGanache('releasegold:transfer-dollars cmd', (web3: Web3) => { - let accounts: string[] = [] - let contractAddress: any - let kit: ContractKit - - beforeEach(async () => { - contractAddress = await getContractFromEvent( - 'ReleaseGoldInstanceCreated(address,address)', - web3, - { index: 1 } // canValidate = false - ) - kit = newKitFromWeb3(web3) - accounts = await web3.eth.getAccounts() - await testLocally(Register, ['--from', accounts[0]]) - await testLocally(CreateAccount, ['--contract', contractAddress]) - }) - - test('can transfer dollars out of the ReleaseGold contract', async () => { - const balanceBefore = await kit.getTotalBalance(accounts[0]) - const cUSDToTransfer = '500000000000000000000' - // Send cUSD to RG contract - await testLocally(TransferDollars, [ - '--from', - accounts[0], - '--to', - contractAddress, - '--value', - cUSDToTransfer, - '--gasCurrency', - 'CELO', - ]) - // RG cUSD balance should match the amount sent - const contractBalance = await kit.getTotalBalance(contractAddress) - expect(contractBalance.cUSD!.toFixed()).toEqual(cUSDToTransfer) - // Attempt to send cUSD back - await testLocally(RGTransferDollars, [ - '--contract', - contractAddress, - '--to', - accounts[0], - '--value', - cUSDToTransfer, - '--gasCurrency', - 'CELO', - ]) - const balanceAfter = await kit.getTotalBalance(accounts[0]) - expect(balanceBefore.cUSD).toEqual(balanceAfter.cUSD) - }) - - test('should fail if contract has no celo dollars', async () => { - await expect( - testLocally(RGTransferDollars, [ - '--contract', - contractAddress, - '--to', - accounts[0], - '--value', - '1', - ]) - ).rejects.toThrow() - }) -}) diff --git a/packages/cli/src/commands/releasegold/transfer-dollars.ts b/packages/cli/src/commands/releasegold/transfer-dollars.ts deleted file mode 100644 index ccdde1e50..000000000 --- a/packages/cli/src/commands/releasegold/transfer-dollars.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { displaySendTx } from '../../utils/cli' -import { CustomFlags } from '../../utils/command' -import { ReleaseGoldBaseCommand } from '../../utils/release-gold-base' - -export default class TransferDollars extends ReleaseGoldBaseCommand { - static description = - 'Transfer Celo Dollars from the given contract address. Dollars may be accrued to the ReleaseGold contract via validator epoch rewards.' - - static flags = { - ...ReleaseGoldBaseCommand.flags, - to: CustomFlags.address({ - required: true, - description: 'Address of the recipient of Celo Dollars transfer', - }), - value: CustomFlags.wei({ - required: true, - description: 'Value (in Wei) of Celo Dollars to transfer', - }), - } - - static args = {} - - static examples = [ - 'transfer-dollars --contract 0x5409ED021D9299bf6814279A6A1411A7e866A631 --to 0x6Ecbe1DB9EF729CBe972C83Fb886247691Fb6beb --value 10000000000000000000000', - ] - - async run() { - const kit = await this.getKit() - const { flags } = await this.parse(TransferDollars) - const isRevoked = await this.releaseGoldWrapper.isRevoked() - kit.defaultAccount = isRevoked - ? await this.releaseGoldWrapper.getReleaseOwner() - : await this.releaseGoldWrapper.getBeneficiary() - await displaySendTx('transfer', this.releaseGoldWrapper.transfer(flags.to, flags.value)) - } -} diff --git a/packages/cli/src/commands/releasegold/withdraw.test.ts b/packages/cli/src/commands/releasegold/withdraw.test.ts deleted file mode 100644 index 1acd89dd5..000000000 --- a/packages/cli/src/commands/releasegold/withdraw.test.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { newReleaseGold } from '@celo/abis/web3/ReleaseGold' -import { ContractKit, newKitFromWeb3 } from '@celo/contractkit' -import { ReleaseGoldWrapper } from '@celo/contractkit/lib/wrappers/ReleaseGold' -import { getContractFromEvent, testWithGanache, timeTravel } from '@celo/dev-utils/lib/ganache-test' -import { BigNumber } from 'bignumber.js' -import Web3 from 'web3' -import { testLocally } from '../../test-utils/cliUtils' -import CreateAccount from './create-account' -import SetLiquidityProvision from './set-liquidity-provision' -import RGTransferDollars from './transfer-dollars' -import Withdraw from './withdraw' - -process.env.NO_SYNCCHECK = 'true' - -testWithGanache('releasegold:withdraw cmd', (web3: Web3) => { - let contractAddress: string - let kit: ContractKit - - beforeEach(async () => { - contractAddress = await getContractFromEvent( - 'ReleaseGoldInstanceCreated(address,address)', - web3 - ) - kit = newKitFromWeb3(web3) - await testLocally(CreateAccount, ['--contract', contractAddress]) - }) - - test('can withdraw released celo to beneficiary', async () => { - await testLocally(SetLiquidityProvision, ['--contract', contractAddress, '--yesreally']) - // ReleasePeriod of default contract - await timeTravel(300000000, web3) - const releaseGoldWrapper = new ReleaseGoldWrapper( - kit.connection, - newReleaseGold(web3, contractAddress), - kit.contracts - ) - const beneficiary = await releaseGoldWrapper.getBeneficiary() - const balanceBefore = (await kit.getTotalBalance(beneficiary)).CELO! - // Use a value which would lose precision if converted to a normal javascript number - const withdrawalAmount = '10000000000000000000005' - await testLocally(Withdraw, ['--contract', contractAddress, '--value', withdrawalAmount]) - const balanceAfter = (await kit.getTotalBalance(beneficiary)).CELO! - const difference = balanceAfter.minus(balanceBefore) - expect(difference).toEqBigNumber(new BigNumber(withdrawalAmount)) - }) - - test("can't withdraw the whole balance if there is a cUSD balance", async () => { - await testLocally(SetLiquidityProvision, ['--contract', contractAddress, '--yesreally']) - // ReleasePeriod of default contract - await timeTravel(300000000, web3) - const releaseGoldWrapper = new ReleaseGoldWrapper( - kit.connection, - newReleaseGold(web3, contractAddress), - kit.contracts - ) - const beneficiary = await releaseGoldWrapper.getBeneficiary() - const balanceBefore = await kit.getTotalBalance(beneficiary) - const remainingBalance = await releaseGoldWrapper.getRemainingUnlockedBalance() - - const stableToken = await kit.contracts.getStableToken() - - await stableToken.transfer(contractAddress, 100).sendAndWaitForReceipt({ from: beneficiary }) - - // Can't withdraw since there is cUSD balance still - await expect( - testLocally(Withdraw, ['--contract', contractAddress, '--value', remainingBalance.toString()]) - ).rejects.toThrow() - - // Move out the cUSD balance - await testLocally(RGTransferDollars, [ - '--contract', - contractAddress, - '--to', - beneficiary, - '--value', - '100', - ]) - - await testLocally(Withdraw, [ - '--contract', - contractAddress, - '--value', - remainingBalance.toString(), - ]) - const balanceAfter = await kit.getTotalBalance(beneficiary) - expect(balanceBefore.CELO!.toNumber()).toBeLessThan(balanceAfter.CELO!.toNumber()) - - // Contract should self-destruct now - await expect(releaseGoldWrapper.getRemainingUnlockedBalance()).rejects.toThrow() - }) -}) diff --git a/packages/cli/src/commands/releasegold/withdraw.ts b/packages/cli/src/commands/releasegold/withdraw.ts deleted file mode 100644 index 7d42098e3..000000000 --- a/packages/cli/src/commands/releasegold/withdraw.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { newCheckBuilder } from '../../utils/checks' -import { displaySendTx } from '../../utils/cli' -import { CustomFlags } from '../../utils/command' -import { ReleaseGoldBaseCommand } from '../../utils/release-gold-base' - -export default class Withdraw extends ReleaseGoldBaseCommand { - static description = - 'Withdraws `value` released celo to the beneficiary address. Fails if `value` worth of celo has not been released yet.' - - static flags = { - ...ReleaseGoldBaseCommand.flags, - value: CustomFlags.wei({ - required: true, - description: 'Amount of released celo (in wei) to withdraw', - }), - } - - static args = {} - - static examples = [ - 'withdraw --contract 0x5409ED021D9299bf6814279A6A1411A7e866A631 --value 10000000000000000000000', - ] - - async run() { - const kit = await this.getKit() - // tslint:disable-next-line - const { flags } = await this.parse(Withdraw) - const value = flags.value - - const remainingUnlockedBalance = await this.releaseGoldWrapper.getRemainingUnlockedBalance() - const maxDistribution = await this.releaseGoldWrapper.getMaxDistribution() - const totalWithdrawn = await this.releaseGoldWrapper.getTotalWithdrawn() - await newCheckBuilder(this) - .addCheck('Value does not exceed available unlocked celo', () => - value.lte(remainingUnlockedBalance) - ) - .addCheck('Value would not exceed maximum distribution', () => - value.plus(totalWithdrawn).lte(maxDistribution) - ) - .addCheck('Contract has met liquidity provision if applicable', () => - this.releaseGoldWrapper.getLiquidityProvisionMet() - ) - .addCheck( - 'Contract would self-destruct with cUSD left when withdrawing the whole balance', - async () => { - if (value.eq(remainingUnlockedBalance)) { - const stableToken = await kit.contracts.getStableToken() - const stableBalance = await stableToken.balanceOf(this.releaseGoldWrapper.address) - if (stableBalance.gt(0)) { - return false - } - } - - return true - } - ) - .runChecks() - - kit.defaultAccount = await this.releaseGoldWrapper.getBeneficiary() - await displaySendTx('withdrawTx', this.releaseGoldWrapper.withdraw(value)) - } -}