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

Compliance + Test #149

Merged
merged 8 commits into from
Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/two-poems-complain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@celo/celocli': patch
---

Require addresses the cli sends from or to not to be sanctioned
2 changes: 2 additions & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"dependencies": {
"@celo/abis": "10.0.0",
"@celo/base": "^6.0.0",
"@celo/compliance": "^1.0.15",
"@celo/connect": "^5.1.2",
"@celo/contractkit": "^7.0.0",
"@celo/cryptographic-utils": "^5.0.7",
Expand All @@ -60,6 +61,7 @@
"bip32": "3.1.0",
"chalk": "^2.4.2",
"command-exists": "^1.2.9",
"cross-fetch": "3.0.6",
"debug": "^4.1.1",
"ethers": "5",
"fs-extra": "^8.1.0",
Expand Down
5 changes: 4 additions & 1 deletion packages/cli/src/commands/exchange/celo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@ export default class ExchangeCelo extends BaseCommand {
const minBuyAmount = res.flags.forAtLeast
const stableToken = stableTokenOptions[res.flags.stableToken]

await newCheckBuilder(this).hasEnoughCelo(res.flags.from, sellAmount).runChecks()
await newCheckBuilder(this)
.isNotSanctioned(res.flags.from)
.hasEnoughCelo(res.flags.from, sellAmount)
.runChecks()

const [celoToken, stableTokenAddress, { mento, brokerAddress }] = await Promise.all([
kit.contracts.getGoldToken(),
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/commands/lockedgold/withdraw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default class Withdraw extends BaseCommand {
kit.defaultAccount = flags.from
const lockedgold = await kit.contracts.getLockedGold()

await newCheckBuilder(this).isAccount(flags.from).runChecks()
await newCheckBuilder(this).isAccount(flags.from).isNotSanctioned(flags.from).runChecks()

const currentTime = Math.round(new Date().getTime() / 1000)
let madeWithdrawal = false
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/src/commands/releasecelo/transfer-dollars.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { newCheckBuilder } from '../../utils/checks'
import { displaySendTx } from '../../utils/cli'
import { CustomFlags } from '../../utils/command'
import { ReleaseGoldBaseCommand } from '../../utils/release-gold-base'
Expand Down Expand Up @@ -31,6 +32,7 @@ export default class TransferDollars extends ReleaseGoldBaseCommand {
kit.defaultAccount = isRevoked
? await this.releaseGoldWrapper.getReleaseOwner()
: await this.releaseGoldWrapper.getBeneficiary()
newCheckBuilder(this).isNotSanctioned(kit.defaultAccount).isNotSanctioned(flags.to).runChecks()
await displaySendTx('transfer', this.releaseGoldWrapper.transfer(flags.to, flags.value))
}
}
6 changes: 4 additions & 2 deletions packages/cli/src/commands/releasecelo/withdraw.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ testWithGanache('releasegold:withdraw cmd', (web3: Web3) => {
})

test("can't withdraw the whole balance if there is a cUSD balance", async () => {
const spy = jest.spyOn(console, 'log')
await testLocally(SetLiquidityProvision, ['--contract', contractAddress, '--yesreally'])
// ReleasePeriod of default contract
await timeTravel(300000000, web3)
Expand All @@ -65,7 +66,9 @@ testWithGanache('releasegold:withdraw cmd', (web3: Web3) => {
await expect(
testLocally(Withdraw, ['--contract', contractAddress, '--value', remainingBalance.toString()])
).rejects.toThrow()

expect(spy).toHaveBeenCalledWith(
expect.stringContaining('The liquidity provision has not already been set')
)
// Move out the cUSD balance
await testLocally(RGTransferDollars, [
'--contract',
Expand All @@ -84,7 +87,6 @@ testWithGanache('releasegold:withdraw cmd', (web3: Web3) => {
])
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()
})
Expand Down
3 changes: 2 additions & 1 deletion packages/cli/src/commands/releasecelo/withdraw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export default class Withdraw extends ReleaseGoldBaseCommand {
const remainingUnlockedBalance = await this.releaseGoldWrapper.getRemainingUnlockedBalance()
const maxDistribution = await this.releaseGoldWrapper.getMaxDistribution()
const totalWithdrawn = await this.releaseGoldWrapper.getTotalWithdrawn()
kit.defaultAccount = await this.releaseGoldWrapper.getBeneficiary()
await newCheckBuilder(this)
.addCheck('Value does not exceed available unlocked celo', () =>
value.lte(remainingUnlockedBalance)
Expand All @@ -53,9 +54,9 @@ export default class Withdraw extends ReleaseGoldBaseCommand {
return true
}
)
.isNotSanctioned(kit.defaultAccount as string)
.runChecks()

kit.defaultAccount = await this.releaseGoldWrapper.getBeneficiary()
await displaySendTx('withdrawTx', this.releaseGoldWrapper.withdraw(value))
}
}
85 changes: 85 additions & 0 deletions packages/cli/src/commands/transfer/celo.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { COMPLIANT_ERROR_RESPONSE, SANCTIONED_ADDRESSES } from '@celo/compliance'
import { ContractKit, newKitFromWeb3 } from '@celo/contractkit'
import { testWithGanache } from '@celo/dev-utils/lib/ganache-test'
import Web3 from 'web3'
import { testLocally } from '../../test-utils/cliUtils'
import TransferCelo from './celo'

process.env.NO_SYNCCHECK = 'true'

// Lots of commands, sometimes times out
jest.setTimeout(15000)

testWithGanache('transfer:celo cmd', (web3: Web3) => {
let accounts: string[] = []
let kit: ContractKit

beforeEach(async () => {
kit = newKitFromWeb3(web3)
accounts = await web3.eth.getAccounts()
})

test('can transfer celo', async () => {
const balanceBefore = await kit.getTotalBalance(accounts[0])
const receiverBalanceBefore = await kit.getTotalBalance(accounts[1])
const amountToTransfer = '500000000000000000000'
// Send cUSD to RG contract
await testLocally(TransferCelo, [
'--from',
accounts[0],
'--to',
accounts[1],
'--value',
amountToTransfer,
'--gasCurrency',
'cusd',
])
// RG cUSD balance should match the amount sent
const receiverBalance = await kit.getTotalBalance(accounts[1])
expect(receiverBalance.CELO!.toFixed()).toEqual(
receiverBalanceBefore.CELO!.plus(amountToTransfer).toFixed()
)
// Attempt to send cUSD back
await testLocally(TransferCelo, [
'--from',
accounts[1],
'--to',
accounts[0],
'--value',
amountToTransfer,
'--gasCurrency',
'cusd',
])
const balanceAfter = await kit.getTotalBalance(accounts[0])
expect(balanceBefore.CELO).toEqual(balanceAfter.CELO)
})

test('should fail if to address is sanctioned', async () => {
const spy = jest.spyOn(console, 'log')
await expect(
testLocally(TransferCelo, [
'--from',
accounts[1],
'--to',
SANCTIONED_ADDRESSES[0],
'--value',
'1',
])
).rejects.toThrow()
expect(spy).toHaveBeenCalledWith(expect.stringContaining(COMPLIANT_ERROR_RESPONSE))
})
test('should fail if from address is sanctioned', async () => {
const spy = jest.spyOn(console, 'log')
await expect(
testLocally(TransferCelo, [
'--from',
SANCTIONED_ADDRESSES[0],
'--to',
accounts[0],
'--value',
'1',
])
).rejects.toThrow()
expect(spy).toHaveBeenCalledWith(expect.stringContaining(COMPLIANT_ERROR_RESPONSE))
})
})
6 changes: 5 additions & 1 deletion packages/cli/src/commands/transfer/celo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ export default class TransferCelo extends BaseCommand {
kit.defaultAccount = from
const celoToken = await kit.contracts.getGoldToken()

await newCheckBuilder(this).hasEnoughCelo(from, value).runChecks()
await newCheckBuilder(this)
.isNotSanctioned(from)
.isNotSanctioned(to)
.hasEnoughCelo(from, value)
.runChecks()

await (res.flags.comment
? displaySendTx(
Expand Down
71 changes: 71 additions & 0 deletions packages/cli/src/commands/transfer/dollars.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { COMPLIANT_ERROR_RESPONSE, SANCTIONED_ADDRESSES } from '@celo/compliance'
import { ContractKit, newKitFromWeb3 } from '@celo/contractkit'
import { testWithGanache } from '@celo/dev-utils/lib/ganache-test'
import Web3 from 'web3'
import { testLocally } from '../../test-utils/cliUtils'
import TransferCUSD from './dollars'

process.env.NO_SYNCCHECK = 'true'

// Lots of commands, sometimes times out
jest.setTimeout(15000)

testWithGanache('transfer:dollars cmd', (web3: Web3) => {
let accounts: string[] = []
let kit: ContractKit

beforeEach(async () => {
kit = newKitFromWeb3(web3)
accounts = await web3.eth.getAccounts()
})

test('can transfer cusd', async () => {
const balanceBefore = await kit.getTotalBalance(accounts[0])
const receiverBalanceBefore = await kit.getTotalBalance(accounts[1])
const amountToTransfer = '500000000000000000000'
// Send cUSD to RG contract
await testLocally(TransferCUSD, [
'--from',
accounts[0],
'--to',
accounts[1],
'--value',
amountToTransfer,
'--gasCurrency',
'CELO',
])
// RG cUSD balance should match the amount sent
const receiverBalance = await kit.getTotalBalance(accounts[1])
expect(receiverBalance.cUSD!.toFixed()).toEqual(
receiverBalanceBefore.cUSD!.plus(amountToTransfer).toFixed()
)
// Attempt to send cUSD back
await testLocally(TransferCUSD, [
'--from',
accounts[1],
'--to',
accounts[0],
'--value',
amountToTransfer,
'--gasCurrency',
'CELO',
])
const balanceAfter = await kit.getTotalBalance(accounts[0])
expect(balanceBefore.cUSD).toEqual(balanceAfter.cUSD)
})

test('should fail if to address is sanctioned', async () => {
const spy = jest.spyOn(console, 'log')
await expect(
testLocally(TransferCUSD, [
'--from',
accounts[1],
'--to',
SANCTIONED_ADDRESSES[0],
'--value',
'1',
])
).rejects.toThrow()
expect(spy).toHaveBeenCalledWith(expect.stringContaining(COMPLIANT_ERROR_RESPONSE))
})
})
6 changes: 5 additions & 1 deletion packages/cli/src/commands/transfer/erc20.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,11 @@ export default class TransferErc20 extends BaseCommand {
} catch {
failWith('Invalid erc20 address')
}
await newCheckBuilder(this).hasEnoughErc20(from, value, res.flags.erc20Address).runChecks()
await newCheckBuilder(this)
.isNotSanctioned(from)
.isNotSanctioned(to)
.hasEnoughErc20(from, value, res.flags.erc20Address)
.runChecks()

await displaySendTx('transfer', celoToken.transfer(to, value.toFixed()))
}
Expand Down
71 changes: 71 additions & 0 deletions packages/cli/src/commands/transfer/euros.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { COMPLIANT_ERROR_RESPONSE, SANCTIONED_ADDRESSES } from '@celo/compliance'
import { ContractKit, newKitFromWeb3 } from '@celo/contractkit'
import { testWithGanache } from '@celo/dev-utils/lib/ganache-test'
import Web3 from 'web3'
import { testLocally } from '../../test-utils/cliUtils'
import TransferEURO from './euros'

process.env.NO_SYNCCHECK = 'true'

// Lots of commands, sometimes times out
jest.setTimeout(15000)

testWithGanache('transfer:euros cmd', (web3: Web3) => {
let accounts: string[] = []
let kit: ContractKit

beforeEach(async () => {
kit = newKitFromWeb3(web3)
accounts = await web3.eth.getAccounts()
})

test('can transfer ceur', async () => {
const balanceBefore = await kit.getTotalBalance(accounts[0])
const receiverBalanceBefore = await kit.getTotalBalance(accounts[1])
const amountToTransfer = '500000000000000000000'
// Send cEUR to RG contract
await testLocally(TransferEURO, [
'--from',
accounts[0],
'--to',
accounts[1],
'--value',
amountToTransfer,
'--gasCurrency',
'CELO',
])
// RG cEUR balance should match the amount sent
const receiverBalance = await kit.getTotalBalance(accounts[1])
expect(receiverBalance.cEUR!.toFixed()).toEqual(
receiverBalanceBefore.cEUR!.plus(amountToTransfer).toFixed()
)
// Attempt to send cEUR back
await testLocally(TransferEURO, [
'--from',
accounts[1],
'--to',
accounts[0],
'--value',
amountToTransfer,
'--gasCurrency',
'CELO',
])
const balanceAfter = await kit.getTotalBalance(accounts[0])
expect(balanceBefore.cEUR).toEqual(balanceAfter.cEUR)
})

test('should fail if to address is sanctioned', async () => {
const spy = jest.spyOn(console, 'log')
await expect(
testLocally(TransferEURO, [
'--from',
accounts[1],
'--to',
SANCTIONED_ADDRESSES[0],
'--value',
'1',
])
).rejects.toThrow()
expect(spy).toHaveBeenCalledWith(expect.stringContaining(COMPLIANT_ERROR_RESPONSE))
})
})
1 change: 1 addition & 0 deletions packages/cli/src/exchange-stable-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export default class ExchangeStableBase extends BaseCommand {
}
await newCheckBuilder(this)
.hasEnoughStable(res.flags.from, sellAmount, this._stableCurrency)
.isNotSanctioned(res.flags.from)
.runChecks()

const [stableToken, celoNativeTokenAddress, { mento, brokerAddress }] = await Promise.all([
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/src/transfer-stable-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ export abstract class TransferStableBase extends BaseCommand {

await newCheckBuilder(this)
.hasEnoughStable(from, value, this._stableCurrency)
.isNotSanctioned(from)
.isNotSanctioned(to)
.addConditionalCheck(
`Account can afford transfer and gas paid in ${this._stableCurrency}`,
kit.connection.defaultFeeCurrency === stableToken.address,
Expand Down
Loading
Loading