From f42ead056110a74fa1301765da29d36273597775 Mon Sep 17 00:00:00 2001
From: Joe Tsang <30622993+jtsang586@users.noreply.github.com>
Date: Thu, 27 Oct 2022 11:58:20 +0100
Subject: [PATCH] Test/766 withdrawals with wallet (#1869)
* test: withdrawal flow passing
* chore: functions for depositing assets
* test: withdrawal full flow passing
* test: unhappy withdrawal paths
* chore: add variable
---
.../integration/flow/withdrawal-flow.cy.js | 177 ++++++++++++++++++
.../src/support/wallet-teardown.functions.js | 50 +++++
apps/token/src/routes/withdrawals/index.tsx | 4 +-
.../pages/portfolio/withdrawals-container.tsx | 5 +-
libs/cypress/src/index.ts | 2 +
.../commands/add-validators-to-multisig.ts | 21 +++
.../vega-wallet-receive-fauceted-asset.ts | 3 +-
.../src/contracts/collateral-bridge.ts | 8 +
.../src/lib/pending-withdrawals-table.tsx | 6 +-
libs/withdraws/src/lib/withdraw-form.tsx | 3 +
.../withdraws/src/lib/withdrawal-feedback.tsx | 8 +-
11 files changed, 281 insertions(+), 6 deletions(-)
create mode 100644 apps/token-e2e/src/integration/flow/withdrawal-flow.cy.js
create mode 100644 libs/cypress/src/lib/commands/add-validators-to-multisig.ts
diff --git a/apps/token-e2e/src/integration/flow/withdrawal-flow.cy.js b/apps/token-e2e/src/integration/flow/withdrawal-flow.cy.js
new file mode 100644
index 000000000..2c276a37a
--- /dev/null
+++ b/apps/token-e2e/src/integration/flow/withdrawal-flow.cy.js
@@ -0,0 +1,177 @@
+const withdraw = 'withdraw';
+const selectAsset = 'select-asset';
+const ethAddressInput = 'eth-address-input';
+const amountInput = 'amount-input';
+const balanceAvailable = 'BALANCE_AVAILABLE_value';
+const withdrawalThreshold = 'WITHDRAWAL_THRESHOLD_value';
+const delayTime = 'DELAY_TIME_value';
+const useMaximum = 'use-maximum';
+const submitWithdrawalButton = 'submit-withdrawal';
+const dialogTitle = 'dialog-title';
+const dialogClose = 'dialog-close';
+const txExplorerLink = 'tx-block-explorer';
+const withdrawalAssetSymbol = 'withdrawal-asset-symbol';
+const withdrawalAmount = 'withdrawal-amount';
+const withdrawalRecipient = 'withdrawal-recipient';
+const withdrawFundsButton = 'withdraw-funds';
+const completeWithdrawalButton = 'complete-withdrawal';
+const usdtName = 'USDC (local)';
+const usdcEthAddress = '0x1b8a1B6CBE5c93609b46D1829Cc7f3Cb8eeE23a0';
+const usdcSymbol = 'tUSDC';
+const truncatedWithdrawalEthAddress = '0xEe7D…22d94F';
+const formValidationError = 'input-error-text';
+const txTimeout = Cypress.env('txTimeout');
+
+context(
+ 'Withdrawals - with eth and vega wallet connected',
+ { tags: '@slow' },
+ function () {
+ before('visit withdrawals and connect vega wallet', function () {
+ cy.updateCapsuleMultiSig(); // When running tests locally, will fail if run without restarting capsule
+ cy.vega_wallet_import();
+ cy.deposit_asset(usdcEthAddress);
+ });
+
+ beforeEach('Navigate to withdrawal page', function () {
+ cy.visit('/');
+ cy.navigate_to('withdrawals');
+ cy.vega_wallet_connect();
+ cy.ethereum_wallet_connect();
+ waitForAssetsDisplayed(usdtName);
+ });
+
+ it('Able to open withdrawal form with vega wallet connected', function () {
+ cy.getByTestId(withdraw).should('be.visible').click();
+ cy.getByTestId(selectAsset)
+ .find('option')
+ .should('have.length.at.least', 5);
+ cy.getByTestId(ethAddressInput).should('be.visible');
+ cy.getByTestId(amountInput).should('be.visible');
+ });
+
+ it('Unable to submit withdrawal with invalid fields', function () {
+ cy.getByTestId(withdraw).should('be.visible').click();
+ cy.getByTestId(selectAsset).select('BTC (local)');
+ cy.getByTestId(balanceAvailable).should('have.text', '0.00000');
+ cy.getByTestId(submitWithdrawalButton).click();
+ cy.getByTestId(formValidationError).should('have.length', 1);
+ cy.getByTestId(useMaximum).click();
+ cy.getByTestId(submitWithdrawalButton).click();
+ cy.getByTestId(formValidationError).should(
+ 'have.text',
+ 'Value is below minimum'
+ );
+ cy.getByTestId(selectAsset).select(usdtName);
+ cy.getByTestId(amountInput).clear().click().type('10');
+ cy.getByTestId(ethAddressInput).click().type('123');
+ cy.getByTestId(submitWithdrawalButton).click();
+ cy.getByTestId(formValidationError).should(
+ 'have.text',
+ 'Invalid Ethereum address'
+ );
+ });
+
+ it('Able to withdraw asset: -eth wallet connected -withdraw funds button', function () {
+ // fill in withdrawal form
+ cy.getByTestId(withdraw).should('be.visible').click();
+ cy.getByTestId(selectAsset).select(usdtName);
+ cy.getByTestId(balanceAvailable, txTimeout).should('exist');
+ cy.getByTestId(withdrawalThreshold).should('have.text', '100,000.00000T');
+ cy.getByTestId(delayTime).should('have.text', 'None');
+ cy.getByTestId(amountInput).click().type('100');
+ cy.getByTestId(submitWithdrawalButton).click();
+
+ cy.contains('Awaiting network confirmation').should('be.visible');
+ // assert withdrawal request
+ cy.getByTestId(dialogTitle, txTimeout).should(
+ 'have.text',
+ 'Transaction complete'
+ );
+ cy.getByTestId(txExplorerLink)
+ .should('have.attr', 'href')
+ .and('contain', '/txs/');
+ cy.getByTestId(withdrawalAssetSymbol).should('have.text', usdcSymbol);
+ cy.getByTestId(withdrawalAmount).should('have.text', '100.00000');
+ cy.getByTestId(withdrawalRecipient)
+ .should('have.text', truncatedWithdrawalEthAddress)
+ .and('have.attr', 'href')
+ .and('contain', `/address/${Cypress.env('ethWalletPublicKey')}`);
+ cy.getByTestId(withdrawFundsButton).click();
+ // withdrawal complete
+ cy.getByTestId(dialogTitle, txTimeout).should(
+ 'have.text',
+ 'Withdraw asset complete'
+ );
+ cy.getByTestId(dialogClose).click();
+
+ // need to reload page to see withdrawal history complete
+ cy.reload();
+ waitForAssetsDisplayed(usdtName);
+
+ // withdrawal history for complete withdrawal displayed
+ cy.get('[col-id="txHash"]', txTimeout)
+ .should('have.length.above', 1)
+ .eq(1)
+ .parent()
+ .within(() => {
+ cy.get('[col-id="asset.symbol"]').should('have.text', usdcSymbol);
+ cy.get('[col-id="amount"]').should('have.text', '100.00000');
+ cy.get('[col-id="details.receiverAddress"]')
+ .find('a')
+ .should('have.attr', 'href')
+ .and('contain', 'https://sepolia.etherscan.io/address/');
+ cy.get('[col-id="withdrawnTimestamp"]').should('not.be.empty');
+ cy.get('[col-id="status"]').should('have.text', 'Completed');
+ cy.get('[col-id="txHash"]')
+ .find('a')
+ .should('have.attr', 'href')
+ .and('contain', 'https://sepolia.etherscan.io/tx/');
+ });
+ });
+
+ // Skipping because of bug #1857
+ it.skip('Able to withdraw asset: -eth wallet not connected', function () {
+ const ethWalletAddress = Cypress.env('ethWalletPublicKey');
+ cy.reload();
+ waitForAssetsDisplayed(usdtName);
+ // fill in withdrawal form
+ cy.getByTestId(withdraw).should('be.visible').click();
+ cy.getByTestId(selectAsset).select(usdtName);
+ cy.getByTestId(ethAddressInput).should('be.empty');
+ cy.getByTestId(amountInput).click().type('100');
+ cy.getByTestId(submitWithdrawalButton).click();
+
+ // Need eth address to submit withdrawal
+ cy.getByTestId(formValidationError).should('have.length', 1);
+ cy.getByTestId(ethAddressInput).click().type(ethWalletAddress);
+ cy.getByTestId(submitWithdrawalButton).click();
+
+ cy.contains('Awaiting network confirmation').should('be.visible');
+ // assert withdrawal request
+ cy.getByTestId(dialogTitle, txTimeout).should(
+ 'have.text',
+ 'Transaction complete'
+ );
+ cy.getByTestId(dialogClose).click();
+
+ cy.getByTestId(completeWithdrawalButton)
+ .eq(0)
+ .parent()
+ .parent()
+ .within(() => {
+ cy.get('[col-id="asset.symbol"]').should('have.text', usdcSymbol);
+ cy.get('[col-id="amount"]').should('have.text', '100.00000');
+ cy.get('[col-id="details.receiverAddress"]')
+ .find('a')
+ .should('have.attr', 'href')
+ .and('contain', 'https://sepolia.etherscan.io/address/');
+ cy.get('[col-id="createdTimestamp"]').should('not.be.empty');
+ cy.getByTestId(completeWithdrawalButton).click();
+ });
+ });
+
+ function waitForAssetsDisplayed(expectedAsset) {
+ cy.contains(expectedAsset, txTimeout).should('be.visible');
+ }
+ }
+);
diff --git a/apps/token-e2e/src/support/wallet-teardown.functions.js b/apps/token-e2e/src/support/wallet-teardown.functions.js
index f08793e93..9b94bb725 100644
--- a/apps/token-e2e/src/support/wallet-teardown.functions.js
+++ b/apps/token-e2e/src/support/wallet-teardown.functions.js
@@ -2,6 +2,8 @@ import {
StakingBridge,
Token,
TokenVesting,
+ TokenFaucetable,
+ CollateralBridge,
} from '@vegaprotocol/smart-contracts';
import { ethers, Wallet } from 'ethers';
@@ -18,6 +20,7 @@ const ethStakingBridgeContractAddress = Cypress.env(
const ethProviderUrl = Cypress.env('ethProviderUrl');
const getAccount = (number = 0) => `m/44'/60'/0'/0/${number}`;
const transactionTimeout = '90000';
+const Erc20BridgeAddress = '0x9708FF7510D4A7B9541e1699d15b53Ecb1AFDc54';
before('Vega wallet teardown prep', function () {
cy.wrap(new ethers.providers.JsonRpcProvider({ url: ethProviderUrl }), {
@@ -40,6 +43,53 @@ before('Vega wallet teardown prep', function () {
});
});
+Cypress.Commands.add('deposit_asset', function (assetEthAddress) {
+ cy.get('@signer', { log: false }).then((signer) => {
+ // Approve asset
+ cy.wrap(
+ new TokenFaucetable(assetEthAddress, signer).approve(
+ Erc20BridgeAddress,
+ '10000000000'
+ )
+ )
+ .then((tx) => {
+ cy.wait_for_transaction(tx);
+ })
+ .then(() => {
+ cy.wrap(new CollateralBridge(Erc20BridgeAddress, signer), {
+ log: false,
+ }).then((bridge) => {
+ // Deposit asset into vega wallet
+ cy.wrap(
+ bridge.deposit_asset(
+ assetEthAddress,
+ '1000000000',
+ '0x' + vegaWalletPubKey
+ ),
+ { timeout: transactionTimeout, log: false }
+ ).then((tx) => {
+ cy.wait_for_transaction(tx);
+ });
+ });
+ });
+ });
+});
+
+Cypress.Commands.add('faucet_asset', function (assetEthAddress) {
+ cy.get('@signer', { log: false }).then((signer) => {
+ cy.wrap(new TokenFaucetable(assetEthAddress, signer), { log: false }).then(
+ (token) => {
+ cy.wrap(token.faucet(), {
+ timeout: transactionTimeout,
+ log: false,
+ }).then((tx) => {
+ cy.wait_for_transaction(tx);
+ });
+ }
+ );
+ });
+});
+
Cypress.Commands.add('vega_wallet_teardown', function () {
cy.get(vegaWalletContainer).within(() => {
cy.get(vegaWalletAssociatedBalance)
diff --git a/apps/token/src/routes/withdrawals/index.tsx b/apps/token/src/routes/withdrawals/index.tsx
index 9fe4e9ae9..f11622b19 100644
--- a/apps/token/src/routes/withdrawals/index.tsx
+++ b/apps/token/src/routes/withdrawals/index.tsx
@@ -54,7 +54,9 @@ const WithdrawPendingContainer = () => {
<>
{t('withdrawalsPreparedWarningHeading')}
-
+
{t('withdrawalsText')}
{t('withdrawalsPreparedWarningText')}
diff --git a/apps/trading/pages/portfolio/withdrawals-container.tsx b/apps/trading/pages/portfolio/withdrawals-container.tsx index 14b9eba56..8fcd75f37 100644 --- a/apps/trading/pages/portfolio/withdrawals-container.tsx +++ b/apps/trading/pages/portfolio/withdrawals-container.tsx @@ -34,7 +34,10 @@ export const WithdrawalsContainer = () => { {completed && completed.length > 0 && (