diff --git a/.env b/.env
index fbb63d96e..a9a73b1f8 100644
--- a/.env
+++ b/.env
@@ -1,11 +1,16 @@
+# TODO remove after tenderly testing
# graphql Subsquid endpoint
VITE_SUBSQUID_URL="https://origin.squids.live/origin-squid/graphql"
+
# graphql Snapshot endpoint
VITE_SNAPSHOT_URL="https://hub.snapshot.org/graphql"
+
# Alchemy rpc url
VITE_ALCHEMY_RPC="https://eth-mainnet.g.alchemy.com/v2/"
+
# Alchemy arbitrum rpc url
VITE_ALCHEMY_ARBITRUM_RPC="https://arb-mainnet.g.alchemy.com/v2/"
+
# Nx 18 enables using plugins to infer targets by default
# This is disabled for existing workspaces to maintain compatibility
# For more info, see: https://nx.dev/concepts/inferred-tasks
diff --git a/apps/defi/.env b/apps/defi/.env
index 9ea258cf4..5d49b01a1 100644
--- a/apps/defi/.env
+++ b/apps/defi/.env
@@ -1,5 +1,6 @@
-# Set this to any custom RPC to override public endpoint
+# Set these to any custom RPC to override public endpoint
VITE_CUSTOM_RPC=
+VITE_CUSTOM_ARBITRUM_RPC=
# Wallet Connect v2 project id
VITE_WALLET_CONNECT_PROJECT_ID=
diff --git a/apps/defi/src/lang/en.json b/apps/defi/src/lang/en.json
index 534f8075a..e4651c77d 100644
--- a/apps/defi/src/lang/en.json
+++ b/apps/defi/src/lang/en.json
@@ -1,4 +1,16 @@
{
+ "+0NTt9": [
+ {
+ "type": 0,
+ "value": "Withdrawal request is taking a long time to process"
+ }
+ ],
+ "+0zAiT": [
+ {
+ "type": 0,
+ "value": "The updated amount of xOGN you will receive by adding OGN to this lockup."
+ }
+ ],
"+14VoL": [
{
"type": 0,
@@ -47,6 +59,18 @@
"value": "Connect"
}
],
+ "/0TOL5": [
+ {
+ "type": 0,
+ "value": "Amount"
+ }
+ ],
+ "/2Xryp": [
+ {
+ "type": 0,
+ "value": "Claimed Withdrawal"
+ }
+ ],
"/6/sPX": [
{
"type": 0,
@@ -155,6 +179,12 @@
"value": "No activity"
}
],
+ "1Ia8qN": [
+ {
+ "type": 0,
+ "value": "Processing"
+ }
+ ],
"1Og5F/": [
{
"type": 0,
@@ -229,6 +259,12 @@
"value": "Powered by Chainlink CCIP"
}
],
+ "2MrktG": [
+ {
+ "type": 0,
+ "value": "~1 min"
+ }
+ ],
"2NfxfO": [
{
"type": 0,
@@ -247,12 +283,6 @@
"value": "Liquid staking"
}
],
- "2W3kP3": [
- {
- "type": 0,
- "value": "~1min"
- }
- ],
"2ahSeJ": [
{
"type": 0,
@@ -265,12 +295,6 @@
"value": "Enable rebasing"
}
],
- "3Lr8o5": [
- {
- "type": 0,
- "value": "Larger redemptions coming soon"
- }
- ],
"3PhHPe": [
{
"type": 0,
@@ -289,6 +313,12 @@
"value": "Legacy governance"
}
],
+ "3cpPa4": [
+ {
+ "type": 0,
+ "value": "Claiming your withdrawal will incur this estimated additional gas fee"
+ }
+ ],
"3lOoIq": [
{
"offset": 0,
@@ -377,6 +407,12 @@
"value": "monthDuration"
}
],
+ "3t3uoD": [
+ {
+ "type": 0,
+ "value": "You have no withdrawal requests"
+ }
+ ],
"3townk": [
{
"type": 0,
@@ -475,6 +511,12 @@
"value": "No description"
}
],
+ "5yP3uI": [
+ {
+ "type": 0,
+ "value": "Claim Withdrawal"
+ }
+ ],
"5zH79K": [
{
"type": 0,
@@ -619,6 +661,20 @@
"value": "Redeem for mix via Origin Vault"
}
],
+ "8g703D": [
+ {
+ "type": 0,
+ "value": "~"
+ },
+ {
+ "type": 1,
+ "value": "WITHDRAW_DELAY"
+ },
+ {
+ "type": 0,
+ "value": " min - few days"
+ }
+ ],
"8nvhZ9": [
{
"type": 0,
@@ -869,6 +925,12 @@
"value": "Stablecoin mix"
}
],
+ "DK7ein": [
+ {
+ "type": 0,
+ "value": "Your pending amount"
+ }
+ ],
"DKaqyQ": [
{
"type": 0,
@@ -967,6 +1029,12 @@
"value": "symbolOut"
}
],
+ "EJv8r2": [
+ {
+ "type": 0,
+ "value": "Refresh the page"
+ }
+ ],
"EMU/OA": [
{
"type": 0,
@@ -1087,6 +1155,12 @@
"value": "Waiting for CCIP"
}
],
+ "Gtdie8": [
+ {
+ "type": 0,
+ "value": "Available to claim"
+ }
+ ],
"H1+3mH": [
{
"type": 0,
@@ -1173,12 +1247,24 @@
"value": "Error while enabling rebasing"
}
],
+ "IZFEUg": [
+ {
+ "type": 0,
+ "value": "Ready"
+ }
+ ],
"IfZsEo": [
{
"type": 0,
"value": "Vote against"
}
],
+ "IuFETn": [
+ {
+ "type": 0,
+ "value": "Duration"
+ }
+ ],
"IzHsvX": [
{
"type": 0,
@@ -1347,6 +1433,12 @@
"value": "Reload Page"
}
],
+ "MTN/Zf": [
+ {
+ "type": 0,
+ "value": "Try to refresh the page and go to the Claim tab to see your withdrawal request"
+ }
+ ],
"MW9FHt": [
{
"type": 0,
@@ -1551,6 +1643,12 @@
"value": "The length of time you will lock up your OGN in order to receive yield and voting power. Unstaking early carries a penalty relative to the remaining duration of the lockup"
}
],
+ "PEzaGo": [
+ {
+ "type": 0,
+ "value": "Request withdrawal"
+ }
+ ],
"PFtMy9": [
{
"type": 0,
@@ -1593,6 +1691,12 @@
"value": "symbolOut"
}
],
+ "Pkf9/r": [
+ {
+ "type": 0,
+ "value": "This operation can take a few seconds to complete"
+ }
+ ],
"PmkP1H": [
{
"type": 0,
@@ -1655,6 +1759,12 @@
"value": "Select lockup"
}
],
+ "RR8vve": [
+ {
+ "type": 0,
+ "value": "Redeem via the ARM"
+ }
+ ],
"RVH0u3": [
{
"type": 0,
@@ -1721,6 +1831,12 @@
"value": "Custom"
}
],
+ "SsufnP": [
+ {
+ "type": 0,
+ "value": "Withdrawal request successfully sent"
+ }
+ ],
"SzA4oV": [
{
"offset": 0,
@@ -1761,6 +1877,12 @@
"value": "count"
}
],
+ "T1d+7b": [
+ {
+ "type": 0,
+ "value": "Claiming Withdrawal"
+ }
+ ],
"TIBoMl": [
{
"type": 0,
@@ -1853,6 +1975,12 @@
"value": "You are lawfully permitted to access this site. You understand and accept the risks associated with using the products in this dapp (OETH, OUSD, etc.)"
}
],
+ "UjXhyn": [
+ {
+ "type": 0,
+ "value": "Your requests"
+ }
+ ],
"UkXeBW": [
{
"type": 0,
@@ -1923,6 +2051,12 @@
"value": "Origin Ether"
}
],
+ "W7LOXq": [
+ {
+ "type": 0,
+ "value": "Error while claiming withdrawal"
+ }
+ ],
"W87PYU": [
{
"type": 0,
@@ -1963,6 +2097,12 @@
"value": "Redeem"
}
],
+ "XrnF+v": [
+ {
+ "type": 0,
+ "value": "Processing withdrawal request"
+ }
+ ],
"Y/oE4U": [
{
"type": 0,
@@ -2197,6 +2337,36 @@
"value": "Add to stake"
}
],
+ "cXVyuA": [
+ {
+ "type": 0,
+ "value": "Your request to withdraw "
+ },
+ {
+ "type": 1,
+ "value": "amountOut"
+ },
+ {
+ "type": 0,
+ "value": " "
+ },
+ {
+ "type": 1,
+ "value": "symbolOut"
+ },
+ {
+ "type": 0,
+ "value": " from "
+ },
+ {
+ "type": 1,
+ "value": "symbolIn"
+ },
+ {
+ "type": 0,
+ "value": " has been sent. Check the Claim tab to view your withdrawal requests."
+ }
+ ],
"cg1VJ2": [
{
"type": 0,
@@ -2277,24 +2447,26 @@
"value": "Claiming Rewards"
}
],
- "e+yfm6": [
+ "dxLIdA": [
{
"type": 0,
- "value": "Connect your wallet to see your balances"
+ "value": "Claim"
+ },
+ {
+ "type": 1,
+ "value": "amount"
}
],
- "e/f0yl": [
+ "e+yfm6": [
{
"type": 0,
- "value": "Add unclaimed rewards to stake ("
- },
- {
- "type": 1,
- "value": "rewards"
- },
+ "value": "Connect your wallet to see your balances"
+ }
+ ],
+ "e61Jf3": [
{
"type": 0,
- "value": " OGN)"
+ "value": "Coming soon"
}
],
"e6Ph5+": [
@@ -2611,6 +2783,12 @@
"value": "Connect wallet to view"
}
],
+ "lN55fl": [
+ {
+ "type": 0,
+ "value": "Your withdrawal is being processed"
+ }
+ ],
"lQmZjB": [
{
"type": 0,
@@ -2623,6 +2801,12 @@
"value": "Mins"
}
],
+ "lc3LYh": [
+ {
+ "type": 0,
+ "value": "Your claims"
+ }
+ ],
"lozEho": [
{
"type": 0,
@@ -2813,6 +2997,24 @@
"value": "Error while bridging"
}
],
+ "phZMsU": [
+ {
+ "type": 0,
+ "value": "Claim "
+ },
+ {
+ "type": 1,
+ "value": "amount"
+ },
+ {
+ "type": 0,
+ "value": " "
+ },
+ {
+ "type": 1,
+ "value": "symbolIn"
+ }
+ ],
"qGZxc4": [
{
"type": 0,
@@ -2895,6 +3097,12 @@
"value": "Swap"
}
],
+ "sjKCFv": [
+ {
+ "type": 0,
+ "value": "Approximate gas cost:"
+ }
+ ],
"stTYBM": [
{
"type": 0,
@@ -2995,6 +3203,12 @@
"value": "Redeem amount"
}
],
+ "uD4xKE": [
+ {
+ "type": 0,
+ "value": "View withdrawal requests"
+ }
+ ],
"uEFsHG": [
{
"type": 0,
@@ -3365,4 +3579,4 @@
"value": "Waiting for signature"
}
]
-}
\ No newline at end of file
+}
diff --git a/apps/defi/src/lang/extracts/en.json b/apps/defi/src/lang/extracts/en.json
index f8524eede..97cf39d38 100644
--- a/apps/defi/src/lang/extracts/en.json
+++ b/apps/defi/src/lang/extracts/en.json
@@ -1,4 +1,10 @@
{
+ "+0NTt9": {
+ "defaultMessage": "Withdrawal request is taking a long time to process"
+ },
+ "+0zAiT": {
+ "defaultMessage": "The updated amount of xOGN you will receive by adding OGN to this lockup."
+ },
"+14VoL": {
"defaultMessage": "Staking"
},
@@ -23,6 +29,12 @@
"+vVZ/G": {
"defaultMessage": "Connect"
},
+ "/0TOL5": {
+ "defaultMessage": "Amount"
+ },
+ "/2Xryp": {
+ "defaultMessage": "Claimed Withdrawal"
+ },
"/6/sPX": {
"defaultMessage": "Docs"
},
@@ -71,6 +83,9 @@
"17g+HZ": {
"defaultMessage": "No activity"
},
+ "1Ia8qN": {
+ "defaultMessage": "Processing"
+ },
"1Og5F/": {
"defaultMessage": "Migration"
},
@@ -98,6 +113,9 @@
"2CoE53": {
"defaultMessage": "Powered by Chainlink CCIP"
},
+ "2MrktG": {
+ "defaultMessage": "~1 min"
+ },
"2NfxfO": {
"defaultMessage": "Impossible to execute"
},
@@ -107,18 +125,12 @@
"2R/YHR": {
"defaultMessage": "Liquid staking"
},
- "2W3kP3": {
- "defaultMessage": "~1min"
- },
"2ahSeJ": {
"defaultMessage": "OETH analytics"
},
"2zUGfB": {
"defaultMessage": "Enable rebasing"
},
- "3Lr8o5": {
- "defaultMessage": "Larger redemptions coming soon"
- },
"3PhHPe": {
"defaultMessage": "The variable APY currently being earned on staked xOGN."
},
@@ -128,9 +140,15 @@
"3at7Yr": {
"defaultMessage": "Legacy governance"
},
+ "3cpPa4": {
+ "defaultMessage": "Claiming your withdrawal will incur this estimated additional gas fee"
+ },
"3lOoIq": {
"defaultMessage": "{monthDuration,plural,=1{Extend lockup {lockupId} by {amount} {symbolIn} for # month} other{Extend lockup {lockupId} by {amount} {symbolIn} for # months}}"
},
+ "3t3uoD": {
+ "defaultMessage": "You have no withdrawal requests"
+ },
"3townk": {
"defaultMessage": "Max vAPY"
},
@@ -176,6 +194,9 @@
"5lVaeB": {
"defaultMessage": "No description"
},
+ "5yP3uI": {
+ "defaultMessage": "Claim Withdrawal"
+ },
"5zH79K": {
"defaultMessage": "Your veOGV staked positions"
},
@@ -248,6 +269,9 @@
"8cCxx8": {
"defaultMessage": "Redeem for mix via Origin Vault"
},
+ "8g703D": {
+ "defaultMessage": "~{WITHDRAW_DELAY} min - few days"
+ },
"8nvhZ9": {
"defaultMessage": "Last"
},
@@ -353,6 +377,9 @@
"DBP9Xf": {
"defaultMessage": "Stablecoin mix"
},
+ "DK7ein": {
+ "defaultMessage": "Your pending amount"
+ },
"DKaqyQ": {
"defaultMessage": "Redeeming"
},
@@ -386,6 +413,9 @@
"EEwopl": {
"defaultMessage": "{amountIn} {symbolIn} for {amountOut} {symbolOut}"
},
+ "EJv8r2": {
+ "defaultMessage": "Refresh the page"
+ },
"EMU/OA": {
"defaultMessage": "The amount of xOGN you will receive today in return for your lockup. The more xOGN you have, the more voting power you have and the more staking rewards you will earn."
},
@@ -440,6 +470,9 @@
"GtABHs": {
"defaultMessage": "Waiting for CCIP"
},
+ "Gtdie8": {
+ "defaultMessage": "Available to claim"
+ },
"H1+3mH": {
"defaultMessage": "A superior LST for earning yield across DeFi"
},
@@ -473,9 +506,15 @@
"IP0AHa": {
"defaultMessage": "Error while enabling rebasing"
},
+ "IZFEUg": {
+ "defaultMessage": "Ready"
+ },
"IfZsEo": {
"defaultMessage": "Vote against"
},
+ "IuFETn": {
+ "defaultMessage": "Duration"
+ },
"IzHsvX": {
"defaultMessage": "Est. gas:"
},
@@ -554,6 +593,9 @@
"MSTVqC": {
"defaultMessage": "Reload Page"
},
+ "MTN/Zf": {
+ "defaultMessage": "Try to refresh the page and go to the Claim tab to see your withdrawal request"
+ },
"MW9FHt": {
"defaultMessage": "Ooops..."
},
@@ -617,6 +659,9 @@
"P9sirH": {
"defaultMessage": "The length of time you will lock up your OGN in order to receive yield and voting power. Unstaking early carries a penalty relative to the remaining duration of the lockup"
},
+ "PEzaGo": {
+ "defaultMessage": "Request withdrawal"
+ },
"PFtMy9": {
"defaultMessage": "Canceled"
},
@@ -626,6 +671,9 @@
"PdEKuc": {
"defaultMessage": "{amtIn} {symbolIn} for {amtOut} {symbolOut}"
},
+ "Pkf9/r": {
+ "defaultMessage": "This operation can take a few seconds to complete"
+ },
"PmkP1H": {
"defaultMessage": "Unsupported Network"
},
@@ -653,6 +701,9 @@
"RIV67a": {
"defaultMessage": "Select lockup"
},
+ "RR8vve": {
+ "defaultMessage": "Redeem via the ARM"
+ },
"RVH0u3": {
"defaultMessage": "Delegating Voting Power"
},
@@ -686,9 +737,15 @@
"Sjo1P4": {
"defaultMessage": "Custom"
},
+ "SsufnP": {
+ "defaultMessage": "Withdrawal request successfully sent"
+ },
"SzA4oV": {
"defaultMessage": "{count,plural,=0{No address} =1{# address} other{# addresses}}"
},
+ "T1d+7b": {
+ "defaultMessage": "Claiming Withdrawal"
+ },
"TIBoMl": {
"defaultMessage": "Total value locked {symbol}"
},
@@ -713,6 +770,9 @@
"ULVduL": {
"defaultMessage": "You are lawfully permitted to access this site. You understand and accept the risks associated with using the products in this dapp (OETH, OUSD, etc.)"
},
+ "UjXhyn": {
+ "defaultMessage": "Your requests"
+ },
"UkXeBW": {
"defaultMessage": "If the problem persists, you can contact us through our {support}."
},
@@ -740,6 +800,9 @@
"W33FNz": {
"defaultMessage": "Origin Ether"
},
+ "W7LOXq": {
+ "defaultMessage": "Error while claiming withdrawal"
+ },
"W87PYU": {
"defaultMessage": "View on {name}"
},
@@ -758,6 +821,9 @@
"XSdWHA": {
"defaultMessage": "Redeem"
},
+ "XrnF+v": {
+ "defaultMessage": "Processing withdrawal request"
+ },
"Y/oE4U": {
"defaultMessage": "Calldata"
},
@@ -857,6 +923,9 @@
"cWvi0w": {
"defaultMessage": "Add to stake"
},
+ "cXVyuA": {
+ "defaultMessage": "Your request to withdraw {amountOut} {symbolOut} from {symbolIn} has been sent. Check the Claim tab to view your withdrawal requests."
+ },
"cg1VJ2": {
"defaultMessage": "Connect Wallet"
},
@@ -890,11 +959,14 @@
"dx9Xxj": {
"defaultMessage": "Claiming Rewards"
},
+ "dxLIdA": {
+ "defaultMessage": "Claim{amount}"
+ },
"e+yfm6": {
"defaultMessage": "Connect your wallet to see your balances"
},
- "e/f0yl": {
- "defaultMessage": "Add unclaimed rewards to stake ({rewards} OGN)"
+ "e61Jf3": {
+ "defaultMessage": "Coming soon"
},
"e6Ph5+": {
"defaultMessage": "Address"
@@ -1037,12 +1109,18 @@
"ksTDub": {
"defaultMessage": "Connect wallet to view"
},
+ "lN55fl": {
+ "defaultMessage": "Your withdrawal is being processed"
+ },
"lQmZjB": {
"defaultMessage": "Swap via Curve"
},
"lb8m6m": {
"defaultMessage": "Mins"
},
+ "lc3LYh": {
+ "defaultMessage": "Your claims"
+ },
"lozEho": {
"defaultMessage": "Error while approving"
},
@@ -1118,6 +1196,9 @@
"pYbH7c": {
"defaultMessage": "Error while bridging"
},
+ "phZMsU": {
+ "defaultMessage": "Claim {amount} {symbolIn}"
+ },
"qGZxc4": {
"defaultMessage": "Connect your wallet to
select the network"
},
@@ -1154,6 +1235,9 @@
"s8BnAC": {
"defaultMessage": "Swap"
},
+ "sjKCFv": {
+ "defaultMessage": "Approximate gas cost:"
+ },
"stTYBM": {
"defaultMessage": "You confirm that you are not a resident of, citizen of, located in, incorporated in, or have a registered office in the United States or any country or region currently currently subject to sanctions by the United States."
},
@@ -1202,6 +1286,9 @@
"u53ROb": {
"defaultMessage": "Redeem amount"
},
+ "uD4xKE": {
+ "defaultMessage": "View withdrawal requests"
+ },
"uEFsHG": {
"defaultMessage": "Discord forum"
},
diff --git a/apps/defi/src/routes.ts b/apps/defi/src/routes.ts
index e1939fa91..27adf0192 100644
--- a/apps/defi/src/routes.ts
+++ b/apps/defi/src/routes.ts
@@ -49,7 +49,8 @@ export const routes: RouteObject[] = [
},
},
{
- ...oeth.oethRedeemRoute,
+ path: 'redeem',
+ Component: oeth.RedeemView,
handle: {
title: defineMessage({ defaultMessage: 'Redeem' }),
icon: FaArrowDownFromArcRegular,
diff --git a/libs/defi/oeth/src/redeem/actions.ts b/libs/defi/oeth/src/redeem/actions.ts
index be64853b2..1776447ce 100644
--- a/libs/defi/oeth/src/redeem/actions.ts
+++ b/libs/defi/oeth/src/redeem/actions.ts
@@ -1,4 +1,4 @@
-import { redeemVaultOeth, SwapCurveOeth } from '@origin/shared/routes';
+import { redeemArmOeth, redeemVaultOeth } from '@origin/shared/routes';
import { defineMessage } from 'react-intl';
import type { SwapApi } from '@origin/shared/providers';
@@ -6,14 +6,14 @@ import type { SwapApi } from '@origin/shared/providers';
import type { OethRedeemAction } from './types';
export const redeemActions: Record = {
- 'swap-curve-oeth': {
- ...SwapCurveOeth,
- routeLabel: defineMessage({ defaultMessage: 'Swap via Curve' }),
+ 'redeem-arm-oeth': {
+ ...redeemArmOeth,
+ routeLabel: defineMessage({ defaultMessage: 'Redeem via the ARM' }),
buttonLabel: defineMessage({ defaultMessage: 'Redeem' }),
},
- 'redeem-vault-oeth': {
+ 'redeem-vault-async-oeth': {
...redeemVaultOeth,
routeLabel: defineMessage({ defaultMessage: 'Redeem via OETH Vault' }),
- buttonLabel: defineMessage({ defaultMessage: 'Redeem' }),
+ buttonLabel: defineMessage({ defaultMessage: 'Request withdrawal' }),
},
};
diff --git a/libs/defi/oeth/src/redeem/components/ClaimForm.tsx b/libs/defi/oeth/src/redeem/components/ClaimForm.tsx
new file mode 100644
index 000000000..4e6714b3c
--- /dev/null
+++ b/libs/defi/oeth/src/redeem/components/ClaimForm.tsx
@@ -0,0 +1,304 @@
+import { useMemo, useState } from 'react';
+
+import {
+ Button,
+ Checkbox,
+ CircularProgress,
+ Collapse,
+ Divider,
+ FormControlLabel,
+ Stack,
+ Typography,
+} from '@mui/material';
+import { SectionCard, useTxButton } from '@origin/defi/shared';
+import { ValueLabel } from '@origin/shared/components';
+import { contracts, tokens } from '@origin/shared/contracts';
+import {
+ FaArrowUpRightRegular,
+ FaCircleCheckRegular,
+ FaClockRegular,
+} from '@origin/shared/icons';
+import { TxButton, useRefresher } from '@origin/shared/providers';
+import {
+ getFormatPrecision,
+ isNilOrEmpty,
+ ZERO_ADDRESS,
+} from '@origin/shared/utils';
+import { useQueryClient } from '@tanstack/react-query';
+import { add, eq, format, from } from 'dnum';
+import { remove } from 'ramda';
+import { useIntl } from 'react-intl';
+import { useAccount, useConfig } from 'wagmi';
+
+import { useWithdrawalRequests } from '../hooks';
+
+import type { StackProps } from '@mui/material';
+import type { Dnum } from 'dnum';
+
+import type { WithdrawalRequest } from '../types';
+
+export const ClaimForm = (props: StackProps) => {
+ const intl = useIntl();
+ const { address } = useAccount();
+ const config = useConfig();
+ const queryClient = useQueryClient();
+ const [selectedClaimIds, setSelectedClaimIds] = useState([]);
+ const { data: requests, isLoading: isRequestsLoading } =
+ useWithdrawalRequests({
+ select: (data) => data?.filter((r) => !r.claimed),
+ });
+ const { startRefresh, status } = useRefresher({
+ queryKey: useWithdrawalRequests.getKey(address ?? ZERO_ADDRESS),
+ queryFn: useWithdrawalRequests.fetcher(config, queryClient),
+ isResultProcessed: (prev, next) =>
+ prev.filter((r) => r.claimed).length <
+ next.filter((r) => r.claimed).length,
+ onSettled: () => {
+ setSelectedClaimIds([]);
+ queryClient.invalidateQueries();
+ },
+ });
+ const args =
+ selectedClaimIds.length === 1
+ ? {
+ contract: contracts.mainnet.OETHVault,
+ functionName: 'claimWithdrawal',
+ args: [selectedClaimIds[0]],
+ }
+ : {
+ contract: contracts.mainnet.OETHVault,
+ functionName: 'claimWithdrawals',
+ args: [selectedClaimIds],
+ };
+ const selectedAmount = useMemo(
+ () =>
+ selectedClaimIds.reduce((acc, curr) => {
+ const req = requests?.find((r) => r.requestId === curr);
+
+ return add([req?.amount ?? 0n, tokens.mainnet.WETH.decimals], acc);
+ }, from(0)),
+ [requests, selectedClaimIds],
+ );
+ const { params, callbacks, gasPrice, isWriteGasLoading } = useTxButton({
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ params: args as any,
+ callbacks: {
+ onWriteSuccess: () => {
+ startRefresh();
+ },
+ },
+ activity: {
+ type: 'claim-withdrawal',
+ status: 'idle',
+ amountIn: selectedAmount[0],
+ tokenIdIn: tokens.mainnet.WETH.id,
+ },
+ enableGas: true,
+ });
+
+ const handleClaimClick = (requestId: bigint) => () => {
+ const idx = selectedClaimIds.findIndex((id) => id === requestId);
+ if (idx === -1) {
+ setSelectedClaimIds((prev) => [...prev, requestId]);
+ } else {
+ setSelectedClaimIds((prev) => remove(idx, 1, prev));
+ }
+ };
+
+ return (
+
+
+ }>
+ {isRequestsLoading ? (
+
+
+
+ ) : isNilOrEmpty(requests) ? (
+
+
+ {intl.formatMessage({
+ defaultMessage: 'You have no withdrawal requests',
+ })}
+
+
+ ) : (
+ requests?.map((r) => (
+
+ ))
+ )}
+
+
+
+
+
+
+
+ );
+};
+
+type ClaimRowProps = {
+ request: WithdrawalRequest;
+ selected: boolean;
+ onSelect: () => void;
+ isProcessing: boolean;
+} & StackProps;
+
+const ClaimRow = ({
+ request,
+ selected,
+ onSelect,
+ isProcessing,
+ ...rest
+}: ClaimRowProps) => {
+ const amt = [request?.amount ?? 0n, tokens.mainnet.WETH.decimals] as Dnum;
+ const disabled = !request.claimable || isProcessing;
+
+ return (
+
+ }
+ label={
+
+
+ {format(amt, {
+ digits: getFormatPrecision(amt),
+ decimalsRounding: 'ROUND_DOWN',
+ })}
+
+
+ {tokens.mainnet.WETH.symbol}
+
+
+ }
+ onChange={onSelect}
+ disabled={disabled}
+ disableTypography
+ />
+
+
+
+
+
+ );
+};
+
+type ClaimChipProps = {
+ claimable: boolean;
+ isProcessing: boolean;
+} & StackProps;
+
+const ClaimChip = ({ claimable, isProcessing, ...rest }: ClaimChipProps) => {
+ const intl = useIntl();
+
+ const icon = isProcessing ? (
+
+ ) : claimable ? (
+
+ ) : (
+
+ );
+ const label = isProcessing
+ ? intl.formatMessage({ defaultMessage: 'Processing' })
+ : claimable
+ ? intl.formatMessage({ defaultMessage: 'Ready' })
+ : intl.formatMessage({ defaultMessage: 'Pending' });
+ const color = isProcessing
+ ? 'primary.main'
+ : claimable
+ ? 'success.dark'
+ : 'warning.dark';
+ const bgColor = isProcessing
+ ? 'primary.faded'
+ : claimable
+ ? 'success.faded'
+ : 'warning.faded';
+
+ return (
+
+ {icon}
+ {label}
+
+ );
+};
diff --git a/libs/defi/oeth/src/redeem/components/ClaimHeader.tsx b/libs/defi/oeth/src/redeem/components/ClaimHeader.tsx
new file mode 100644
index 000000000..9d15e6ae1
--- /dev/null
+++ b/libs/defi/oeth/src/redeem/components/ClaimHeader.tsx
@@ -0,0 +1,130 @@
+import { Divider, Stack, Typography } from '@mui/material';
+import { LoadingLabel } from '@origin/shared/components';
+import { tokens } from '@origin/shared/contracts';
+import { FaCircleCheckRegular, FaClockRegular } from '@origin/shared/icons';
+import { getFormatPrecision } from '@origin/shared/utils';
+import { add, eq, format, from } from 'dnum';
+import { groupBy } from 'ramda';
+import { useIntl } from 'react-intl';
+
+import { useWithdrawalRequests } from '../hooks';
+
+import type { StackProps } from '@mui/material';
+
+export const ClaimHeader = (props: StackProps) => {
+ const intl = useIntl();
+ const { data: requests, isLoading: isRequestsLoading } =
+ useWithdrawalRequests({
+ select: (data) => data?.filter((r) => !r.claimed),
+ });
+
+ const { claimable, pending } = groupBy(
+ (r) => (r.claimable ? 'claimable' : 'pending'),
+ requests ?? [],
+ );
+ const availableToClaim =
+ claimable?.reduce(
+ (acc, curr) => add([curr.amount, tokens.mainnet.WETH.decimals], acc),
+ from(0),
+ ) ?? from(0);
+ const pendingAmount =
+ pending?.reduce(
+ (acc, curr) => add([curr.amount, tokens.mainnet.WETH.decimals], acc),
+ from(0),
+ ) ?? from(0);
+
+ return (
+
+
+
+ {intl.formatMessage({ defaultMessage: 'Available to claim' })}
+
+
+
+ {eq(availableToClaim, 0)
+ ? '0.0'
+ : format(availableToClaim, getFormatPrecision(availableToClaim))}
+
+ {tokens.mainnet.WETH.symbol}
+
+
+
+
+
+
+ {intl.formatMessage({ defaultMessage: 'Your requests' })}
+
+
+
+
+
+
+
+
+
+
+ {intl.formatMessage({ defaultMessage: 'Your pending amount' })}
+
+
+
+ {format(pendingAmount, getFormatPrecision(pendingAmount))}
+
+
+ {tokens.mainnet.OETH.symbol}
+
+
+
+
+
+ );
+};
+
+type IconChipProps = {
+ claimable: boolean;
+ amount: number;
+} & StackProps;
+
+const IconChip = ({ claimable, amount, ...rest }: IconChipProps) => {
+ return (
+
+ {claimable ? : }
+
+ {amount}
+
+
+ );
+};
diff --git a/libs/defi/oeth/src/redeem/components/RedeemActionCard.tsx b/libs/defi/oeth/src/redeem/components/RedeemActionCard.tsx
index bf36a85c4..23d9dd023 100644
--- a/libs/defi/oeth/src/redeem/components/RedeemActionCard.tsx
+++ b/libs/defi/oeth/src/redeem/components/RedeemActionCard.tsx
@@ -1,22 +1,20 @@
-import { Card, Stack, Typography } from '@mui/material';
+import { alpha, Card, Stack, SvgIcon, Typography } from '@mui/material';
import { ValueLabel } from '@origin/shared/components';
-import { Curve, Origin } from '@origin/shared/icons';
+import { OETH } from '@origin/shared/icons';
import {
routeEq,
- useGasPrice,
useHandleSelectSwapRoute,
useIsSwapRouteAvailable,
- useSwapRouteAllowance,
useSwapState,
} from '@origin/shared/providers';
import { isNilOrEmpty } from '@origin/shared/utils';
-import { add, format, from } from 'dnum';
import { useIntl } from 'react-intl';
-import type { CardProps, TypographyProps } from '@mui/material';
+import type { CardProps } from '@mui/material';
import type { ValueLabelProps } from '@origin/shared/components';
+import type { SwapRoute } from '@origin/shared/providers';
-import type { OethRedeemAction } from '../types';
+import type { Meta, OethRedeemAction } from '../types';
export type RedeemActionCardProps = {
action: OethRedeemAction;
@@ -33,9 +31,9 @@ export const RedeemActionCard = ({
tokenIn,
tokenOut,
isSwapRoutesLoading,
+ selectedSwapRoute,
swapRoutes,
swapActions,
- selectedSwapRoute,
estimatedSwapRoutes,
},
] = useSwapState();
@@ -43,61 +41,26 @@ export const RedeemActionCard = ({
const route = swapRoutes.find((r) =>
routeEq({ tokenIn, tokenOut, action }, r),
- );
- const estimatedRoute = estimatedSwapRoutes.find((r) => routeEq(route, r));
-
- const {
- data: swapGasPrice,
- isLoading: swapGasPriceLoading,
- isFetching: swapGasPriceFetching,
- } = useGasPrice(estimatedRoute?.gas, estimatedRoute?.tokenIn.chainId, {
- refetchInterval: 30e3,
- enabled: !!estimatedRoute && estimatedRoute?.gas > 0n,
- });
- const {
- data: approvalGasPrice,
- isLoading: approvalGasPriceLoading,
- isFetching: approvalGasPriceFetching,
- } = useGasPrice(
- estimatedRoute?.approvalGas,
- estimatedRoute?.tokenIn.chainId,
- {
- refetchInterval: 30e3,
- enabled: !!estimatedRoute && estimatedRoute?.approvalGas > 0n,
- },
- );
- const { data: allowance } = useSwapRouteAllowance(route);
+ ) as SwapRoute;
const { data: isRouteAvailable, isLoading: isRouteAvailableLoading } =
useIsSwapRouteAvailable(route);
-
- const isSelected = routeEq(selectedSwapRoute, route);
- const isEmptyValue = isNilOrEmpty(estimatedRoute) || amountIn === 0n;
- const isGasLoading =
- isSwapRoutesLoading ||
- (swapGasPriceLoading && swapGasPriceFetching) ||
- (approvalGasPriceLoading && approvalGasPriceFetching);
- const gasPrice = add(
- swapGasPrice?.gasCostUsd ?? from(0),
- (allowance ?? 0n) < amountIn
- ? (approvalGasPrice?.gasCostUsd ?? from(0))
- : from(0),
- );
+ const estimatedRoute = estimatedSwapRoutes.find((r) => routeEq(route, r));
+ const isSelected = routeEq({ tokenIn, tokenOut, action }, selectedSwapRoute);
+ const isComingSoon =
+ (route as SwapRoute)?.meta?.comingSoon ?? false;
const routeLabel = swapActions[action].routeLabel;
- const isDisabled = !isRouteAvailableLoading && !isRouteAvailable;
+ const isDisabled =
+ !isRouteAvailable || isRouteAvailableLoading || isComingSoon;
return (
0n && {
- cursor: 'pointer',
- '&:hover': {
- borderColor: 'primary.main',
- },
- }),
+ backgroundColor: 'background.highlight',
...(isDisabled
? { opacity: 0.5, cursor: 'default' }
: isSelected
@@ -105,7 +68,14 @@ export const RedeemActionCard = ({
borderColor: 'primary.main',
backgroundColor: 'background.highlight',
}
- : {}),
+ : amountIn > 0n
+ ? {
+ cursor: 'pointer',
+ '&:hover': {
+ borderColor: 'primary.main',
+ },
+ }
+ : {}),
...rest?.sx,
}}
role="button"
@@ -115,6 +85,34 @@ export const RedeemActionCard = ({
}
}}
>
+ {isComingSoon && (
+
+ alpha(theme.palette.background.highlight, 0.8),
+ backdropFilter: 'blur(px)',
+ }}
+ >
+
+ theme.palette.getContrastText(
+ theme.palette.background.highlight,
+ ),
+ }}
+ >
+ {intl.formatMessage({ defaultMessage: 'Coming soon' })}
+
+
+ )}
- {intl.formatMessage(routeLabel)}
+ {intl.formatMessage(routeLabel ?? { defaultMessage: 'Route' })}
- {action === 'redeem-vault-oeth' ? (
-
- ) : (
-
- )}
+
+
+
+
+
- {isDisabled ? (
-
- {intl.formatMessage({
- defaultMessage: 'Larger redemptions coming soon',
- })}
-
- ) : (
-
-
- ) : (
- intl.formatMessage({ defaultMessage: '~1min' })
- )
- }
- isLoading={isSwapRoutesLoading}
- />
-
- ) : (
- intl.formatMessage(
- { defaultMessage: '1:{rate}' },
- {
- rate: format(from(estimatedRoute?.rate ?? 0), 3),
- },
- )
- )
- }
- isLoading={isSwapRoutesLoading}
- />
-
- ) : (
- intl.formatMessage(
- { defaultMessage: '~{value}' },
- {
- value: `$${format(gasPrice, 2)}`,
- },
- )
- )
- }
- isLoading={isGasLoading}
- />
-
- )}
);
};
-function EmptyValue(props: TypographyProps) {
- return (
-
- -
-
- );
-}
-
const valueLabelProps: Partial = {
direction: 'row',
justifyContent: 'space-between',
diff --git a/libs/defi/oeth/src/redeem/components/Swapper.tsx b/libs/defi/oeth/src/redeem/components/Swapper.tsx
index c4603daaa..ef27c1223 100644
--- a/libs/defi/oeth/src/redeem/components/Swapper.tsx
+++ b/libs/defi/oeth/src/redeem/components/Swapper.tsx
@@ -1,3 +1,5 @@
+import { useState } from 'react';
+
import {
Button,
Card,
@@ -11,7 +13,6 @@ import {
} from '@mui/material';
import {
activityOptions,
- SettingsButton,
TokenButton,
TokenInput,
useDeleteActivity,
@@ -19,9 +20,9 @@ import {
useUpdateActivity,
} from '@origin/defi/shared';
import {
- ErrorBoundary,
- ErrorCard,
+ InfoTooltipLabel,
LoadingLabel,
+ ValueLabel,
} from '@origin/shared/components';
import {
ConnectedButton,
@@ -29,33 +30,35 @@ import {
isNativeCurrency,
SwapProvider,
useDeleteNotification,
+ useGasPrice,
useHandleAmountInChange,
useHandleApprove,
useHandleSwap,
usePushNotification,
- useSlippage,
useSwapperPrices,
useSwapRouteAllowance,
useSwapState,
useWatchBalance,
} from '@origin/shared/providers';
-import {
- formatError,
- getFormatPrecision,
- isNilOrEmpty,
- subPercentage,
-} from '@origin/shared/utils';
-import { format, mul } from 'dnum';
+import { formatError, isNilOrEmpty } from '@origin/shared/utils';
+import { format, from, mul } from 'dnum';
import { useIntl } from 'react-intl';
import { useAccount } from 'wagmi';
import { RedeemActionCard } from './RedeemActionCard';
+import { WithdrawalRequestModal } from './WithdrawalRequestModal';
import type { StackProps } from '@mui/material';
import type { Activity } from '@origin/defi/shared';
-import type { SwapState } from '@origin/shared/providers';
+import type {
+ EstimatedSwapRoute,
+ GasPrice,
+ SwapState,
+} from '@origin/shared/providers';
import type { Dnum } from 'dnum';
+import type { WithdrawalRequestModalProps } from './WithdrawalRequestModal';
+
export type SwapperProps = Pick<
SwapState,
'swapActions' | 'swapRoutes' | 'trackEvent'
@@ -75,6 +78,8 @@ export const Swapper = ({
const pushActivity = usePushActivity();
const updateActivity = useUpdateActivity();
const deleteActivity = useDeleteActivity();
+ const [open, setOpen] = useState(false);
+ const [info, setInfo] = useState>();
return (
{
+ onSwapSuccess={({
+ amountOut,
+ tokenIn,
+ tokenOut,
+ trackId,
+ txReceipt,
+ notifId,
+ }) => {
+ setInfo({
+ amountOut,
+ tokenIn,
+ tokenOut,
+ txReceipt,
+ });
+ setOpen(true);
deleteNotification(notifId);
const updated = updateActivity({
id: trackId,
@@ -230,13 +249,21 @@ export const Swapper = ({
}}
>
+ {
+ setOpen(false);
+ }}
+ keepMounted={false}
+ {...info}
+ />
);
};
function SwapperWrapped({
onError,
- ...rest
}: Omit) {
const intl = useIntl();
const { isConnected } = useAccount();
@@ -255,12 +282,14 @@ function SwapperWrapped({
swapActions,
},
] = useSwapState();
- const { value: slippage } = useSlippage();
const { data: prices, isLoading: isPriceLoading } = useSwapperPrices();
const { data: allowance } = useSwapRouteAllowance(selectedSwapRoute);
const { data: balTokenIn, isLoading: isBalTokenInLoading } = useWatchBalance({
token: tokenIn,
});
+ const { data: gasPrice, isLoading: isGasPriceLoading } = useGasPrice(
+ selectedSwapRoute?.gas,
+ );
const handleAmountInChange = useHandleAmountInChange();
const handleApprove = useHandleApprove();
const handleSwap = useHandleSwap();
@@ -273,7 +302,6 @@ function SwapperWrapped({
estimatedAmount,
prices?.[getTokenPriceKey(tokenOut)] ?? 0,
);
- const minReceived = subPercentage(amountOutUsd, slippage);
const needsApproval =
isConnected &&
amountIn > 0n &&
@@ -312,171 +340,188 @@ function SwapperWrapped({
amountIn === 0n;
return (
-
- } onError={onError}>
-
- }
+
+
+
+
+
+ {intl.formatMessage({ defaultMessage: 'Amount' })}
+
+
+
+ {intl.formatMessage({ defaultMessage: 'Duration' })}
+
+
+
+
-
-
-
- {intl.formatMessage({ defaultMessage: 'Redeem amount' })}
-
-
-
- {intl.formatMessage({ defaultMessage: 'Route' })}
-
-
-
-
-
-
- {intl.formatMessage({ defaultMessage: 'Receive amount' })}
-
-
+
+ {intl.formatMessage({ defaultMessage: 'Receive amount' })}
+
+
+
+
-
-
- {format([amountOut ?? 0n, tokenOut?.decimals ?? 18], {
- digits: getFormatPrecision([
- amountOut ?? 0n,
- tokenOut?.decimals ?? 18,
- ]),
- decimalsRounding: 'ROUND_DOWN',
- })}
-
-
- ${amountIn === 0n ? '0.00' : format(amountOutUsd, 2)}
-
-
-
-
-
-
- 0n}>
-
-
- {intl.formatMessage(
- {
- defaultMessage:
- 'Minimum received with {slippage} slippage:',
- },
- {
- slippage: intl.formatNumber(slippage, {
- style: 'percent',
- minimumFractionDigits: 2,
- maximumFractionDigits: 2,
- }),
- },
- )}
-
-
-
- $
- {format(minReceived, {
- digits: getFormatPrecision(minReceived),
- decimalsRounding: 'ROUND_DOWN',
- })}
-
-
-
-
-
-
-
-
-
-
+
- {isSwapRoutesLoading ? (
-
- ) : isSwapWaitingForSignature ? (
- intl.formatMessage({ defaultMessage: 'Waiting for signature' })
- ) : isSwapLoading ? (
- intl.formatMessage({ defaultMessage: 'Processing Transaction' })
- ) : (
- swapButtonLabel
- )}
-
-
-
-
-
+ ${amountIn === 0n ? '0.00' : format(amountOutUsd, 2)}
+
+
+
+
+
+
+ 0n}>
+
+ }
+ isLoading={isGasPriceLoading}
+ direction="row"
+ justifyContent="space-between"
+ px={1}
+ mb={3}
+ labelProps={{
+ variant: 'body3',
+ fontWeight: 'medium',
+ }}
+ />
+
+
+
+
+
+
+
+ {isSwapRoutesLoading ? (
+
+ ) : isSwapWaitingForSignature ? (
+ intl.formatMessage({
+ defaultMessage: 'Waiting for signature',
+ })
+ ) : isSwapLoading ? (
+ intl.formatMessage({
+ defaultMessage: 'Processing Transaction',
+ })
+ ) : (
+ swapButtonLabel
+ )}
+
+
+
);
}
+
+type GasPriceLabelProps = {
+ route?: EstimatedSwapRoute | null;
+ gasPrice?: GasPrice;
+};
+
+const GasPriceLabel = ({ route, gasPrice, ...rest }: GasPriceLabelProps) => {
+ const intl = useIntl();
+
+ if (!gasPrice || !route || isNilOrEmpty(gasPrice?.gasCostUsd)) {
+ return `$0.00`;
+ }
+
+ if (route.action !== 'redeem-vault-async') {
+ return `$${format(gasPrice?.gasCostUsd ?? from(0), 2)}`;
+ }
+
+ const req = mul(gasPrice.gasCostUsd, 0.6);
+ const claim = mul(gasPrice.gasCostUsd, 0.4);
+
+ return (
+
+ ${format(req, 2)}
+
+ {`+ $${format(claim, 2)}`}
+
+
+ );
+};
diff --git a/libs/defi/oeth/src/redeem/components/ViewSwitch.tsx b/libs/defi/oeth/src/redeem/components/ViewSwitch.tsx
new file mode 100644
index 000000000..0337a2703
--- /dev/null
+++ b/libs/defi/oeth/src/redeem/components/ViewSwitch.tsx
@@ -0,0 +1,64 @@
+import { Stack } from '@mui/material';
+import { SliderSwitch } from '@origin/shared/components';
+import { isNilOrEmpty } from '@origin/shared/utils';
+import { useIntl } from 'react-intl';
+
+import { useViewSelect, useWithdrawalRequests } from '../hooks';
+
+import type { StackProps } from '@mui/material';
+import type { Option } from '@origin/shared/components';
+
+export const ViewSwitch = (props: StackProps) => {
+ const intl = useIntl();
+ const { view, update } = useViewSelect();
+ const { data: claimableRequests, isLoading: isClaimableRequestsLoading } =
+ useWithdrawalRequests({
+ select: (data) => data?.filter?.((r) => r.claimable),
+ });
+
+ const handleChange = (newVal: string | number) => {
+ update(newVal as 'request' | 'claim');
+ };
+
+ const options: Option[] = [
+ {
+ label: intl.formatMessage({ defaultMessage: 'Request' }),
+ value: 'request',
+ },
+ {
+ label: intl.formatMessage(
+ { defaultMessage: 'Claim{amount}' },
+ {
+ amount:
+ isClaimableRequestsLoading || isNilOrEmpty(claimableRequests)
+ ? ''
+ : ` (${claimableRequests?.length})`,
+ },
+ ),
+ value: 'claim',
+ },
+ ];
+
+ return (
+
+
+ `inset 0 0 0 1px ${theme.palette.background.default}`,
+ }}
+ />
+
+ );
+};
diff --git a/libs/defi/oeth/src/redeem/components/WithdrawalRequestModal.tsx b/libs/defi/oeth/src/redeem/components/WithdrawalRequestModal.tsx
new file mode 100644
index 000000000..92e448912
--- /dev/null
+++ b/libs/defi/oeth/src/redeem/components/WithdrawalRequestModal.tsx
@@ -0,0 +1,273 @@
+import { useEffect } from 'react';
+
+import {
+ alpha,
+ Box,
+ Button,
+ CircularProgress,
+ Dialog,
+ DialogContent,
+ DialogTitle,
+ IconButton,
+ Stack,
+ Typography,
+ useMediaQuery,
+ useTheme,
+} from '@mui/material';
+import {
+ FaCheckRegular,
+ FaExclamationRegular,
+ FaXmarkRegular,
+} from '@origin/shared/icons';
+import { BlockExplorerLink, useRefresher } from '@origin/shared/providers';
+import { getFormatPrecision, ZERO_ADDRESS } from '@origin/shared/utils';
+import { useQueryClient } from '@tanstack/react-query';
+import { format } from 'dnum';
+import { useIntl } from 'react-intl';
+import { useAccount } from 'wagmi';
+
+import { useViewSelect } from '../hooks';
+import { useWithdrawalRequestsQuery } from '../queries.generated';
+
+import type { DialogProps } from '@mui/material';
+import type { Token } from '@origin/shared/contracts';
+import type { Dnum } from 'dnum';
+import type { TransactionReceipt } from 'viem';
+
+import type { WithdrawalRequestsQuery } from '../queries.generated';
+
+export type WithdrawalRequestModalProps = {
+ amountOut?: bigint;
+ tokenIn?: Token;
+ tokenOut?: Token;
+ txReceipt?: TransactionReceipt;
+} & DialogProps;
+
+export const WithdrawalRequestModal = ({
+ amountOut,
+ tokenIn,
+ tokenOut,
+ txReceipt,
+ open,
+ onClose,
+ ...rest
+}: WithdrawalRequestModalProps) => {
+ const intl = useIntl();
+ const theme = useTheme();
+ const fullScreen = useMediaQuery(theme.breakpoints.down('md'));
+ const { update } = useViewSelect();
+ const queryClient = useQueryClient();
+ const { address } = useAccount();
+ const { status, startRefresh } = useRefresher({
+ queryKey: useWithdrawalRequestsQuery.getKey({
+ address: address ?? ZERO_ADDRESS,
+ }),
+ queryFn: useWithdrawalRequestsQuery.fetcher({
+ address: address ?? ZERO_ADDRESS,
+ }),
+ isResultProcessed: (prev, next) =>
+ prev.oethWithdrawalRequests.length < next.oethWithdrawalRequests.length,
+ });
+
+ useEffect(() => {
+ if (open) {
+ startRefresh();
+ }
+ }, [open, startRefresh]);
+
+ const handleClaimClick = () => {
+ update('claim');
+ onClose?.({}, 'backdropClick');
+ };
+
+ const amt = [amountOut ?? 0n, tokenOut?.decimals ?? 18] as Dnum;
+ const icon = {
+ idle: null,
+ error: null,
+ polling: (
+
+ alpha(theme.palette.primary.main, 0.3),
+ }}
+ size={85}
+ thickness={4.4}
+ value={100}
+ />
+
+
+ ),
+ processed: (
+
+
+
+ ),
+ timeout: (
+
+
+
+ ),
+ }[status];
+ const label = {
+ idle: null,
+ error: null,
+ processed: {
+ title: intl.formatMessage({
+ defaultMessage: 'Withdrawal request successfully sent',
+ }),
+ subtitle: intl.formatMessage(
+ {
+ defaultMessage:
+ 'Your request to withdraw {amountOut} {symbolOut} from {symbolIn} has been sent. Check the Claim tab to view your withdrawal requests.',
+ },
+ {
+ amountOut: format(amt, {
+ digits: getFormatPrecision(amt),
+ decimalsRounding: 'ROUND_DOWN',
+ }),
+ symbolIn: tokenIn?.symbol ?? '',
+ symbolOut: tokenOut?.symbol ?? '',
+ },
+ ),
+ },
+ timeout: {
+ title: intl.formatMessage({
+ defaultMessage: 'Withdrawal request is taking a long time to process',
+ }),
+ subtitle: intl.formatMessage({
+ defaultMessage:
+ 'Try to refresh the page and go to the Claim tab to see your withdrawal request',
+ }),
+ },
+ polling: {
+ title: intl.formatMessage({
+ defaultMessage: 'Your withdrawal is being processed',
+ }),
+ subtitle: intl.formatMessage({
+ defaultMessage: 'This operation can take a few seconds to complete',
+ }),
+ },
+ }[status];
+ const button = {
+ idle: null,
+ error: null,
+ timeout: (
+
+ ),
+ processed: (
+
+ ),
+ polling: (
+
+ ),
+ }[status];
+
+ return (
+
+ );
+};
diff --git a/libs/defi/oeth/src/redeem/constants.ts b/libs/defi/oeth/src/redeem/constants.ts
index 59cae9b81..591aeb85f 100644
--- a/libs/defi/oeth/src/redeem/constants.ts
+++ b/libs/defi/oeth/src/redeem/constants.ts
@@ -1,18 +1,34 @@
import { tokens } from '@origin/shared/contracts';
+import { ARM, OETH } from '@origin/shared/icons';
+import { defineMessage } from 'react-intl';
import type { SwapRoute } from '@origin/shared/providers';
-import type { OethRedeemAction } from './types';
+import type { Meta, OethRedeemAction } from './types';
-export const redeemRoutes: SwapRoute[] = [
+export const WITHDRAW_DELAY = 10; // minutes
+
+export const redeemRoutes: SwapRoute[] = [
{
tokenIn: tokens.mainnet.OETH,
tokenOut: tokens.mainnet.WETH,
- action: 'swap-curve-oeth',
+ action: 'redeem-arm-oeth',
+ meta: {
+ icon: ARM,
+ waitTime: defineMessage({ defaultMessage: '~1 min' }),
+ comingSoon: true,
+ },
},
{
tokenIn: tokens.mainnet.OETH,
tokenOut: tokens.mainnet.WETH,
- action: 'redeem-vault-oeth',
+ action: 'redeem-vault-async-oeth',
+ meta: {
+ icon: OETH,
+ waitTime: defineMessage({
+ defaultMessage: `a few days`,
+ }),
+ waitTimeColor: 'warning.dark',
+ },
},
];
diff --git a/libs/defi/oeth/src/redeem/hooks.ts b/libs/defi/oeth/src/redeem/hooks.ts
new file mode 100644
index 000000000..ab8831daf
--- /dev/null
+++ b/libs/defi/oeth/src/redeem/hooks.ts
@@ -0,0 +1,115 @@
+import { useMemo } from 'react';
+
+import { contracts } from '@origin/shared/contracts';
+import { isFulfilled, ZERO_ADDRESS } from '@origin/shared/utils';
+import { useQuery, useQueryClient } from '@tanstack/react-query';
+import { readContract } from '@wagmi/core';
+import { addMinutes, isAfter } from 'date-fns';
+import { useSearchParams } from 'react-router-dom';
+import { useAccount, useConfig } from 'wagmi';
+
+import { WITHDRAW_DELAY } from './constants';
+import { useWithdrawalRequestsQuery } from './queries.generated';
+
+import type { HexAddress } from '@origin/shared/utils';
+import type {
+ QueryClient,
+ QueryFunction,
+ UseQueryOptions,
+} from '@tanstack/react-query';
+import type { Config } from '@wagmi/core';
+
+import type { WithdrawalRequest } from './types';
+
+export const useViewSelect = () => {
+ const [search, setSearch] = useSearchParams({
+ v: 'request',
+ });
+
+ return useMemo(
+ () => ({
+ view: search.get('v') ?? 'request',
+ update: (newVal: 'request' | 'claim') => {
+ setSearch((params) => {
+ params.set('v', newVal);
+ return params;
+ });
+ },
+ }),
+ [search, setSearch],
+ );
+};
+
+const getKey = (address: HexAddress | undefined) => [
+ 'useClaimableRequests',
+ address,
+];
+
+const fetcher: (
+ config: Config,
+ queryClient: QueryClient,
+) => QueryFunction =
+ (config, queryClient) =>
+ async ({ queryKey: [, address] }) => {
+ const res = await Promise.allSettled([
+ readContract(config, {
+ address: contracts.mainnet.OETHVault.address,
+ abi: contracts.mainnet.OETHVault.abi,
+ functionName: 'withdrawalQueueMetadata',
+ chainId: contracts.mainnet.OETHVault.chainId,
+ }),
+ queryClient.fetchQuery({
+ queryKey: useWithdrawalRequestsQuery.getKey({
+ address: (address as string) ?? ZERO_ADDRESS,
+ }),
+ queryFn: useWithdrawalRequestsQuery.fetcher({
+ address: (address as string) ?? ZERO_ADDRESS,
+ }),
+ }),
+ ]);
+ const queueData = isFulfilled(res[0]) ? res[0].value : null;
+ const requests = isFulfilled(res[1])
+ ? (res[1].value?.oethWithdrawalRequests ?? [])
+ : [];
+ return requests.map((r) => {
+ const claimable =
+ !r.claimed &&
+ BigInt(r.queued) <= BigInt(queueData?.[1] ?? 0) &&
+ isAfter(
+ new Date(),
+ addMinutes(new Date(r.timestamp), WITHDRAW_DELAY + 1),
+ );
+
+ return {
+ ...r,
+ requestId: BigInt(r.requestId),
+ amount: BigInt(r.amount),
+ queued: BigInt(r.queued),
+ claimable,
+ };
+ });
+ };
+
+export const useWithdrawalRequests = (
+ options?: Omit<
+ UseQueryOptions<
+ WithdrawalRequest[],
+ Error,
+ WithdrawalRequest[],
+ ReturnType
+ >,
+ 'queryKey' | 'queryFn'
+ >,
+) => {
+ const { address } = useAccount();
+ const config = useConfig();
+ const queryClient = useQueryClient();
+
+ return useQuery({
+ ...options,
+ queryKey: getKey(address),
+ queryFn: fetcher(config, queryClient),
+ });
+};
+useWithdrawalRequests.getKey = getKey;
+useWithdrawalRequests.fetcher = fetcher;
diff --git a/libs/defi/oeth/src/redeem/index.ts b/libs/defi/oeth/src/redeem/index.ts
index a3820983e..2d32501e5 100644
--- a/libs/defi/oeth/src/redeem/index.ts
+++ b/libs/defi/oeth/src/redeem/index.ts
@@ -1 +1 @@
-export * from './routes';
+export * from './views/RedeemView';
diff --git a/libs/defi/oeth/src/redeem/queries.generated.ts b/libs/defi/oeth/src/redeem/queries.generated.ts
new file mode 100644
index 000000000..aaf6feb94
--- /dev/null
+++ b/libs/defi/oeth/src/redeem/queries.generated.ts
@@ -0,0 +1,49 @@
+import * as Types from '@origin/defi/shared';
+
+import { useQuery, UseQueryOptions } from '@tanstack/react-query';
+import { graphqlClient } from '@origin/defi/shared';
+export type WithdrawalRequestsQueryVariables = Types.Exact<{
+ address: Types.Scalars['String']['input'];
+}>;
+
+
+export type WithdrawalRequestsQuery = { __typename?: 'Query', oethWithdrawalRequests: Array<{ __typename?: 'OETHWithdrawalRequest', id: string, requestId: string, timestamp: string, amount: string, queued: string, claimed: boolean, blockNumber: number, txHash: string }> };
+
+
+
+export const WithdrawalRequestsDocument = `
+ query WithdrawalRequests($address: String!) {
+ oethWithdrawalRequests(where: {withdrawer_containsInsensitive: $address}) {
+ id
+ requestId
+ timestamp
+ amount
+ queued
+ claimed
+ blockNumber
+ requestId
+ txHash
+ }
+}
+ `;
+
+export const useWithdrawalRequestsQuery = <
+ TData = WithdrawalRequestsQuery,
+ TError = unknown
+ >(
+ variables: WithdrawalRequestsQueryVariables,
+ options?: Omit, 'queryKey'> & { queryKey?: UseQueryOptions['queryKey'] }
+ ) => {
+
+ return useQuery(
+ {
+ queryKey: ['WithdrawalRequests', variables],
+ queryFn: graphqlClient(WithdrawalRequestsDocument, variables),
+ ...options
+ }
+ )};
+
+useWithdrawalRequestsQuery.getKey = (variables: WithdrawalRequestsQueryVariables) => ['WithdrawalRequests', variables];
+
+
+useWithdrawalRequestsQuery.fetcher = (variables: WithdrawalRequestsQueryVariables, options?: RequestInit['headers']) => graphqlClient(WithdrawalRequestsDocument, variables, options);
diff --git a/libs/defi/oeth/src/redeem/queries.graphql b/libs/defi/oeth/src/redeem/queries.graphql
new file mode 100644
index 000000000..0d9ed4d97
--- /dev/null
+++ b/libs/defi/oeth/src/redeem/queries.graphql
@@ -0,0 +1,13 @@
+query WithdrawalRequests($address: String!) {
+ oethWithdrawalRequests(where: { withdrawer_containsInsensitive: $address }) {
+ id
+ requestId
+ timestamp
+ amount
+ queued
+ claimed
+ blockNumber
+ requestId
+ txHash
+ }
+}
diff --git a/libs/defi/oeth/src/redeem/routes.tsx b/libs/defi/oeth/src/redeem/routes.tsx
deleted file mode 100644
index 6691d83d8..000000000
--- a/libs/defi/oeth/src/redeem/routes.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import { defineMessage } from 'react-intl';
-
-import { ClaimView } from './views/ClaimView';
-import { RedeemView } from './views/RedeemView';
-import { RequestView } from './views/RequestView';
-
-import type { NonIndexRouteObject } from 'react-router-dom';
-
-export const oethRedeemRoute: NonIndexRouteObject = {
- path: 'redeem',
- Component: RedeemView,
- children: [
- {
- index: true,
- Component: RequestView,
- handle: { label: defineMessage({ defaultMessage: 'Request' }) },
- },
- {
- path: 'claim',
- Component: ClaimView,
- handle: { label: defineMessage({ defaultMessage: 'Claim' }) },
- },
- ],
-};
diff --git a/libs/defi/oeth/src/redeem/types.ts b/libs/defi/oeth/src/redeem/types.ts
index 47c13bdfc..64869ce69 100644
--- a/libs/defi/oeth/src/redeem/types.ts
+++ b/libs/defi/oeth/src/redeem/types.ts
@@ -1,6 +1,28 @@
+import type { SvgIconProps } from '@mui/material';
import type { OethRoute } from '@origin/shared/routes';
+import type { ComponentType } from 'react';
+import type { MessageDescriptor } from 'react-intl';
+
+export type Meta = {
+ icon?: ComponentType;
+ waitTime?: MessageDescriptor;
+ waitTimeColor?: string;
+ comingSoon?: boolean;
+};
export type OethRedeemAction = Extract<
OethRoute,
- 'swap-curve-oeth' | 'redeem-vault-oeth'
+ 'redeem-arm-oeth' | 'redeem-vault-async-oeth'
>;
+
+export type WithdrawalRequest = {
+ id: string;
+ requestId: bigint;
+ timestamp: string;
+ amount: bigint;
+ queued: bigint;
+ claimed: boolean;
+ blockNumber: number;
+ claimable: boolean;
+ txHash: string;
+};
diff --git a/libs/defi/oeth/src/redeem/views/ClaimView.tsx b/libs/defi/oeth/src/redeem/views/ClaimView.tsx
index c04dd2048..dcd1aa63f 100644
--- a/libs/defi/oeth/src/redeem/views/ClaimView.tsx
+++ b/libs/defi/oeth/src/redeem/views/ClaimView.tsx
@@ -1,10 +1,15 @@
-import { Typography } from '@mui/material';
-import { useIntl } from 'react-intl';
+import { Card, CardContent } from '@mui/material';
-export const ClaimView = () => {
- const intl = useIntl();
+import { ClaimForm } from '../components/ClaimForm';
+import { ClaimHeader } from '../components/ClaimHeader';
+export const ClaimView = () => {
return (
- {intl.formatMessage({ defaultMessage: 'Claim' })}
+
+
+
+
+
+
);
};
diff --git a/libs/defi/oeth/src/redeem/views/RedeemView.tsx b/libs/defi/oeth/src/redeem/views/RedeemView.tsx
index c5cfa17d8..43375ab4c 100644
--- a/libs/defi/oeth/src/redeem/views/RedeemView.tsx
+++ b/libs/defi/oeth/src/redeem/views/RedeemView.tsx
@@ -1,12 +1,22 @@
-import { Page, PageSection, PageTitle } from '@origin/defi/shared';
+import { Stack } from '@mui/material';
+import {
+ Page,
+ PageSection,
+ PageTitle,
+ trackSentryError,
+} from '@origin/defi/shared';
+import { ErrorBoundary, ErrorCard } from '@origin/shared/components';
import { tokens } from '@origin/shared/contracts';
import { useIntl } from 'react-intl';
-import { Outlet } from 'react-router-dom';
+
+import { ViewSwitch } from '../components/ViewSwitch';
+import { useViewSelect } from '../hooks';
+import { ClaimView } from './ClaimView';
+import { RequestView } from './RequestView';
export const RedeemView = () => {
const intl = useIntl();
- // const navigate = useNavigate();
- // const location = useLocation();
+ const { view } = useViewSelect();
return (
@@ -17,30 +27,17 @@ export const RedeemView = () => {
})}
token={tokens.mainnet.OETH}
/>
- {/* {
- navigate(value);
- }}
- sx={{ mb: 5 }}
- >
- {oethRedeemRoute?.children?.map((route) => {
- const path = route.index
- ? '/oeth/redeem'
- : `/oeth/redeem/${route.path}`;
- return (
-
- );
- })}
- */}
-
-
+
+
+
+ }
+ onError={trackSentryError}
+ >
+ {view === 'request' ? : }
+
+
);
diff --git a/libs/defi/shared/src/components/Activities/constants.tsx b/libs/defi/shared/src/components/Activities/constants.tsx
index 761dedec6..cb013c8db 100644
--- a/libs/defi/shared/src/components/Activities/constants.tsx
+++ b/libs/defi/shared/src/components/Activities/constants.tsx
@@ -24,6 +24,7 @@ import type {
ApprovalActivity,
BridgeActivity,
ClaimRewardsActivity,
+ ClaimWithdrawalActivity,
DelegateVoteActivity,
ExtendStakeActivity,
MigrateActivity,
@@ -191,6 +192,47 @@ export const activityOptions: Record = {
);
},
},
+ 'claim-withdrawal': {
+ title: (activity, intl) =>
+ ({
+ pending: intl.formatMessage({ defaultMessage: 'Claiming Withdrawal' }),
+ signed: intl.formatMessage({ defaultMessage: 'Claiming Withdrawal' }),
+ success: intl.formatMessage({ defaultMessage: 'Claimed Withdrawal' }),
+ error: intl.formatMessage({
+ defaultMessage: 'Error while claiming withdrawal',
+ }),
+ idle: intl.formatMessage({ defaultMessage: 'Claim Withdrawal' }),
+ })[activity.status],
+ subtitle: (activity, intl) => {
+ const { amountIn, tokenIdIn } = activity as ClaimWithdrawalActivity;
+ const tokenIn = getTokenById(tokenIdIn);
+ const amount = format([amountIn ?? 0n, tokenIn.decimals ?? 18], 4);
+
+ return intl.formatMessage(
+ {
+ defaultMessage: 'Claim {amount} {symbolIn}',
+ },
+ { amount, symbolIn: tokenIn.symbol },
+ );
+ },
+ icon: (activity) => {
+ const { tokenIdIn } = activity as ClaimRewardsActivity;
+ const tokenIn = getTokenById(tokenIdIn);
+
+ return (
+
+ }
+ badgeBkgColor="primary.main"
+ >
+
+
+ );
+ },
+ },
delegate: {
title: (activity, intl) =>
({
diff --git a/libs/defi/shared/src/components/Activities/types.ts b/libs/defi/shared/src/components/Activities/types.ts
index 5d4a58fc6..7d75e82b1 100644
--- a/libs/defi/shared/src/components/Activities/types.ts
+++ b/libs/defi/shared/src/components/Activities/types.ts
@@ -35,6 +35,12 @@ export interface ClaimRewardsActivity extends ActivityBase {
amountIn: bigint;
}
+export interface ClaimWithdrawalActivity extends ActivityBase {
+ type: 'claim-withdrawal';
+ amountIn: bigint;
+ tokenIdIn: TokenId;
+}
+
export interface DelegateVoteActivity extends ActivityBase {
type: 'delegate';
tokenIdIn: TokenId;
@@ -105,6 +111,7 @@ export type Activity =
| ApprovalActivity
| BridgeActivity
| ClaimRewardsActivity
+ | ClaimWithdrawalActivity
| DelegateVoteActivity
| ExtendStakeActivity
| MigrateActivity
diff --git a/libs/defi/shared/src/generated/graphql.ts b/libs/defi/shared/src/generated/graphql.ts
index 2af37c450..62555c749 100644
--- a/libs/defi/shared/src/generated/graphql.ts
+++ b/libs/defi/shared/src/generated/graphql.ts
@@ -14,6 +14,15 @@ export type Scalars = {
Float: { input: number; output: number; }
BigInt: { input: string; output: string; }
DateTime: { input: string; output: string; }
+ JSON: { input: any; output: any; }
+};
+
+export type Balance = {
+ __typename?: 'Balance';
+ asset: Scalars['String']['output'];
+ balance: Scalars['BigInt']['output'];
+ blockNumber: Scalars['Int']['output'];
+ timestamp: Scalars['DateTime']['output'];
};
export type BalancerPool = {
@@ -2305,6 +2314,15 @@ export type Erc20State = {
totalSupply: Scalars['BigInt']['output'];
};
+export type Erc20StateByDay = {
+ __typename?: 'ERC20StateByDay';
+ address: Scalars['String']['output'];
+ chainId: Scalars['String']['output'];
+ day: Scalars['DateTime']['output'];
+ holderCount: Scalars['Int']['output'];
+ totalSupply: Scalars['BigInt']['output'];
+};
+
export type Erc20StateEdge = {
__typename?: 'ERC20StateEdge';
cursor: Scalars['String']['output'];
@@ -9933,6 +9951,193 @@ export type OethVaultsConnection = {
totalCount: Scalars['Int']['output'];
};
+export type OethWithdrawalRequest = {
+ __typename?: 'OETHWithdrawalRequest';
+ amount: Scalars['BigInt']['output'];
+ blockNumber: Scalars['Int']['output'];
+ claimed: Scalars['Boolean']['output'];
+ id: Scalars['String']['output'];
+ queued: Scalars['BigInt']['output'];
+ requestId: Scalars['BigInt']['output'];
+ timestamp: Scalars['DateTime']['output'];
+ txHash: Scalars['String']['output'];
+ withdrawer: Scalars['String']['output'];
+};
+
+export type OethWithdrawalRequestEdge = {
+ __typename?: 'OETHWithdrawalRequestEdge';
+ cursor: Scalars['String']['output'];
+ node: OethWithdrawalRequest;
+};
+
+export enum OethWithdrawalRequestOrderByInput {
+ AmountAsc = 'amount_ASC',
+ AmountAscNullsFirst = 'amount_ASC_NULLS_FIRST',
+ AmountAscNullsLast = 'amount_ASC_NULLS_LAST',
+ AmountDesc = 'amount_DESC',
+ AmountDescNullsFirst = 'amount_DESC_NULLS_FIRST',
+ AmountDescNullsLast = 'amount_DESC_NULLS_LAST',
+ BlockNumberAsc = 'blockNumber_ASC',
+ BlockNumberAscNullsFirst = 'blockNumber_ASC_NULLS_FIRST',
+ BlockNumberAscNullsLast = 'blockNumber_ASC_NULLS_LAST',
+ BlockNumberDesc = 'blockNumber_DESC',
+ BlockNumberDescNullsFirst = 'blockNumber_DESC_NULLS_FIRST',
+ BlockNumberDescNullsLast = 'blockNumber_DESC_NULLS_LAST',
+ ClaimedAsc = 'claimed_ASC',
+ ClaimedAscNullsFirst = 'claimed_ASC_NULLS_FIRST',
+ ClaimedAscNullsLast = 'claimed_ASC_NULLS_LAST',
+ ClaimedDesc = 'claimed_DESC',
+ ClaimedDescNullsFirst = 'claimed_DESC_NULLS_FIRST',
+ ClaimedDescNullsLast = 'claimed_DESC_NULLS_LAST',
+ IdAsc = 'id_ASC',
+ IdAscNullsFirst = 'id_ASC_NULLS_FIRST',
+ IdAscNullsLast = 'id_ASC_NULLS_LAST',
+ IdDesc = 'id_DESC',
+ IdDescNullsFirst = 'id_DESC_NULLS_FIRST',
+ IdDescNullsLast = 'id_DESC_NULLS_LAST',
+ QueuedAsc = 'queued_ASC',
+ QueuedAscNullsFirst = 'queued_ASC_NULLS_FIRST',
+ QueuedAscNullsLast = 'queued_ASC_NULLS_LAST',
+ QueuedDesc = 'queued_DESC',
+ QueuedDescNullsFirst = 'queued_DESC_NULLS_FIRST',
+ QueuedDescNullsLast = 'queued_DESC_NULLS_LAST',
+ RequestIdAsc = 'requestId_ASC',
+ RequestIdAscNullsFirst = 'requestId_ASC_NULLS_FIRST',
+ RequestIdAscNullsLast = 'requestId_ASC_NULLS_LAST',
+ RequestIdDesc = 'requestId_DESC',
+ RequestIdDescNullsFirst = 'requestId_DESC_NULLS_FIRST',
+ RequestIdDescNullsLast = 'requestId_DESC_NULLS_LAST',
+ TimestampAsc = 'timestamp_ASC',
+ TimestampAscNullsFirst = 'timestamp_ASC_NULLS_FIRST',
+ TimestampAscNullsLast = 'timestamp_ASC_NULLS_LAST',
+ TimestampDesc = 'timestamp_DESC',
+ TimestampDescNullsFirst = 'timestamp_DESC_NULLS_FIRST',
+ TimestampDescNullsLast = 'timestamp_DESC_NULLS_LAST',
+ TxHashAsc = 'txHash_ASC',
+ TxHashAscNullsFirst = 'txHash_ASC_NULLS_FIRST',
+ TxHashAscNullsLast = 'txHash_ASC_NULLS_LAST',
+ TxHashDesc = 'txHash_DESC',
+ TxHashDescNullsFirst = 'txHash_DESC_NULLS_FIRST',
+ TxHashDescNullsLast = 'txHash_DESC_NULLS_LAST',
+ WithdrawerAsc = 'withdrawer_ASC',
+ WithdrawerAscNullsFirst = 'withdrawer_ASC_NULLS_FIRST',
+ WithdrawerAscNullsLast = 'withdrawer_ASC_NULLS_LAST',
+ WithdrawerDesc = 'withdrawer_DESC',
+ WithdrawerDescNullsFirst = 'withdrawer_DESC_NULLS_FIRST',
+ WithdrawerDescNullsLast = 'withdrawer_DESC_NULLS_LAST'
+}
+
+export type OethWithdrawalRequestWhereInput = {
+ AND?: InputMaybe>;
+ OR?: InputMaybe>;
+ amount_eq?: InputMaybe;
+ amount_gt?: InputMaybe;
+ amount_gte?: InputMaybe;
+ amount_in?: InputMaybe>;
+ amount_isNull?: InputMaybe;
+ amount_lt?: InputMaybe;
+ amount_lte?: InputMaybe;
+ amount_not_eq?: InputMaybe;
+ amount_not_in?: InputMaybe>;
+ blockNumber_eq?: InputMaybe;
+ blockNumber_gt?: InputMaybe;
+ blockNumber_gte?: InputMaybe;
+ blockNumber_in?: InputMaybe>;
+ blockNumber_isNull?: InputMaybe;
+ blockNumber_lt?: InputMaybe;
+ blockNumber_lte?: InputMaybe;
+ blockNumber_not_eq?: InputMaybe;
+ blockNumber_not_in?: InputMaybe>;
+ claimed_eq?: InputMaybe;
+ claimed_isNull?: InputMaybe;
+ claimed_not_eq?: InputMaybe;
+ id_contains?: InputMaybe;
+ id_containsInsensitive?: InputMaybe;
+ id_endsWith?: InputMaybe;
+ id_eq?: InputMaybe;
+ id_gt?: InputMaybe;
+ id_gte?: InputMaybe;
+ id_in?: InputMaybe>;
+ id_isNull?: InputMaybe;
+ id_lt?: InputMaybe;
+ id_lte?: InputMaybe;
+ id_not_contains?: InputMaybe;
+ id_not_containsInsensitive?: InputMaybe;
+ id_not_endsWith?: InputMaybe;
+ id_not_eq?: InputMaybe;
+ id_not_in?: InputMaybe>;
+ id_not_startsWith?: InputMaybe;
+ id_startsWith?: InputMaybe;
+ queued_eq?: InputMaybe;
+ queued_gt?: InputMaybe;
+ queued_gte?: InputMaybe;
+ queued_in?: InputMaybe>;
+ queued_isNull?: InputMaybe;
+ queued_lt?: InputMaybe;
+ queued_lte?: InputMaybe;
+ queued_not_eq?: InputMaybe;
+ queued_not_in?: InputMaybe>;
+ requestId_eq?: InputMaybe;
+ requestId_gt?: InputMaybe;
+ requestId_gte?: InputMaybe;
+ requestId_in?: InputMaybe>;
+ requestId_isNull?: InputMaybe;
+ requestId_lt?: InputMaybe;
+ requestId_lte?: InputMaybe;
+ requestId_not_eq?: InputMaybe;
+ requestId_not_in?: InputMaybe>;
+ timestamp_eq?: InputMaybe;
+ timestamp_gt?: InputMaybe;
+ timestamp_gte?: InputMaybe;
+ timestamp_in?: InputMaybe>;
+ timestamp_isNull?: InputMaybe;
+ timestamp_lt?: InputMaybe;
+ timestamp_lte?: InputMaybe;
+ timestamp_not_eq?: InputMaybe;
+ timestamp_not_in?: InputMaybe>;
+ txHash_contains?: InputMaybe;
+ txHash_containsInsensitive?: InputMaybe;
+ txHash_endsWith?: InputMaybe;
+ txHash_eq?: InputMaybe;
+ txHash_gt?: InputMaybe;
+ txHash_gte?: InputMaybe;
+ txHash_in?: InputMaybe>;
+ txHash_isNull?: InputMaybe;
+ txHash_lt?: InputMaybe;
+ txHash_lte?: InputMaybe;
+ txHash_not_contains?: InputMaybe;
+ txHash_not_containsInsensitive?: InputMaybe;
+ txHash_not_endsWith?: InputMaybe;
+ txHash_not_eq?: InputMaybe;
+ txHash_not_in?: InputMaybe>;
+ txHash_not_startsWith?: InputMaybe;
+ txHash_startsWith?: InputMaybe;
+ withdrawer_contains?: InputMaybe;
+ withdrawer_containsInsensitive?: InputMaybe;
+ withdrawer_endsWith?: InputMaybe;
+ withdrawer_eq?: InputMaybe;
+ withdrawer_gt?: InputMaybe;
+ withdrawer_gte?: InputMaybe;
+ withdrawer_in?: InputMaybe>;
+ withdrawer_isNull?: InputMaybe;
+ withdrawer_lt?: InputMaybe;
+ withdrawer_lte?: InputMaybe;
+ withdrawer_not_contains?: InputMaybe;
+ withdrawer_not_containsInsensitive?: InputMaybe;
+ withdrawer_not_endsWith?: InputMaybe;
+ withdrawer_not_eq?: InputMaybe;
+ withdrawer_not_in?: InputMaybe>;
+ withdrawer_not_startsWith?: InputMaybe;
+ withdrawer_startsWith?: InputMaybe;
+};
+
+export type OethWithdrawalRequestsConnection = {
+ __typename?: 'OETHWithdrawalRequestsConnection';
+ edges: Array;
+ pageInfo: PageInfo;
+ totalCount: Scalars['Int']['output'];
+};
+
export type OgnStatsResult = {
__typename?: 'OGNStatsResult';
circulatingSupply: Scalars['Float']['output'];
@@ -11691,21 +11896,14 @@ export type OTokenActivitiesConnection = {
export type OTokenActivity = {
__typename?: 'OTokenActivity';
- action?: Maybe;
- address?: Maybe;
- amount?: Maybe;
blockNumber: Scalars['Int']['output'];
- callDataLast4Bytes: Scalars['String']['output'];
chainId: Scalars['Int']['output'];
- exchange?: Maybe;
- fromSymbol?: Maybe;
+ data?: Maybe;
id: Scalars['String']['output'];
- interface?: Maybe;
otoken: Scalars['String']['output'];
- sighash?: Maybe;
timestamp: Scalars['DateTime']['output'];
- toSymbol?: Maybe;
txHash: Scalars['String']['output'];
+ type?: Maybe;
};
export type OTokenActivityEdge = {
@@ -11715,144 +11913,72 @@ export type OTokenActivityEdge = {
};
export enum OTokenActivityOrderByInput {
- ActionAsc = 'action_ASC',
- ActionAscNullsFirst = 'action_ASC_NULLS_FIRST',
- ActionAscNullsLast = 'action_ASC_NULLS_LAST',
- ActionDesc = 'action_DESC',
- ActionDescNullsFirst = 'action_DESC_NULLS_FIRST',
- ActionDescNullsLast = 'action_DESC_NULLS_LAST',
- AddressAsc = 'address_ASC',
- AddressAscNullsFirst = 'address_ASC_NULLS_FIRST',
- AddressAscNullsLast = 'address_ASC_NULLS_LAST',
- AddressDesc = 'address_DESC',
- AddressDescNullsFirst = 'address_DESC_NULLS_FIRST',
- AddressDescNullsLast = 'address_DESC_NULLS_LAST',
- AmountAsc = 'amount_ASC',
- AmountAscNullsFirst = 'amount_ASC_NULLS_FIRST',
- AmountAscNullsLast = 'amount_ASC_NULLS_LAST',
- AmountDesc = 'amount_DESC',
- AmountDescNullsFirst = 'amount_DESC_NULLS_FIRST',
- AmountDescNullsLast = 'amount_DESC_NULLS_LAST',
BlockNumberAsc = 'blockNumber_ASC',
BlockNumberAscNullsFirst = 'blockNumber_ASC_NULLS_FIRST',
BlockNumberAscNullsLast = 'blockNumber_ASC_NULLS_LAST',
BlockNumberDesc = 'blockNumber_DESC',
BlockNumberDescNullsFirst = 'blockNumber_DESC_NULLS_FIRST',
BlockNumberDescNullsLast = 'blockNumber_DESC_NULLS_LAST',
- CallDataLast4BytesAsc = 'callDataLast4Bytes_ASC',
- CallDataLast4BytesAscNullsFirst = 'callDataLast4Bytes_ASC_NULLS_FIRST',
- CallDataLast4BytesAscNullsLast = 'callDataLast4Bytes_ASC_NULLS_LAST',
- CallDataLast4BytesDesc = 'callDataLast4Bytes_DESC',
- CallDataLast4BytesDescNullsFirst = 'callDataLast4Bytes_DESC_NULLS_FIRST',
- CallDataLast4BytesDescNullsLast = 'callDataLast4Bytes_DESC_NULLS_LAST',
ChainIdAsc = 'chainId_ASC',
ChainIdAscNullsFirst = 'chainId_ASC_NULLS_FIRST',
ChainIdAscNullsLast = 'chainId_ASC_NULLS_LAST',
ChainIdDesc = 'chainId_DESC',
ChainIdDescNullsFirst = 'chainId_DESC_NULLS_FIRST',
ChainIdDescNullsLast = 'chainId_DESC_NULLS_LAST',
- ExchangeAsc = 'exchange_ASC',
- ExchangeAscNullsFirst = 'exchange_ASC_NULLS_FIRST',
- ExchangeAscNullsLast = 'exchange_ASC_NULLS_LAST',
- ExchangeDesc = 'exchange_DESC',
- ExchangeDescNullsFirst = 'exchange_DESC_NULLS_FIRST',
- ExchangeDescNullsLast = 'exchange_DESC_NULLS_LAST',
- FromSymbolAsc = 'fromSymbol_ASC',
- FromSymbolAscNullsFirst = 'fromSymbol_ASC_NULLS_FIRST',
- FromSymbolAscNullsLast = 'fromSymbol_ASC_NULLS_LAST',
- FromSymbolDesc = 'fromSymbol_DESC',
- FromSymbolDescNullsFirst = 'fromSymbol_DESC_NULLS_FIRST',
- FromSymbolDescNullsLast = 'fromSymbol_DESC_NULLS_LAST',
IdAsc = 'id_ASC',
IdAscNullsFirst = 'id_ASC_NULLS_FIRST',
IdAscNullsLast = 'id_ASC_NULLS_LAST',
IdDesc = 'id_DESC',
IdDescNullsFirst = 'id_DESC_NULLS_FIRST',
IdDescNullsLast = 'id_DESC_NULLS_LAST',
- InterfaceAsc = 'interface_ASC',
- InterfaceAscNullsFirst = 'interface_ASC_NULLS_FIRST',
- InterfaceAscNullsLast = 'interface_ASC_NULLS_LAST',
- InterfaceDesc = 'interface_DESC',
- InterfaceDescNullsFirst = 'interface_DESC_NULLS_FIRST',
- InterfaceDescNullsLast = 'interface_DESC_NULLS_LAST',
OtokenAsc = 'otoken_ASC',
OtokenAscNullsFirst = 'otoken_ASC_NULLS_FIRST',
OtokenAscNullsLast = 'otoken_ASC_NULLS_LAST',
OtokenDesc = 'otoken_DESC',
OtokenDescNullsFirst = 'otoken_DESC_NULLS_FIRST',
OtokenDescNullsLast = 'otoken_DESC_NULLS_LAST',
- SighashAsc = 'sighash_ASC',
- SighashAscNullsFirst = 'sighash_ASC_NULLS_FIRST',
- SighashAscNullsLast = 'sighash_ASC_NULLS_LAST',
- SighashDesc = 'sighash_DESC',
- SighashDescNullsFirst = 'sighash_DESC_NULLS_FIRST',
- SighashDescNullsLast = 'sighash_DESC_NULLS_LAST',
TimestampAsc = 'timestamp_ASC',
TimestampAscNullsFirst = 'timestamp_ASC_NULLS_FIRST',
TimestampAscNullsLast = 'timestamp_ASC_NULLS_LAST',
TimestampDesc = 'timestamp_DESC',
TimestampDescNullsFirst = 'timestamp_DESC_NULLS_FIRST',
TimestampDescNullsLast = 'timestamp_DESC_NULLS_LAST',
- ToSymbolAsc = 'toSymbol_ASC',
- ToSymbolAscNullsFirst = 'toSymbol_ASC_NULLS_FIRST',
- ToSymbolAscNullsLast = 'toSymbol_ASC_NULLS_LAST',
- ToSymbolDesc = 'toSymbol_DESC',
- ToSymbolDescNullsFirst = 'toSymbol_DESC_NULLS_FIRST',
- ToSymbolDescNullsLast = 'toSymbol_DESC_NULLS_LAST',
TxHashAsc = 'txHash_ASC',
TxHashAscNullsFirst = 'txHash_ASC_NULLS_FIRST',
TxHashAscNullsLast = 'txHash_ASC_NULLS_LAST',
TxHashDesc = 'txHash_DESC',
TxHashDescNullsFirst = 'txHash_DESC_NULLS_FIRST',
- TxHashDescNullsLast = 'txHash_DESC_NULLS_LAST'
+ TxHashDescNullsLast = 'txHash_DESC_NULLS_LAST',
+ TypeAsc = 'type_ASC',
+ TypeAscNullsFirst = 'type_ASC_NULLS_FIRST',
+ TypeAscNullsLast = 'type_ASC_NULLS_LAST',
+ TypeDesc = 'type_DESC',
+ TypeDescNullsFirst = 'type_DESC_NULLS_FIRST',
+ TypeDescNullsLast = 'type_DESC_NULLS_LAST'
+}
+
+export enum OTokenActivityType {
+ Approval = 'Approval',
+ Bridge = 'Bridge',
+ ClaimRewards = 'ClaimRewards',
+ DelegateVote = 'DelegateVote',
+ ExtendStake = 'ExtendStake',
+ Migrate = 'Migrate',
+ Mint = 'Mint',
+ Redeem = 'Redeem',
+ Stake = 'Stake',
+ Swap = 'Swap',
+ Transfer = 'Transfer',
+ Unstake = 'Unstake',
+ Unwrap = 'Unwrap',
+ Vote = 'Vote',
+ Wrap = 'Wrap',
+ Zap = 'Zap'
}
export type OTokenActivityWhereInput = {
AND?: InputMaybe>;
OR?: InputMaybe>;
- action_contains?: InputMaybe;
- action_containsInsensitive?: InputMaybe;
- action_endsWith?: InputMaybe;
- action_eq?: InputMaybe;
- action_gt?: InputMaybe;
- action_gte?: InputMaybe;
- action_in?: InputMaybe>;
- action_isNull?: InputMaybe;
- action_lt?: InputMaybe;
- action_lte?: InputMaybe;
- action_not_contains?: InputMaybe;
- action_not_containsInsensitive?: InputMaybe;
- action_not_endsWith?: InputMaybe;
- action_not_eq?: InputMaybe;
- action_not_in?: InputMaybe>;
- action_not_startsWith?: InputMaybe;
- action_startsWith?: InputMaybe;
- address_contains?: InputMaybe;
- address_containsInsensitive?: InputMaybe;
- address_endsWith?: InputMaybe;
- address_eq?: InputMaybe;
- address_gt?: InputMaybe;
- address_gte?: InputMaybe;
- address_in?: InputMaybe>;
- address_isNull?: InputMaybe;
- address_lt?: InputMaybe;
- address_lte?: InputMaybe;
- address_not_contains?: InputMaybe;
- address_not_containsInsensitive?: InputMaybe;
- address_not_endsWith?: InputMaybe;
- address_not_eq?: InputMaybe;
- address_not_in?: InputMaybe>;
- address_not_startsWith?: InputMaybe;
- address_startsWith?: InputMaybe;
- amount_eq?: InputMaybe;
- amount_gt?: InputMaybe;
- amount_gte?: InputMaybe;
- amount_in?: InputMaybe>;
- amount_isNull?: InputMaybe;
- amount_lt?: InputMaybe;
- amount_lte?: InputMaybe;
- amount_not_eq?: InputMaybe;
- amount_not_in?: InputMaybe>;
blockNumber_eq?: InputMaybe;
blockNumber_gt?: InputMaybe;
blockNumber_gte?: InputMaybe;
@@ -11862,23 +11988,6 @@ export type OTokenActivityWhereInput = {
blockNumber_lte?: InputMaybe;
blockNumber_not_eq?: InputMaybe;
blockNumber_not_in?: InputMaybe>;
- callDataLast4Bytes_contains?: InputMaybe;
- callDataLast4Bytes_containsInsensitive?: InputMaybe;
- callDataLast4Bytes_endsWith?: InputMaybe;
- callDataLast4Bytes_eq?: InputMaybe;
- callDataLast4Bytes_gt?: InputMaybe;
- callDataLast4Bytes_gte?: InputMaybe;
- callDataLast4Bytes_in?: InputMaybe>;
- callDataLast4Bytes_isNull?: InputMaybe;
- callDataLast4Bytes_lt?: InputMaybe;
- callDataLast4Bytes_lte?: InputMaybe;
- callDataLast4Bytes_not_contains?: InputMaybe;
- callDataLast4Bytes_not_containsInsensitive?: InputMaybe;
- callDataLast4Bytes_not_endsWith?: InputMaybe;
- callDataLast4Bytes_not_eq?: InputMaybe;
- callDataLast4Bytes_not_in?: InputMaybe>;
- callDataLast4Bytes_not_startsWith?: InputMaybe;
- callDataLast4Bytes_startsWith?: InputMaybe;
chainId_eq?: InputMaybe;
chainId_gt?: InputMaybe;
chainId_gte?: InputMaybe;
@@ -11888,40 +11997,11 @@ export type OTokenActivityWhereInput = {
chainId_lte?: InputMaybe;
chainId_not_eq?: InputMaybe;
chainId_not_in?: InputMaybe>;
- exchange_contains?: InputMaybe;
- exchange_containsInsensitive?: InputMaybe;
- exchange_endsWith?: InputMaybe;
- exchange_eq?: InputMaybe;
- exchange_gt?: InputMaybe;
- exchange_gte?: InputMaybe;
- exchange_in?: InputMaybe>;
- exchange_isNull?: InputMaybe;
- exchange_lt?: InputMaybe;
- exchange_lte?: InputMaybe;
- exchange_not_contains?: InputMaybe;
- exchange_not_containsInsensitive?: InputMaybe;
- exchange_not_endsWith?: InputMaybe;
- exchange_not_eq?: InputMaybe;
- exchange_not_in?: InputMaybe>;
- exchange_not_startsWith?: InputMaybe;
- exchange_startsWith?: InputMaybe;
- fromSymbol_contains?: InputMaybe;
- fromSymbol_containsInsensitive?: InputMaybe;
- fromSymbol_endsWith?: InputMaybe;
- fromSymbol_eq?: InputMaybe;
- fromSymbol_gt?: InputMaybe;
- fromSymbol_gte?: InputMaybe;
- fromSymbol_in?: InputMaybe>;
- fromSymbol_isNull?: InputMaybe;
- fromSymbol_lt?: InputMaybe;
- fromSymbol_lte?: InputMaybe;
- fromSymbol_not_contains?: InputMaybe;
- fromSymbol_not_containsInsensitive?: InputMaybe;
- fromSymbol_not_endsWith?: InputMaybe;
- fromSymbol_not_eq?: InputMaybe;
- fromSymbol_not_in?: InputMaybe>;
- fromSymbol_not_startsWith?: InputMaybe;
- fromSymbol_startsWith?: InputMaybe;
+ data_eq?: InputMaybe;
+ data_isNull?: InputMaybe;
+ data_jsonContains?: InputMaybe;
+ data_jsonHasKey?: InputMaybe;
+ data_not_eq?: InputMaybe;
id_contains?: InputMaybe;
id_containsInsensitive?: InputMaybe;
id_endsWith?: InputMaybe;
@@ -11939,23 +12019,6 @@ export type OTokenActivityWhereInput = {
id_not_in?: InputMaybe>;
id_not_startsWith?: InputMaybe;
id_startsWith?: InputMaybe;
- interface_contains?: InputMaybe;
- interface_containsInsensitive?: InputMaybe;
- interface_endsWith?: InputMaybe;
- interface_eq?: InputMaybe