From 9266ff4bd80dddfd020566116a4e7a483dd72ced Mon Sep 17 00:00:00 2001 From: Dexter Edwards Date: Fri, 10 Jun 2022 11:36:38 +0100 Subject: [PATCH] Feat/smart contracts update (#536) * feat: add new bridge contract logic * chore: remove unused contract from provider * chore: remove minimum as no longer exists * feat: use new withdrawals contract, but allow for old contract for token * feat: power contracts selection by a flag * style: lint * Update libs/smart-contracts/src/contracts/collateral-bridge-new.ts Co-authored-by: Matthew Russell * chore: rename env var as per feedback * chore: consistent varaible names as per PR comments * chore: add back in checks for minimum as per PR comments * style: formatting Co-authored-by: Matthew Russell --- apps/token/.env | 1 + apps/token/src/config/flags.ts | 3 + .../contexts/contracts/contracts-context.ts | 2 - .../contexts/contracts/contracts-provider.tsx | 11 +- apps/token/src/routes/withdraw/index.tsx | 7 +- apps/token/src/routes/withdrawals/index.tsx | 5 +- .../withdraw/withdraw-page-container.tsx | 1 + .../__generated__/DealTicketQuery.ts | 112 ++++ .../src/hooks/__generated__/OrderEvent.ts | 108 ++++ libs/deposits/src/lib/deposit-form.spec.tsx | 23 +- libs/deposits/src/lib/deposit-form.tsx | 27 +- libs/deposits/src/lib/deposit-limits.tsx | 6 - .../src/lib/use-get-deposit-limits.ts | 11 +- libs/deposits/src/lib/use-submit-deposit.ts | 2 +- .../__generated__/MarketDepthSubscription.ts | 2 +- .../src/abis/erc20_bridge_abi.json | 198 +++++- .../src/abis/erc20_bridge_new_abi.json | 589 ++++++++++++++++++ .../src/contracts/collateral-bridge-new.ts | 51 ++ .../src/contracts/collateral-bridge.ts | 1 + libs/smart-contracts/src/contracts/index.ts | 1 + libs/types/.env | 1 + libs/web3/src/lib/use-bridge-contract.ts | 22 +- .../src/lib/__generated__/Erc20ApprovalNew.ts | 52 ++ libs/withdraws/src/lib/queries.ts | 14 + .../src/lib/use-complete-withdraw.spec.tsx | 19 +- .../src/lib/use-complete-withdraw.ts | 58 +- libs/withdraws/src/lib/use-withdraw.spec.tsx | 11 +- libs/withdraws/src/lib/use-withdraw.ts | 58 +- .../src/lib/withdraw-manager.spec.tsx | 1 + libs/withdraws/src/lib/withdraw-manager.tsx | 5 +- libs/withdraws/src/lib/withdrawals-table.tsx | 2 +- 31 files changed, 1254 insertions(+), 150 deletions(-) create mode 100644 libs/deal-ticket/src/components/__generated__/DealTicketQuery.ts create mode 100644 libs/deal-ticket/src/hooks/__generated__/OrderEvent.ts create mode 100644 libs/smart-contracts/src/abis/erc20_bridge_new_abi.json create mode 100644 libs/smart-contracts/src/contracts/collateral-bridge-new.ts create mode 100644 libs/types/.env create mode 100644 libs/withdraws/src/lib/__generated__/Erc20ApprovalNew.ts diff --git a/apps/token/.env b/apps/token/.env index e58d5dd3c..4eacba644 100644 --- a/apps/token/.env +++ b/apps/token/.env @@ -25,6 +25,7 @@ NX_ETHEREUM_CHAIN_ID = 3 NX_ETHEREUM_PROVIDER_URL = "https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8" NX_ETHERSCAN_URL = "https://ropsten.etherscan.io" NX_FAIRGROUND = false +NX_IS_NEW_BRIDGE_CONTRACT = true NX_VEGA_NETWORKS='{\"DEVNET\":\"https://dev.token.vega.xyz\",\"STAGNET\":\"https://dev.token.vega.xyz\",\"STAGNET2\":\"staging2.token.vega.xyz\",\"TESTNET\":\"token.fairground.wtf\",\"MAINNET\":\"token.vega.xyz\"}' #Test configuration variables diff --git a/apps/token/src/config/flags.ts b/apps/token/src/config/flags.ts index d02e3c34b..6ef78b9cf 100644 --- a/apps/token/src/config/flags.ts +++ b/apps/token/src/config/flags.ts @@ -8,4 +8,7 @@ export const Flags = { MOCK: TRUTHY.includes(process.env['NX_MOCKED'] as string), FAIRGROUND: TRUTHY.includes(process.env['NX_FAIRGROUND'] as string), NETWORK_LIMITS: TRUTHY.includes(process.env['NX_NETWORK_LIMITS'] as string), + USE_NEW_BRIDGE_CONTRACT: TRUTHY.includes( + process.env['NX_IS_NEW_BRIDGE_CONTRACT'] as string + ), }; diff --git a/apps/token/src/contexts/contracts/contracts-context.ts b/apps/token/src/contexts/contracts/contracts-context.ts index a415f68c8..253874265 100644 --- a/apps/token/src/contexts/contracts/contracts-context.ts +++ b/apps/token/src/contexts/contracts/contracts-context.ts @@ -1,6 +1,5 @@ import type { Claim, - CollateralBridge, Token, TokenVesting, StakingBridge, @@ -12,7 +11,6 @@ export interface ContractsContextShape { staking: StakingBridge; vesting: TokenVesting; claim: Claim; - erc20Bridge: CollateralBridge; } export const ContractsContext = React.createContext< diff --git a/apps/token/src/contexts/contracts/contracts-provider.tsx b/apps/token/src/contexts/contracts/contracts-provider.tsx index 0d288cf99..e11bf8b9a 100644 --- a/apps/token/src/contexts/contracts/contracts-provider.tsx +++ b/apps/token/src/contexts/contracts/contracts-provider.tsx @@ -2,7 +2,6 @@ import { Token, TokenVesting, Claim, - CollateralBridge, StakingBridge, } from '@vegaprotocol/smart-contracts'; import { Splash } from '@vegaprotocol/ui-toolkit'; @@ -23,10 +22,8 @@ export const ContractsProvider = ({ children }: { children: JSX.Element }) => { const { provider: activeProvider, account } = useWeb3React(); const { config } = useEthereumConfig(); const { VEGA_ENV, ADDRESSES } = useEnvironment(); - const [contracts, setContracts] = React.useState | null>(null); + const [contracts, setContracts] = + React.useState(null); // Create instances of contract classes. If we have an account use a signer for the // contracts so that we can sign transactions, otherwise use the provider for just @@ -56,10 +53,6 @@ export const ContractsProvider = ({ children }: { children: JSX.Element }) => { signer || provider ), claim: new Claim(ADDRESSES.claimAddress, signer || provider), - erc20Bridge: new CollateralBridge( - config.collateral_bridge_contract.address, - signer || provider - ), }); } }, [activeProvider, account, config, ADDRESSES, VEGA_ENV]); diff --git a/apps/token/src/routes/withdraw/index.tsx b/apps/token/src/routes/withdraw/index.tsx index d8b6d47e8..0f063d324 100644 --- a/apps/token/src/routes/withdraw/index.tsx +++ b/apps/token/src/routes/withdraw/index.tsx @@ -15,6 +15,7 @@ import type { WithdrawPageVariables, } from './__generated__/WithdrawPage'; import { WithdrawManager } from '@vegaprotocol/withdraws'; +import { Flags } from '../../config'; const Withdraw = () => { const { t } = useTranslation(); @@ -149,7 +150,11 @@ export const WithdrawContainer = ({ currVegaKey }: WithdrawContainerProps) => { )} - + ); }; diff --git a/apps/token/src/routes/withdrawals/index.tsx b/apps/token/src/routes/withdrawals/index.tsx index fea7ecd1d..b00aae9ba 100644 --- a/apps/token/src/routes/withdrawals/index.tsx +++ b/apps/token/src/routes/withdrawals/index.tsx @@ -18,6 +18,7 @@ import type { Withdrawals_party_withdrawals } from '@vegaprotocol/withdraws'; import { useCompleteWithdraw, useWithdrawals } from '@vegaprotocol/withdraws'; import { TransactionDialog } from '@vegaprotocol/web3'; import { WithdrawalStatus } from '../../__generated__/globalTypes'; +import { Flags } from '../../config'; const Withdrawals = () => { const { t } = useTranslation(); @@ -34,7 +35,9 @@ const Withdrawals = () => { const WithdrawPendingContainer = () => { const { t } = useTranslation(); - const { transaction, submit } = useCompleteWithdraw(); + const { transaction, submit } = useCompleteWithdraw( + Flags.USE_NEW_BRIDGE_CONTRACT + ); const { data, loading, error } = useWithdrawals(); const withdrawals = React.useMemo(() => { diff --git a/apps/trading/pages/portfolio/withdraw/withdraw-page-container.tsx b/apps/trading/pages/portfolio/withdraw/withdraw-page-container.tsx index 091e81d08..4e28898ed 100644 --- a/apps/trading/pages/portfolio/withdraw/withdraw-page-container.tsx +++ b/apps/trading/pages/portfolio/withdraw/withdraw-page-container.tsx @@ -83,6 +83,7 @@ export const WithdrawPageContainer = ({ assets={data.assets} accounts={data.party?.accounts || []} initialAssetId={assetId} + isNewContract={true} /> ); diff --git a/libs/deal-ticket/src/components/__generated__/DealTicketQuery.ts b/libs/deal-ticket/src/components/__generated__/DealTicketQuery.ts new file mode 100644 index 000000000..5bb0c3d36 --- /dev/null +++ b/libs/deal-ticket/src/components/__generated__/DealTicketQuery.ts @@ -0,0 +1,112 @@ +/* tslint:disable */ +/* eslint-disable */ +// @generated +// This file was automatically generated and should not be edited. + +import { MarketState, MarketTradingMode } from "@vegaprotocol/types"; + +// ==================================================== +// GraphQL query operation: DealTicketQuery +// ==================================================== + +export interface DealTicketQuery_market_tradableInstrument_instrument_product { + __typename: "Future"; + /** + * String representing the quote (e.g. BTCUSD -> USD is quote) + */ + quoteName: string; +} + +export interface DealTicketQuery_market_tradableInstrument_instrument { + __typename: "Instrument"; + /** + * A reference to or instance of a fully specified product, including all required product parameters for that product (Product union) + */ + product: DealTicketQuery_market_tradableInstrument_instrument_product; +} + +export interface DealTicketQuery_market_tradableInstrument { + __typename: "TradableInstrument"; + /** + * An instance of or reference to a fully specified instrument. + */ + instrument: DealTicketQuery_market_tradableInstrument_instrument; +} + +export interface DealTicketQuery_market_depth_lastTrade { + __typename: "Trade"; + /** + * The price of the trade (probably initially the passive order price, other determination algorithms are possible though) (uint64) + */ + price: string; +} + +export interface DealTicketQuery_market_depth { + __typename: "MarketDepth"; + /** + * Last trade for the given market (if available) + */ + lastTrade: DealTicketQuery_market_depth_lastTrade | null; +} + +export interface DealTicketQuery_market { + __typename: "Market"; + /** + * Market ID + */ + id: string; + /** + * Market full name + */ + name: string; + /** + * decimalPlaces indicates the number of decimal places that an integer must be shifted by in order to get a correct + * number denominated in the currency of the Market. (uint64) + * + * Examples: + * Currency Balance decimalPlaces Real Balance + * GBP 100 0 GBP 100 + * GBP 100 2 GBP 1.00 + * GBP 100 4 GBP 0.01 + * GBP 1 4 GBP 0.0001 ( 0.01p ) + * + * GBX (pence) 100 0 GBP 1.00 (100p ) + * GBX (pence) 100 2 GBP 0.01 ( 1p ) + * GBX (pence) 100 4 GBP 0.0001 ( 0.01p ) + * GBX (pence) 1 4 GBP 0.000001 ( 0.0001p) + */ + decimalPlaces: number; + /** + * positionDecimalPlaces indicated the number of decimal places that an integer must be shifted in order to get a correct size (uint64). + * i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes. + * 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market. + */ + positionDecimalPlaces: number; + /** + * Current state of the market + */ + state: MarketState; + /** + * Current mode of execution of the market + */ + tradingMode: MarketTradingMode; + /** + * An instance of or reference to a tradable instrument. + */ + tradableInstrument: DealTicketQuery_market_tradableInstrument; + /** + * Current depth on the order book for this market + */ + depth: DealTicketQuery_market_depth; +} + +export interface DealTicketQuery { + /** + * An instrument that is trading on the VEGA network + */ + market: DealTicketQuery_market | null; +} + +export interface DealTicketQueryVariables { + marketId: string; +} diff --git a/libs/deal-ticket/src/hooks/__generated__/OrderEvent.ts b/libs/deal-ticket/src/hooks/__generated__/OrderEvent.ts new file mode 100644 index 000000000..7aafc6716 --- /dev/null +++ b/libs/deal-ticket/src/hooks/__generated__/OrderEvent.ts @@ -0,0 +1,108 @@ +/* tslint:disable */ +/* eslint-disable */ +// @generated +// This file was automatically generated and should not be edited. + +import { BusEventType, OrderType, OrderStatus, OrderRejectionReason } from "@vegaprotocol/types"; + +// ==================================================== +// GraphQL subscription operation: OrderEvent +// ==================================================== + +export interface OrderEvent_busEvents_event_TimeUpdate { + __typename: "TimeUpdate" | "MarketEvent" | "TransferResponses" | "PositionResolution" | "Trade" | "Account" | "Party" | "MarginLevels" | "Proposal" | "Vote" | "MarketData" | "NodeSignature" | "LossSocialization" | "SettlePosition" | "Market" | "Asset" | "MarketTick" | "SettleDistressed" | "AuctionEvent" | "RiskFactor" | "Deposit" | "Withdrawal" | "OracleSpec" | "LiquidityProvision"; +} + +export interface OrderEvent_busEvents_event_Order_market { + __typename: "Market"; + /** + * Market full name + */ + name: string; + /** + * decimalPlaces indicates the number of decimal places that an integer must be shifted by in order to get a correct + * number denominated in the currency of the Market. (uint64) + * + * Examples: + * Currency Balance decimalPlaces Real Balance + * GBP 100 0 GBP 100 + * GBP 100 2 GBP 1.00 + * GBP 100 4 GBP 0.01 + * GBP 1 4 GBP 0.0001 ( 0.01p ) + * + * GBX (pence) 100 0 GBP 1.00 (100p ) + * GBX (pence) 100 2 GBP 0.01 ( 1p ) + * GBX (pence) 100 4 GBP 0.0001 ( 0.01p ) + * GBX (pence) 1 4 GBP 0.000001 ( 0.0001p) + */ + decimalPlaces: number; +} + +export interface OrderEvent_busEvents_event_Order { + __typename: "Order"; + /** + * Type the order type (defaults to PARTY) + */ + type: OrderType | null; + /** + * Hash of the order data + */ + id: string; + /** + * The status of an order, for example 'Active' + */ + status: OrderStatus; + /** + * Reason for the order to be rejected + */ + rejectionReason: OrderRejectionReason | null; + /** + * RFC3339Nano formatted date and time for when the order was created (timestamp) + */ + createdAt: string; + /** + * Total number of contracts that may be bought or sold (immutable) (uint64) + */ + size: string; + /** + * The worst price the order will trade at (e.g. buy for price or less, sell for price or more) (uint64) + */ + price: string; + /** + * The market the order is trading on (probably stored internally as a hash of the market details) + */ + market: OrderEvent_busEvents_event_Order_market | null; +} + +export type OrderEvent_busEvents_event = OrderEvent_busEvents_event_TimeUpdate | OrderEvent_busEvents_event_Order; + +export interface OrderEvent_busEvents { + __typename: "BusEvent"; + /** + * the id for this event + */ + eventId: string; + /** + * the block hash + */ + block: string; + /** + * the type of event we're dealing with + */ + type: BusEventType; + /** + * the payload - the wrapped event + */ + event: OrderEvent_busEvents_event; +} + +export interface OrderEvent { + /** + * Subscribe to event data from the event bus + */ + busEvents: OrderEvent_busEvents[] | null; +} + +export interface OrderEventVariables { + partyId: string; +} diff --git a/libs/deposits/src/lib/deposit-form.spec.tsx b/libs/deposits/src/lib/deposit-form.spec.tsx index 27785a797..1f42f0e91 100644 --- a/libs/deposits/src/lib/deposit-form.spec.tsx +++ b/libs/deposits/src/lib/deposit-form.spec.tsx @@ -105,12 +105,7 @@ it('Form validation', async () => { await screen.findByText('Amount is above permitted maximum') ).toBeInTheDocument(); - rerender( - - ); + rerender(); const amountMoreThanAllowance = '31'; fireEvent.change(screen.getByLabelText('Amount'), { @@ -130,16 +125,11 @@ it('Form validation', async () => { expect(await screen.findByText('Value is below minimum')).toBeInTheDocument(); - rerender( - - ); - const amountLessThanLimit = '5'; + const amountLessThanZero = '-0.00001'; fireEvent.change(screen.getByLabelText('Amount'), { - target: { value: amountLessThanLimit }, + target: { value: amountLessThanZero }, }); + expect(await screen.findByText('Value is below minimum')).toBeInTheDocument(); }); @@ -190,10 +180,7 @@ it('Deposit', async () => { /> ); - // Check deposit limits are displayed - expect( - screen.getByText('Minimum', { selector: 'th' }).nextElementSibling - ).toHaveTextContent(limits.min.toString()); + // Check deposit limit is displayed expect( screen.getByText('Maximum', { selector: 'th' }).nextElementSibling ).toHaveTextContent(limits.max.toString()); diff --git a/libs/deposits/src/lib/deposit-form.tsx b/libs/deposits/src/lib/deposit-form.tsx index 3111dda78..fd690ee76 100644 --- a/libs/deposits/src/lib/deposit-form.tsx +++ b/libs/deposits/src/lib/deposit-form.tsx @@ -1,5 +1,4 @@ import { - addDecimal, removeDecimal, t, ethereumAddress, @@ -7,6 +6,7 @@ import { vegaPublicKey, minSafe, maxSafe, + addDecimal, } from '@vegaprotocol/react-helpers'; import { Button, @@ -46,7 +46,6 @@ export interface DepositFormProps { }) => Promise; requestFaucet: () => Promise; limits: { - min: BigNumber; max: BigNumber; } | null; allowance: BigNumber | undefined; @@ -97,19 +96,6 @@ export const DepositForm = ({ const assetId = useWatch({ name: 'asset', control }); const amount = useWatch({ name: 'amount', control }); - const min = useMemo(() => { - // Min viable amount given asset decimals EG for WEI 0.000000000000000001 - const minViableAmount = selectedAsset - ? new BigNumber(addDecimal('1', selectedAsset.decimals)) - : new BigNumber(0); - - const min = limits - ? BigNumber.maximum(minViableAmount, limits.min) - : minViableAmount; - - return min; - }, [limits, selectedAsset]); - const max = useMemo(() => { const maxApproved = allowance ? allowance : new BigNumber(Infinity); const maxAvailable = available ? available : new BigNumber(Infinity); @@ -127,6 +113,15 @@ export const DepositForm = ({ }; }, [limits, allowance, available]); + const min = useMemo(() => { + // Min viable amount given asset decimals EG for WEI 0.000000000000000001 + const minViableAmount = selectedAsset + ? new BigNumber(addDecimal('1', selectedAsset.decimals)) + : new BigNumber(0); + + return minViableAmount; + }, [selectedAsset]); + useEffect(() => { onSelectAsset(assetId); }, [assetId, onSelectAsset]); @@ -207,7 +202,7 @@ export const DepositForm = ({ {...register('amount', { validate: { required, - minSafe: (value) => minSafe(min)(value), + minSafe: (value) => minSafe(new BigNumber(min))(value), maxSafe: (v) => { const value = new BigNumber(v); if (value.isGreaterThan(max.approved)) { diff --git a/libs/deposits/src/lib/deposit-limits.tsx b/libs/deposits/src/lib/deposit-limits.tsx index b355c011a..2677f254b 100644 --- a/libs/deposits/src/lib/deposit-limits.tsx +++ b/libs/deposits/src/lib/deposit-limits.tsx @@ -3,13 +3,11 @@ import type BigNumber from 'bignumber.js'; interface DepositLimitsProps { limits: { - min: BigNumber; max: BigNumber; }; } export const DepositLimits = ({ limits }: DepositLimitsProps) => { - const minLimit = limits.min.toString(); const maxLimit = limits.max.isEqualTo(Infinity) ? t('No limit') : limits.max.toString(); @@ -18,10 +16,6 @@ export const DepositLimits = ({ limits }: DepositLimitsProps) => {

{t('Temporary deposit limits')}

- - - - diff --git a/libs/deposits/src/lib/use-get-deposit-limits.ts b/libs/deposits/src/lib/use-get-deposit-limits.ts index c6c7c130c..5e1d5620f 100644 --- a/libs/deposits/src/lib/use-get-deposit-limits.ts +++ b/libs/deposits/src/lib/use-get-deposit-limits.ts @@ -5,16 +5,13 @@ import BigNumber from 'bignumber.js'; import { addDecimal } from '@vegaprotocol/react-helpers'; export const useGetDepositLimits = (asset?: Asset, decimals?: number) => { - const contract = useBridgeContract(); + const contract = useBridgeContract(true); const getLimits = useCallback(async () => { if (!contract || !asset || asset.source.__typename !== 'ERC20') { return; } - return Promise.all([ - contract.getDepositMinimum(asset.source.contractAddress), - contract.getDepositMaximum(asset.source.contractAddress), - ]); + return contract.getDepositMaximum(asset.source.contractAddress); }, [asset, contract]); const { @@ -23,11 +20,9 @@ export const useGetDepositLimits = (asset?: Asset, decimals?: number) => { if (!data || !decimals) return null; - const min = new BigNumber(addDecimal(data[0].toString(), decimals)); - const max = new BigNumber(addDecimal(data[1].toString(), decimals)); + const max = new BigNumber(addDecimal(data.toString(), decimals)); return { - min, max: max.isEqualTo(0) ? new BigNumber(Infinity) : max, }; }; diff --git a/libs/deposits/src/lib/use-submit-deposit.ts b/libs/deposits/src/lib/use-submit-deposit.ts index 9a65a6fda..599a2622c 100644 --- a/libs/deposits/src/lib/use-submit-deposit.ts +++ b/libs/deposits/src/lib/use-submit-deposit.ts @@ -29,7 +29,7 @@ const DEPOSIT_EVENT_SUB = gql` export const useSubmitDeposit = () => { const { config } = useEthereumConfig(); - const contract = useBridgeContract(); + const contract = useBridgeContract(true); const [confirmationEvent, setConfirmationEvent] = useState(null); // Store public key from contract arguments for use in the subscription, diff --git a/libs/market-depth/src/lib/__generated__/MarketDepthSubscription.ts b/libs/market-depth/src/lib/__generated__/MarketDepthSubscription.ts index 9981dd8c9..7a81dd677 100644 --- a/libs/market-depth/src/lib/__generated__/MarketDepthSubscription.ts +++ b/libs/market-depth/src/lib/__generated__/MarketDepthSubscription.ts @@ -86,7 +86,7 @@ export interface MarketDepthSubscription_marketDepthUpdate { */ buy: MarketDepthSubscription_marketDepthUpdate_buy[] | null; /** - * Sequence number for the current snapshot of the market depth + * Sequence number for the current snapshot of the market depth. It is always increasing but not monotonic. */ sequenceNumber: string; } diff --git a/libs/smart-contracts/src/abis/erc20_bridge_abi.json b/libs/smart-contracts/src/abis/erc20_bridge_abi.json index 27b901a26..0c3ea7b6d 100644 --- a/libs/smart-contracts/src/abis/erc20_bridge_abi.json +++ b/libs/smart-contracts/src/abis/erc20_bridge_abi.json @@ -173,8 +173,16 @@ }, { "inputs": [ - { "internalType": "address", "name": "asset_source", "type": "address" }, - { "internalType": "uint256", "name": "amount", "type": "uint256" }, + { + "internalType": "address", + "name": "asset_source", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, { "internalType": "bytes32", "name": "vega_public_key", @@ -188,62 +196,134 @@ }, { "inputs": [ - { "internalType": "bytes32", "name": "vega_asset_id", "type": "bytes32" } + { + "internalType": "bytes32", + "name": "vega_asset_id", + "type": "bytes32" + } ], "name": "get_asset_source", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], "stateMutability": "view", "type": "function" }, { "inputs": [ - { "internalType": "address", "name": "asset_source", "type": "address" } + { + "internalType": "address", + "name": "asset_source", + "type": "address" + } ], "name": "get_deposit_maximum", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], "stateMutability": "view", "type": "function" }, { "inputs": [ - { "internalType": "address", "name": "asset_source", "type": "address" } + { + "internalType": "address", + "name": "asset_source", + "type": "address" + } ], "name": "get_deposit_minimum", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "get_multisig_control_address", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], "stateMutability": "view", "type": "function" }, { "inputs": [ - { "internalType": "address", "name": "asset_source", "type": "address" } + { + "internalType": "address", + "name": "asset_source", + "type": "address" + } ], "name": "get_vega_asset_id", - "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], "stateMutability": "view", "type": "function" }, { "inputs": [ - { "internalType": "address", "name": "asset_source", "type": "address" } + { + "internalType": "address", + "name": "asset_source", + "type": "address" + } ], "name": "is_asset_listed", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], "stateMutability": "view", "type": "function" }, { "inputs": [ - { "internalType": "address", "name": "asset_source", "type": "address" }, - { "internalType": "bytes32", "name": "vega_asset_id", "type": "bytes32" }, - { "internalType": "uint256", "name": "nonce", "type": "uint256" }, - { "internalType": "bytes", "name": "signatures", "type": "bytes" } + { + "internalType": "address", + "name": "asset_source", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "vega_asset_id", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + } ], "name": "list_asset", "outputs": [], @@ -252,9 +332,21 @@ }, { "inputs": [ - { "internalType": "address", "name": "asset_source", "type": "address" }, - { "internalType": "uint256", "name": "nonce", "type": "uint256" }, - { "internalType": "bytes", "name": "signatures", "type": "bytes" } + { + "internalType": "address", + "name": "asset_source", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + } ], "name": "remove_asset", "outputs": [], @@ -263,14 +355,26 @@ }, { "inputs": [ - { "internalType": "address", "name": "asset_source", "type": "address" }, + { + "internalType": "address", + "name": "asset_source", + "type": "address" + }, { "internalType": "uint256", "name": "maximum_amount", "type": "uint256" }, - { "internalType": "uint256", "name": "nonce", "type": "uint256" }, - { "internalType": "bytes", "name": "signatures", "type": "bytes" } + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + } ], "name": "set_deposit_maximum", "outputs": [], @@ -279,14 +383,26 @@ }, { "inputs": [ - { "internalType": "address", "name": "asset_source", "type": "address" }, + { + "internalType": "address", + "name": "asset_source", + "type": "address" + }, { "internalType": "uint256", "name": "minimum_amount", "type": "uint256" }, - { "internalType": "uint256", "name": "nonce", "type": "uint256" }, - { "internalType": "bytes", "name": "signatures", "type": "bytes" } + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + } ], "name": "set_deposit_minimum", "outputs": [], @@ -295,11 +411,31 @@ }, { "inputs": [ - { "internalType": "address", "name": "asset_source", "type": "address" }, - { "internalType": "uint256", "name": "amount", "type": "uint256" }, - { "internalType": "address", "name": "target", "type": "address" }, - { "internalType": "uint256", "name": "nonce", "type": "uint256" }, - { "internalType": "bytes", "name": "signatures", "type": "bytes" } + { + "internalType": "address", + "name": "asset_source", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + } ], "name": "withdraw_asset", "outputs": [], diff --git a/libs/smart-contracts/src/abis/erc20_bridge_new_abi.json b/libs/smart-contracts/src/abis/erc20_bridge_new_abi.json new file mode 100644 index 000000000..e2a19660b --- /dev/null +++ b/libs/smart-contracts/src/abis/erc20_bridge_new_abi.json @@ -0,0 +1,589 @@ +[ + { + "inputs": [ + { + "internalType": "address payable", + "name": "erc20_asset_pool", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "user_address", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "asset_source", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "vega_public_key", + "type": "bytes32" + } + ], + "name": "Asset_Deposited", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "asset_source", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "lifetime_limit", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "withdraw_threshold", + "type": "uint256" + } + ], + "name": "Asset_Limits_Updated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "asset_source", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "vega_asset_id", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + } + ], + "name": "Asset_Listed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "asset_source", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + } + ], + "name": "Asset_Removed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "user_address", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "asset_source", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + } + ], + "name": "Asset_Withdrawn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "Bridge_Resumed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "Bridge_Stopped", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "withdraw_delay", + "type": "uint256" + } + ], + "name": "Bridge_Withdraw_Delay_Set", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "depositor", + "type": "address" + } + ], + "name": "Depositor_Exempted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "depositor", + "type": "address" + } + ], + "name": "Depositor_Exemption_Revoked", + "type": "event" + }, + { + "inputs": [], + "name": "default_withdraw_delay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "asset_source", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "vega_public_key", + "type": "bytes32" + } + ], + "name": "deposit_asset", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "erc20_asset_pool_address", + "outputs": [ + { + "internalType": "address payable", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "exempt_depositor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "asset_source", + "type": "address" + } + ], + "name": "get_asset_deposit_lifetime_limit", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "vega_asset_id", + "type": "bytes32" + } + ], + "name": "get_asset_source", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "get_multisig_control_address", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "asset_source", + "type": "address" + } + ], + "name": "get_vega_asset_id", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "asset_source", + "type": "address" + } + ], + "name": "get_withdraw_threshold", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + } + ], + "name": "global_resume", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + } + ], + "name": "global_stop", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "asset_source", + "type": "address" + } + ], + "name": "is_asset_listed", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "depositor", + "type": "address" + } + ], + "name": "is_exempt_depositor", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "is_stopped", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "asset_source", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "vega_asset_id", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "lifetime_limit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "withdraw_threshold", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + } + ], + "name": "list_asset", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "asset_source", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + } + ], + "name": "remove_asset", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "revoke_exempt_depositor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "asset_source", + "type": "address" + }, + { + "internalType": "uint256", + "name": "lifetime_limit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "threshold", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + } + ], + "name": "set_asset_limits", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "delay", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + } + ], + "name": "set_withdraw_delay", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "asset_source", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "uint256", + "name": "creation", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + } + ], + "name": "withdraw_asset", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/libs/smart-contracts/src/contracts/collateral-bridge-new.ts b/libs/smart-contracts/src/contracts/collateral-bridge-new.ts new file mode 100644 index 000000000..5908f3974 --- /dev/null +++ b/libs/smart-contracts/src/contracts/collateral-bridge-new.ts @@ -0,0 +1,51 @@ +import type { BigNumber } from 'ethers'; +import { ethers } from 'ethers'; +import abi from '../abis/erc20_bridge_new_abi.json'; + +export class CollateralBridgeNew { + public contract: ethers.Contract; + public isNewContract = true; + + constructor( + address: string, + signerOrProvider: ethers.Signer | ethers.providers.Provider + ) { + this.contract = new ethers.Contract(address, abi, signerOrProvider); + } + + depositAsset(assetSource: string, amount: string, vegaPublicKey: string) { + return this.contract.deposit_asset(assetSource, amount, vegaPublicKey); + } + getAssetSource(vegaAssetId: string) { + return this.contract.get_asset_source(vegaAssetId); + } + getDepositMaximum(assetSource: string): Promise { + return this.contract.get_asset_deposit_lifetime_limit(assetSource); + } + getMultisigControlAddres() { + return this.contract.get_multisig_control_address(); + } + getVegaAssetId(address: string) { + return this.contract.get_vega_asset_id(address); + } + isAssetListed(address: string) { + return this.contract.is_asset_listed(address); + } + withdrawAsset( + assetSource: string, + amount: string, + target: string, + creation: string, + nonce: string, + signatures: string + ) { + return this.contract.withdraw_asset( + assetSource, + amount, + target, + creation, + nonce, + signatures + ); + } +} diff --git a/libs/smart-contracts/src/contracts/collateral-bridge.ts b/libs/smart-contracts/src/contracts/collateral-bridge.ts index 3824491a8..82de09551 100644 --- a/libs/smart-contracts/src/contracts/collateral-bridge.ts +++ b/libs/smart-contracts/src/contracts/collateral-bridge.ts @@ -4,6 +4,7 @@ import abi from '../abis/erc20_bridge_abi.json'; export class CollateralBridge { public contract: ethers.Contract; + public isNewContract = false; constructor( address: string, diff --git a/libs/smart-contracts/src/contracts/index.ts b/libs/smart-contracts/src/contracts/index.ts index 15ec967b1..1f5a6bd57 100644 --- a/libs/smart-contracts/src/contracts/index.ts +++ b/libs/smart-contracts/src/contracts/index.ts @@ -2,6 +2,7 @@ export * from './vega-web3-types'; export * from './claim'; export * from './collateral-bridge'; +export * from './collateral-bridge-new'; export * from './staking-bridge'; export * from './token-vesting'; export * from './token'; diff --git a/libs/types/.env b/libs/types/.env new file mode 100644 index 000000000..45bf75a13 --- /dev/null +++ b/libs/types/.env @@ -0,0 +1 @@ +NX_VEGA_URL = "https://n04.d.vega.xyz/query" diff --git a/libs/web3/src/lib/use-bridge-contract.ts b/libs/web3/src/lib/use-bridge-contract.ts index db7637bf2..f3c15eadc 100644 --- a/libs/web3/src/lib/use-bridge-contract.ts +++ b/libs/web3/src/lib/use-bridge-contract.ts @@ -1,9 +1,12 @@ -import { CollateralBridge } from '@vegaprotocol/smart-contracts'; +import { + CollateralBridge, + CollateralBridgeNew, +} from '@vegaprotocol/smart-contracts'; import { useWeb3React } from '@web3-react/core'; import { useMemo } from 'react'; import { useEthereumConfig } from './use-ethereum-config'; -export const useBridgeContract = () => { +export const useBridgeContract = (isNewContract: boolean) => { const { provider } = useWeb3React(); const { config } = useEthereumConfig(); @@ -14,11 +17,16 @@ export const useBridgeContract = () => { const signer = provider.getSigner(); - return new CollateralBridge( - config.collateral_bridge_contract.address, - signer || provider - ); - }, [provider, config]); + return isNewContract + ? new CollateralBridgeNew( + config.collateral_bridge_contract.address, + signer || provider + ) + : new CollateralBridge( + config.collateral_bridge_contract.address, + signer || provider + ); + }, [provider, config, isNewContract]); return contract; }; diff --git a/libs/withdraws/src/lib/__generated__/Erc20ApprovalNew.ts b/libs/withdraws/src/lib/__generated__/Erc20ApprovalNew.ts new file mode 100644 index 000000000..9a48ec9b6 --- /dev/null +++ b/libs/withdraws/src/lib/__generated__/Erc20ApprovalNew.ts @@ -0,0 +1,52 @@ +/* tslint:disable */ +/* eslint-disable */ +// @generated +// This file was automatically generated and should not be edited. + +// ==================================================== +// GraphQL query operation: Erc20ApprovalNew +// ==================================================== + +export interface Erc20ApprovalNew_erc20WithdrawalApproval { + __typename: "Erc20WithdrawalApproval"; + /** + * The source asset in the ethereum network + */ + assetSource: string; + /** + * The amount to be withdrawn + */ + amount: string; + /** + * The nonce to be used in the request + */ + nonce: string; + /** + * Signature aggregate from the nodes, in the following format: + * 0x + sig1 + sig2 + ... + sigN + */ + signatures: string; + /** + * The target address which will receive the funds + */ + targetAddress: string; + /** + * Timestamp in seconds for expiry of the approval + */ + expiry: string; + /** + * Timestamp at which the withdrawal was created + */ + creation: string; +} + +export interface Erc20ApprovalNew { + /** + * find an erc20 withdrawal approval using its withdrawal id + */ + erc20WithdrawalApproval: Erc20ApprovalNew_erc20WithdrawalApproval | null; +} + +export interface Erc20ApprovalNewVariables { + withdrawalId: string; +} diff --git a/libs/withdraws/src/lib/queries.ts b/libs/withdraws/src/lib/queries.ts index 9cb86846c..0347c90b1 100644 --- a/libs/withdraws/src/lib/queries.ts +++ b/libs/withdraws/src/lib/queries.ts @@ -12,3 +12,17 @@ export const ERC20_APPROVAL_QUERY = gql` } } `; + +export const ERC20_APPROVAL_QUERY_NEW = gql` + query Erc20ApprovalNew($withdrawalId: ID!) { + erc20WithdrawalApproval(withdrawalId: $withdrawalId) { + assetSource + amount + nonce + signatures + targetAddress + expiry + creation + } + } +`; diff --git a/libs/withdraws/src/lib/use-complete-withdraw.spec.tsx b/libs/withdraws/src/lib/use-complete-withdraw.spec.tsx index 2eb5c1ebc..e5a80c287 100644 --- a/libs/withdraws/src/lib/use-complete-withdraw.spec.tsx +++ b/libs/withdraws/src/lib/use-complete-withdraw.spec.tsx @@ -4,13 +4,11 @@ import type { MockedResponse } from '@apollo/client/testing'; import { MockedProvider } from '@apollo/client/testing'; import type { ReactNode } from 'react'; import { useCompleteWithdraw } from './use-complete-withdraw'; -import type { - Erc20Approval, - Erc20Approval_erc20WithdrawalApproval, -} from './__generated__/Erc20Approval'; -import { ERC20_APPROVAL_QUERY } from './queries'; +import type { Erc20Approval } from './__generated__/Erc20Approval'; +import { ERC20_APPROVAL_QUERY_NEW } from './queries'; import * as web3 from '@vegaprotocol/web3'; import * as sentry from '@sentry/nextjs'; +import type { Erc20ApprovalNew_erc20WithdrawalApproval } from './__generated__/Erc20ApprovalNew'; jest.mock('@vegaprotocol/web3', () => ({ useBridgeContract: jest.fn(), @@ -21,23 +19,24 @@ function setup(mocks?: MockedResponse[]) { const wrapper = ({ children }: { children: ReactNode }) => ( {children} ); - return renderHook(() => useCompleteWithdraw(), { wrapper }); + return renderHook(() => useCompleteWithdraw(true), { wrapper }); } it('Should perform the Ethereum transaction with the fetched approval', async () => { const withdrawalId = 'withdrawal-id'; - const erc20WithdrawalApproval: Erc20Approval_erc20WithdrawalApproval = { + const erc20WithdrawalApproval: Erc20ApprovalNew_erc20WithdrawalApproval = { __typename: 'Erc20WithdrawalApproval', assetSource: 'asset-source', amount: '100', nonce: '1', + creation: '1', signatures: 'signatures', targetAddress: 'target-address', expiry: 'expiry', }; const mockERC20Approval: MockedResponse = { request: { - query: ERC20_APPROVAL_QUERY, + query: ERC20_APPROVAL_QUERY_NEW, variables: { withdrawalId }, }, result: { @@ -66,7 +65,7 @@ it('Captures an error if the erc20Withdrawal is not found', async () => { const withdrawalId = 'withdrawal-id'; const mockERC20Approval: MockedResponse = { request: { - query: ERC20_APPROVAL_QUERY, + query: ERC20_APPROVAL_QUERY_NEW, variables: { withdrawalId }, }, result: { @@ -97,7 +96,7 @@ it('Captures an error if erc20 approval query fails', async () => { const withdrawalId = 'withdrawal-id'; const mockERC20Approval: MockedResponse = { request: { - query: ERC20_APPROVAL_QUERY, + query: ERC20_APPROVAL_QUERY_NEW, variables: { withdrawalId }, }, error: new Error('query failed'), diff --git a/libs/withdraws/src/lib/use-complete-withdraw.ts b/libs/withdraws/src/lib/use-complete-withdraw.ts index 5171ee2d8..dac2e9189 100644 --- a/libs/withdraws/src/lib/use-complete-withdraw.ts +++ b/libs/withdraws/src/lib/use-complete-withdraw.ts @@ -1,12 +1,17 @@ import { gql, useApolloClient } from '@apollo/client'; import { captureException } from '@sentry/nextjs'; +import type { + CollateralBridge, + CollateralBridgeNew, +} from '@vegaprotocol/smart-contracts'; import { useBridgeContract, useEthereumTransaction } from '@vegaprotocol/web3'; import { useCallback, useEffect, useState } from 'react'; -import { ERC20_APPROVAL_QUERY } from './queries'; +import { ERC20_APPROVAL_QUERY, ERC20_APPROVAL_QUERY_NEW } from './queries'; import type { Erc20Approval, Erc20ApprovalVariables, } from './__generated__/Erc20Approval'; +import type { Erc20ApprovalNew } from './__generated__/Erc20ApprovalNew'; import type { PendingWithdrawal } from './__generated__/PendingWithdrawal'; export const PENDING_WITHDRAWAL_FRAGMMENT = gql` @@ -16,6 +21,15 @@ export const PENDING_WITHDRAWAL_FRAGMMENT = gql` } `; +export interface NewWithdrawTransactionArgs { + assetSource: string; + amount: string; + nonce: string; + signatures: string; + targetAddress: string; + creation: string; +} + export interface WithdrawTransactionArgs { assetSource: string; amount: string; @@ -24,30 +38,48 @@ export interface WithdrawTransactionArgs { targetAddress: string; } -export const useCompleteWithdraw = () => { +export const useCompleteWithdraw = (isNewContract: boolean) => { const { query, cache } = useApolloClient(); - const contract = useBridgeContract(); + const contract = useBridgeContract(isNewContract); const [id, setId] = useState(''); - const { transaction, perform } = - useEthereumTransaction((args) => { - if (!contract) { - return null; - } - return contract.withdrawAsset( + const { transaction, perform } = useEthereumTransaction< + WithdrawTransactionArgs | NewWithdrawTransactionArgs + >((args) => { + if (!contract) { + return null; + } + if (contract.isNewContract) { + const withdrawalData = args as NewWithdrawTransactionArgs; + return (contract as CollateralBridgeNew).withdrawAsset( + withdrawalData.assetSource, + withdrawalData.amount, + withdrawalData.targetAddress, + withdrawalData.creation, + withdrawalData.nonce, + withdrawalData.signatures + ); + } else { + return (contract as CollateralBridge).withdrawAsset( args.assetSource, args.amount, args.targetAddress, args.nonce, args.signatures ); - }); + } + }); const submit = useCallback( async (withdrawalId: string) => { setId(withdrawalId); try { - const res = await query({ - query: ERC20_APPROVAL_QUERY, + const res = await query< + Erc20Approval | Erc20ApprovalNew, + Erc20ApprovalVariables + >({ + query: isNewContract + ? ERC20_APPROVAL_QUERY_NEW + : ERC20_APPROVAL_QUERY, variables: { withdrawalId }, }); @@ -60,7 +92,7 @@ export const useCompleteWithdraw = () => { captureException(err); } }, - [query, perform] + [query, isNewContract, perform] ); useEffect(() => { diff --git a/libs/withdraws/src/lib/use-withdraw.spec.tsx b/libs/withdraws/src/lib/use-withdraw.spec.tsx index a2dea26d8..226b078d7 100644 --- a/libs/withdraws/src/lib/use-withdraw.spec.tsx +++ b/libs/withdraws/src/lib/use-withdraw.spec.tsx @@ -2,12 +2,12 @@ import { act, renderHook } from '@testing-library/react-hooks'; import type { MockedResponse } from '@apollo/client/testing'; import { MockedProvider } from '@apollo/client/testing'; import type { ReactNode } from 'react'; -import type { Erc20Approval } from './__generated__/Erc20Approval'; -import { ERC20_APPROVAL_QUERY } from './queries'; +import { ERC20_APPROVAL_QUERY_NEW } from './queries'; import * as web3 from '@vegaprotocol/web3'; import * as wallet from '@vegaprotocol/wallet'; import type { WithdrawalFields } from './use-withdraw'; import { useWithdraw } from './use-withdraw'; +import type { Erc20ApprovalNew } from './__generated__/Erc20ApprovalNew'; jest.mock('@vegaprotocol/web3', () => ({ useBridgeContract: jest.fn(), @@ -27,7 +27,7 @@ function setup(mocks?: MockedResponse[], cancelled = false) { const wrapper = ({ children }: { children: ReactNode }) => ( {children} ); - return renderHook(() => useWithdraw(cancelled), { wrapper }); + return renderHook(() => useWithdraw(cancelled, true), { wrapper }); } const signature = @@ -49,7 +49,7 @@ let mockPerform: jest.Mock; let mockEthReset: jest.Mock; let mockVegaReset: jest.Mock; let withdrawalInput: WithdrawalFields; -let mockERC20Approval: MockedResponse; +let mockERC20Approval: MockedResponse; beforeEach(() => { pubkey = 'pubkey'; @@ -82,7 +82,7 @@ beforeEach(() => { }; mockERC20Approval = { request: { - query: ERC20_APPROVAL_QUERY, + query: ERC20_APPROVAL_QUERY_NEW, variables: { withdrawalId: derivedWithdrawalId }, }, result: { @@ -95,6 +95,7 @@ beforeEach(() => { signatures: 'signatures', targetAddress: 'targetAddress', expiry: 'expiry', + creation: '1', }, }, }, diff --git a/libs/withdraws/src/lib/use-withdraw.ts b/libs/withdraws/src/lib/use-withdraw.ts index 1f242c524..9ebbc218c 100644 --- a/libs/withdraws/src/lib/use-withdraw.ts +++ b/libs/withdraws/src/lib/use-withdraw.ts @@ -3,13 +3,21 @@ import { determineId } from '@vegaprotocol/react-helpers'; import { useBridgeContract, useEthereumTransaction } from '@vegaprotocol/web3'; import { useVegaTransaction, useVegaWallet } from '@vegaprotocol/wallet'; import { useCallback, useEffect, useState } from 'react'; -import { ERC20_APPROVAL_QUERY } from './queries'; -import type { WithdrawTransactionArgs } from './use-complete-withdraw'; +import { ERC20_APPROVAL_QUERY, ERC20_APPROVAL_QUERY_NEW } from './queries'; +import type { + NewWithdrawTransactionArgs, + WithdrawTransactionArgs, +} from './use-complete-withdraw'; import type { Erc20Approval, Erc20ApprovalVariables, Erc20Approval_erc20WithdrawalApproval, } from './__generated__/Erc20Approval'; +import type { + CollateralBridge, + CollateralBridgeNew, +} from '@vegaprotocol/smart-contracts'; +import type { Erc20ApprovalNew } from './__generated__/Erc20ApprovalNew'; export interface WithdrawalFields { amount: string; @@ -17,12 +25,12 @@ export interface WithdrawalFields { receiverAddress: string; } -export const useWithdraw = (cancelled: boolean) => { +export const useWithdraw = (cancelled: boolean, isNewContract: boolean) => { const [withdrawalId, setWithdrawalId] = useState(null); const [approval, setApproval] = useState(null); - const contract = useBridgeContract(); + const contract = useBridgeContract(isNewContract); const { keypair } = useVegaWallet(); const { transaction: vegaTx, @@ -38,23 +46,35 @@ export const useWithdraw = (cancelled: boolean) => { if (!contract) { return null; } - return contract.withdrawAsset( - args.assetSource, - args.amount, - args.targetAddress, - args.nonce, - args.signatures - ); + if (contract.isNewContract) { + const withdrawalArguments = args as NewWithdrawTransactionArgs; + return (contract as CollateralBridgeNew).withdrawAsset( + withdrawalArguments.assetSource, + withdrawalArguments.amount, + withdrawalArguments.targetAddress, + withdrawalArguments.creation, + withdrawalArguments.nonce, + withdrawalArguments.signatures + ); + } else { + return (contract as CollateralBridge).withdrawAsset( + args.assetSource, + args.amount, + args.targetAddress, + args.nonce, + args.signatures + ); + } }); - const { data, stopPolling } = useQuery( - ERC20_APPROVAL_QUERY, - { - variables: { withdrawalId: withdrawalId || '' }, - skip: !withdrawalId, - pollInterval: 1000, - } - ); + const { data, stopPolling } = useQuery< + Erc20Approval | Erc20ApprovalNew, + Erc20ApprovalVariables + >(isNewContract ? ERC20_APPROVAL_QUERY_NEW : ERC20_APPROVAL_QUERY, { + variables: { withdrawalId: withdrawalId || '' }, + skip: !withdrawalId, + pollInterval: 1000, + }); const submit = useCallback( async (withdrawal: WithdrawalFields) => { diff --git a/libs/withdraws/src/lib/withdraw-manager.spec.tsx b/libs/withdraws/src/lib/withdraw-manager.spec.tsx index 35dd4fac9..674948fcf 100644 --- a/libs/withdraws/src/lib/withdraw-manager.spec.tsx +++ b/libs/withdraws/src/lib/withdraw-manager.spec.tsx @@ -27,6 +27,7 @@ beforeEach(() => { assets: [generateAsset()], accounts: [generateAccount()], initialAssetId: undefined, + isNewContract: true, }; mockSubmit = jest.fn(); mockReset = jest.fn(); diff --git a/libs/withdraws/src/lib/withdraw-manager.tsx b/libs/withdraws/src/lib/withdraw-manager.tsx index 8c68037af..f4639af84 100644 --- a/libs/withdraws/src/lib/withdraw-manager.tsx +++ b/libs/withdraws/src/lib/withdraw-manager.tsx @@ -15,12 +15,14 @@ export interface WithdrawManagerProps { assets: Asset[]; accounts: Account[]; initialAssetId?: string; + isNewContract: boolean; } export const WithdrawManager = ({ assets, accounts, initialAssetId, + isNewContract, }: WithdrawManagerProps) => { const dialogDismissed = useRef(false); const [dialogOpen, setDialogOpen] = useState(false); @@ -28,7 +30,8 @@ export const WithdrawManager = ({ const { account: ethereumAccount } = useWeb3React(); const { ethTx, vegaTx, approval, submit, reset } = useWithdraw( - dialogDismissed.current + dialogDismissed.current, + isNewContract ); // Find the asset object from the select box diff --git a/libs/withdraws/src/lib/withdrawals-table.tsx b/libs/withdraws/src/lib/withdrawals-table.tsx index 5ab28cde4..53b7e63cd 100644 --- a/libs/withdraws/src/lib/withdrawals-table.tsx +++ b/libs/withdraws/src/lib/withdrawals-table.tsx @@ -22,7 +22,7 @@ export interface WithdrawalsTableProps { export const WithdrawalsTable = ({ withdrawals }: WithdrawalsTableProps) => { const { ETHERSCAN_URL } = useEnvironment(); - const { transaction, submit } = useCompleteWithdraw(); + const { transaction, submit } = useCompleteWithdraw(true); return ( <>
{t('Minimum')}{minLimit}
{t('Maximum')} {maxLimit}