Skip to content

Commit

Permalink
ci: fix e2e funding script (#4877)
Browse files Browse the repository at this point in the history
### Description

E2E funding script broke because the Exchange contract (Mento V1) was
retired.
We now have to use Mento V2.

See
celo-org/developer-tooling#5 (comment)
and this Slack
[thread](https://valora-app.slack.com/archives/C02E2FE98P2/p1707313527742089).

### Test plan

- Faucet script works

```
❯ NODE_OPTIONS='--unhandled-rejections=strict' yarn ts-node ./e2e/scripts/fund-e2e-accounts.ts
yarn run v1.22.21
$ /Users/jean/src/github.com/valora-inc/wallet/node_modules/.bin/ts-node ./e2e/scripts/fund-e2e-accounts.ts
Initial balance for 0x6131a6d616a4be3737b38988847270a64bc10caa:
┌─────────┬────────────────────┐
│ (index) │       Values       │
├─────────┼────────────────────┤
│  CELO   │ 296.4630610934859  │
│  cUSD   │ 210.81235045479227 │
│  cEUR   │ 254.58206490185884 │
│  cREAL  │ 0.5079986401468344 │
└─────────┴────────────────────┘
Initial balance for 0x86b8f44386cb2d457db79c3dab8cf42f9d8a3fc0:
┌─────────┬────────────────────┐
│ (index) │       Values       │
├─────────┼────────────────────┤
│  CELO   │ 200.1086345828401  │
│  cUSD   │ 284.97333333333336 │
│  cEUR   │ 299.99761512691964 │
│  cREAL  │  4.97972124268512  │
└─────────┴────────────────────┘
Initial faucet balance:
┌─────────┬────────────────────┐
│ (index) │       Values       │
├─────────┼────────────────────┤
│  CELO   │ 0.3998044596294922 │
│  cUSD   │ 314.92579075821374 │
│  cEUR   │ 208.37725279341225 │
│  cREAL  │ 547.2075494343318  │
└─────────┴────────────────────┘
CELO balance is 0.3998044596294922, which is lower than target 174.56761600375182.
Buying 174.16781154412234 CELO with ~126.230605652876074139 cUSD with max slippage of 1%.
Received allowance tx hash 0x779e593031093e3c8fce959660f5eb66d35461e1a601113cf34de762140bce0b with status 1
Received swap tx hash 0xcc5e02c3ae987f49cd78cbb14dcd9327aa3cb65c5602a9181a57e5b08d3e0115 with status 1
cUSD balance is 314.92579075821374, which is higher than target 174.56761600375182.
Selling 140.3581747544619 cUSD for ~193.65329082439476394 CELO with max slippage of 1%.
Received allowance tx hash 0x199799819bf1c921a9f8822dc4cce26b49b7d5ff1297d78c036e21715724a13e with status 1
Received swap tx hash 0xde418d00719b76760731170153a437901f4d3e1187f2b37ef17f5c4405042ebd with status 1
cEUR balance is 208.37725279341225, which is higher than target 174.56761600375182.
Selling 33.80963678966043 cEUR for ~50.263771272202399881 CELO with max slippage of 1%.
Received allowance tx hash 0x4b7e3e7c64dc0dec5c7c6934b37d9e4cee6d3db6a242c5d446081663109f7f5d with status 1
Received swap tx hash 0x3471806819ad3e914e08a4f7fd2694df606616121ac3f1e8657fdf3cd23dfa78 with status 1
Finished funding wallets.
E2E Test Account: 0x6131a6d616a4be3737b38988847270a64bc10caa
┌─────────┬────────────────────┐
│ (index) │       Values       │
├─────────┼────────────────────┤
│  CELO   │ 296.4630610934859  │
│  cUSD   │ 210.81235045479227 │
│  cEUR   │ 254.58206490185884 │
│  cREAL  │ 0.5079986401468344 │
└─────────┴────────────────────┘
E2E Test Account Secure Send: 0x86b8f44386cb2d457db79c3dab8cf42f9d8a3fc0
┌─────────┬────────────────────┐
│ (index) │       Values       │
├─────────┼────────────────────┤
│  CELO   │ 200.1086345828401  │
│  cUSD   │ 284.97333333333336 │
│  cEUR   │ 299.99761512691964 │
│  cREAL  │  4.97972124268512  │
└─────────┴────────────────────┘
Valora Test Faucet: 0xe5F5363e31351C38ac82DBAdeaD91Fd5a7B08846
┌─────────┬────────────────────┐
│ (index) │       Values       │
├─────────┼────────────────────┤
│  CELO   │  418.478571902849  │
│  cUSD   │ 48.33701035087574  │
│  cEUR   │ 174.56761600375185 │
│  cREAL  │ 547.2075494343318  │
└─────────┴────────────────────┘
✨  Done in 55.69s.
```

### Related issues

- N/A

### Backwards compatibility

Yes
  • Loading branch information
jeanregisser committed Feb 10, 2024
1 parent a547627 commit fe63cf5
Show file tree
Hide file tree
Showing 3 changed files with 183 additions and 147 deletions.
314 changes: 168 additions & 146 deletions e2e/scripts/fund-e2e-accounts.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { newKitFromWeb3, StableToken } from '@celo/contractkit'
import { Mento } from '@mento-protocol/mento-sdk'
import dotenv from 'dotenv'
import Web3 from 'web3'
// Would be nice to use viem, but mento is using ethers
import { Contract, providers, utils, Wallet } from 'ethers'
import {
E2E_TEST_FAUCET,
E2E_TEST_WALLET,
Expand All @@ -9,12 +10,39 @@ import {
} from './consts'
import { checkBalance, getBalance } from './utils'

const provider = new providers.JsonRpcProvider('https://alfajores-forno.celo-testnet.org')

dotenv.config({ path: `${__dirname}/../.env` })

const web3 = new Web3('https://alfajores-forno.celo-testnet.org')
const kit = newKitFromWeb3(web3)
const valoraTestFaucetSecret = process.env['TEST_FAUCET_SECRET']!

interface Token {
symbol: string
address: string // Mento expects address to be in checksum format, or else it won't find the trading pair
decimals: number
}

const CELO: Token = {
symbol: 'CELO',
address: utils.getAddress('0xf194afdf50b03e69bd7d057c1aa9e10c9954e4c9'),
decimals: 18,
}
const CUSD: Token = {
symbol: 'cUSD',
address: utils.getAddress('0x874069fa1eb16d44d622f2e0ca25eea172369bc1'),
decimals: 18,
}
const CEUR: Token = {
symbol: 'cEUR',
address: utils.getAddress('0x10c892a6ec43a53e45d0b916b4b7d383b1b78c0f'),
decimals: 18,
}
const TOKENS_BY_SYMBOL: Record<string, Token> = {
CELO,
cUSD: CUSD,
cEUR: CEUR,
}

;(async () => {
const walletsToBeFunded = [E2E_TEST_WALLET, E2E_TEST_WALLET_SECURE_SEND]
const walletBalances = await Promise.all(walletsToBeFunded.map(getBalance))
Expand All @@ -28,17 +56,8 @@ const valoraTestFaucetSecret = process.env['TEST_FAUCET_SECRET']!
console.table(faucetTokenBalances)

// Connect Valora E2E Test Faucet - Private Key Stored in GitHub Secrets
kit.connection.addAccount(
web3.eth.accounts.privateKeyToAccount(valoraTestFaucetSecret.toString()).privateKey
)

// Get Token Contract Wrappers
const celoToken = await kit.contracts.getGoldToken()
const cusdToken = await kit.contracts.getStableToken()
const ceurToken = await kit.contracts.getStableToken(StableToken.cEUR)
const celoExchange = await kit.contracts.getExchange()
const cusdExchange = await kit.contracts.getExchange(StableToken.cUSD)
const ceurExchange = await kit.contracts.getExchange(StableToken.cEUR)
const signer = new Wallet(valoraTestFaucetSecret, provider)
const mento = await Mento.create(signer)

// Balance Faucet
let totalTokenHoldings = 0 // the absolute number of faucet tokens the faucet is holding
Expand All @@ -49,160 +68,163 @@ const valoraTestFaucetSecret = process.env['TEST_FAUCET_SECRET']!
})
const targetFaucetTokenBalance = totalTokenHoldings / REFILL_TOKENS.length

async function swapSell(
sellToken: Token,
buyToken: Token,
sellAmount: number, // in decimal
maxSlippagePercent: number
) {
try {
const sellAmountInSmallestUnit = utils.parseUnits(sellAmount.toString(), sellToken.decimals)
const quoteAmountOut = await mento.getAmountOut(
sellToken.address,
buyToken.address,
sellAmountInSmallestUnit
)
console.log(
`Selling ${sellAmount} ${sellToken.symbol} for ~${utils.formatUnits(
quoteAmountOut,
buyToken.decimals
)} ${buyToken.symbol} with max slippage of ${maxSlippagePercent}%.`
)
const allowanceTxObj = await mento.increaseTradingAllowance(
sellToken.address,
sellAmountInSmallestUnit
)
const allowanceTx = await signer.sendTransaction(allowanceTxObj)
const allowanceReceipt = await allowanceTx.wait()
console.log(
`Received allowance tx hash ${allowanceReceipt.transactionHash} with status ${allowanceReceipt.status}`
)
// allow maxSlippagePercent from quote
const amountOutMin = quoteAmountOut.mul(100 - maxSlippagePercent).div(100)
const swapTxObj = await mento.swapIn(
sellToken.address,
buyToken.address,
sellAmountInSmallestUnit,
amountOutMin
)
const swapTx = await signer.sendTransaction(swapTxObj)
const swapTxReceipt = await swapTx.wait()
console.log(
`Received swap tx hash ${swapTxReceipt.transactionHash} with status ${swapTxReceipt.status}`
)
if (swapTxReceipt.status !== 1) {
throw new Error(`Swap reverted. Tx hash: ${swapTxReceipt.transactionHash}`)
}
} catch (err) {
console.log(`Failed to sell ${sellToken.symbol} for ${buyToken.symbol}`, err)
}
}

async function swapBuy(
sellToken: Token,
buyToken: Token,
buyAmount: number, // in decimal
maxSlippagePercent: number
) {
try {
const buyAmountInSmallestUnit = utils.parseUnits(buyAmount.toString(), buyToken.decimals)
const quoteAmountIn = await mento.getAmountIn(
sellToken.address,
buyToken.address,
buyAmountInSmallestUnit
)
console.log(
`Buying ${buyAmount} ${buyToken.symbol} with ~${utils.formatUnits(quoteAmountIn, sellToken.decimals)} ${sellToken.symbol} with max slippage of ${maxSlippagePercent}%.`
)
// allow maxSlippagePercent from quote
const amountInMax = quoteAmountIn.mul(100 + maxSlippagePercent).div(100)
const allowanceTxObj = await mento.increaseTradingAllowance(sellToken.address, amountInMax)
const allowanceTx = await signer.sendTransaction(allowanceTxObj)
const allowanceReceipt = await allowanceTx.wait()
console.log(
`Received allowance tx hash ${allowanceReceipt.transactionHash} with status ${allowanceReceipt.status}`
)
const swapTxObj = await mento.swapOut(
sellToken.address,
buyToken.address,
buyAmountInSmallestUnit,
amountInMax
)
const swapTx = await signer.sendTransaction(swapTxObj)
const swapTxReceipt = await swapTx.wait()
console.log(
`Received swap tx hash ${swapTxReceipt.transactionHash} with status ${swapTxReceipt.status}`
)
if (swapTxReceipt.status !== 1) {
throw new Error(`Swap reverted. Tx hash: ${swapTxReceipt.transactionHash}`)
}
} catch (err) {
console.log(`Failed to buy ${buyToken.symbol} with ${sellToken.symbol}`, err)
}
}

// Ensure that the faucet has enough balance for each refill tokens
for (const [tokenSymbol, tokenBalance] of Object.entries(faucetTokenBalances)) {
if (!REFILL_TOKENS.includes(tokenSymbol)) {
continue
}

if (tokenBalance >= targetFaucetTokenBalance) {
const sellAmount = tokenBalance - targetFaucetTokenBalance
const amountToExchange = kit.web3.utils.toWei(`${sellAmount}`, 'ether')
console.log(
`${tokenSymbol} balance is ${tokenBalance}, which is higher than target ${targetFaucetTokenBalance}. Selling ${sellAmount}.`
`${tokenSymbol} balance is ${tokenBalance}, which is higher than target ${targetFaucetTokenBalance}.`
)
const sellAmount = tokenBalance - targetFaucetTokenBalance
await swapSell(
TOKENS_BY_SYMBOL[tokenSymbol],
tokenSymbol === 'CELO' ? CUSD : CELO,
sellAmount,
1
)
switch (tokenSymbol) {
case 'CELO':
try {
const celoApproveTx = await celoToken
.approve(celoExchange.address, amountToExchange)
.send({ from: E2E_TEST_FAUCET })
await celoApproveTx.waitReceipt()
const celoSellAmount = await celoExchange.quoteGoldSell(amountToExchange)
const celoSellTx = await celoExchange
.sellGold(amountToExchange, celoSellAmount)
.send({ from: E2E_TEST_FAUCET })
await celoSellTx.waitReceipt()
} catch (err) {
console.log('Failed to sell CELO', err)
} finally {
break
}
case 'cUSD':
try {
const cusdApproveTx = await cusdToken
.approve(cusdExchange.address, amountToExchange)
.send({ from: E2E_TEST_FAUCET })
await cusdApproveTx.waitReceipt()
const cusdSellAmount = await cusdExchange.quoteStableSell(amountToExchange)
const cusdSellTx = await cusdExchange
.sellStable(amountToExchange, cusdSellAmount)
.send({ from: E2E_TEST_FAUCET })
await cusdSellTx.waitReceipt()
} catch (err) {
console.log('Failed to sell cUSD', err)
} finally {
break
}
case 'cEUR':
try {
const ceurApproveTx = await ceurToken
.approve(ceurExchange.address, amountToExchange)
.send({ from: E2E_TEST_FAUCET })
await ceurApproveTx.waitReceipt()
const ceurSellAmount = await ceurExchange.quoteStableSell(amountToExchange)
const ceurSellTx = await ceurExchange
.sellStable(amountToExchange, ceurSellAmount)
.send({ from: E2E_TEST_FAUCET })
await ceurSellTx.waitReceipt()
} catch (err) {
console.log('Failed to sell cEUR', err)
} finally {
break
}
}
} else {
const buyAmount = targetFaucetTokenBalance - tokenBalance
const amountToExchange = kit.web3.utils.toWei(`${buyAmount}`, 'ether')
console.log(
`${tokenSymbol} balance is ${tokenBalance}, which is lower than target ${targetFaucetTokenBalance}. Buying ${buyAmount}.`
`${tokenSymbol} balance is ${tokenBalance}, which is lower than target ${targetFaucetTokenBalance}.`
)
switch (tokenSymbol) {
case 'CELO':
try {
const celoApproveTx = await celoToken
.approve(cusdExchange.address, amountToExchange)
.send({ from: E2E_TEST_FAUCET })
await celoApproveTx.waitReceipt()
const celoBuyAmount = await celoExchange.quoteGoldBuy(amountToExchange)
const celoBuyTx = await celoExchange
.buyGold(amountToExchange, celoBuyAmount)
.send({ from: E2E_TEST_FAUCET })
await celoBuyTx.waitReceipt()
} catch (err) {
console.log('Failed to buy CELO', err)
} finally {
break
}
case 'cUSD':
try {
const cusdApproveTx = await celoToken
.approve(cusdExchange.address, amountToExchange)
.send({ from: E2E_TEST_FAUCET })
await cusdApproveTx.waitReceipt()
const cusdBuyAmount = await cusdExchange.quoteStableBuy(amountToExchange)
const cusdBuyTx = await cusdExchange
.buyStable(amountToExchange, cusdBuyAmount)
.send({ from: E2E_TEST_FAUCET })
await cusdBuyTx.waitReceipt()
} catch (err) {
console.log('Failed to buy cUSD', err)
} finally {
break
}
case 'cEUR':
try {
const ceurApproveTx = await celoToken
.approve(ceurExchange.address, amountToExchange)
.send({ from: E2E_TEST_FAUCET })
await ceurApproveTx.waitReceipt()
const ceurBuyAmount = await ceurExchange.quoteStableBuy(amountToExchange)
const ceurBuyTx = await ceurExchange
.buyStable(amountToExchange, ceurBuyAmount)
.send({ from: E2E_TEST_FAUCET })
await ceurBuyTx.waitReceipt()
} catch (err) {
console.log('Failed to buy cEUR', err)
} finally {
break
}
}
const buyAmount = targetFaucetTokenBalance - tokenBalance
await swapBuy(
tokenSymbol === 'CELO' ? CUSD : CELO,
TOKENS_BY_SYMBOL[tokenSymbol],
buyAmount,
1
)
}
}

async function transferToken(
token: Token,
amount: string, // in decimal
to: string
): Promise<providers.TransactionReceipt> {
const abi = ['function transfer(address to, uint256 value) returns (bool)']
const contract = new Contract(token.address, abi, signer)

const amountInSmallestUnit = utils.parseUnits(amount, token.decimals)
const txObj = await contract.populateTransaction.transfer(to, amountInSmallestUnit)
const tx = await signer.sendTransaction(txObj)
const receipt = await tx.wait()
console.log(
`Received transfer tx hash ${receipt.transactionHash} with status ${receipt.status}`
)

if (receipt.status !== 1) {
throw new Error(`Transfer reverted. Tx hash: ${receipt.transactionHash}`)
}

return receipt
}

// Set Amount To Send
const amountToSend = '100'
const amountToSendWei = web3.utils.toWei(amountToSend, 'ether')

for (let i = 0; i < walletsToBeFunded.length; i++) {
const walletAddress = walletsToBeFunded[i]
const walletBalance = walletBalances[i]
for (const tokenSymbol of REFILL_TOKENS) {
// @ts-ignore
if (walletBalance && walletBalance[tokenSymbol] < 200) {
console.log(`Sending ${amountToSend} ${tokenSymbol} to ${walletAddress}`)
let tx: any
switch (tokenSymbol) {
case 'CELO':
tx = await celoToken
.transfer(walletAddress, amountToSendWei)
.send({ from: E2E_TEST_FAUCET })
break
case 'cUSD':
tx = await cusdToken
.transfer(walletAddress, amountToSendWei)
.send({ from: E2E_TEST_FAUCET })
break
case 'cEUR':
tx = await ceurToken
.transfer(walletAddress, amountToSendWei)
.send({ from: E2E_TEST_FAUCET })
break
}
const receipt = await tx.waitReceipt()

console.log(
`Received tx hash ${receipt.transactionHash} for ${tokenSymbol} transfer to ${walletAddress}`
)
await transferToken(TOKENS_BY_SYMBOL[tokenSymbol], amountToSend, walletAddress)
}
}
}
Expand All @@ -213,7 +235,7 @@ const valoraTestFaucetSecret = process.env['TEST_FAUCET_SECRET']!
console.table(await getBalance(E2E_TEST_WALLET))
console.log('E2E Test Account Secure Send:', E2E_TEST_WALLET_SECURE_SEND)
console.table(await getBalance(E2E_TEST_WALLET_SECURE_SEND))
console.log('Valora Test Facuet:', E2E_TEST_FAUCET)
console.log('Valora Test Faucet:', E2E_TEST_FAUCET)
console.table(await getBalance(E2E_TEST_FAUCET))

await checkBalance(E2E_TEST_WALLET)
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@
"@babel/runtime": "^7.20.0",
"@faker-js/faker": "^5.5.3",
"@jambit/eslint-plugin-typed-redux-saga": "^0.4.0",
"@mento-protocol/mento-sdk": "^0.2.3",
"@testing-library/jest-native": "^5.4.3",
"@testing-library/react-native": "^12.4.3",
"@types/crypto-js": "^4.1.1",
Expand Down Expand Up @@ -257,6 +258,7 @@
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-native": "^4.0.0",
"ethers": "^5.7.2",
"husky": "^3.0.0",
"jest": "^29.6.2",
"jest-circus": "^29.6.2",
Expand Down
Loading

0 comments on commit fe63cf5

Please sign in to comment.