From 8263da33c5ff7f0d85823311580a38c5e02ceb2e Mon Sep 17 00:00:00 2001 From: Phil Date: Thu, 25 Jul 2024 14:07:05 -0700 Subject: [PATCH] Update withdraws to use new safe functions --- package.json | 2 +- .../v1/BoringWithdrawQueueContractABI.tsx | 234 +- src/contexts/v1/BoringVaultContextV1.tsx | 2031 +++++++++-------- src/examples/v1.tsx | 4 +- 4 files changed, 1025 insertions(+), 1246 deletions(-) diff --git a/package.json b/package.json index 13e81d9..50f849a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "boring-vault-ui", - "version": "1.6.0", + "version": "1.6.1", "description": "A reusable package to quickly integrate boring vaults onto a UI.", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/src/abis/v1/BoringWithdrawQueueContractABI.tsx b/src/abis/v1/BoringWithdrawQueueContractABI.tsx index df43e40..8bbe7ad 100644 --- a/src/abis/v1/BoringWithdrawQueueContractABI.tsx +++ b/src/abis/v1/BoringWithdrawQueueContractABI.tsx @@ -1,233 +1 @@ -export default [ - { - inputs: [{ internalType: "address", name: "user", type: "address" }], - name: "AtomicQueue__RequestDeadlineExceeded", - type: "error", - }, - { - inputs: [{ internalType: "address", name: "user", type: "address" }], - name: "AtomicQueue__UserNotInSolve", - type: "error", - }, - { - inputs: [{ internalType: "address", name: "user", type: "address" }], - name: "AtomicQueue__UserRepeated", - type: "error", - }, - { - inputs: [{ internalType: "address", name: "user", type: "address" }], - name: "AtomicQueue__ZeroOfferAmount", - type: "error", - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: "address", - name: "user", - type: "address", - }, - { - indexed: false, - internalType: "address", - name: "offerToken", - type: "address", - }, - { - indexed: false, - internalType: "address", - name: "wantToken", - type: "address", - }, - { - indexed: false, - internalType: "uint256", - name: "offerAmountSpent", - type: "uint256", - }, - { - indexed: false, - internalType: "uint256", - name: "wantAmountReceived", - type: "uint256", - }, - { - indexed: false, - internalType: "uint256", - name: "timestamp", - type: "uint256", - }, - ], - name: "AtomicRequestFulfilled", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: "address", - name: "user", - type: "address", - }, - { - indexed: false, - internalType: "address", - name: "offerToken", - type: "address", - }, - { - indexed: false, - internalType: "address", - name: "wantToken", - type: "address", - }, - { - indexed: false, - internalType: "uint256", - name: "amount", - type: "uint256", - }, - { - indexed: false, - internalType: "uint256", - name: "deadline", - type: "uint256", - }, - { - indexed: false, - internalType: "uint256", - name: "minPrice", - type: "uint256", - }, - { - indexed: false, - internalType: "uint256", - name: "timestamp", - type: "uint256", - }, - ], - name: "AtomicRequestUpdated", - type: "event", - }, - { - inputs: [ - { internalType: "address", name: "user", type: "address" }, - { internalType: "contract ERC20", name: "offer", type: "address" }, - { internalType: "contract ERC20", name: "want", type: "address" }, - ], - name: "getUserAtomicRequest", - outputs: [ - { - components: [ - { internalType: "uint64", name: "deadline", type: "uint64" }, - { internalType: "uint88", name: "atomicPrice", type: "uint88" }, - { internalType: "uint96", name: "offerAmount", type: "uint96" }, - { internalType: "bool", name: "inSolve", type: "bool" }, - ], - internalType: "struct AtomicQueue.AtomicRequest", - name: "", - type: "tuple", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { internalType: "contract ERC20", name: "offer", type: "address" }, - { internalType: "address", name: "user", type: "address" }, - { - components: [ - { internalType: "uint64", name: "deadline", type: "uint64" }, - { internalType: "uint88", name: "atomicPrice", type: "uint88" }, - { internalType: "uint96", name: "offerAmount", type: "uint96" }, - { internalType: "bool", name: "inSolve", type: "bool" }, - ], - internalType: "struct AtomicQueue.AtomicRequest", - name: "userRequest", - type: "tuple", - }, - ], - name: "isAtomicRequestValid", - outputs: [{ internalType: "bool", name: "", type: "bool" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { internalType: "contract ERC20", name: "offer", type: "address" }, - { internalType: "contract ERC20", name: "want", type: "address" }, - { internalType: "address[]", name: "users", type: "address[]" }, - { internalType: "bytes", name: "runData", type: "bytes" }, - { internalType: "address", name: "solver", type: "address" }, - ], - name: "solve", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { internalType: "contract ERC20", name: "offer", type: "address" }, - { internalType: "contract ERC20", name: "want", type: "address" }, - { - components: [ - { internalType: "uint64", name: "deadline", type: "uint64" }, - { internalType: "uint88", name: "atomicPrice", type: "uint88" }, - { internalType: "uint96", name: "offerAmount", type: "uint96" }, - { internalType: "bool", name: "inSolve", type: "bool" }, - ], - internalType: "struct AtomicQueue.AtomicRequest", - name: "userRequest", - type: "tuple", - }, - ], - name: "updateAtomicRequest", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { internalType: "address", name: "", type: "address" }, - { internalType: "contract ERC20", name: "", type: "address" }, - { internalType: "contract ERC20", name: "", type: "address" }, - ], - name: "userAtomicRequest", - outputs: [ - { internalType: "uint64", name: "deadline", type: "uint64" }, - { internalType: "uint88", name: "atomicPrice", type: "uint88" }, - { internalType: "uint96", name: "offerAmount", type: "uint96" }, - { internalType: "bool", name: "inSolve", type: "bool" }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { internalType: "contract ERC20", name: "offer", type: "address" }, - { internalType: "contract ERC20", name: "want", type: "address" }, - { internalType: "address[]", name: "users", type: "address[]" }, - ], - name: "viewSolveMetaData", - outputs: [ - { - components: [ - { internalType: "address", name: "user", type: "address" }, - { internalType: "uint8", name: "flags", type: "uint8" }, - { internalType: "uint256", name: "assetsToOffer", type: "uint256" }, - { internalType: "uint256", name: "assetsForWant", type: "uint256" }, - ], - internalType: "struct AtomicQueue.SolveMetaData[]", - name: "metaData", - type: "tuple[]", - }, - { internalType: "uint256", name: "totalAssetsForWant", type: "uint256" }, - { internalType: "uint256", name: "totalAssetsToOffer", type: "uint256" }, - ], - stateMutability: "view", - type: "function", - }, -]; +export default [{ "inputs": [{ "internalType": "address", "name": "_owner", "type": "address" }, { "internalType": "contract Authority", "name": "_auth", "type": "address" }], "stateMutability": "nonpayable", "type": "constructor" }, { "inputs": [], "name": "AtomicQueue__Paused", "type": "error" }, { "inputs": [{ "internalType": "address", "name": "user", "type": "address" }], "name": "AtomicQueue__RequestDeadlineExceeded", "type": "error" }, { "inputs": [], "name": "AtomicQueue__SafeRequestAccountantOfferMismatch", "type": "error" }, { "inputs": [], "name": "AtomicQueue__SafeRequestCannotCastToUint88", "type": "error" }, { "inputs": [{ "internalType": "uint256", "name": "deadline", "type": "uint256" }], "name": "AtomicQueue__SafeRequestDeadlineExceeded", "type": "error" }, { "inputs": [], "name": "AtomicQueue__SafeRequestDiscountTooLarge", "type": "error" }, { "inputs": [{ "internalType": "uint256", "name": "offerAmount", "type": "uint256" }, { "internalType": "uint256", "name": "offerAllowance", "type": "uint256" }], "name": "AtomicQueue__SafeRequestInsufficientOfferAllowance", "type": "error" }, { "inputs": [{ "internalType": "uint256", "name": "offerAmount", "type": "uint256" }, { "internalType": "uint256", "name": "offerBalance", "type": "uint256" }], "name": "AtomicQueue__SafeRequestOfferAmountGreaterThanOfferBalance", "type": "error" }, { "inputs": [], "name": "AtomicQueue__SafeRequestOfferAmountZero", "type": "error" }, { "inputs": [{ "internalType": "address", "name": "user", "type": "address" }], "name": "AtomicQueue__UserNotInSolve", "type": "error" }, { "inputs": [{ "internalType": "address", "name": "user", "type": "address" }], "name": "AtomicQueue__UserRepeated", "type": "error" }, { "inputs": [{ "internalType": "address", "name": "user", "type": "address" }], "name": "AtomicQueue__ZeroOfferAmount", "type": "error" }, { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "address", "name": "user", "type": "address" }, { "indexed": true, "internalType": "address", "name": "offerToken", "type": "address" }, { "indexed": true, "internalType": "address", "name": "wantToken", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "offerAmountSpent", "type": "uint256" }, { "indexed": false, "internalType": "uint256", "name": "wantAmountReceived", "type": "uint256" }, { "indexed": false, "internalType": "uint256", "name": "timestamp", "type": "uint256" }], "name": "AtomicRequestFulfilled", "type": "event" }, { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "address", "name": "user", "type": "address" }, { "indexed": true, "internalType": "address", "name": "offerToken", "type": "address" }, { "indexed": true, "internalType": "address", "name": "wantToken", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" }, { "indexed": false, "internalType": "uint256", "name": "deadline", "type": "uint256" }, { "indexed": false, "internalType": "uint256", "name": "minPrice", "type": "uint256" }, { "indexed": false, "internalType": "uint256", "name": "timestamp", "type": "uint256" }], "name": "AtomicRequestUpdated", "type": "event" }, { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "address", "name": "user", "type": "address" }, { "indexed": true, "internalType": "contract Authority", "name": "newAuthority", "type": "address" }], "name": "AuthorityUpdated", "type": "event" }, { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "address", "name": "user", "type": "address" }, { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" }], "name": "OwnershipTransferred", "type": "event" }, { "anonymous": false, "inputs": [], "name": "Paused", "type": "event" }, { "anonymous": false, "inputs": [], "name": "Unpaused", "type": "event" }, { "inputs": [], "name": "MAX_DISCOUNT", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "authority", "outputs": [{ "internalType": "contract Authority", "name": "", "type": "address" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "user", "type": "address" }, { "internalType": "contract ERC20", "name": "offer", "type": "address" }, { "internalType": "contract ERC20", "name": "want", "type": "address" }], "name": "getUserAtomicRequest", "outputs": [{ "components": [{ "internalType": "uint64", "name": "deadline", "type": "uint64" }, { "internalType": "uint88", "name": "atomicPrice", "type": "uint88" }, { "internalType": "uint96", "name": "offerAmount", "type": "uint96" }, { "internalType": "bool", "name": "inSolve", "type": "bool" }], "internalType": "struct AtomicQueue.AtomicRequest", "name": "", "type": "tuple" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "contract ERC20", "name": "offer", "type": "address" }, { "internalType": "address", "name": "user", "type": "address" }, { "components": [{ "internalType": "uint64", "name": "deadline", "type": "uint64" }, { "internalType": "uint88", "name": "atomicPrice", "type": "uint88" }, { "internalType": "uint96", "name": "offerAmount", "type": "uint96" }, { "internalType": "bool", "name": "inSolve", "type": "bool" }], "internalType": "struct AtomicQueue.AtomicRequest", "name": "userRequest", "type": "tuple" }], "name": "isAtomicRequestValid", "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "isPaused", "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "owner", "outputs": [{ "internalType": "address", "name": "", "type": "address" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "pause", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "contract ERC20", "name": "offer", "type": "address" }, { "internalType": "contract ERC20", "name": "want", "type": "address" }, { "components": [{ "internalType": "uint64", "name": "deadline", "type": "uint64" }, { "internalType": "uint88", "name": "atomicPrice", "type": "uint88" }, { "internalType": "uint96", "name": "offerAmount", "type": "uint96" }, { "internalType": "bool", "name": "inSolve", "type": "bool" }], "internalType": "struct AtomicQueue.AtomicRequest", "name": "userRequest", "type": "tuple" }, { "internalType": "contract AccountantWithRateProviders", "name": "accountant", "type": "address" }, { "internalType": "uint256", "name": "discount", "type": "uint256" }], "name": "safeUpdateAtomicRequest", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "contract Authority", "name": "newAuthority", "type": "address" }], "name": "setAuthority", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "contract ERC20", "name": "offer", "type": "address" }, { "internalType": "contract ERC20", "name": "want", "type": "address" }, { "internalType": "address[]", "name": "users", "type": "address[]" }, { "internalType": "bytes", "name": "runData", "type": "bytes" }, { "internalType": "address", "name": "solver", "type": "address" }], "name": "solve", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }], "name": "transferOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "unpause", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "contract ERC20", "name": "offer", "type": "address" }, { "internalType": "contract ERC20", "name": "want", "type": "address" }, { "components": [{ "internalType": "uint64", "name": "deadline", "type": "uint64" }, { "internalType": "uint88", "name": "atomicPrice", "type": "uint88" }, { "internalType": "uint96", "name": "offerAmount", "type": "uint96" }, { "internalType": "bool", "name": "inSolve", "type": "bool" }], "internalType": "struct AtomicQueue.AtomicRequest", "name": "userRequest", "type": "tuple" }], "name": "updateAtomicRequest", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "", "type": "address" }, { "internalType": "contract ERC20", "name": "", "type": "address" }, { "internalType": "contract ERC20", "name": "", "type": "address" }], "name": "userAtomicRequest", "outputs": [{ "internalType": "uint64", "name": "deadline", "type": "uint64" }, { "internalType": "uint88", "name": "atomicPrice", "type": "uint88" }, { "internalType": "uint96", "name": "offerAmount", "type": "uint96" }, { "internalType": "bool", "name": "inSolve", "type": "bool" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "contract ERC20", "name": "offer", "type": "address" }, { "internalType": "contract ERC20", "name": "want", "type": "address" }, { "internalType": "address[]", "name": "users", "type": "address[]" }], "name": "viewSolveMetaData", "outputs": [{ "components": [{ "internalType": "address", "name": "user", "type": "address" }, { "internalType": "uint8", "name": "flags", "type": "uint8" }, { "internalType": "uint256", "name": "assetsToOffer", "type": "uint256" }, { "internalType": "uint256", "name": "assetsForWant", "type": "uint256" }], "internalType": "struct AtomicQueue.SolveMetaData[]", "name": "metaData", "type": "tuple[]" }, { "internalType": "uint256", "name": "totalAssetsForWant", "type": "uint256" }, { "internalType": "uint256", "name": "totalAssetsToOffer", "type": "uint256" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "contract ERC20", "name": "offer", "type": "address" }, { "internalType": "contract ERC20", "name": "want", "type": "address" }, { "internalType": "address[]", "name": "users", "type": "address[]" }], "name": "viewVerboseSolveMetaData", "outputs": [{ "components": [{ "internalType": "address", "name": "user", "type": "address" }, { "internalType": "bool", "name": "deadlineExceeded", "type": "bool" }, { "internalType": "bool", "name": "zeroOfferAmount", "type": "bool" }, { "internalType": "bool", "name": "insufficientOfferBalance", "type": "bool" }, { "internalType": "bool", "name": "insufficientOfferAllowance", "type": "bool" }, { "internalType": "uint256", "name": "assetsToOffer", "type": "uint256" }, { "internalType": "uint256", "name": "assetsForWant", "type": "uint256" }], "internalType": "struct AtomicQueue.VerboseSolveMetaData[]", "name": "metaData", "type": "tuple[]" }, { "internalType": "uint256", "name": "totalAssetsForWant", "type": "uint256" }, { "internalType": "uint256", "name": "totalAssetsToOffer", "type": "uint256" }], "stateMutability": "view", "type": "function" }]; \ No newline at end of file diff --git a/src/contexts/v1/BoringVaultContextV1.tsx b/src/contexts/v1/BoringVaultContextV1.tsx index 1c815aa..6f92cfc 100644 --- a/src/contexts/v1/BoringVaultContextV1.tsx +++ b/src/contexts/v1/BoringVaultContextV1.tsx @@ -130,1197 +130,1208 @@ export const BoringVaultV1Provider: React.FC<{ vaultDecimals, baseAsset, }) => { - const [vaultEthersContract, setVaultEthersContract] = - useState(null); - const [tellerEthersContract, setTellerContract] = useState( - null - ); - const [accountantEthersContract, setAccountantEthersContract] = - useState(null); - const [lensEthersContract, setLensEthersContract] = useState( - null - ); - const [delayWithdrawEthersContract, setDelayWithdrawEthersContract] = - useState(null); - const [withdrawQueueEthersContract, setWithdrawQueueEthersContract] = - useState(null); - - const [baseToken, setBaseToken] = useState(null); - - const [vaultDepositTokens, setVaultDepositTokens] = - useState(depositTokens); - const [vaultWithdrawTokens, setVaultWithdrawTokens] = - useState(withdrawTokens); - - const [decimals, setDecimals] = useState(null); - const [isBoringV1ContextReady, setIsBoringV1ContextReady] = - useState(false); - const [depositStatus, setDepositStatus] = useState({ - initiated: false, - loading: false, - }); - const [withdrawStatus, setWithdrawStatus] = useState({ - initiated: false, - loading: false, - }); - - useEffect(() => { - if ( - chain && - vaultContract && - tellerContract && - accountantContract && - lensContract && - ethersProvider && - baseAsset && - vaultDecimals && - depositTokens.length > 0 && - withdrawTokens.length > 0 - ) { - const vaultEthersContract = new Contract( - vaultContract, - BoringVaultABI, - ethersProvider - ); - const tellerEthersContract = new Contract( - tellerContract, - BoringTellerABI, - ethersProvider - ); - const accountantEthersContract = new Contract( - accountantContract, - BoringAccountantABI, - ethersProvider - ); - const lensEthersContract = new Contract( - lensContract, - BoringLensABI, - ethersProvider - ); - - if (delayWithdrawContract) { - const delayWithdrawEthersContract = new Contract( - delayWithdrawContract, - BoringDelayWithdrawContractABI, + const [vaultEthersContract, setVaultEthersContract] = + useState(null); + const [tellerEthersContract, setTellerContract] = useState( + null + ); + const [accountantEthersContract, setAccountantEthersContract] = + useState(null); + const [lensEthersContract, setLensEthersContract] = useState( + null + ); + const [delayWithdrawEthersContract, setDelayWithdrawEthersContract] = + useState(null); + const [withdrawQueueEthersContract, setWithdrawQueueEthersContract] = + useState(null); + + const [baseToken, setBaseToken] = useState(null); + + const [vaultDepositTokens, setVaultDepositTokens] = + useState(depositTokens); + const [vaultWithdrawTokens, setVaultWithdrawTokens] = + useState(withdrawTokens); + + const [decimals, setDecimals] = useState(null); + const [isBoringV1ContextReady, setIsBoringV1ContextReady] = + useState(false); + const [depositStatus, setDepositStatus] = useState({ + initiated: false, + loading: false, + }); + const [withdrawStatus, setWithdrawStatus] = useState({ + initiated: false, + loading: false, + }); + + useEffect(() => { + if ( + chain && + vaultContract && + tellerContract && + accountantContract && + lensContract && + ethersProvider && + baseAsset && + vaultDecimals && + depositTokens.length > 0 && + withdrawTokens.length > 0 + ) { + const vaultEthersContract = new Contract( + vaultContract, + BoringVaultABI, ethersProvider ); - setDelayWithdrawEthersContract(delayWithdrawEthersContract); - } - - if (withdrawQueueContract) { - const withdrawQueueEthersContract = new Contract( - withdrawQueueContract, - BoringWithdrawQueueContractABI, + const tellerEthersContract = new Contract( + tellerContract, + BoringTellerABI, + ethersProvider + ); + const accountantEthersContract = new Contract( + accountantContract, + BoringAccountantABI, + ethersProvider + ); + const lensEthersContract = new Contract( + lensContract, + BoringLensABI, ethersProvider ); - setWithdrawQueueEthersContract(withdrawQueueEthersContract); + + if (delayWithdrawContract) { + const delayWithdrawEthersContract = new Contract( + delayWithdrawContract, + BoringDelayWithdrawContractABI, + ethersProvider + ); + setDelayWithdrawEthersContract(delayWithdrawEthersContract); + } + + if (withdrawQueueContract) { + const withdrawQueueEthersContract = new Contract( + withdrawQueueContract, + BoringWithdrawQueueContractABI, + ethersProvider + ); + setWithdrawQueueEthersContract(withdrawQueueEthersContract); + } + + setVaultEthersContract(vaultEthersContract); + setTellerContract(tellerEthersContract); + setAccountantEthersContract(accountantEthersContract); + setLensEthersContract(lensEthersContract); + setBaseToken(baseAsset); + setDecimals(vaultDecimals); + setIsBoringV1ContextReady(true); + console.warn("Boring vault contracts initialized"); + } else { + console.warn("Boring vault contracts not initialized"); + console.warn("Missing: ", { + chain, + vaultContract, + tellerContract, + accountantContract, + lensContract, + ethersProvider, + baseAsset, + decimals, + depositTokens, + withdrawTokens, + }); } + }, [ + chain, + vaultContract, + tellerContract, + accountantContract, + lensContract, + baseAsset, + vaultDecimals, + ethersProvider, + depositTokens, + withdrawTokens, + delayWithdrawContract, + ]); - setVaultEthersContract(vaultEthersContract); - setTellerContract(tellerEthersContract); - setAccountantEthersContract(accountantEthersContract); - setLensEthersContract(lensEthersContract); - setBaseToken(baseAsset); - setDecimals(vaultDecimals); - setIsBoringV1ContextReady(true); - console.warn("Boring vault contracts initialized"); - } else { - console.warn("Boring vault contracts not initialized"); - console.warn("Missing: ", { - chain, - vaultContract, - tellerContract, - accountantContract, - lensContract, - ethersProvider, - baseAsset, - decimals, - depositTokens, - withdrawTokens, - }); - } - }, [ - chain, - vaultContract, - tellerContract, - accountantContract, - lensContract, - baseAsset, - vaultDecimals, - ethersProvider, - depositTokens, - withdrawTokens, - delayWithdrawContract, - ]); - - // Effect to handle updates on acceptedTokens if needed - useEffect(() => { - setVaultDepositTokens(depositTokens); - }, [depositTokens]); - - // Effect to handle updates on withdrawTokens if needed - useEffect(() => { - setVaultWithdrawTokens(withdrawTokens); - }, [withdrawTokens]); - - const fetchTotalAssets = useCallback(async () => { - if ( - !vaultEthersContract || - !lensEthersContract || - !accountantEthersContract || - !baseToken || - !isBoringV1ContextReady - ) { - console.error("Contracts not ready", { - /* Dependencies here */ - }); - return Promise.reject("Contracts not ready"); - } - console.log("Fetching total assets..."); - - try { - const assets = await lensEthersContract.totalAssets( - vaultContract, - accountantContract - ); - console.log("Total assets from contract: ", assets); - return Number(assets[1]) / Math.pow(10, baseToken.decimals); - } catch (error) { - console.error("Error fetching total assets", error); - throw error; - } - }, [ - vaultEthersContract, - lensEthersContract, - accountantEthersContract, - baseToken, - isBoringV1ContextReady, - ]); - - const fetchUserShares = useCallback( - async (userAddress: string) => { + // Effect to handle updates on acceptedTokens if needed + useEffect(() => { + setVaultDepositTokens(depositTokens); + }, [depositTokens]); + + // Effect to handle updates on withdrawTokens if needed + useEffect(() => { + setVaultWithdrawTokens(withdrawTokens); + }, [withdrawTokens]); + + const fetchTotalAssets = useCallback(async () => { if ( !vaultEthersContract || !lensEthersContract || + !accountantEthersContract || !baseToken || - !isBoringV1ContextReady || - !userAddress + !isBoringV1ContextReady ) { - console.error("Contracts or user not ready", { - vaultEthersContract, - lensEthersContract, - baseToken, - isBoringV1ContextReady, - userAddress, + console.error("Contracts not ready", { + /* Dependencies here */ }); - return Promise.reject("Contracts or user not ready"); + return Promise.reject("Contracts not ready"); } - console.log("Fetching user balance ..."); + console.log("Fetching total assets..."); try { - const balance = await lensEthersContract.balanceOf( - userAddress, - vaultContract + const assets = await lensEthersContract.totalAssets( + vaultContract, + accountantContract ); - console.log("User balance from contract: ", balance); - return Number(balance) / Math.pow(10, decimals!); + console.log("Total assets from contract: ", assets); + return Number(assets[1]) / Math.pow(10, baseToken.decimals); } catch (error) { - console.error("Error fetching user balance", error); + console.error("Error fetching total assets", error); throw error; } - }, - [vaultEthersContract, lensEthersContract, baseToken, isBoringV1ContextReady] - ); - - const fetchShareValue = useCallback(async () => { - if ( - !lensEthersContract || - !accountantEthersContract || - !baseToken || - !isBoringV1ContextReady - ) { - console.error("Contracts not ready", { - /* Dependencies here */ - }); - return Promise.reject("Contracts not ready"); - } - console.log("Fetching share value ..."); - - try { - const shareValue = await lensEthersContract.exchangeRate( - accountantContract - ); - console.log("Share value from contract: ", shareValue); - return Number(shareValue) / Math.pow(10, baseToken.decimals); - } catch (error) { - console.error("Error fetching share value from contract", error); - throw error; - } - }, [ - lensEthersContract, - accountantEthersContract, - baseToken, - isBoringV1ContextReady, - ]); - - const fetchUserUnlockTime = useCallback( - async (userAddress: string) => { + }, [ + vaultEthersContract, + lensEthersContract, + accountantEthersContract, + baseToken, + isBoringV1ContextReady, + ]); + + const fetchUserShares = useCallback( + async (userAddress: string) => { + if ( + !vaultEthersContract || + !lensEthersContract || + !baseToken || + !isBoringV1ContextReady || + !userAddress + ) { + console.error("Contracts or user not ready", { + vaultEthersContract, + lensEthersContract, + baseToken, + isBoringV1ContextReady, + userAddress, + }); + return Promise.reject("Contracts or user not ready"); + } + console.log("Fetching user balance ..."); + + try { + const balance = await lensEthersContract.balanceOf( + userAddress, + vaultContract + ); + console.log("User balance from contract: ", balance); + return Number(balance) / Math.pow(10, decimals!); + } catch (error) { + console.error("Error fetching user balance", error); + throw error; + } + }, + [vaultEthersContract, lensEthersContract, baseToken, isBoringV1ContextReady] + ); + + const fetchShareValue = useCallback(async () => { if ( !lensEthersContract || - !tellerEthersContract || - !isBoringV1ContextReady || - !userAddress + !accountantEthersContract || + !baseToken || + !isBoringV1ContextReady ) { - console.error("Contracts or user not ready", { - lensEthersContract, - tellerEthersContract, - isBoringV1ContextReady, - userAddress, + console.error("Contracts not ready", { + /* Dependencies here */ }); - return Promise.reject("Contracts or user not ready"); + return Promise.reject("Contracts not ready"); } - console.log("Fetching user unlock time..."); + console.log("Fetching share value ..."); try { - const userUnlockTime = await lensEthersContract.userUnlockTime( - userAddress, - tellerContract + const shareValue = await lensEthersContract.exchangeRate( + accountantContract ); - console.log("User unlock time from contract: ", userUnlockTime); - return Number(userUnlockTime); + console.log("Share value from contract: ", shareValue); + return Number(shareValue) / Math.pow(10, baseToken.decimals); } catch (error) { - console.error("Error fetching user unlock time from contract", error); + console.error("Error fetching share value from contract", error); throw error; } - }, - [lensEthersContract, accountantEthersContract, isBoringV1ContextReady] - ); - - const deposit = useCallback( - async ( - signer: JsonRpcSigner, - amountHumanReadable: string, - token: Token - ) => { - if ( - !vaultEthersContract || - !isBoringV1ContextReady || - !decimals || - !signer - ) { - console.error("Contracts or user not ready", { - /* Dependencies here */ - }); + }, [ + lensEthersContract, + accountantEthersContract, + baseToken, + isBoringV1ContextReady, + ]); + + const fetchUserUnlockTime = useCallback( + async (userAddress: string) => { + if ( + !lensEthersContract || + !tellerEthersContract || + !isBoringV1ContextReady || + !userAddress + ) { + console.error("Contracts or user not ready", { + lensEthersContract, + tellerEthersContract, + isBoringV1ContextReady, + userAddress, + }); + return Promise.reject("Contracts or user not ready"); + } + console.log("Fetching user unlock time..."); + + try { + const userUnlockTime = await lensEthersContract.userUnlockTime( + userAddress, + tellerContract + ); + console.log("User unlock time from contract: ", userUnlockTime); + return Number(userUnlockTime); + } catch (error) { + console.error("Error fetching user unlock time from contract", error); + throw error; + } + }, + [lensEthersContract, accountantEthersContract, isBoringV1ContextReady] + ); + + const deposit = useCallback( + async ( + signer: JsonRpcSigner, + amountHumanReadable: string, + token: Token + ) => { + if ( + !vaultEthersContract || + !isBoringV1ContextReady || + !decimals || + !signer + ) { + console.error("Contracts or user not ready", { + /* Dependencies here */ + }); + + setDepositStatus({ + initiated: false, + loading: false, + success: false, + error: "Contracts or user not ready", + }); + + return depositStatus; + } + console.log("Depositing ..."); setDepositStatus({ - initiated: false, - loading: false, - success: false, - error: "Contracts or user not ready", + initiated: true, + loading: true, }); - return depositStatus; - } - console.log("Depositing ..."); + try { + // First check if the token is approved for at least the amount + const erc20Contract = new Contract(token.address, erc20Abi, signer); + const allowance = Number( + await erc20Contract.allowance( + await signer.getAddress(), + vaultContract + ) + ); + const bigNumAmt = new BigNumber(amountHumanReadable); + console.warn(amountHumanReadable); + console.warn("Amount to deposit: ", bigNumAmt.toNumber()); + const amountDepositBaseDenom = bigNumAmt.multipliedBy( + new BigNumber(10).pow(token.decimals) + ); + console.warn("Amount to deposit: ", amountDepositBaseDenom.toNumber()); - setDepositStatus({ - initiated: true, - loading: true, - }); + if (allowance < amountDepositBaseDenom.toNumber()) { + setDepositStatus({ + initiated: true, + loading: true, + }); + console.log("Approving token ..."); + const approveTx = await erc20Contract.approve( + vaultContract, + amountDepositBaseDenom.toNumber() + ); - try { - // First check if the token is approved for at least the amount - const erc20Contract = new Contract(token.address, erc20Abi, signer); - const allowance = Number( - await erc20Contract.allowance( - await signer.getAddress(), - vaultContract - ) - ); - const bigNumAmt = new BigNumber(amountHumanReadable); - console.warn(amountHumanReadable); - console.warn("Amount to deposit: ", bigNumAmt.toNumber()); - const amountDepositBaseDenom = bigNumAmt.multipliedBy( - new BigNumber(10).pow(token.decimals) - ); - console.warn("Amount to deposit: ", amountDepositBaseDenom.toNumber()); + // Wait for confirmation + const approvedReceipt: ContractTransactionReceipt = + await approveTx.wait(); + console.log("Token approved in tx: ", approvedReceipt); + + if (!approvedReceipt.hash) { + console.error("Token approval failed"); + setDepositStatus({ + initiated: false, + loading: false, + success: false, + error: "Token approval reverted", + }); + return depositStatus; + } + console.log("Approved hash: ", approvedReceipt.hash); + } - if (allowance < amountDepositBaseDenom.toNumber()) { - setDepositStatus({ - initiated: true, - loading: true, - }); - console.log("Approving token ..."); - const approveTx = await erc20Contract.approve( - vaultContract, - amountDepositBaseDenom.toNumber() + console.log("Depositing token ..."); + // Get teller contract ready + const tellerContractWithSigner = new Contract( + tellerContract, + BoringTellerABI, + signer + ); + + // Deposit, but specifically only set the fields depositAsset and depositAmount + // TODO: Set the other fields as well (payableAmount -- relevant for vanilla ETH deposits, and minimumMint) + // TODO: Allow for custom gas limits + const depositTx = await tellerContractWithSigner.deposit( + token.address, + amountDepositBaseDenom.toNumber(), + 0 ); // Wait for confirmation - const approvedReceipt: ContractTransactionReceipt = - await approveTx.wait(); - console.log("Token approved in tx: ", approvedReceipt); + const depositReceipt: ContractTransactionReceipt = + await depositTx.wait(); - if (!approvedReceipt.hash) { - console.error("Token approval failed"); + console.log("Token deposited in tx: ", depositReceipt); + if (!depositReceipt.hash) { + console.error("Deposit failed"); setDepositStatus({ initiated: false, loading: false, success: false, - error: "Token approval reverted", + error: "Deposit reverted", }); return depositStatus; } - console.log("Approved hash: ", approvedReceipt.hash); - } - - console.log("Depositing token ..."); - // Get teller contract ready - const tellerContractWithSigner = new Contract( - tellerContract, - BoringTellerABI, - signer - ); + console.log("Deposit hash: ", depositReceipt.hash); - // Deposit, but specifically only set the fields depositAsset and depositAmount - // TODO: Set the other fields as well (payableAmount -- relevant for vanilla ETH deposits, and minimumMint) - // TODO: Allow for custom gas limits - const depositTx = await tellerContractWithSigner.deposit( - token.address, - amountDepositBaseDenom.toNumber(), - 0 - ); - - // Wait for confirmation - const depositReceipt: ContractTransactionReceipt = - await depositTx.wait(); - - console.log("Token deposited in tx: ", depositReceipt); - if (!depositReceipt.hash) { - console.error("Deposit failed"); + // Set status + setDepositStatus({ + initiated: false, + loading: false, + success: true, + tx_hash: depositReceipt.hash, + }); + } catch (error: any) { + console.error("Error depositing", error); setDepositStatus({ initiated: false, loading: false, success: false, - error: "Deposit reverted", + error: (error as Error).message, }); return depositStatus; } - console.log("Deposit hash: ", depositReceipt.hash); - // Set status - setDepositStatus({ - initiated: false, - loading: false, - success: true, - tx_hash: depositReceipt.hash, - }); - } catch (error: any) { - console.error("Error depositing", error); - setDepositStatus({ - initiated: false, - loading: false, - success: false, - error: (error as Error).message, - }); return depositStatus; - } - - return depositStatus; - }, - [ - vaultEthersContract, - tellerEthersContract, - decimals, - ethersProvider, - isBoringV1ContextReady, - ] - ); + }, + [ + vaultEthersContract, + tellerEthersContract, + decimals, + ethersProvider, + isBoringV1ContextReady, + ] + ); + + /* Delay Withdraws */ + + const delayWithdraw = useCallback( + async ( + signer: JsonRpcSigner, + shareAmountHumanReadable: string, + tokenOut: Token, + maxLossHumanReadable: string, + thirdPartyClaimer: boolean + ) => { + if ( + !delayWithdrawEthersContract || + !vaultEthersContract || + !isBoringV1ContextReady || + !decimals || + !signer + ) { + console.error("Contracts or user not ready", { + delayWithdrawEthersContract, + isBoringV1ContextReady, + decimals, + signer, + }); - /* Delay Withdraws */ + setWithdrawStatus({ + initiated: false, + loading: false, + success: false, + error: "Contracts or user not ready", + }); - const delayWithdraw = useCallback( - async ( - signer: JsonRpcSigner, - shareAmountHumanReadable: string, - tokenOut: Token, - maxLossHumanReadable: string, - thirdPartyClaimer: boolean - ) => { - if ( - !delayWithdrawEthersContract || - !vaultEthersContract || - !isBoringV1ContextReady || - !decimals || - !signer - ) { - console.error("Contracts or user not ready", { - delayWithdrawEthersContract, - isBoringV1ContextReady, - decimals, - signer, - }); + return withdrawStatus; + } + console.log("Beginning delay withdraw ..."); setWithdrawStatus({ - initiated: false, - loading: false, - success: false, - error: "Contracts or user not ready", + initiated: true, + loading: true, }); - return withdrawStatus; - } - console.log("Beginning delay withdraw ..."); + try { + // First check if the delay withdraw is approved for at least the amount + const vaultContractWithSigner = new Contract( + vaultContract, + BoringVaultABI, + signer + ); - setWithdrawStatus({ - initiated: true, - loading: true, - }); + const allowance = Number( + await vaultContractWithSigner.allowance( + await signer.getAddress(), + delayWithdrawContract + ) + ); + const bigNumAmt = new BigNumber(shareAmountHumanReadable); + console.warn(shareAmountHumanReadable); + console.warn("Amount to withdraw: ", bigNumAmt.toNumber()); + const amountWithdrawBaseDenom = bigNumAmt.multipliedBy( + new BigNumber(10).pow(vaultDecimals) + ); + console.warn( + "Amount to withdraw: ", + amountWithdrawBaseDenom.toNumber() + ); - try { - // First check if the delay withdraw is approved for at least the amount - const vaultContractWithSigner = new Contract( - vaultContract, - BoringVaultABI, - signer - ); + if (allowance < amountWithdrawBaseDenom.toNumber()) { + setWithdrawStatus({ + initiated: true, + loading: true, + }); + console.log("Approving token ..."); + const approveTx = await vaultContractWithSigner.approve( + delayWithdrawContract, + amountWithdrawBaseDenom.toNumber() + ); - const allowance = Number( - await vaultContractWithSigner.allowance( - await signer.getAddress(), - delayWithdrawContract - ) - ); - const bigNumAmt = new BigNumber(shareAmountHumanReadable); - console.warn(shareAmountHumanReadable); - console.warn("Amount to withdraw: ", bigNumAmt.toNumber()); - const amountWithdrawBaseDenom = bigNumAmt.multipliedBy( - new BigNumber(10).pow(vaultDecimals) - ); - console.warn( - "Amount to withdraw: ", - amountWithdrawBaseDenom.toNumber() - ); + // Wait for confirmation + const approvedReceipt: ContractTransactionReceipt = + await approveTx.wait(); + console.log("Token approved in tx: ", approvedReceipt); + + if (!approvedReceipt.hash) { + console.error("Token approval failed"); + setWithdrawStatus({ + initiated: false, + loading: false, + success: false, + error: "Token approval reverted", + }); + return withdrawStatus; + } + console.log("Approved hash: ", approvedReceipt.hash); + } - if (allowance < amountWithdrawBaseDenom.toNumber()) { - setWithdrawStatus({ - initiated: true, - loading: true, - }); - console.log("Approving token ..."); - const approveTx = await vaultContractWithSigner.approve( - delayWithdrawContract, - amountWithdrawBaseDenom.toNumber() + console.log("Withdrawing token ..."); + // Get withdraw contract ready + const delayWithdrawContractWithSigner = new Contract( + delayWithdrawContract!, + BoringDelayWithdrawContractABI, + signer ); + // Max loss is truncated(human readable * 100) + const maxLossBaseDenom = new BigNumber(maxLossHumanReadable) + .multipliedBy(100) + .decimalPlaces(0, BigNumber.ROUND_DOWN); + + const withdrawTx = + await delayWithdrawContractWithSigner.requestWithdraw( + tokenOut.address, + amountWithdrawBaseDenom.toNumber(), + maxLossBaseDenom.toNumber(), + thirdPartyClaimer + ); + // Wait for confirmation - const approvedReceipt: ContractTransactionReceipt = - await approveTx.wait(); - console.log("Token approved in tx: ", approvedReceipt); + const withdrawReceipt: ContractTransactionReceipt = + await withdrawTx.wait(); - if (!approvedReceipt.hash) { - console.error("Token approval failed"); + console.log("Withdraw Requested in tx: ", withdrawReceipt); + if (!withdrawReceipt.hash) { + console.error("Withdraw Request failed"); setWithdrawStatus({ initiated: false, loading: false, success: false, - error: "Token approval reverted", + error: "Withdraw reverted", }); return withdrawStatus; } - console.log("Approved hash: ", approvedReceipt.hash); - } + console.log("Withdraw Request hash: ", withdrawReceipt.hash); - console.log("Withdrawing token ..."); - // Get withdraw contract ready - const delayWithdrawContractWithSigner = new Contract( - delayWithdrawContract!, - BoringDelayWithdrawContractABI, - signer - ); + // Set status + setWithdrawStatus({ + initiated: false, + loading: false, + success: true, + tx_hash: withdrawReceipt.hash, + }); + } catch (error: any) { + console.error("Error withdrawing", error); + setWithdrawStatus({ + initiated: false, + loading: false, + success: false, + error: (error as Error).message, + }); + return withdrawStatus; + } - // Max loss is truncated(human readable * 100) - const maxLossBaseDenom = new BigNumber(maxLossHumanReadable) - .multipliedBy(100) - .decimalPlaces(0, BigNumber.ROUND_DOWN); + return withdrawStatus; + }, + [ + vaultEthersContract, + decimals, + ethersProvider, + isBoringV1ContextReady, + delayWithdrawEthersContract, + ] + ); + + const delayWithdrawStatuses = useCallback( + async (signer: JsonRpcSigner) => { + if ( + !delayWithdrawEthersContract || + !isBoringV1ContextReady || + !decimals || + !signer + ) { + console.error("Contracts or user not ready for withdraw statuses...", { + delayWithdrawEthersContract, + isBoringV1ContextReady, + decimals, + signer, + }); - const withdrawTx = - await delayWithdrawContractWithSigner.requestWithdraw( - tokenOut.address, - amountWithdrawBaseDenom.toNumber(), - maxLossBaseDenom.toNumber(), - thirdPartyClaimer + return []; + } + console.log("Fetching delay withdraw statuses ..."); + + try { + // Create a request per token + const statuses = await Promise.all( + withdrawTokens.map(async (token) => { + const status = await delayWithdrawEthersContract.withdrawRequests( + await signer.getAddress(), + token.address + ); + console.log("Status from contract: ", status); + // Format the status object + + if (Number(status.shares) === 0) { + // Skip if no shares + return null; + } + + return { + allowThirdPartyToComplete: status.allowThirdPartyToComplete, + maxLoss: Number(status.maxLoss) / 100, + maturity: Number(status.maturity), + shares: Number(status.shares) / Math.pow(10, vaultDecimals), + exchangeRateAtTimeOfRequest: + Number(status.exchangeRateAtTimeOfRequest) / + Math.pow(10, vaultDecimals), + token: token, + } as DelayWithdrawStatus; + }) ); + console.log("All statuses: ", statuses); - // Wait for confirmation - const withdrawReceipt: ContractTransactionReceipt = - await withdrawTx.wait(); + // Drop null statuses + return statuses.filter( + (status): status is DelayWithdrawStatus => status !== null + ); + } catch (error) { + console.error("Error fetching delay withdraw statuses", error); + return []; // Return an empty array in case of an error + } + }, + [ + delayWithdrawEthersContract, + decimals, + isBoringV1ContextReady, + withdrawTokens, + ] + ); + + const delayWithdrawCancel = useCallback( + async (signer: JsonRpcSigner, tokenOut: Token) => { + if ( + !delayWithdrawEthersContract || + !isBoringV1ContextReady || + !decimals || + !signer + ) { + console.error("Contracts or user not ready to cancel withdraw", { + delayWithdrawEthersContract, + isBoringV1ContextReady, + decimals, + signer, + }); - console.log("Withdraw Requested in tx: ", withdrawReceipt); - if (!withdrawReceipt.hash) { - console.error("Withdraw Request failed"); setWithdrawStatus({ initiated: false, loading: false, success: false, - error: "Withdraw reverted", + error: "Contracts or user not ready", }); + return withdrawStatus; } - console.log("Withdraw Request hash: ", withdrawReceipt.hash); - // Set status - setWithdrawStatus({ - initiated: false, - loading: false, - success: true, - tx_hash: withdrawReceipt.hash, - }); - } catch (error: any) { - console.error("Error withdrawing", error); + console.log("Cancelling delay withdraw ..."); + const delayWithdrawContractWithSigner = new Contract( + delayWithdrawContract!, + BoringDelayWithdrawContractABI, + signer + ); + setWithdrawStatus({ - initiated: false, - loading: false, - success: false, - error: (error as Error).message, + initiated: true, + loading: true, }); - return withdrawStatus; - } - - return withdrawStatus; - }, - [ - vaultEthersContract, - decimals, - ethersProvider, - isBoringV1ContextReady, - delayWithdrawEthersContract, - ] - ); - const delayWithdrawStatuses = useCallback( - async (signer: JsonRpcSigner) => { - if ( - !delayWithdrawEthersContract || - !isBoringV1ContextReady || - !decimals || - !signer - ) { - console.error("Contracts or user not ready for withdraw statuses...", { - delayWithdrawEthersContract, - isBoringV1ContextReady, - decimals, - signer, - }); + try { + const cancelTx = await delayWithdrawContractWithSigner.cancelWithdraw( + tokenOut.address + ); - return []; - } - console.log("Fetching delay withdraw statuses ..."); + // Wait for confirmation + const cancelReceipt: ContractTransactionReceipt = await cancelTx.wait(); - try { - // Create a request per token - const statuses = await Promise.all( - withdrawTokens.map(async (token) => { - const status = await delayWithdrawEthersContract.withdrawRequests( - await signer.getAddress(), - token.address - ); - console.log("Status from contract: ", status); - // Format the status object + console.log("Withdraw Cancelled in tx: ", cancelReceipt); + if (!cancelReceipt.hash) { + console.error("Withdraw Cancel failed"); + setWithdrawStatus({ + initiated: false, + loading: false, + success: false, + error: "Withdraw Cancel reverted", + }); + return withdrawStatus; + } + console.log("Withdraw Cancel hash: ", cancelReceipt.hash); - if (Number(status.shares) === 0) { - // Skip if no shares - return null; - } + // Set status + setWithdrawStatus({ + initiated: false, + loading: false, + success: true, + tx_hash: cancelReceipt.hash, + }); + } catch (error: any) { + console.error("Error cancelling withdraw", error); + setWithdrawStatus({ + initiated: false, + loading: false, + success: false, + error: (error as Error).message, + }); + return withdrawStatus; + } + return withdrawStatus; + }, + [ + delayWithdrawEthersContract, + decimals, + ethersProvider, + isBoringV1ContextReady, + ] + ); + + const delayWithdrawComplete = useCallback( + async (signer: JsonRpcSigner, tokenOut: Token) => { + if ( + !delayWithdrawEthersContract || + !isBoringV1ContextReady || + !decimals || + !signer + ) { + console.error("Contracts or user not ready to complete withdraw", { + delayWithdrawEthersContract, + isBoringV1ContextReady, + decimals, + signer, + }); - return { - allowThirdPartyToComplete: status.allowThirdPartyToComplete, - maxLoss: Number(status.maxLoss) / 100, - maturity: Number(status.maturity), - shares: Number(status.shares) / Math.pow(10, vaultDecimals), - exchangeRateAtTimeOfRequest: - Number(status.exchangeRateAtTimeOfRequest) / - Math.pow(10, vaultDecimals), - token: token, - } as DelayWithdrawStatus; - }) - ); - console.log("All statuses: ", statuses); + setWithdrawStatus({ + initiated: false, + loading: false, + success: false, + error: "Contracts or user not ready", + }); - // Drop null statuses - return statuses.filter( - (status): status is DelayWithdrawStatus => status !== null - ); - } catch (error) { - console.error("Error fetching delay withdraw statuses", error); - return []; // Return an empty array in case of an error - } - }, - [ - delayWithdrawEthersContract, - decimals, - isBoringV1ContextReady, - withdrawTokens, - ] - ); + return withdrawStatus; + } - const delayWithdrawCancel = useCallback( - async (signer: JsonRpcSigner, tokenOut: Token) => { - if ( - !delayWithdrawEthersContract || - !isBoringV1ContextReady || - !decimals || - !signer - ) { - console.error("Contracts or user not ready to cancel withdraw", { - delayWithdrawEthersContract, - isBoringV1ContextReady, - decimals, - signer, - }); + try { + const delayWithdrawContractWithSigner = new Contract( + delayWithdrawContract!, + BoringDelayWithdrawContractABI, + signer + ); - setWithdrawStatus({ - initiated: false, - loading: false, - success: false, - error: "Contracts or user not ready", - }); + console.log("Completing delay withdraw ..."); - return withdrawStatus; - } + setWithdrawStatus({ + initiated: true, + loading: true, + }); - console.log("Cancelling delay withdraw ..."); - const delayWithdrawContractWithSigner = new Contract( - delayWithdrawContract!, - BoringDelayWithdrawContractABI, - signer - ); + const completeTx = + await delayWithdrawContractWithSigner.completeWithdraw( + tokenOut.address, + await signer.getAddress() + ); - setWithdrawStatus({ - initiated: true, - loading: true, - }); + // Wait for confirmation + const completeReceipt: ContractTransactionReceipt = + await completeTx.wait(); - try { - const cancelTx = await delayWithdrawContractWithSigner.cancelWithdraw( - tokenOut.address - ); + console.log("Withdraw Completed in tx: ", completeReceipt); - // Wait for confirmation - const cancelReceipt: ContractTransactionReceipt = await cancelTx.wait(); + if (!completeReceipt.hash) { + console.error("Withdraw Complete failed"); + setWithdrawStatus({ + initiated: false, + loading: false, + success: false, + error: "Withdraw Complete reverted", + }); + return withdrawStatus; + } + + console.log("Withdraw Complete hash: ", completeReceipt.hash); - console.log("Withdraw Cancelled in tx: ", cancelReceipt); - if (!cancelReceipt.hash) { - console.error("Withdraw Cancel failed"); + // Set status + setWithdrawStatus({ + initiated: false, + loading: false, + success: true, + tx_hash: completeReceipt.hash, + }); + } catch (error: any) { + console.error("Error completing withdraw", error); setWithdrawStatus({ initiated: false, loading: false, success: false, - error: "Withdraw Cancel reverted", + error: (error as Error).message, }); return withdrawStatus; } - console.log("Withdraw Cancel hash: ", cancelReceipt.hash); - - // Set status - setWithdrawStatus({ - initiated: false, - loading: false, - success: true, - tx_hash: cancelReceipt.hash, - }); - } catch (error: any) { - console.error("Error cancelling withdraw", error); - setWithdrawStatus({ - initiated: false, - loading: false, - success: false, - error: (error as Error).message, - }); return withdrawStatus; - } - return withdrawStatus; - }, - [ - delayWithdrawEthersContract, - decimals, - ethersProvider, - isBoringV1ContextReady, - ] - ); - - const delayWithdrawComplete = useCallback( - async (signer: JsonRpcSigner, tokenOut: Token) => { - if ( - !delayWithdrawEthersContract || - !isBoringV1ContextReady || - !decimals || - !signer - ) { - console.error("Contracts or user not ready to complete withdraw", { - delayWithdrawEthersContract, - isBoringV1ContextReady, - decimals, - signer, - }); + }, + [ + delayWithdrawEthersContract, + decimals, + ethersProvider, + isBoringV1ContextReady, + ] + ); + + /* withdrawQueue */ + const queueWithdraw = useCallback( + async ( + signer: JsonRpcSigner, + amountHumanReadable: string, + token: Token, + discountPercent: string, + daysValid: string + ) => { + if ( + !withdrawQueueEthersContract || + !vaultEthersContract || + !isBoringV1ContextReady || + !lensEthersContract || + !accountantContract || + !decimals || + !signer + ) { + console.error("Contracts or user not ready", { + withdrawQueueEthersContract, + isBoringV1ContextReady, + decimals, + signer, + }); - setWithdrawStatus({ - initiated: false, - loading: false, - success: false, - error: "Contracts or user not ready", - }); + setWithdrawStatus({ + initiated: false, + loading: false, + success: false, + error: "Contracts or user not ready", + }); - return withdrawStatus; - } + return withdrawStatus; + } - try { - const delayWithdrawContractWithSigner = new Contract( - delayWithdrawContract!, - BoringDelayWithdrawContractABI, + console.log("Queueing withdraw ..."); + const withdrawQueueContractWithSigner = new Contract( + withdrawQueueContract!, + BoringWithdrawQueueContractABI, signer ); - console.log("Completing delay withdraw ..."); - setWithdrawStatus({ initiated: true, loading: true, }); - const completeTx = - await delayWithdrawContractWithSigner.completeWithdraw( - tokenOut.address, - await signer.getAddress() - ); - - // Wait for confirmation - const completeReceipt: ContractTransactionReceipt = - await completeTx.wait(); - - console.log("Withdraw Completed in tx: ", completeReceipt); - - if (!completeReceipt.hash) { - console.error("Withdraw Complete failed"); - setWithdrawStatus({ - initiated: false, - loading: false, - success: false, - error: "Withdraw Complete reverted", - }); - return withdrawStatus; - } + // Get the amount in base denomination + const bigNumAmt = new BigNumber(amountHumanReadable); + console.warn(amountHumanReadable); + console.warn("Amount to withdraw: ", bigNumAmt.toNumber()); + const amountWithdrawBaseDenom = bigNumAmt + .multipliedBy(new BigNumber(10).pow(vaultDecimals)) + .decimalPlaces(0, BigNumber.ROUND_DOWN); - console.log("Withdraw Complete hash: ", completeReceipt.hash); + try { + // First check if the delay withdraw is approved for at least the amount + const vaultContractWithSigner = new Contract( + vaultContract, + BoringVaultABI, + signer + ); - // Set status - setWithdrawStatus({ - initiated: false, - loading: false, - success: true, - tx_hash: completeReceipt.hash, - }); - } catch (error: any) { - console.error("Error completing withdraw", error); - setWithdrawStatus({ - initiated: false, - loading: false, - success: false, - error: (error as Error).message, - }); - return withdrawStatus; - } - return withdrawStatus; - }, - [ - delayWithdrawEthersContract, - decimals, - ethersProvider, - isBoringV1ContextReady, - ] - ); + const allowance = Number( + await vaultContractWithSigner.allowance( + await signer.getAddress(), + withdrawQueueContract + ) + ); - /* withdrawQueue */ - const queueWithdraw = useCallback( - async ( - signer: JsonRpcSigner, - amountHumanReadable: string, - token: Token, - discountPercent: string, - daysValid: string - ) => { - if ( - !withdrawQueueEthersContract || - !vaultEthersContract || - !isBoringV1ContextReady || - !lensEthersContract || - !decimals || - !signer - ) { - console.error("Contracts or user not ready", { - withdrawQueueEthersContract, - isBoringV1ContextReady, - decimals, - signer, - }); + if (allowance < amountWithdrawBaseDenom.toNumber()) { + setWithdrawStatus({ + initiated: true, + loading: true, + }); + console.log("Approving token ..."); + const approveTx = await vaultContractWithSigner.approve( + withdrawQueueContract, + amountWithdrawBaseDenom.toNumber() + ); - setWithdrawStatus({ - initiated: false, - loading: false, - success: false, - error: "Contracts or user not ready", - }); + // Wait for confirmation + const approvedReceipt: ContractTransactionReceipt = + await approveTx.wait(); + console.log("Token approved in tx: ", approvedReceipt); + + if (!approvedReceipt.hash) { + console.error("Token approval failed"); + setWithdrawStatus({ + initiated: false, + loading: false, + success: false, + error: "Token approval reverted", + }); + return withdrawStatus; + } + console.log("Approved hash: ", approvedReceipt.hash); + } - return withdrawStatus; - } + console.warn( + "Amount to withdraw: ", + amountWithdrawBaseDenom.toNumber() + ); - console.log("Queueing withdraw ..."); - const withdrawQueueContractWithSigner = new Contract( - withdrawQueueContract!, - BoringWithdrawQueueContractABI, - signer - ); - - setWithdrawStatus({ - initiated: true, - loading: true, - }); - - // Get the amount in base denomination - const bigNumAmt = new BigNumber(amountHumanReadable); - console.warn(amountHumanReadable); - console.warn("Amount to withdraw: ", bigNumAmt.toNumber()); - const amountWithdrawBaseDenom = bigNumAmt - .multipliedBy(new BigNumber(10).pow(vaultDecimals)) - .decimalPlaces(0, BigNumber.ROUND_DOWN); + // Get the current share price + const sharePrice = await lensEthersContract.exchangeRate( + accountantContract + ); - try { - // First check if the delay withdraw is approved for at least the amount - const vaultContractWithSigner = new Contract( - vaultContract, - BoringVaultABI, - signer - ); + // Discounted share price + /* + const discountedSharePrice = new BigNumber(sharePrice) + .multipliedBy( + new BigNumber(100) + .minus(new BigNumber(discountPercent)) + .dividedBy(100) + ) + .decimalPlaces(0, BigNumber.ROUND_DOWN); + */ + + // Get the days valid + const daysValidSeconds = new BigNumber(daysValid).multipliedBy( + new BigNumber(86400) // 1 day in seconds + ); + // Get the current unix time seconds and add the days valid + const deadline = new BigNumber( + Math.floor(Date.now() / 1000) + + Math.floor(daysValidSeconds.toNumber()) + ).decimalPlaces(0, BigNumber.ROUND_DOWN); - const allowance = Number( - await vaultContractWithSigner.allowance( - await signer.getAddress(), - withdrawQueueContract + const formattedDiscountPercent = new BigNumber(discountPercent).multipliedBy( + new BigNumber(10000) // 1% = 10000 ) - ); - if (allowance < amountWithdrawBaseDenom.toNumber()) { - setWithdrawStatus({ - initiated: true, - loading: true, - }); - console.log("Approving token ..."); - const approveTx = await vaultContractWithSigner.approve( - withdrawQueueContract, - amountWithdrawBaseDenom.toNumber() - ); + const queueTx = + await withdrawQueueContractWithSigner.safeUpdateAtomicRequest( + vaultContract, // offer + token.address, // want + [ + deadline.toNumber(), // Deadline + Number(0),//discountedSharePrice.toNumber(), // atomicPrice, this is actually overriden in safeUpdateAtomicRequest + amountWithdrawBaseDenom.toNumber(), // offerAmount + false, // inSolver + ], + accountantContract, // accountant + formattedDiscountPercent.toNumber() + ); // Wait for confirmation - const approvedReceipt: ContractTransactionReceipt = - await approveTx.wait(); - console.log("Token approved in tx: ", approvedReceipt); + const queueReceipt: ContractTransactionReceipt = await queueTx.wait(); - if (!approvedReceipt.hash) { - console.error("Token approval failed"); + console.log("Withdraw Queued in tx: ", queueReceipt); + if (!queueReceipt.hash) { + console.error("Withdraw Queue failed"); setWithdrawStatus({ initiated: false, loading: false, success: false, - error: "Token approval reverted", + error: "Withdraw Queue reverted", }); return withdrawStatus; } - console.log("Approved hash: ", approvedReceipt.hash); - } - - console.warn( - "Amount to withdraw: ", - amountWithdrawBaseDenom.toNumber() - ); + console.log("Withdraw Queue hash: ", queueReceipt.hash); - // Get the current share price - const sharePrice = await lensEthersContract.exchangeRate( - accountantContract - ); - - // Discounted share price - const discountedSharePrice = new BigNumber(sharePrice) - .multipliedBy( - new BigNumber(100) - .minus(new BigNumber(discountPercent)) - .dividedBy(100) - ) - .decimalPlaces(0, BigNumber.ROUND_DOWN); - - // Get the days valid - const daysValidSeconds = new BigNumber(daysValid).multipliedBy( - new BigNumber(86400) // 1 day in seconds - ); - // Get the current unix time seconds and add the days valid - const deadline = new BigNumber( - Math.floor(Date.now() / 1000) + - Math.floor(daysValidSeconds.toNumber()) - ).decimalPlaces(0, BigNumber.ROUND_DOWN); - - const queueTx = - await withdrawQueueContractWithSigner.updateAtomicRequest( - vaultContract, - token.address, - [ - deadline.toNumber(), // Deadline - discountedSharePrice.toNumber(), // atomicPrice - amountWithdrawBaseDenom.toNumber(), // offerAmount - false, // inSolver - ] - ); - - // Wait for confirmation - const queueReceipt: ContractTransactionReceipt = await queueTx.wait(); - - console.log("Withdraw Queued in tx: ", queueReceipt); - if (!queueReceipt.hash) { - console.error("Withdraw Queue failed"); + // Set status + setWithdrawStatus({ + initiated: false, + loading: false, + success: true, + tx_hash: queueReceipt.hash, + }); + } catch (error: any) { + console.error("Error queueing withdraw", error); setWithdrawStatus({ initiated: false, loading: false, success: false, - error: "Withdraw Queue reverted", + error: (error as Error).message, }); return withdrawStatus; } - console.log("Withdraw Queue hash: ", queueReceipt.hash); - // Set status - setWithdrawStatus({ - initiated: false, - loading: false, - success: true, - tx_hash: queueReceipt.hash, - }); - } catch (error: any) { - console.error("Error queueing withdraw", error); - setWithdrawStatus({ - initiated: false, - loading: false, - success: false, - error: (error as Error).message, - }); return withdrawStatus; - } + }, + [ + withdrawQueueEthersContract, + lensEthersContract, + decimals, + ethersProvider, + isBoringV1ContextReady, + accountantContract, + ] + ); + + const withdrawQueueCancel = useCallback( + async (signer: JsonRpcSigner, token: Token) => { + if ( + !withdrawQueueEthersContract || + !isBoringV1ContextReady || + !decimals || + !signer + ) { + console.error("Contracts or user not ready to cancel withdraw", { + withdrawQueueEthersContract, + isBoringV1ContextReady, + decimals, + signer, + }); - return withdrawStatus; - }, - [ - withdrawQueueEthersContract, - lensEthersContract, - decimals, - ethersProvider, - isBoringV1ContextReady, - ] - ); + setWithdrawStatus({ + initiated: false, + loading: false, + success: false, + error: "Contracts or user not ready", + }); - const withdrawQueueCancel = useCallback( - async (signer: JsonRpcSigner, token: Token) => { - if ( - !withdrawQueueEthersContract || - !isBoringV1ContextReady || - !decimals || - !signer - ) { - console.error("Contracts or user not ready to cancel withdraw", { - withdrawQueueEthersContract, - isBoringV1ContextReady, - decimals, - signer, - }); + return withdrawStatus; + } + + console.log("Cancelling withdraw queue ..."); + const withdrawQueueContractWithSigner = new Contract( + withdrawQueueContract!, + BoringWithdrawQueueContractABI, + signer + ); setWithdrawStatus({ - initiated: false, - loading: false, - success: false, - error: "Contracts or user not ready", + initiated: true, + loading: true, }); - return withdrawStatus; - } - - console.log("Cancelling withdraw queue ..."); - const withdrawQueueContractWithSigner = new Contract( - withdrawQueueContract!, - BoringWithdrawQueueContractABI, - signer - ); + try { + // Update request with same token, but 0 amount + const cancelTx = + await withdrawQueueContractWithSigner.updateAtomicRequest( + vaultContract, // Offer + token.address, // Want + [ + 0, // Deadline + 0, // atomicPrice + 0, // offerAmount + false, // inSolver + ], - setWithdrawStatus({ - initiated: true, - loading: true, - }); + ); - try { - // Update request with same token, but 0 amount - const cancelTx = - await withdrawQueueContractWithSigner.updateAtomicRequest( - vaultContract, - token.address, - [ - 0, // Deadline - 0, // atomicPrice - 0, // offerAmount - false, // inSolver - ] - ); + // Wait for confirmation + const cancelReceipt: ContractTransactionReceipt = await cancelTx.wait(); - // Wait for confirmation - const cancelReceipt: ContractTransactionReceipt = await cancelTx.wait(); + console.log("Withdraw Cancelled in tx: ", cancelReceipt); + if (!cancelReceipt.hash) { + console.error("Withdraw Cancel failed"); + setWithdrawStatus({ + initiated: false, + loading: false, + success: false, + error: "Withdraw Cancel reverted", + }); + return withdrawStatus; + } + console.log("Withdraw Cancel hash: ", cancelReceipt.hash); - console.log("Withdraw Cancelled in tx: ", cancelReceipt); - if (!cancelReceipt.hash) { - console.error("Withdraw Cancel failed"); + // Set status + setWithdrawStatus({ + initiated: false, + loading: false, + success: true, + tx_hash: cancelReceipt.hash, + }); + } catch (error: any) { + console.error("Error cancelling withdraw", error); setWithdrawStatus({ initiated: false, loading: false, success: false, - error: "Withdraw Cancel reverted", + error: (error as Error).message, }); return withdrawStatus; } - console.log("Withdraw Cancel hash: ", cancelReceipt.hash); - // Set status - setWithdrawStatus({ - initiated: false, - loading: false, - success: true, - tx_hash: cancelReceipt.hash, - }); - } catch (error: any) { - console.error("Error cancelling withdraw", error); - setWithdrawStatus({ - initiated: false, - loading: false, - success: false, - error: (error as Error).message, - }); return withdrawStatus; - } - - return withdrawStatus; - }, - [ - withdrawQueueEthersContract, - decimals, - ethersProvider, - isBoringV1ContextReady, - ] - ); - - const withdrawQueueStatuses = useCallback( - async (signer: JsonRpcSigner) => { - if ( - !withdrawQueueEthersContract || - !isBoringV1ContextReady || - !decimals || - !signer - ) { - console.error( - "Contracts or user not ready for withdraw queue statuses...", - { - withdrawQueueEthersContract, - isBoringV1ContextReady, - decimals, - signer, - } - ); - return []; - } - console.log("Fetching withdraw queue statuses ..."); + }, + [ + withdrawQueueEthersContract, + decimals, + ethersProvider, + isBoringV1ContextReady, + ] + ); + + const withdrawQueueStatuses = useCallback( + async (signer: JsonRpcSigner) => { + if ( + !withdrawQueueEthersContract || + !isBoringV1ContextReady || + !decimals || + !signer + ) { + console.error( + "Contracts or user not ready for withdraw queue statuses...", + { + withdrawQueueEthersContract, + isBoringV1ContextReady, + decimals, + signer, + } + ); + return []; + } + console.log("Fetching withdraw queue statuses ..."); + + try { + const withdrawURL = `${SEVEN_SEAS_BASE_API_URL}/withdrawRequests/${chain.toLowerCase()}/${vaultContract}/${await signer.getAddress()}`; + const response = await fetch(withdrawURL) + .then((response) => { + return response.json(); + }) + .catch((error) => { + console.error("Error fetching withdraw queue statuses", error); + return []; + }); + console.log("Response from Withdraw API: ", response); + // Parse on ["Response"]["open_requests"] + const openRequests = response["Response"]["open_requests"]; - try { - const withdrawURL = `${SEVEN_SEAS_BASE_API_URL}/withdrawRequests/${chain.toLowerCase()}/${vaultContract}/${await signer.getAddress()}`; - const response = await fetch(withdrawURL) - .then((response) => { - return response.json(); - }) - .catch((error) => { - console.error("Error fetching withdraw queue statuses", error); - return []; + // Format the status object + return openRequests.map((request: any) => { + return { + sharesWithdrawing: Number(request["amount"]) / 10 ** vaultDecimals, + blockNumberOpened: Number(request["blockNumber"]), + deadlineUnixSeconds: Number(request["deadline"]), + errorCode: Number(request["errorCode"]), + minSharePrice: Number(request["minPrice"]) / 10 ** vaultDecimals, + timestampOpenedUnixSeconds: Number(request["timestamp"]), + transactionHashOpened: request["transactionHash"], + tokenOut: withdrawTokens.find( + (token) => + token.address.toLowerCase() === + request["wantToken"].toLowerCase() + )!, + } as WithdrawQueueStatus; }); - console.log("Response from Withdraw API: ", response); - // Parse on ["Response"]["open_requests"] - const openRequests = response["Response"]["open_requests"]; - - // Format the status object - return openRequests.map((request: any) => { - return { - sharesWithdrawing: Number(request["amount"]) / 10 ** vaultDecimals, - blockNumberOpened: Number(request["blockNumber"]), - deadlineUnixSeconds: Number(request["deadline"]), - errorCode: Number(request["errorCode"]), - minSharePrice: Number(request["minPrice"]) / 10 ** vaultDecimals, - timestampOpenedUnixSeconds: Number(request["timestamp"]), - transactionHashOpened: request["transactionHash"], - tokenOut: withdrawTokens.find( - (token) => - token.address.toLowerCase() === - request["wantToken"].toLowerCase() - )!, - } as WithdrawQueueStatus; - }); - } catch (error) { - console.error("Error fetching withdraw queue statuses", error); - return []; // Return an empty array in case of an error - } - }, - [ - withdrawQueueEthersContract, - decimals, - ethersProvider, - isBoringV1ContextReady, - ] - ); - - return ( - - {children} - - ); -}; + ] + ); + + return ( + + {children} + + ); + }; export const useBoringVaultV1 = () => { const context = useContext(BoringVaultV1Context); diff --git a/src/examples/v1.tsx b/src/examples/v1.tsx index f8a1144..156fb97 100644 --- a/src/examples/v1.tsx +++ b/src/examples/v1.tsx @@ -244,7 +244,7 @@ const App = () => { tellerContract="0x221Ea02d409074546265CCD1123050F4D498ef64" accountantContract="0xc315D6e14DDCDC7407784e2Caf815d131Bc1D3E7" lensContract="0x5232bc0F5999f8dA604c42E1748A13a170F94A1B" - withdrawQueueContract="0xD45884B592E316eB816199615A95C182F75dea07" + withdrawQueueContract="0x7c12C550FE8857380B8F5A9e55D9145A0d7A7198" ethersProvider={ethersInfuraProvider} depositTokens={[ { @@ -267,7 +267,7 @@ const App = () => { displayName: "USDe", image: "https://s2.coinmarketcap.com/static/img/coins/64x64/29470.png", - address: "0x9D39A5DE30e57443BfF2A8307A4256c8797A3497", + address: "0x4c9EDD5852cd905f086C759E8383e09bff1E68B3", decimals: 18, }, ]}