diff --git a/.env b/.env index 082fa015c..331684bac 100644 --- a/.env +++ b/.env @@ -1,5 +1,4 @@ VITE_SUBSQUID_URL="https://squid.subsquid.io/origin-squid/v/v4/graphql" -# VITE_CUSTOM_RPC="https://rpc.tenderly.co/fork/751e79c6-6420-4ea9-ac13-1f6b20f318bc" -# VITE_CUSTOM_RPC="http://127.0.0.1:8545" +VITE_CUSTOM_RPC= VITE_WALLET_CONNECT_PROJECT_ID= VITE_ALCHEMY_ID= diff --git a/libs/oeth/swap/src/actions/defaultApi.ts b/libs/oeth/swap/src/actions/defaultApi.ts index 8232b1e9a..bf90bab98 100644 --- a/libs/oeth/swap/src/actions/defaultApi.ts +++ b/libs/oeth/swap/src/actions/defaultApi.ts @@ -45,7 +45,13 @@ const estimateRoute: EstimateRoute = async ( return { ...route, estimatedAmount, gas, rate: 0 }; }; -const swap: Swap = async (_tokenIn, _tokenOut, _amountIn, _route) => { +const swap: Swap = async ( + _tokenIn, + _tokenOut, + _amountIn, + _route, + _slippage, +) => { console.log('Route swap operation not implemented'); }; diff --git a/libs/oeth/swap/src/actions/mintVault.ts b/libs/oeth/swap/src/actions/mintVault.ts index d510ad69a..35515b2c3 100644 --- a/libs/oeth/swap/src/actions/mintVault.ts +++ b/libs/oeth/swap/src/actions/mintVault.ts @@ -1,12 +1,22 @@ +import { queryClient } from '@origin/oeth/shared'; import { contracts } from '@origin/shared/contracts'; import { isNilOrEmpty } from '@origin/shared/utils'; -import { getAccount, getPublicClient, readContract } from '@wagmi/core'; -import { formatUnits } from 'viem'; - -import type { EstimateGas, EstimateRoute } from '../types'; +import { + erc20ABI, + getAccount, + getPublicClient, + prepareWriteContract, + readContract, + readContracts, + waitForTransaction, + writeContract, +} from '@wagmi/core'; +import { formatUnits, parseUnits } from 'viem'; + +import type { EstimateGas, EstimateRoute, Swap } from '../types'; import type { EstimateAmount } from '../types'; -const estimateAmount: EstimateAmount = async (tokenIn, _tokenOut, amountIn) => { +const estimateAmount: EstimateAmount = async (tokenIn, tokenOut, amountIn) => { if (amountIn === 0n) { return 0n; } @@ -18,43 +28,85 @@ const estimateAmount: EstimateAmount = async (tokenIn, _tokenOut, amountIn) => { args: [tokenIn.address], }); - return amountIn * data; + return parseUnits( + ( + +formatUnits(amountIn, tokenIn.decimals) * + +formatUnits(data, tokenIn.decimals) + ).toString(), + tokenOut.decimals, + ); }; const estimateGas: EstimateGas = async ( - _tokenIn, - _tokenOut, + tokenIn, + tokenOut, amountIn, slippage, + amountOut, ) => { let gasEstimate = 0n; - const publicClient = getPublicClient(); - if (amountIn === 0n) { return gasEstimate; } + const publicClient = getPublicClient(); const { address } = getAccount(); - if (!isNilOrEmpty(address)) { - try { - gasEstimate = await publicClient.estimateContractGas({ - address: contracts.mainnet.WOETH.address, - abi: contracts.mainnet.WOETH.abi, - functionName: 'deposit', - args: [amountIn, address], - account: address, - }); - - return gasEstimate; - } catch {} - } + const minAmountOut = parseUnits( + ( + +formatUnits(amountOut, tokenOut.decimals) - + +formatUnits(amountOut, tokenOut.decimals) * slippage + ).toString(), + tokenOut.decimals, + ); try { - gasEstimate = 0n; + gasEstimate = await publicClient.estimateContractGas({ + address: contracts.mainnet.OETHVaultCore.address, + abi: contracts.mainnet.OETHVaultCore.abi, + functionName: 'mint', + args: [tokenIn.address, amountIn, minAmountOut], + account: address, + }); + + return gasEstimate; } catch {} + try { + const [rebaseThreshold, autoAllocateThreshold] = + await queryClient.fetchQuery({ + queryKey: ['vault-info', tokenOut.address], + queryFn: () => + readContracts({ + contracts: [ + { + address: contracts.mainnet.OETHVaultCore.address, + abi: contracts.mainnet.OETHVaultCore.abi, + functionName: 'rebaseThreshold', + }, + { + address: contracts.mainnet.OETHVaultCore.address, + abi: contracts.mainnet.OETHVaultCore.abi, + functionName: 'autoAllocateThreshold', + }, + ], + }), + staleTime: Infinity, + }); + + // TODO check validity + gasEstimate = 220000n; + if (amountIn > autoAllocateThreshold?.result) { + gasEstimate = 2900000n; + } else if (amountIn > rebaseThreshold?.result) { + gasEstimate = 510000n; + } + } catch (e) { + // TODO trigger notification + console.error(`mint vault gas estimate error!\n${e.message}`); + } + return gasEstimate; }; @@ -69,10 +121,14 @@ const estimateRoute: EstimateRoute = async ( return { ...route, estimatedAmount: 0n, gas: 0n, rate: 0 }; } - const [estimatedAmount, gas] = await Promise.all([ - estimateAmount(tokenIn, tokenOut, amountIn), - estimateGas(tokenIn, tokenOut, amountIn, slippage), - ]); + const estimatedAmount = await estimateAmount(tokenIn, tokenOut, amountIn); + const gas = await estimateGas( + tokenIn, + tokenOut, + amountIn, + slippage, + estimatedAmount, + ); return { ...route, @@ -84,8 +140,76 @@ const estimateRoute: EstimateRoute = async ( }; }; +const swap: Swap = async ( + tokenIn, + tokenOut, + amountIn, + _route, + slippage, + amountOut, +) => { + const { address } = getAccount(); + + if (amountIn === 0n || isNilOrEmpty(address)) { + return; + } + + const allowance = await readContract({ + address: tokenIn.address, + abi: erc20ABI, + functionName: 'allowance', + args: [address, contracts.mainnet.OETHVaultCore.address], + }); + + if (allowance < amountIn) { + try { + const { request } = await prepareWriteContract({ + address: tokenIn.address, + abi: erc20ABI, + functionName: 'approve', + args: [contracts.mainnet.OETHVaultCore.address, amountIn], + }); + const { hash } = await writeContract(request); + await waitForTransaction({ hash }); + + // TODO trigger notification + console.log(`mint vault approval done!`); + } catch (e) { + // TODO trigger notification + console.error(`mint vault approval error!\n${e.message}`); + return; + } + } + + const minAmountOut = parseUnits( + ( + +formatUnits(amountOut, tokenOut.decimals) - + +formatUnits(amountOut, tokenOut.decimals) * slippage + ).toString(), + tokenOut.decimals, + ); + + try { + const { request } = await prepareWriteContract({ + address: contracts.mainnet.OETHVaultCore.address, + abi: contracts.mainnet.OETHVaultCore.abi, + functionName: 'mint', + args: [tokenIn.address, amountIn, minAmountOut], + }); + const { hash } = await writeContract(request); + await waitForTransaction({ hash }); + + // TODO trigger notification + console.log('mint vault done!'); + } catch (e) { + // TODO trigger notification + console.error(`mint vault error!\n${e.message}`); + } +}; + export default { estimateAmount, estimateGas, estimateRoute, + swap, }; diff --git a/libs/oeth/swap/src/actions/redeemVault.ts b/libs/oeth/swap/src/actions/redeemVault.ts index 323ad32a5..faccafc2e 100644 --- a/libs/oeth/swap/src/actions/redeemVault.ts +++ b/libs/oeth/swap/src/actions/redeemVault.ts @@ -1,13 +1,186 @@ -import type { EstimateAmount } from '../types'; +import { queryClient } from '@origin/oeth/shared'; +import { contracts } from '@origin/shared/contracts'; +import { isNilOrEmpty } from '@origin/shared/utils'; +import { + erc20ABI, + getAccount, + getPublicClient, + prepareWriteContract, + readContract, + readContracts, + waitForTransaction, + writeContract, +} from '@wagmi/core'; +import { formatUnits, parseUnits } from 'viem'; -const estimateAmount: EstimateAmount = async (tokenIn, tokenOut, amountIn) => { +import { MIX_TOKEN } from '../constants'; + +import type { + EstimateAmount, + EstimateGas, + EstimateRoute, + Swap, +} from '../types'; + +const estimateAmount: EstimateAmount = async ( + _tokenIn, + _tokenOut, + amountIn, +) => { if (amountIn === 0n) { return 0n; } - return amountIn * 2n; + const assetsDecimals = await queryClient.fetchQuery({ + queryKey: ['assetsDecimals'], + queryFn: async () => { + const assets = await readContract({ + address: contracts.mainnet.OETHVaultCore.address, + abi: contracts.mainnet.OETHVaultCore.abi, + functionName: 'getAllAssets', + }); + + const decimals = await readContracts({ + contracts: assets.map((address) => ({ + address, + abi: erc20ABI, + functionName: 'decimals', + })), + }); + + return decimals.map((r) => r.result); + }, + staleTime: Infinity, + }); + + const split = await readContract({ + address: contracts.mainnet.OETHVaultCore.address, + abi: contracts.mainnet.OETHVaultCore.abi, + functionName: 'calculateRedeemOutputs', + args: [amountIn], + }); + + return split.reduce((acc, curr, i) => { + if (assetsDecimals[i] !== MIX_TOKEN.decimals) { + const exp = MIX_TOKEN.decimals - assetsDecimals[i]; + + return acc + curr * (10n ^ BigInt(exp)); + } + + return acc + curr; + }, 0n); +}; + +const estimateGas: EstimateGas = async ( + _tokenIn, + tokenOut, + amountIn, + slippage, + amountOut, +) => { + let gasEstimate = 0n; + + if (amountIn === 0n) { + return gasEstimate; + } + + const publicClient = getPublicClient(); + const { address } = getAccount(); + + const minAmountOut = parseUnits( + ( + +formatUnits(amountOut, tokenOut.decimals) - + +formatUnits(amountOut, tokenOut.decimals) * slippage + ).toString(), + tokenOut.decimals, + ); + + try { + gasEstimate = await publicClient.estimateContractGas({ + address: contracts.mainnet.OETHVaultCore.address, + abi: contracts.mainnet.OETHVaultCore.abi, + functionName: 'redeem', + args: [amountIn, minAmountOut], + account: address, + }); + } catch {} + + return gasEstimate; +}; + +const estimateRoute: EstimateRoute = async ( + tokenIn, + tokenOut, + amountIn, + route, + slippage, +) => { + if (amountIn === 0n) { + return { ...route, estimatedAmount: 0n, gas: 0n, rate: 0 }; + } + + const estimatedAmount = await estimateAmount(tokenIn, tokenOut, amountIn); + const gas = await estimateGas( + tokenIn, + tokenOut, + amountIn, + slippage, + estimatedAmount, + ); + + return { + ...route, + estimatedAmount, + gas, + rate: + +formatUnits(amountIn, tokenIn.decimals) / + +formatUnits(estimatedAmount, tokenOut.decimals), + }; +}; + +const swap: Swap = async ( + _tokenIn, + tokenOut, + amountIn, + _route, + slippage, + amountOut, +) => { + const { address } = getAccount(); + + if (amountIn === 0n || isNilOrEmpty(address)) { + return; + } + + const minAmountOut = parseUnits( + ( + +formatUnits(amountOut, tokenOut.decimals) - + +formatUnits(amountOut, tokenOut.decimals) * slippage + ).toString(), + tokenOut.decimals, + ); + + try { + const { request } = await prepareWriteContract({ + address: contracts.mainnet.OETHVaultCore.address, + abi: contracts.mainnet.OETHVaultCore.abi, + functionName: 'redeem', + args: [amountIn, minAmountOut], + }); + const { hash } = await writeContract(request); + await waitForTransaction({ hash }); + + // TODO trigger notification + console.log('redeem vault done!'); + } catch (e) { + // TODO trigger notification + console.error(`redeem vault error!\n${e.message}`); + } }; export default { estimateAmount, + estimateGas, + estimateRoute, + swap, }; diff --git a/libs/oeth/swap/src/actions/swapZapperEth.ts b/libs/oeth/swap/src/actions/swapZapperEth.ts index 129bb7aa0..a3983c1c4 100644 --- a/libs/oeth/swap/src/actions/swapZapperEth.ts +++ b/libs/oeth/swap/src/actions/swapZapperEth.ts @@ -1,13 +1,120 @@ -import type { EstimateAmount } from '../types'; +import { contracts } from '@origin/shared/contracts'; +import { isNilOrEmpty } from '@origin/shared/utils'; +import { + getAccount, + getPublicClient, + prepareWriteContract, + waitForTransaction, + writeContract, +} from '@wagmi/core'; +import { formatUnits } from 'viem'; -const estimateAmount: EstimateAmount = async (tokenIn, tokenOut, amountIn) => { +import type { + EstimateAmount, + EstimateGas, + EstimateRoute, + Swap, +} from '../types'; + +const estimateAmount: EstimateAmount = async ( + _tokenIn, + _tokenOut, + amountIn, +) => { + return amountIn; +}; + +const estimateGas: EstimateGas = async ( + _tokenIn, + _tokenOut, + amountIn, + _slippage, + _amountOut, +) => { + let gasEstimate = 200000n; + + const { address } = getAccount(); + + if (amountIn === 0n || isNilOrEmpty(address)) { + return gasEstimate; + } + + const publicClient = getPublicClient(); + + try { + gasEstimate = await publicClient.estimateContractGas({ + address: contracts.mainnet.OETHZapper.address, + abi: contracts.mainnet.OETHZapper.abi, + functionName: 'deposit', + value: amountIn, + account: address, + }); + } catch {} + + return gasEstimate; +}; + +const estimateRoute: EstimateRoute = async ( + tokenIn, + tokenOut, + amountIn, + route, + slippage, +) => { if (amountIn === 0n) { - return 0n; + return { ...route, estimatedAmount: 0n, gas: 0n, rate: 0 }; } - return amountIn; + const [estimatedAmount, gas] = await Promise.all([ + estimateAmount(tokenIn, tokenOut, amountIn), + estimateGas(tokenIn, tokenOut, amountIn, slippage), + ]); + + return { + ...route, + estimatedAmount, + gas, + rate: + +formatUnits(amountIn, tokenIn.decimals) / + +formatUnits(estimatedAmount, tokenOut.decimals), + }; +}; + +const swap: Swap = async ( + _tokenIn, + _tokenOut, + amountIn, + _route, + _slippage, + _amountOut, +) => { + const { address } = getAccount(); + + if (amountIn === 0n || isNilOrEmpty(address)) { + return; + } + + try { + const { request } = await prepareWriteContract({ + address: contracts.mainnet.OETHZapper.address, + abi: contracts.mainnet.OETHZapper.abi, + functionName: 'deposit', + value: amountIn, + }); + const { hash } = await writeContract(request); + await waitForTransaction({ hash }); + + // TODO trigger notification + console.log('swap zapper eth done!'); + } catch (e) { + // TODO trigger notification + console.error(`swap zapper eth error!\n${e.message}`); + } }; export default { estimateAmount, + estimateGas, + estimateRoute, + swap, }; diff --git a/libs/oeth/swap/src/actions/swapZapperSfrxeth.ts b/libs/oeth/swap/src/actions/swapZapperSfrxeth.ts index 129bb7aa0..4c869bf1d 100644 --- a/libs/oeth/swap/src/actions/swapZapperSfrxeth.ts +++ b/libs/oeth/swap/src/actions/swapZapperSfrxeth.ts @@ -1,13 +1,160 @@ -import type { EstimateAmount } from '../types'; +import { contracts, tokens } from '@origin/shared/contracts'; +import { isNilOrEmpty } from '@origin/shared/utils'; +import { + erc20ABI, + getAccount, + prepareWriteContract, + readContract, + readContracts, + waitForTransaction, + writeContract, +} from '@wagmi/core'; +import { formatUnits, parseUnits } from 'viem'; -const estimateAmount: EstimateAmount = async (tokenIn, tokenOut, amountIn) => { +import type { + EstimateAmount, + EstimateGas, + EstimateRoute, + Swap, +} from '../types'; + +const estimateAmount: EstimateAmount = async (_tokenIn, tokenOut, amountIn) => { if (amountIn === 0n) { return 0n; } - return amountIn; + const [previewRedeem, priceUnitMint] = await readContracts({ + contracts: [ + { + address: tokens.mainnet.sfrxETH.address, + abi: tokens.mainnet.sfrxETH.abi, + functionName: 'previewRedeem', + args: [amountIn], + }, + { + address: contracts.mainnet.OETHVaultCore.address, + abi: contracts.mainnet.OETHVaultCore.abi, + functionName: 'priceUnitMint', + args: [tokens.mainnet.frxETH.address], + }, + ], + }); + + return parseUnits( + ( + +formatUnits(previewRedeem?.result, tokens.mainnet.frxETH.decimals) * + +formatUnits(priceUnitMint?.result, tokenOut.decimals) + ).toString(), + tokenOut.decimals, + ); +}; + +const estimateGas: EstimateGas = async ( + _tokenIn, + _tokenOut, + amountIn, + _slippage, + _amountOut, +) => { + return 90000n; +}; + +const estimateRoute: EstimateRoute = async ( + tokenIn, + tokenOut, + amountIn, + route, + slippage, +) => { + if (amountIn === 0n) { + return { ...route, estimatedAmount: 0n, gas: 0n, rate: 0 }; + } + + const [estimatedAmount, gas] = await Promise.all([ + estimateAmount(tokenIn, tokenOut, amountIn), + estimateGas(tokenIn, tokenOut, amountIn, slippage), + ]); + + return { + ...route, + estimatedAmount, + gas, + rate: + +formatUnits(amountIn, tokenIn.decimals) / + +formatUnits(estimatedAmount, tokenOut.decimals), + }; +}; + +const swap: Swap = async ( + tokenIn, + tokenOut, + amountIn, + _route, + slippage, + amountOut, +) => { + const { address } = getAccount(); + + if (amountIn === 0n || isNilOrEmpty(address)) { + return; + } + + const allowance = await readContract({ + address: tokenIn.address, + abi: erc20ABI, + functionName: 'allowance', + args: [address, contracts.mainnet.OETHZapper.address], + }); + + if (allowance < amountIn) { + try { + const { request } = await prepareWriteContract({ + address: tokenIn.address, + abi: erc20ABI, + functionName: 'approve', + args: [contracts.mainnet.OETHZapper.address, amountIn], + }); + const { hash } = await writeContract(request); + await waitForTransaction({ hash }); + + // TODO trigger notification + console.log(`swap zapper sfrxEth approval done!`); + } catch (e) { + // TODO trigger notification + console.error(`swap zapper sfrxEth error!\n${e.message}`); + return; + } + } + + const minAmountOut = parseUnits( + ( + +formatUnits(amountOut, tokenOut.decimals) - + +formatUnits(amountOut, tokenOut.decimals) * slippage + ).toString(), + tokenOut.decimals, + ); + + try { + const { request } = await prepareWriteContract({ + address: contracts.mainnet.OETHZapper.address, + abi: contracts.mainnet.OETHZapper.abi, + functionName: 'depositSFRXETH', + args: [amountIn, minAmountOut], + }); + const { hash } = await writeContract(request); + await waitForTransaction({ hash }); + + // TODO trigger notification + console.log('swap zapper sfrxEth done!'); + } catch (e) { + // TODO trigger notification + console.error(`swap zapper sfrxEth error!\n${e.message}`); + } }; export default { estimateAmount, + estimateGas, + estimateRoute, + swap, }; diff --git a/libs/oeth/swap/src/hooks.ts b/libs/oeth/swap/src/hooks.ts index 3b19781fb..e5e2dccba 100644 --- a/libs/oeth/swap/src/hooks.ts +++ b/libs/oeth/swap/src/hooks.ts @@ -102,6 +102,7 @@ export const useHandleTokenChange = () => { state.amountIn = 0n; state.amountOut = 0n; state.swapRoutes = []; + state.selectedSwapRoute = null; }), ); }, @@ -114,12 +115,14 @@ export const useHandleTokenFlip = () => { return useCallback(() => { setSwapState( - produce((draft) => { - draft.amountIn = 0n; - draft.amountOut = 0n; - const oldTokenOut = draft.tokenOut; - draft.tokenOut = draft.tokenIn; - draft.tokenIn = oldTokenOut; + produce((state) => { + state.amountIn = 0n; + state.amountOut = 0n; + const oldTokenOut = state.tokenOut; + state.tokenOut = state.tokenIn; + state.tokenIn = oldTokenOut; + state.swapRoutes = []; + state.selectedSwapRoute = null; }), ); }, [setSwapState]); @@ -131,9 +134,9 @@ export const useHandleSelectSwapRoute = () => { return useCallback( (route: EstimatedSwapRoute) => { setSwapState( - produce((draft) => { - draft.selectedSwapRoute = route; - draft.amountOut = route.estimatedAmount; + produce((state) => { + state.selectedSwapRoute = route; + state.amountOut = route.estimatedAmount; }), ); }, @@ -142,7 +145,9 @@ export const useHandleSelectSwapRoute = () => { }; export const useHandleSwap = () => { - const [{ tokenIn, tokenOut, amountIn, selectedSwapRoute }] = useSwapState(); + const [ + { amountIn, amountOut, selectedSwapRoute, slippage, tokenIn, tokenOut }, + ] = useSwapState(); return useCallback(async () => { if (isNilOrEmpty(selectedSwapRoute)) { @@ -154,6 +159,8 @@ export const useHandleSwap = () => { tokenOut, amountIn, selectedSwapRoute, + slippage, + amountOut, ); - }, [amountIn, selectedSwapRoute, tokenIn, tokenOut]); + }, [amountIn, amountOut, selectedSwapRoute, slippage, tokenIn, tokenOut]); }; diff --git a/libs/oeth/swap/src/types.ts b/libs/oeth/swap/src/types.ts index e3ae62878..0a69f7d43 100644 --- a/libs/oeth/swap/src/types.ts +++ b/libs/oeth/swap/src/types.ts @@ -22,6 +22,7 @@ export type EstimateGas = ( tokenOut: Token, amountIn: bigint, slippage: number, + amountOut?: bigint, ) => Promise; export type EstimateRoute = ( @@ -37,6 +38,8 @@ export type Swap = ( tokenOut: Token, amountIn: bigint, route: EstimatedSwapRoute, + slippage: number, + amountOut?: bigint, ) => Promise; export type SwapApi = { diff --git a/libs/shared/contracts/abi-json/sfrxeth.json b/libs/shared/contracts/abi-json/sfrxeth.json new file mode 100644 index 000000000..772ab0bab --- /dev/null +++ b/libs/shared/contracts/abi-json/sfrxeth.json @@ -0,0 +1,472 @@ +[ + { + "inputs": [ + { + "internalType": "contract ERC20", + "name": "_underlying", + "type": "address" + }, + { + "internalType": "uint32", + "name": "_rewardsCycleLength", + "type": "uint32" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { "inputs": [], "name": "SyncError", "type": "error" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "assets", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "shares", + "type": "uint256" + } + ], + "name": "Deposit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint32", + "name": "cycleEnd", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "rewardAmount", + "type": "uint256" + } + ], + "name": "NewRewardsCycle", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "assets", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "shares", + "type": "uint256" + } + ], + "name": "Withdraw", + "type": "event" + }, + { + "inputs": [], + "name": "DOMAIN_SEPARATOR", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "address", "name": "", "type": "address" } + ], + "name": "allowance", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "spender", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "approve", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "asset", + "outputs": [ + { "internalType": "contract ERC20", "name": "", "type": "address" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "balanceOf", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "shares", "type": "uint256" } + ], + "name": "convertToAssets", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "assets", "type": "uint256" } + ], + "name": "convertToShares", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "assets", "type": "uint256" }, + { "internalType": "address", "name": "receiver", "type": "address" } + ], + "name": "deposit", + "outputs": [ + { "internalType": "uint256", "name": "shares", "type": "uint256" } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "assets", "type": "uint256" }, + { "internalType": "address", "name": "receiver", "type": "address" }, + { "internalType": "uint256", "name": "deadline", "type": "uint256" }, + { "internalType": "bool", "name": "approveMax", "type": "bool" }, + { "internalType": "uint8", "name": "v", "type": "uint8" }, + { "internalType": "bytes32", "name": "r", "type": "bytes32" }, + { "internalType": "bytes32", "name": "s", "type": "bytes32" } + ], + "name": "depositWithSignature", + "outputs": [ + { "internalType": "uint256", "name": "shares", "type": "uint256" } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "lastRewardAmount", + "outputs": [{ "internalType": "uint192", "name": "", "type": "uint192" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastSync", + "outputs": [{ "internalType": "uint32", "name": "", "type": "uint32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "maxDeposit", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "maxMint", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "owner", "type": "address" } + ], + "name": "maxRedeem", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "owner", "type": "address" } + ], + "name": "maxWithdraw", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "shares", "type": "uint256" }, + { "internalType": "address", "name": "receiver", "type": "address" } + ], + "name": "mint", + "outputs": [ + { "internalType": "uint256", "name": "assets", "type": "uint256" } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "nonces", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "owner", "type": "address" }, + { "internalType": "address", "name": "spender", "type": "address" }, + { "internalType": "uint256", "name": "value", "type": "uint256" }, + { "internalType": "uint256", "name": "deadline", "type": "uint256" }, + { "internalType": "uint8", "name": "v", "type": "uint8" }, + { "internalType": "bytes32", "name": "r", "type": "bytes32" }, + { "internalType": "bytes32", "name": "s", "type": "bytes32" } + ], + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "assets", "type": "uint256" } + ], + "name": "previewDeposit", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "shares", "type": "uint256" } + ], + "name": "previewMint", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "shares", "type": "uint256" } + ], + "name": "previewRedeem", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "assets", "type": "uint256" } + ], + "name": "previewWithdraw", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pricePerShare", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "shares", "type": "uint256" }, + { "internalType": "address", "name": "receiver", "type": "address" }, + { "internalType": "address", "name": "owner", "type": "address" } + ], + "name": "redeem", + "outputs": [ + { "internalType": "uint256", "name": "assets", "type": "uint256" } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "rewardsCycleEnd", + "outputs": [{ "internalType": "uint32", "name": "", "type": "uint32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rewardsCycleLength", + "outputs": [{ "internalType": "uint32", "name": "", "type": "uint32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "syncRewards", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "totalAssets", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "transfer", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "from", "type": "address" }, + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "transferFrom", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "assets", "type": "uint256" }, + { "internalType": "address", "name": "receiver", "type": "address" }, + { "internalType": "address", "name": "owner", "type": "address" } + ], + "name": "withdraw", + "outputs": [ + { "internalType": "uint256", "name": "shares", "type": "uint256" } + ], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/libs/shared/contracts/src/abis/sfrxeth.ts b/libs/shared/contracts/src/abis/sfrxeth.ts new file mode 100644 index 000000000..df7e433c9 --- /dev/null +++ b/libs/shared/contracts/src/abis/sfrxeth.ts @@ -0,0 +1,427 @@ +// DO NOT EDIT - GENERATED +export const sfrxethABI = [ + { + inputs: [ + { internalType: 'contract ERC20', name: '_underlying', type: 'address' }, + { internalType: 'uint32', name: '_rewardsCycleLength', type: 'uint32' }, + ], + stateMutability: 'nonpayable', + type: 'constructor', + }, + { inputs: [], name: 'SyncError', type: 'error' }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'owner', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'spender', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + ], + name: 'Approval', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'caller', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'owner', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'assets', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint256', + name: 'shares', + type: 'uint256', + }, + ], + name: 'Deposit', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'uint32', + name: 'cycleEnd', + type: 'uint32', + }, + { + indexed: false, + internalType: 'uint256', + name: 'rewardAmount', + type: 'uint256', + }, + ], + name: 'NewRewardsCycle', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: 'address', name: 'from', type: 'address' }, + { indexed: true, internalType: 'address', name: 'to', type: 'address' }, + { + indexed: false, + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + ], + name: 'Transfer', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'caller', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'receiver', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'owner', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'assets', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint256', + name: 'shares', + type: 'uint256', + }, + ], + name: 'Withdraw', + type: 'event', + }, + { + inputs: [], + name: 'DOMAIN_SEPARATOR', + outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: '', type: 'address' }, + { internalType: 'address', name: '', type: 'address' }, + ], + name: 'allowance', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'spender', type: 'address' }, + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + ], + name: 'approve', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'asset', + outputs: [{ internalType: 'contract ERC20', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: '', type: 'address' }], + name: 'balanceOf', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'uint256', name: 'shares', type: 'uint256' }], + name: 'convertToAssets', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'uint256', name: 'assets', type: 'uint256' }], + name: 'convertToShares', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'decimals', + outputs: [{ internalType: 'uint8', name: '', type: 'uint8' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'uint256', name: 'assets', type: 'uint256' }, + { internalType: 'address', name: 'receiver', type: 'address' }, + ], + name: 'deposit', + outputs: [{ internalType: 'uint256', name: 'shares', type: 'uint256' }], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'uint256', name: 'assets', type: 'uint256' }, + { internalType: 'address', name: 'receiver', type: 'address' }, + { internalType: 'uint256', name: 'deadline', type: 'uint256' }, + { internalType: 'bool', name: 'approveMax', type: 'bool' }, + { internalType: 'uint8', name: 'v', type: 'uint8' }, + { internalType: 'bytes32', name: 'r', type: 'bytes32' }, + { internalType: 'bytes32', name: 's', type: 'bytes32' }, + ], + name: 'depositWithSignature', + outputs: [{ internalType: 'uint256', name: 'shares', type: 'uint256' }], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'lastRewardAmount', + outputs: [{ internalType: 'uint192', name: '', type: 'uint192' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'lastSync', + outputs: [{ internalType: 'uint32', name: '', type: 'uint32' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: '', type: 'address' }], + name: 'maxDeposit', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: '', type: 'address' }], + name: 'maxMint', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'owner', type: 'address' }], + name: 'maxRedeem', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'owner', type: 'address' }], + name: 'maxWithdraw', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'uint256', name: 'shares', type: 'uint256' }, + { internalType: 'address', name: 'receiver', type: 'address' }, + ], + name: 'mint', + outputs: [{ internalType: 'uint256', name: 'assets', type: 'uint256' }], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'name', + outputs: [{ internalType: 'string', name: '', type: 'string' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: '', type: 'address' }], + name: 'nonces', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'owner', type: 'address' }, + { internalType: 'address', name: 'spender', type: 'address' }, + { internalType: 'uint256', name: 'value', type: 'uint256' }, + { internalType: 'uint256', name: 'deadline', type: 'uint256' }, + { internalType: 'uint8', name: 'v', type: 'uint8' }, + { internalType: 'bytes32', name: 'r', type: 'bytes32' }, + { internalType: 'bytes32', name: 's', type: 'bytes32' }, + ], + name: 'permit', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'uint256', name: 'assets', type: 'uint256' }], + name: 'previewDeposit', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'uint256', name: 'shares', type: 'uint256' }], + name: 'previewMint', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'uint256', name: 'shares', type: 'uint256' }], + name: 'previewRedeem', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'uint256', name: 'assets', type: 'uint256' }], + name: 'previewWithdraw', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'pricePerShare', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'uint256', name: 'shares', type: 'uint256' }, + { internalType: 'address', name: 'receiver', type: 'address' }, + { internalType: 'address', name: 'owner', type: 'address' }, + ], + name: 'redeem', + outputs: [{ internalType: 'uint256', name: 'assets', type: 'uint256' }], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'rewardsCycleEnd', + outputs: [{ internalType: 'uint32', name: '', type: 'uint32' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'rewardsCycleLength', + outputs: [{ internalType: 'uint32', name: '', type: 'uint32' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'symbol', + outputs: [{ internalType: 'string', name: '', type: 'string' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'syncRewards', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'totalAssets', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'totalSupply', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'to', type: 'address' }, + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + ], + name: 'transfer', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'from', type: 'address' }, + { internalType: 'address', name: 'to', type: 'address' }, + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + ], + name: 'transferFrom', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'uint256', name: 'assets', type: 'uint256' }, + { internalType: 'address', name: 'receiver', type: 'address' }, + { internalType: 'address', name: 'owner', type: 'address' }, + ], + name: 'withdraw', + outputs: [{ internalType: 'uint256', name: 'shares', type: 'uint256' }], + stateMutability: 'nonpayable', + type: 'function', + }, +] as const; diff --git a/libs/shared/contracts/src/tokens.ts b/libs/shared/contracts/src/tokens.ts index 28843bb36..6142129b8 100644 --- a/libs/shared/contracts/src/tokens.ts +++ b/libs/shared/contracts/src/tokens.ts @@ -1,6 +1,8 @@ import { erc20ABI } from 'wagmi'; import { mainnet } from 'wagmi/chains'; +import { sfrxethABI } from './abis/sfrxeth'; + export const tokens = { mainnet: { ETH: { @@ -155,7 +157,7 @@ export const tokens = { sfrxETH: { address: '0xac3E018457B222d93114458476f3E3416Abbe38F', chainId: mainnet.id, - abi: erc20ABI, + abi: sfrxethABI, name: 'Staked Frax Ether', icon: ' /images/tokens/sfrxETH.svg', decimals: 18,