@ape.swap/bonds-sdk 7.0.3 → 7.0.4-test.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/evm/index.d.ts +3 -2
- package/dist/adapters/evm/index.js +11 -2
- package/dist/adapters/evm/index.js.map +1 -1
- package/dist/adapters/evm/state/balances.js +1 -1
- package/dist/adapters/evm/state/balances.js.map +1 -1
- package/dist/adapters/evm/state/fetchBondsDataEVM.js +65 -2
- package/dist/adapters/evm/state/fetchBondsDataEVM.js.map +1 -1
- package/dist/adapters/evm/state/fetchUsersBondsEVM.js +234 -2
- package/dist/adapters/evm/state/fetchUsersBondsEVM.js.map +1 -1
- package/dist/adapters/evm/state/lpStaking/fetchLpStakingLimits.d.ts +24 -0
- package/dist/adapters/evm/state/lpStaking/fetchLpStakingLimits.js +118 -0
- package/dist/adapters/evm/state/lpStaking/fetchLpStakingLimits.js.map +1 -0
- package/dist/adapters/evm/state/lpStaking/useSoulZapLpStakingQuote.d.ts +4 -0
- package/dist/adapters/evm/state/lpStaking/useSoulZapLpStakingQuote.js +140 -0
- package/dist/adapters/evm/state/lpStaking/useSoulZapLpStakingQuote.js.map +1 -0
- package/dist/adapters/evm/state/useSoulZapBondQuote.js +1 -1
- package/dist/adapters/evm/views/BuyComponent.js +3 -3
- package/dist/adapters/evm/views/BuyComponent.js.map +1 -1
- package/dist/adapters/evm/views/lpStaking/BuyComponentLpStaking.d.ts +4 -0
- package/dist/adapters/evm/views/lpStaking/BuyComponentLpStaking.js +212 -0
- package/dist/adapters/evm/views/lpStaking/BuyComponentLpStaking.js.map +1 -0
- package/dist/adapters/evm/views/lpStaking/LpBondModalHeader.d.ts +7 -0
- package/dist/adapters/evm/views/lpStaking/LpBondModalHeader.js +66 -0
- package/dist/adapters/evm/views/lpStaking/LpBondModalHeader.js.map +1 -0
- package/dist/adapters/evm/views/lpStaking/LpStakingEstimations.d.ts +23 -0
- package/dist/adapters/evm/views/lpStaking/LpStakingEstimations.js +40 -0
- package/dist/adapters/evm/views/lpStaking/LpStakingEstimations.js.map +1 -0
- package/dist/adapters/evm/views/lpStaking/ModalHandlerLpStaking.d.ts +3 -0
- package/dist/adapters/evm/views/lpStaking/ModalHandlerLpStaking.js +90 -0
- package/dist/adapters/evm/views/lpStaking/ModalHandlerLpStaking.js.map +1 -0
- package/dist/adapters/evm/views/lpStaking/UserLpStakingBondRow.d.ts +5 -0
- package/dist/adapters/evm/views/lpStaking/UserLpStakingBondRow.js +32 -0
- package/dist/adapters/evm/views/lpStaking/UserLpStakingBondRow.js.map +1 -0
- package/dist/adapters/evm/views/lpStaking/YourLpBondModalHeader.d.ts +7 -0
- package/dist/adapters/evm/views/lpStaking/YourLpBondModalHeader.js +20 -0
- package/dist/adapters/evm/views/lpStaking/YourLpBondModalHeader.js.map +1 -0
- package/dist/adapters/evm/views/lpStaking/YourLpStakingBondModal.d.ts +7 -0
- package/dist/adapters/evm/views/lpStaking/YourLpStakingBondModal.js +78 -0
- package/dist/adapters/evm/views/lpStaking/YourLpStakingBondModal.js.map +1 -0
- package/dist/adapters/solana/views/BuyComponentSolana.js +3 -3
- package/dist/adapters/solana/views/BuyComponentSolana.js.map +1 -1
- package/dist/adapters/types.d.ts +20 -5
- package/dist/components/TokenInfoAndName/index.js +4 -1
- package/dist/components/TokenInfoAndName/index.js.map +1 -1
- package/dist/components/Tooltip/ButtonsRow.js +1 -1
- package/dist/components/Tooltip/ButtonsRow.js.map +1 -1
- package/dist/components/Tooltip/Tooltip.js +3 -2
- package/dist/components/Tooltip/Tooltip.js.map +1 -1
- package/dist/components/uikit-sdk/TokenImage/index.js +3 -1
- package/dist/components/uikit-sdk/TokenImage/index.js.map +1 -1
- package/dist/config/abi/apeBondPositionAdapter.json.js +1347 -0
- package/dist/config/abi/apeBondPositionAdapter.json.js.map +1 -0
- package/dist/config/abi/bonusEscrow.json.js +33 -0
- package/dist/config/abi/bonusEscrow.json.js.map +1 -0
- package/dist/config/abi/lpStakingVault.json.js +34 -0
- package/dist/config/abi/lpStakingVault.json.js.map +1 -0
- package/dist/config/abi/uniswapV3Pool.json.js +47 -0
- package/dist/config/abi/uniswapV3Pool.json.js.map +1 -0
- package/dist/config/abi/uniswapV3QuoterV2.json.js +66 -0
- package/dist/config/abi/uniswapV3QuoterV2.json.js.map +1 -0
- package/dist/config/constants/addresses.d.ts +1 -0
- package/dist/config/constants/addresses.js +7 -1
- package/dist/config/constants/addresses.js.map +1 -1
- package/dist/config/constants/chains.js +3 -1
- package/dist/config/constants/chains.js.map +1 -1
- package/dist/config/constants/networks.js +1 -1
- package/dist/config/constants/networks.js.map +1 -1
- package/dist/config/constants/variables.d.ts +2 -2
- package/dist/config/constants/variables.js +3 -1
- package/dist/config/constants/variables.js.map +1 -1
- package/dist/hooks/useSendReferenceId.d.ts +4 -1
- package/dist/hooks/useSendReferenceId.js +9 -3
- package/dist/hooks/useSendReferenceId.js.map +1 -1
- package/dist/state/bonds/useBondsData.js +1 -0
- package/dist/state/bonds/useBondsData.js.map +1 -1
- package/dist/state/bonds/useUserBonds.d.ts +10 -1
- package/dist/state/bonds/useUserBonds.js +18 -11
- package/dist/state/bonds/useUserBonds.js.map +1 -1
- package/dist/state/useSDKConfig.js +11 -2
- package/dist/state/useSDKConfig.js.map +1 -1
- package/dist/state/zap/getChainParam.d.ts +1 -16
- package/dist/state/zap/getChainParam.js +16 -40
- package/dist/state/zap/getChainParam.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/types/yourbonds.d.ts +24 -0
- package/dist/views/Bonds/components/BondRows/ActiveBondRows.js +19 -2
- package/dist/views/Bonds/components/BondRows/ActiveBondRows.js.map +1 -1
- package/dist/views/Bonds/components/BondRows/BondRow.d.ts +3 -2
- package/dist/views/Bonds/components/BondRows/BondRow.js +15 -10
- package/dist/views/Bonds/components/BondRows/BondRow.js.map +1 -1
- package/dist/views/Bonds/components/BondRows/ModalHandler.js +1 -1
- package/dist/views/Bonds/components/BondRows/ModalHandler.js.map +1 -1
- package/dist/views/Bonds/components/BondRows/SoldOutRows.js +1 -1
- package/dist/views/Bonds/components/BondRows/SoldOutRows.js.map +1 -1
- package/dist/views/Bonds/components/BondsMenu/BondsMenu.js +1 -1
- package/dist/views/Bonds/components/BondsMenu/BondsMenu.js.map +1 -1
- package/dist/views/Bonds/components/BonusComponents/BonusComponent.js +1 -1
- package/dist/views/Bonds/components/BonusComponents/BonusComponent.js.map +1 -1
- package/dist/views/Bonds/components/BuyAgainRow/index.js +1 -1
- package/dist/views/Bonds/components/BuyAgainRow/index.js.map +1 -1
- package/dist/views/Bonds/components/CheckURL/index.js +20 -15
- package/dist/views/Bonds/components/CheckURL/index.js.map +1 -1
- package/dist/views/BuyBond/ChainBuyComponent.d.ts +4 -1
- package/dist/views/BuyBond/ChainBuyComponent.js +14 -2
- package/dist/views/BuyBond/ChainBuyComponent.js.map +1 -1
- package/dist/views/BuyBond/components/BondCards/BondCards.js +1 -7
- package/dist/views/BuyBond/components/BondCards/BondCards.js.map +1 -1
- package/dist/views/BuyBond/components/BondModalHeader.d.ts +1 -2
- package/dist/views/BuyBond/components/BondModalHeader.js +13 -5
- package/dist/views/BuyBond/components/BondModalHeader.js.map +1 -1
- package/dist/views/BuyBond/components/Estimations.js +1 -1
- package/dist/views/BuyBond/components/Estimations.js.map +1 -1
- package/dist/views/BuyBond/components/ExpandedViewButton.d.ts +2 -2
- package/dist/views/BuyBond/components/ExpandedViewButton.js +2 -2
- package/dist/views/BuyBond/components/ExpandedViewButton.js.map +1 -1
- package/dist/views/FullBondsView/FullBondsView.js +2 -1
- package/dist/views/FullBondsView/FullBondsView.js.map +1 -1
- package/dist/views/FullBondsView/YourBondsStatus.d.ts +3 -0
- package/dist/views/FullBondsView/YourBondsStatus.js +54 -0
- package/dist/views/FullBondsView/YourBondsStatus.js.map +1 -0
- package/dist/views/SingleBond/SoldOutBuyBondPlaceholder.js +2 -5
- package/dist/views/SingleBond/SoldOutBuyBondPlaceholder.js.map +1 -1
- package/dist/views/YourBonds/YourBonds.js +6 -1
- package/dist/views/YourBonds/YourBonds.js.map +1 -1
- package/dist/views/YourBonds/components/YourBondsMenu/YourBondsMenu.js +2 -1
- package/dist/views/YourBonds/components/YourBondsMenu/YourBondsMenu.js.map +1 -1
- package/dist/views/YourBondsModal/components/YourBondModalHeader/YourBondModalHeader.d.ts +2 -1
- package/dist/views/YourBondsModal/components/YourBondModalHeader/YourBondModalHeader.js +2 -2
- package/dist/views/YourBondsModal/components/YourBondModalHeader/YourBondModalHeader.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ChainAdapter } from '../types';
|
|
2
2
|
/**
|
|
3
|
-
* EVM bonds (every chain that isn't Solana, Aptos or Sui), plus tiers
|
|
4
|
-
* `wagmi` and `viem`, and the consumer must mount a `WagmiProvider` (see docs/PLAN_CHAIN_ADAPTERS.md,
|
|
3
|
+
* EVM bonds (every chain that isn't Solana, Aptos or Sui), plus tiers, PreTGE / launch / Yield and LP staking bonds.
|
|
4
|
+
* Requires `wagmi` and `viem`, and the consumer must mount a `WagmiProvider` (see docs/PLAN_CHAIN_ADAPTERS.md,
|
|
5
|
+
* section 3.2).
|
|
5
6
|
*/
|
|
6
7
|
export declare const evmAdapter: ChainAdapter;
|
|
@@ -15,11 +15,15 @@ import { fetchUserBondsPreTGE } from './state/preTGE/fetchUserBondsPreTGE.js';
|
|
|
15
15
|
import ModalHandlerPreTGE from './views/preTGE/ModalHandlerPreTGE.js';
|
|
16
16
|
import UserBondRowPreTGE from './views/preTGE/UserBondRowPreTGE.js';
|
|
17
17
|
import UserBondRowYield from './views/preTGE/UserBondRowYield.js';
|
|
18
|
+
import ModalHandlerLpStaking from './views/lpStaking/ModalHandlerLpStaking.js';
|
|
19
|
+
import BuyComponentLpStaking from './views/lpStaking/BuyComponentLpStaking.js';
|
|
20
|
+
import UserLpStakingBondRow from './views/lpStaking/UserLpStakingBondRow.js';
|
|
18
21
|
|
|
19
22
|
const NON_EVM_CHAINS = [ChainId.SOL, ChainId.APTOS, ChainId.SUI];
|
|
20
23
|
/**
|
|
21
|
-
* EVM bonds (every chain that isn't Solana, Aptos or Sui), plus tiers
|
|
22
|
-
* `wagmi` and `viem`, and the consumer must mount a `WagmiProvider` (see docs/PLAN_CHAIN_ADAPTERS.md,
|
|
24
|
+
* EVM bonds (every chain that isn't Solana, Aptos or Sui), plus tiers, PreTGE / launch / Yield and LP staking bonds.
|
|
25
|
+
* Requires `wagmi` and `viem`, and the consumer must mount a `WagmiProvider` (see docs/PLAN_CHAIN_ADAPTERS.md,
|
|
26
|
+
* section 3.2).
|
|
23
27
|
*/
|
|
24
28
|
const evmAdapter = {
|
|
25
29
|
ecosystem: 'evm',
|
|
@@ -47,6 +51,11 @@ const evmAdapter = {
|
|
|
47
51
|
UserBondRow: UserBondRowPreTGE,
|
|
48
52
|
YieldRow: UserBondRowYield,
|
|
49
53
|
},
|
|
54
|
+
lpStaking: {
|
|
55
|
+
ModalHandler: ModalHandlerLpStaking,
|
|
56
|
+
BuyComponent: BuyComponentLpStaking,
|
|
57
|
+
UserBondRow: UserLpStakingBondRow,
|
|
58
|
+
},
|
|
50
59
|
};
|
|
51
60
|
|
|
52
61
|
export { evmAdapter };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../src/adapters/evm/index.ts"],"sourcesContent":["import { ChainId } from '@ape.swap/apeswap-lists'\nimport type { ChainAdapter } from '../types'\nimport EvmAccountBridge from './state/EvmAccountBridge'\nimport { fetchBondsDataEVM } from './state/fetchBondsDataEVM'\nimport { fetchUsersBondsEVM } from './state/fetchUsersBondsEVM'\nimport { getTokenBalanceEVM, getTokensBalanceEVM } from './state/balances'\nimport { getTierPoints } from './state/getTierPoints'\nimport BuyComponent from './views/BuyComponent'\nimport UserBondRow from './views/UserBondRow'\nimport Actions from './views/Actions'\nimport TransferAction from './views/TransferAction'\nimport ClaimAllActionEVM from './views/ClaimAllActionEVM'\nimport ConnectToEVMBanner from './views/ConnectToEvmBanner'\nimport { fetchBondsDataPreTGE } from './state/preTGE/fetchBondsDataPreTGE'\nimport { fetchUserBondsPreTGE } from './state/preTGE/fetchUserBondsPreTGE'\nimport ModalHandlerPreTGE from './views/preTGE/ModalHandlerPreTGE'\nimport UserBondRowPreTGE from './views/preTGE/UserBondRowPreTGE'\nimport UserBondRowYield from './views/preTGE/UserBondRowYield'\n\nconst NON_EVM_CHAINS: ChainId[] = [ChainId.SOL, ChainId.APTOS, ChainId.SUI]\n\n/**\n * EVM bonds (every chain that isn't Solana, Aptos or Sui), plus tiers
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../src/adapters/evm/index.ts"],"sourcesContent":["import { ChainId } from '@ape.swap/apeswap-lists'\nimport type { ChainAdapter } from '../types'\nimport EvmAccountBridge from './state/EvmAccountBridge'\nimport { fetchBondsDataEVM } from './state/fetchBondsDataEVM'\nimport { fetchUsersBondsEVM } from './state/fetchUsersBondsEVM'\nimport { getTokenBalanceEVM, getTokensBalanceEVM } from './state/balances'\nimport { getTierPoints } from './state/getTierPoints'\nimport BuyComponent from './views/BuyComponent'\nimport UserBondRow from './views/UserBondRow'\nimport Actions from './views/Actions'\nimport TransferAction from './views/TransferAction'\nimport ClaimAllActionEVM from './views/ClaimAllActionEVM'\nimport ConnectToEVMBanner from './views/ConnectToEvmBanner'\nimport { fetchBondsDataPreTGE } from './state/preTGE/fetchBondsDataPreTGE'\nimport { fetchUserBondsPreTGE } from './state/preTGE/fetchUserBondsPreTGE'\nimport ModalHandlerPreTGE from './views/preTGE/ModalHandlerPreTGE'\nimport UserBondRowPreTGE from './views/preTGE/UserBondRowPreTGE'\nimport UserBondRowYield from './views/preTGE/UserBondRowYield'\nimport ModalHandlerLpStaking from './views/lpStaking/ModalHandlerLpStaking'\nimport BuyComponentLpStaking from './views/lpStaking/BuyComponentLpStaking'\nimport UserLpStakingBondRow from './views/lpStaking/UserLpStakingBondRow'\n\nconst NON_EVM_CHAINS: ChainId[] = [ChainId.SOL, ChainId.APTOS, ChainId.SUI]\n\n/**\n * EVM bonds (every chain that isn't Solana, Aptos or Sui), plus tiers, PreTGE / launch / Yield and LP staking bonds.\n * Requires `wagmi` and `viem`, and the consumer must mount a `WagmiProvider` (see docs/PLAN_CHAIN_ADAPTERS.md,\n * section 3.2).\n */\nexport const evmAdapter: ChainAdapter = {\n ecosystem: 'evm',\n supportsChain: (chainId) => !NON_EVM_CHAINS.includes(chainId),\n AccountBridge: EvmAccountBridge,\n\n // EVM bonds come from the realtime API; fetchBondsData is only the on-chain (multicall) fallback. Bills are\n // enriched with api-v2 NFT metadata.\n usesRealtimeApi: true,\n fetchBondsData: (chainId, bonds, tokenPrices, apiUrl) => fetchBondsDataEVM(chainId, bonds, apiUrl, tokenPrices),\n fetchUserBonds: (chainId, account, bonds, tokenPrices) => fetchUsersBondsEVM(chainId, account, bonds, tokenPrices),\n enrichUserBondsViaApi: true,\n getTokenBalance: getTokenBalanceEVM,\n getTokensBalances: getTokensBalanceEVM,\n\n BuyComponent,\n UserBondRow,\n BondActions: Actions,\n TransferAction,\n ClaimAllAction: ClaimAllActionEVM,\n ConnectBanner: ConnectToEVMBanner,\n\n getTierPoints,\n preTGE: {\n fetchBondsData: fetchBondsDataPreTGE,\n fetchUserBonds: fetchUserBondsPreTGE,\n ModalHandler: ModalHandlerPreTGE,\n UserBondRow: UserBondRowPreTGE,\n YieldRow: UserBondRowYield,\n },\n lpStaking: {\n ModalHandler: ModalHandlerLpStaking,\n BuyComponent: BuyComponentLpStaking,\n UserBondRow: UserLpStakingBondRow,\n },\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;AAsBA,MAAM,cAAc,GAAc,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC;AAE3E;;;;AAIG;AACI,MAAM,UAAU,GAAiB;AACtC,IAAA,SAAS,EAAE,KAAK;AAChB,IAAA,aAAa,EAAE,CAAC,OAAO,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,OAAO,CAAC;AAC7D,IAAA,aAAa,EAAE,gBAAgB;;;AAI/B,IAAA,eAAe,EAAE,IAAI;IACrB,cAAc,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,KAAK,iBAAiB,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC;IAC/G,cAAc,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,KAAK,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,CAAC;AAClH,IAAA,qBAAqB,EAAE,IAAI;AAC3B,IAAA,eAAe,EAAE,kBAAkB;AACnC,IAAA,iBAAiB,EAAE,mBAAmB;IAEtC,YAAY;IACZ,WAAW;AACX,IAAA,WAAW,EAAE,OAAO;IACpB,cAAc;AACd,IAAA,cAAc,EAAE,iBAAiB;AACjC,IAAA,aAAa,EAAE,kBAAkB;IAEjC,aAAa;AACb,IAAA,MAAM,EAAE;AACN,QAAA,cAAc,EAAE,oBAAoB;AACpC,QAAA,cAAc,EAAE,oBAAoB;AACpC,QAAA,YAAY,EAAE,kBAAkB;AAChC,QAAA,WAAW,EAAE,iBAAiB;AAC9B,QAAA,QAAQ,EAAE,gBAAgB;AAC3B,KAAA;AACD,IAAA,SAAS,EAAE;AACT,QAAA,YAAY,EAAE,qBAAqB;AACnC,QAAA,YAAY,EAAE,qBAAqB;AACnC,QAAA,WAAW,EAAE,oBAAoB;AAClC,KAAA;;;;;"}
|
|
@@ -14,7 +14,7 @@ const getTokenBalanceEVM = async (chainId, currency, account) => {
|
|
|
14
14
|
},
|
|
15
15
|
];
|
|
16
16
|
const data = await multicall(chainId, currency === 'NATIVE' ? multicallV2Abi : erc20ABI, calls);
|
|
17
|
-
return formatUnits(data[0] ?? 0, currency === 'NATIVE' ? 18 : currency.decimals[chainId]);
|
|
17
|
+
return formatUnits(data[0][0] ?? 0, currency === 'NATIVE' ? 18 : currency.decimals[chainId]);
|
|
18
18
|
};
|
|
19
19
|
/** Balances of several tokens (and/or the native coin) on an EVM chain, in two multicalls. */
|
|
20
20
|
const getTokensBalanceEVM = async (chainId, account, tokens) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"balances.js","sources":["../../../../src/adapters/evm/state/balances.ts"],"sourcesContent":["import { ChainId, Token } from '@ape.swap/apeswap-lists'\nimport multicallV2Abi from '../../../config/abi/multicallv2.json'\nimport erc20ABI from '../../../config/abi/erc20.json'\nimport { MULTICALL_V2 } from '../../../config/constants/addresses'\nimport { formatUnits } from '../../../utils/fixedPoint'\nimport type { TokenBalance } from '../../types'\nimport multicall, { Call } from '../utils/multicall'\n\n/** Balance of one token (or the native coin) on an EVM chain. */\nexport const getTokenBalanceEVM = async (chainId: ChainId, currency: 'NATIVE' | Token, account: string) => {\n const calls: Call[] = [\n {\n address: currency === 'NATIVE' ? MULTICALL_V2[chainId]! : currency.address[chainId]!,\n name: currency === 'NATIVE' ? 'getEthBalance' : 'balanceOf',\n params: [account],\n },\n ]\n const data = await multicall(chainId, currency === 'NATIVE' ? multicallV2Abi : erc20ABI, calls)\n return formatUnits(data[0] ?? 0, currency === 'NATIVE' ? 18 : currency.decimals![chainId]!)\n}\n\n/** Balances of several tokens (and/or the native coin) on an EVM chain, in two multicalls. */\nexport const getTokensBalanceEVM = async (\n chainId: ChainId,\n account: string,\n tokens: ('NATIVE' | Token)[],\n): Promise<TokenBalance[]> => {\n const callsToken: Call[] = tokens\n .filter((token) => token !== 'NATIVE')\n .map((token) => {\n return {\n address: token?.address?.[chainId] ?? '',\n name: 'balanceOf',\n params: [account],\n }\n })\n const callNative: Call[] = tokens\n .filter((token) => token === 'NATIVE')\n .map(() => {\n return {\n address: MULTICALL_V2[chainId]!,\n name: 'getEthBalance',\n params: [account],\n }\n })\n const [dataToken, dataNative] = await Promise.all([\n multicall(chainId, erc20ABI, callsToken),\n multicall(chainId, multicallV2Abi, callNative),\n ])\n\n const balancesToken = dataToken.map((balance: any, i: number) => {\n const token = tokens.find(\n (token) =>\n token !== 'NATIVE' &&\n (token as Token)?.address?.[chainId]?.toLowerCase() === callsToken[i].address.toLowerCase(),\n )\n return {\n address: (token as Token)?.address[chainId] as string,\n balance: formatUnits(balance[0], (token as Token).decimals![chainId]!),\n }\n })\n const balancesNative = dataNative.map((balance: any) => {\n return {\n address: 'NATIVE',\n balance: formatUnits(balance[0], 18),\n }\n })\n return [...balancesToken, ...balancesNative]\n}\n"],"names":[],"mappings":";;;;;;AAQA;AACO,MAAM,kBAAkB,GAAG,OAAO,OAAgB,EAAE,QAA0B,EAAE,OAAe,KAAI;AACxG,IAAA,MAAM,KAAK,GAAW;AACpB,QAAA;AACE,YAAA,OAAO,EAAE,QAAQ,KAAK,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAE;YACpF,IAAI,EAAE,QAAQ,KAAK,QAAQ,GAAG,eAAe,GAAG,WAAW;YAC3D,MAAM,EAAE,CAAC,OAAO,CAAC;AAClB,SAAA;KACF;IACD,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,OAAO,EAAE,QAAQ,KAAK,QAAQ,GAAG,cAAc,GAAG,QAAQ,EAAE,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"balances.js","sources":["../../../../src/adapters/evm/state/balances.ts"],"sourcesContent":["import { ChainId, Token } from '@ape.swap/apeswap-lists'\nimport multicallV2Abi from '../../../config/abi/multicallv2.json'\nimport erc20ABI from '../../../config/abi/erc20.json'\nimport { MULTICALL_V2 } from '../../../config/constants/addresses'\nimport { formatUnits } from '../../../utils/fixedPoint'\nimport type { TokenBalance } from '../../types'\nimport multicall, { Call } from '../utils/multicall'\n\n/** Balance of one token (or the native coin) on an EVM chain. */\nexport const getTokenBalanceEVM = async (chainId: ChainId, currency: 'NATIVE' | Token, account: string) => {\n const calls: Call[] = [\n {\n address: currency === 'NATIVE' ? MULTICALL_V2[chainId]! : currency.address[chainId]!,\n name: currency === 'NATIVE' ? 'getEthBalance' : 'balanceOf',\n params: [account],\n },\n ]\n const data = await multicall(chainId, currency === 'NATIVE' ? multicallV2Abi : erc20ABI, calls)\n return formatUnits(data[0][0] ?? 0, currency === 'NATIVE' ? 18 : currency.decimals![chainId]!)\n}\n\n/** Balances of several tokens (and/or the native coin) on an EVM chain, in two multicalls. */\nexport const getTokensBalanceEVM = async (\n chainId: ChainId,\n account: string,\n tokens: ('NATIVE' | Token)[],\n): Promise<TokenBalance[]> => {\n const callsToken: Call[] = tokens\n .filter((token) => token !== 'NATIVE')\n .map((token) => {\n return {\n address: token?.address?.[chainId] ?? '',\n name: 'balanceOf',\n params: [account],\n }\n })\n const callNative: Call[] = tokens\n .filter((token) => token === 'NATIVE')\n .map(() => {\n return {\n address: MULTICALL_V2[chainId]!,\n name: 'getEthBalance',\n params: [account],\n }\n })\n const [dataToken, dataNative] = await Promise.all([\n multicall(chainId, erc20ABI, callsToken),\n multicall(chainId, multicallV2Abi, callNative),\n ])\n\n const balancesToken = dataToken.map((balance: any, i: number) => {\n const token = tokens.find(\n (token) =>\n token !== 'NATIVE' &&\n (token as Token)?.address?.[chainId]?.toLowerCase() === callsToken[i].address.toLowerCase(),\n )\n return {\n address: (token as Token)?.address[chainId] as string,\n balance: formatUnits(balance[0], (token as Token).decimals![chainId]!),\n }\n })\n const balancesNative = dataNative.map((balance: any) => {\n return {\n address: 'NATIVE',\n balance: formatUnits(balance[0], 18),\n }\n })\n return [...balancesToken, ...balancesNative]\n}\n"],"names":[],"mappings":";;;;;;AAQA;AACO,MAAM,kBAAkB,GAAG,OAAO,OAAgB,EAAE,QAA0B,EAAE,OAAe,KAAI;AACxG,IAAA,MAAM,KAAK,GAAW;AACpB,QAAA;AACE,YAAA,OAAO,EAAE,QAAQ,KAAK,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAE;YACpF,IAAI,EAAE,QAAQ,KAAK,QAAQ,GAAG,eAAe,GAAG,WAAW;YAC3D,MAAM,EAAE,CAAC,OAAO,CAAC;AAClB,SAAA;KACF;IACD,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,OAAO,EAAE,QAAQ,KAAK,QAAQ,GAAG,cAAc,GAAG,QAAQ,EAAE,KAAK,CAAC;AAC/F,IAAA,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,QAAQ,KAAK,QAAQ,GAAG,EAAE,GAAG,QAAQ,CAAC,QAAS,CAAC,OAAO,CAAE,CAAC;AAChG;AAEA;AACO,MAAM,mBAAmB,GAAG,OACjC,OAAgB,EAChB,OAAe,EACf,MAA4B,KACD;IAC3B,MAAM,UAAU,GAAW;SACxB,MAAM,CAAC,CAAC,KAAK,KAAK,KAAK,KAAK,QAAQ;AACpC,SAAA,GAAG,CAAC,CAAC,KAAK,KAAI;QACb,OAAO;YACL,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE;AACxC,YAAA,IAAI,EAAE,WAAW;YACjB,MAAM,EAAE,CAAC,OAAO,CAAC;SAClB;AACH,IAAA,CAAC,CAAC;IACJ,MAAM,UAAU,GAAW;SACxB,MAAM,CAAC,CAAC,KAAK,KAAK,KAAK,KAAK,QAAQ;SACpC,GAAG,CAAC,MAAK;QACR,OAAO;AACL,YAAA,OAAO,EAAE,YAAY,CAAC,OAAO,CAAE;AAC/B,YAAA,IAAI,EAAE,eAAe;YACrB,MAAM,EAAE,CAAC,OAAO,CAAC;SAClB;AACH,IAAA,CAAC,CAAC;IACJ,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;AAChD,QAAA,SAAS,CAAC,OAAO,EAAE,QAAQ,EAAE,UAAU,CAAC;AACxC,QAAA,SAAS,CAAC,OAAO,EAAE,cAAc,EAAE,UAAU,CAAC;AAC/C,KAAA,CAAC;IAEF,MAAM,aAAa,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,OAAY,EAAE,CAAS,KAAI;AAC9D,QAAA,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CACvB,CAAC,KAAK,KACJ,KAAK,KAAK,QAAQ;YACjB,KAAe,EAAE,OAAO,GAAG,OAAO,CAAC,EAAE,WAAW,EAAE,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,CAC9F;QACD,OAAO;AACL,YAAA,OAAO,EAAG,KAAe,EAAE,OAAO,CAAC,OAAO,CAAW;AACrD,YAAA,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,EAAG,KAAe,CAAC,QAAS,CAAC,OAAO,CAAE,CAAC;SACvE;AACH,IAAA,CAAC,CAAC;IACF,MAAM,cAAc,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,OAAY,KAAI;QACrD,OAAO;AACL,YAAA,OAAO,EAAE,QAAQ;YACjB,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;SACrC;AACH,IAAA,CAAC,CAAC;AACF,IAAA,OAAO,CAAC,GAAG,aAAa,EAAE,GAAG,cAAc,CAAC;AAC9C;;;;"}
|
|
@@ -2,16 +2,78 @@ import { BillVersion } from '@ape.swap/apeswap-lists';
|
|
|
2
2
|
import multicall from '../utils/multicall.js';
|
|
3
3
|
import BOND_ABI from '../../../config/abi/BOND_2_4_0.json.js';
|
|
4
4
|
import erc20ABI from '../../../config/abi/erc20.json.js';
|
|
5
|
+
import APE_BOND_POSITION_ADAPTER_ABI from '../../../config/abi/apeBondPositionAdapter.json.js';
|
|
5
6
|
import chunk from 'lodash-es/chunk.js';
|
|
6
7
|
import { getBonusWithFee, getDiscountWithFee, getRawBonus, getRawDiscount } from '../../../state/bonds/fetchBondsData/bondPricing.js';
|
|
7
8
|
import { formatUnits } from '../../../utils/fixedPoint.js';
|
|
8
9
|
import { getBalanceNumber } from '../../../utils/getBalanceNumber.js';
|
|
9
10
|
import { TIER_MAPPING } from '../../../state/tiers/tiers.js';
|
|
10
11
|
import { resolveBondTokenPrices } from '../../../state/tokenPrices/resolveTokenPrice.js';
|
|
12
|
+
import { fetchLpStakingLimits } from './lpStaking/fetchLpStakingLimits.js';
|
|
11
13
|
|
|
14
|
+
/**
|
|
15
|
+
* LP staking bonds have no bond contract. The buyer's bonus is a share of the staked position's value, set per campaign
|
|
16
|
+
* on the bond's adapter: `campaigns(campaignId).bonusBps`. It's exposed as the bond's bonus so the UI shows it like any
|
|
17
|
+
* other bond's. The per-purchase and total limits come from the pool's price guard and the bonus escrow
|
|
18
|
+
* (fetchLpStakingLimits). Prices are still placeholder data.
|
|
19
|
+
*/
|
|
20
|
+
const fetchLpStakingBondsData = async (chainId, lpStakingBonds) => {
|
|
21
|
+
const bondsWithCampaign = lpStakingBonds.filter((bond) => bond.lpStakingConfig?.adapter && bond.lpStakingConfig?.campaignId);
|
|
22
|
+
const campaignCalls = bondsWithCampaign.map((bond) => ({
|
|
23
|
+
address: bond.lpStakingConfig.adapter,
|
|
24
|
+
name: 'campaigns',
|
|
25
|
+
params: [bond.lpStakingConfig.campaignId],
|
|
26
|
+
}));
|
|
27
|
+
const campaigns = campaignCalls.length > 0 ? await multicall(chainId, APE_BOND_POSITION_ADAPTER_ABI, campaignCalls) : [];
|
|
28
|
+
// campaigns() → (enabled, downTicks, upTicks, toleranceTicks, bonusCliffSeconds, bonusBps, minBonusAmount)
|
|
29
|
+
const getBonusBps = (bond) => {
|
|
30
|
+
const campaign = campaigns?.[bondsWithCampaign.indexOf(bond)];
|
|
31
|
+
return campaign ? Number(campaign[5]) : 0;
|
|
32
|
+
};
|
|
33
|
+
const limits = await Promise.all(lpStakingBonds.map((bond) => bondsWithCampaign.includes(bond)
|
|
34
|
+
? fetchLpStakingLimits(chainId, bond, getBonusBps(bond)).catch((e) => {
|
|
35
|
+
console.error(e);
|
|
36
|
+
return undefined;
|
|
37
|
+
})
|
|
38
|
+
: undefined));
|
|
39
|
+
return lpStakingBonds.map((bond, index) => {
|
|
40
|
+
const bonusBps = getBonusBps(bond);
|
|
41
|
+
const bonus = bonusBps / 100; // e.g. 1,000 bps → 10 %
|
|
42
|
+
// The bonus is computed on the position value after fees, so there's no separate "with fee" figure
|
|
43
|
+
const discount = bonus > 0 ? (bonus / (100 + bonus)) * 100 : 0;
|
|
44
|
+
return {
|
|
45
|
+
...bond,
|
|
46
|
+
soldOut: false,
|
|
47
|
+
feeInPayout: 0,
|
|
48
|
+
feeInPrincipal: 0,
|
|
49
|
+
trueBondPrices: [
|
|
50
|
+
{
|
|
51
|
+
points: '0',
|
|
52
|
+
boost: 0,
|
|
53
|
+
trueBondPrice: '0',
|
|
54
|
+
bonus,
|
|
55
|
+
bonusWithFee: bonus,
|
|
56
|
+
discount,
|
|
57
|
+
discountWithFee: discount,
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
principalTokenPrice: '0',
|
|
61
|
+
payoutTokenPrice: '0',
|
|
62
|
+
tokensRemaining: limits[index]?.tokensRemaining ?? '0',
|
|
63
|
+
maxTotalPayout: limits[index]?.maxTotalPayout ?? '0',
|
|
64
|
+
maxPayout: limits[index]?.maxPayout ?? '0',
|
|
65
|
+
totalPayoutGiven: limits[index]?.totalPayoutGiven ?? '0',
|
|
66
|
+
vestingTerm: 60 * 60 * 24 * 7, // 1 week
|
|
67
|
+
tierBoostRate: bond.tierBoostRate === undefined ? 1 : bond.tierBoostRate,
|
|
68
|
+
};
|
|
69
|
+
});
|
|
70
|
+
};
|
|
12
71
|
const fetchBondsDataEVM = async (chainId, bonds, apiUrl, tokenPrices) => {
|
|
13
72
|
try {
|
|
14
|
-
|
|
73
|
+
/** First we separate lpStakingBonds and bills. */
|
|
74
|
+
const lpStakingBonds = bonds.filter((b) => !b.soldOut && b.billType === 'lpStaking');
|
|
75
|
+
const lpStakingBondsData = lpStakingBonds.length > 0 ? await fetchLpStakingBondsData(chainId, lpStakingBonds) : [];
|
|
76
|
+
const bills = bonds.filter((b) => !b.soldOut && b.billType !== 'lpStaking');
|
|
15
77
|
const billIds = [];
|
|
16
78
|
const billCalls = bills.flatMap((bill) => {
|
|
17
79
|
billIds.push(bill.index);
|
|
@@ -76,7 +138,7 @@ const fetchBondsDataEVM = async (chainId, bonds, apiUrl, tokenPrices) => {
|
|
|
76
138
|
}, []);
|
|
77
139
|
const chunkSize = updatedVals?.length / bills?.length;
|
|
78
140
|
const chunkedBills = chunk(updatedVals, chunkSize);
|
|
79
|
-
|
|
141
|
+
const regularBondsData = await Promise.all(chunkedBills?.map(async (chunk, index) => {
|
|
80
142
|
const bill = bills?.find((bill) => bill?.index === billIds[index]);
|
|
81
143
|
const { lpPrice, earnTokenPrice } = await resolveBondTokenPrices(bill, tokenPrices);
|
|
82
144
|
const [trueBillPriceFromChunk, totalPayoutGiven, terms, maxTotalPayout, feeInPayoutRaw, feeInPrincipalRaw, paused, , customTreasuryBalance,] = chunk;
|
|
@@ -140,6 +202,7 @@ const fetchBondsDataEVM = async (chainId, bonds, apiUrl, tokenPrices) => {
|
|
|
140
202
|
};
|
|
141
203
|
return cleanedData;
|
|
142
204
|
}));
|
|
205
|
+
return [...lpStakingBondsData, ...regularBondsData];
|
|
143
206
|
}
|
|
144
207
|
catch (e) {
|
|
145
208
|
console.error(e);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetchBondsDataEVM.js","sources":["../../../../src/adapters/evm/state/fetchBondsDataEVM.ts"],"sourcesContent":["import { BillsConfig, BillVersion, ChainId } from '@ape.swap/apeswap-lists'\nimport { TokenPrices } from '../../../state/tokenPrices/useTokenPrices'\nimport multicall from '../utils/multicall'\nimport BOND_2_4_0 from '../../../config/abi/BOND_2_4_0.json'\nimport ERC20ABI from '../../../config/abi/erc20.json'\nimport chunk from 'lodash-es/chunk.js'\nimport {\n getBonusWithFee,\n getDiscountWithFee,\n getRawBonus,\n getRawDiscount,\n} from '../../../state/bonds/fetchBondsData/bondPricing'\nimport { formatUnits } from '../../../utils/fixedPoint'\nimport { getBalanceNumber } from '../../../utils/getBalanceNumber'\nimport { BondsData, TrueBondPrices } from '../../../types/bonds'\nimport { TIER_MAPPING } from '../../../state/tiers/tiers'\nimport { resolveBondTokenPrices } from '../../../state/tokenPrices/resolveTokenPrice'\n\nexport const fetchBondsDataEVM = async (\n chainId: number,\n bonds: BillsConfig[],\n apiUrl: string,\n tokenPrices?: TokenPrices[],\n) => {\n try {\n const bills = bonds.filter((b) => !b.soldOut)\n const billIds: number[] = []\n const billCalls = bills.flatMap((bill) => {\n billIds.push(bill.index)\n return [\n {\n address: bill.contractAddress[bill.chainId] ?? '',\n name: bill.billVersion === BillVersion.V4 ? 'trueBondPrices' : 'trueBillPrice()',\n },\n {\n address: bill.contractAddress[bill.chainId] ?? '',\n name: 'totalPayoutGiven',\n },\n {\n address: bill.contractAddress[bill.chainId] ?? '',\n name: 'terms',\n },\n {\n address: bill.contractAddress[bill.chainId] ?? '',\n name: bill.billVersion !== BillVersion.V1 ? 'getMaxTotalPayout' : 'maxTotalPayout',\n },\n {\n address: bill.contractAddress[bill.chainId] ?? '',\n name: 'feeInPayout',\n },\n {\n address: bill.contractAddress[bill.chainId] ?? '',\n name: 'feeInPrincipal',\n },\n {\n address: bill.contractAddress[bill.chainId] ?? '',\n name: 'paused',\n },\n // keep custom treasury at the very last position\n {\n address: bill.contractAddress[bill.chainId] ?? '',\n name: 'customTreasury',\n },\n ]\n })\n const vals = await multicall(chainId, BOND_2_4_0, billCalls)\n\n // The following lines basically grab the values from customTreasury returned from bills contract and then,\n // appends the treasury contract's balance to each bill's chunk\n\n // appendIndex value assumes customTreasury will be at the end of the billCalls array\n const appendIndex = billCalls.length / bills.length\n const treasuryAddresses = vals\n .filter((_: any, i: number) => (i % appendIndex) + 1 === appendIndex)\n .map((customTreasury: string[]) => customTreasury[0])\n const treasuryBalanceCalls = treasuryAddresses.map((treasuryAddress: string, i: number) => ({\n address: bills?.[i]?.earnToken?.address?.[chainId as ChainId] ?? '',\n name: 'balanceOf',\n params: [treasuryAddress],\n }))\n const treasuryBalances = await multicall(chainId, ERC20ABI, treasuryBalanceCalls)\n const updatedVals = vals.reduce((acc: any, val: any, index: number) => {\n acc.push(val)\n if ((index + 1) % appendIndex === 0) {\n const pos = (index + 1) / appendIndex\n // balanceOf has a single output, so multicall wraps it as [balance] — unwrap it\n acc.push(treasuryBalances[pos - 1][0])\n }\n return acc\n }, [])\n\n const chunkSize = updatedVals?.length / bills?.length\n const chunkedBills = chunk(updatedVals, chunkSize)\n\n return await Promise.all(\n chunkedBills?.map(async (chunk, index) => {\n const bill = bills?.find((bill) => bill?.index === billIds[index]) as BillsConfig\n\n const { lpPrice, earnTokenPrice } = await resolveBondTokenPrices(bill, tokenPrices)\n\n const [\n trueBillPriceFromChunk,\n totalPayoutGiven,\n terms,\n maxTotalPayout,\n feeInPayoutRaw,\n feeInPrincipalRaw,\n paused,\n ,\n customTreasuryBalance,\n ] = chunk as any\n const trueBillPrice = trueBillPriceFromChunk\n\n const feeInPayout = Number(feeInPayoutRaw / 10000)\n const feeInPrincipal = Number(feeInPrincipalRaw / 10000)\n const tierBoostRate = bill.tierBoostRate === undefined ? 1 : bill.tierBoostRate\n const [, vestingTerm, , maxPayout] = terms\n const tokensRemaining = Number(\n formatUnits(\n BigInt(maxTotalPayout ?? '0') - BigInt(totalPayoutGiven),\n bill?.earnToken.decimals[bill?.chainId] ?? 18,\n ),\n )\n const treasuryBalance = customTreasuryBalance\n ? getBalanceNumber(customTreasuryBalance, bill?.earnToken?.decimals?.[bill?.chainId] ?? 18)\n : null\n\n let trueBondPrices: TrueBondPrices[] = []\n if (bill?.billVersion === BillVersion.V4) {\n trueBondPrices = trueBillPrice[0].map((data: any) => {\n return {\n points: data?.points?.toString(),\n trueBondPrice: data?.trueBondPrice.toString(),\n discount: getRawDiscount(data?.trueBondPrice.toString(), lpPrice, earnTokenPrice),\n bonus: getRawBonus(data?.trueBondPrice.toString(), lpPrice, earnTokenPrice),\n discountWithFee: getDiscountWithFee(\n feeInPayout,\n tierBoostRate,\n data?.trueBondPrice.toString(),\n lpPrice,\n earnTokenPrice,\n ),\n bonusWithFee: getBonusWithFee(\n feeInPayout,\n tierBoostRate,\n data?.trueBondPrice.toString(),\n lpPrice,\n earnTokenPrice,\n ),\n boost: TIER_MAPPING[data?.points?.toString() as keyof typeof TIER_MAPPING],\n }\n })\n } else {\n const bonus = getRawBonus(trueBillPrice, lpPrice, earnTokenPrice)\n const bonusWithFee = getBonusWithFee(feeInPayout, tierBoostRate, trueBillPrice, lpPrice, earnTokenPrice)\n const discount = getRawDiscount(trueBillPrice, lpPrice, earnTokenPrice)\n const discountWithFee = getDiscountWithFee(feeInPayout, tierBoostRate, trueBillPrice, lpPrice, earnTokenPrice)\n trueBondPrices = [\n {\n points: '0',\n boost: 0,\n trueBondPrice: trueBillPrice.toString(),\n bonus,\n bonusWithFee,\n discount,\n discountWithFee,\n },\n ]\n }\n const cleanedData: BondsData = {\n ...bill,\n soldOut: paused[0] ? true : bill.soldOut,\n feeInPayout,\n feeInPrincipal,\n showcaseTokenName: bill?.showcaseToken?.symbol ?? bill?.earnToken.symbol ?? '',\n trueBondPrices,\n principalTokenPrice: lpPrice?.toString(),\n payoutTokenPrice: earnTokenPrice?.toString(),\n tokensRemaining:\n treasuryBalance !== null\n ? Math.min(treasuryBalance, tokensRemaining).toString()\n : tokensRemaining.toString(),\n maxTotalPayout: maxTotalPayout?.toString(),\n maxPayout: maxPayout?.toString(),\n totalPayoutGiven: totalPayoutGiven?.toString(),\n vestingTerm: typeof vestingTerm === 'number' ? vestingTerm : parseInt(vestingTerm),\n tierBoostRate: bill.tierBoostRate === undefined ? 1 : bill.tierBoostRate,\n }\n return cleanedData\n }),\n )\n } catch (e) {\n console.error(e)\n reportError({\n apiUrl,\n error: e,\n extraInfo: { type: 'getBondsData', e },\n })\n return []\n }\n}\n"],"names":["BOND_2_4_0","ERC20ABI"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"fetchBondsDataEVM.js","sources":["../../../../src/adapters/evm/state/fetchBondsDataEVM.ts"],"sourcesContent":["import { BillsConfig, BillVersion, ChainId } from '@ape.swap/apeswap-lists'\nimport { TokenPrices } from '../../../state/tokenPrices/useTokenPrices'\nimport multicall from '../utils/multicall'\nimport BOND_2_4_0 from '../../../config/abi/BOND_2_4_0.json'\nimport ERC20ABI from '../../../config/abi/erc20.json'\nimport APE_BOND_POSITION_ADAPTER_ABI from '../../../config/abi/apeBondPositionAdapter.json'\nimport chunk from 'lodash-es/chunk.js'\nimport {\n getBonusWithFee,\n getDiscountWithFee,\n getRawBonus,\n getRawDiscount,\n} from '../../../state/bonds/fetchBondsData/bondPricing'\nimport { formatUnits } from '../../../utils/fixedPoint'\nimport { getBalanceNumber } from '../../../utils/getBalanceNumber'\nimport { BondsData, TrueBondPrices } from '../../../types/bonds'\nimport { TIER_MAPPING } from '../../../state/tiers/tiers'\nimport { resolveBondTokenPrices } from '../../../state/tokenPrices/resolveTokenPrice'\nimport { fetchLpStakingLimits } from './lpStaking/fetchLpStakingLimits'\n\n/**\n * LP staking bonds have no bond contract. The buyer's bonus is a share of the staked position's value, set per campaign\n * on the bond's adapter: `campaigns(campaignId).bonusBps`. It's exposed as the bond's bonus so the UI shows it like any\n * other bond's. The per-purchase and total limits come from the pool's price guard and the bonus escrow\n * (fetchLpStakingLimits). Prices are still placeholder data.\n */\nconst fetchLpStakingBondsData = async (chainId: number, lpStakingBonds: BillsConfig[]): Promise<BondsData[]> => {\n const bondsWithCampaign = lpStakingBonds.filter(\n (bond) => bond.lpStakingConfig?.adapter && bond.lpStakingConfig?.campaignId,\n )\n const campaignCalls = bondsWithCampaign.map((bond) => ({\n address: bond.lpStakingConfig!.adapter,\n name: 'campaigns',\n params: [bond.lpStakingConfig!.campaignId],\n }))\n const campaigns =\n campaignCalls.length > 0 ? await multicall(chainId, APE_BOND_POSITION_ADAPTER_ABI, campaignCalls) : []\n\n // campaigns() → (enabled, downTicks, upTicks, toleranceTicks, bonusCliffSeconds, bonusBps, minBonusAmount)\n const getBonusBps = (bond: BillsConfig) => {\n const campaign = campaigns?.[bondsWithCampaign.indexOf(bond)]\n return campaign ? Number(campaign[5]) : 0\n }\n const limits = await Promise.all(\n lpStakingBonds.map((bond) =>\n bondsWithCampaign.includes(bond)\n ? fetchLpStakingLimits(chainId, bond, getBonusBps(bond)).catch((e) => {\n console.error(e)\n return undefined\n })\n : undefined,\n ),\n )\n\n return lpStakingBonds.map((bond, index) => {\n const bonusBps = getBonusBps(bond)\n const bonus = bonusBps / 100 // e.g. 1,000 bps → 10 %\n // The bonus is computed on the position value after fees, so there's no separate \"with fee\" figure\n const discount = bonus > 0 ? (bonus / (100 + bonus)) * 100 : 0\n return {\n ...bond,\n soldOut: false,\n feeInPayout: 0,\n feeInPrincipal: 0,\n trueBondPrices: [\n {\n points: '0',\n boost: 0,\n trueBondPrice: '0',\n bonus,\n bonusWithFee: bonus,\n discount,\n discountWithFee: discount,\n },\n ],\n principalTokenPrice: '0',\n payoutTokenPrice: '0',\n tokensRemaining: limits[index]?.tokensRemaining ?? '0',\n maxTotalPayout: limits[index]?.maxTotalPayout ?? '0',\n maxPayout: limits[index]?.maxPayout ?? '0',\n totalPayoutGiven: limits[index]?.totalPayoutGiven ?? '0',\n vestingTerm: 60 * 60 * 24 * 7, // 1 week\n tierBoostRate: bond.tierBoostRate === undefined ? 1 : bond.tierBoostRate,\n }\n })\n}\n\nexport const fetchBondsDataEVM = async (\n chainId: number,\n bonds: BillsConfig[],\n apiUrl: string,\n tokenPrices?: TokenPrices[],\n) => {\n try {\n /** First we separate lpStakingBonds and bills. */\n const lpStakingBonds = bonds.filter((b) => !b.soldOut && b.billType === 'lpStaking')\n const lpStakingBondsData = lpStakingBonds.length > 0 ? await fetchLpStakingBondsData(chainId, lpStakingBonds) : []\n\n const bills = bonds.filter((b) => !b.soldOut && b.billType !== 'lpStaking')\n const billIds: number[] = []\n const billCalls = bills.flatMap((bill) => {\n billIds.push(bill.index)\n return [\n {\n address: bill.contractAddress[bill.chainId] ?? '',\n name: bill.billVersion === BillVersion.V4 ? 'trueBondPrices' : 'trueBillPrice()',\n },\n {\n address: bill.contractAddress[bill.chainId] ?? '',\n name: 'totalPayoutGiven',\n },\n {\n address: bill.contractAddress[bill.chainId] ?? '',\n name: 'terms',\n },\n {\n address: bill.contractAddress[bill.chainId] ?? '',\n name: bill.billVersion !== BillVersion.V1 ? 'getMaxTotalPayout' : 'maxTotalPayout',\n },\n {\n address: bill.contractAddress[bill.chainId] ?? '',\n name: 'feeInPayout',\n },\n {\n address: bill.contractAddress[bill.chainId] ?? '',\n name: 'feeInPrincipal',\n },\n {\n address: bill.contractAddress[bill.chainId] ?? '',\n name: 'paused',\n },\n // keep custom treasury at the very last position\n {\n address: bill.contractAddress[bill.chainId] ?? '',\n name: 'customTreasury',\n },\n ]\n })\n const vals = await multicall(chainId, BOND_2_4_0, billCalls)\n\n // The following lines basically grab the values from customTreasury returned from bills contract and then,\n // appends the treasury contract's balance to each bill's chunk\n\n // appendIndex value assumes customTreasury will be at the end of the billCalls array\n const appendIndex = billCalls.length / bills.length\n const treasuryAddresses = vals\n .filter((_: any, i: number) => (i % appendIndex) + 1 === appendIndex)\n .map((customTreasury: string[]) => customTreasury[0])\n const treasuryBalanceCalls = treasuryAddresses.map((treasuryAddress: string, i: number) => ({\n address: bills?.[i]?.earnToken?.address?.[chainId as ChainId] ?? '',\n name: 'balanceOf',\n params: [treasuryAddress],\n }))\n const treasuryBalances = await multicall(chainId, ERC20ABI, treasuryBalanceCalls)\n const updatedVals = vals.reduce((acc: any, val: any, index: number) => {\n acc.push(val)\n if ((index + 1) % appendIndex === 0) {\n const pos = (index + 1) / appendIndex\n // balanceOf has a single output, so multicall wraps it as [balance] — unwrap it\n acc.push(treasuryBalances[pos - 1][0])\n }\n return acc\n }, [])\n\n const chunkSize = updatedVals?.length / bills?.length\n const chunkedBills = chunk(updatedVals, chunkSize)\n\n const regularBondsData = await Promise.all(\n chunkedBills?.map(async (chunk, index) => {\n const bill = bills?.find((bill) => bill?.index === billIds[index]) as BillsConfig\n\n const { lpPrice, earnTokenPrice } = await resolveBondTokenPrices(bill, tokenPrices)\n\n const [\n trueBillPriceFromChunk,\n totalPayoutGiven,\n terms,\n maxTotalPayout,\n feeInPayoutRaw,\n feeInPrincipalRaw,\n paused,\n ,\n customTreasuryBalance,\n ] = chunk as any\n const trueBillPrice = trueBillPriceFromChunk\n\n const feeInPayout = Number(feeInPayoutRaw / 10000)\n const feeInPrincipal = Number(feeInPrincipalRaw / 10000)\n const tierBoostRate = bill.tierBoostRate === undefined ? 1 : bill.tierBoostRate\n const [, vestingTerm, , maxPayout] = terms\n const tokensRemaining = Number(\n formatUnits(\n BigInt(maxTotalPayout ?? '0') - BigInt(totalPayoutGiven),\n bill?.earnToken.decimals[bill?.chainId] ?? 18,\n ),\n )\n const treasuryBalance = customTreasuryBalance\n ? getBalanceNumber(customTreasuryBalance, bill?.earnToken?.decimals?.[bill?.chainId] ?? 18)\n : null\n\n let trueBondPrices: TrueBondPrices[] = []\n if (bill?.billVersion === BillVersion.V4) {\n trueBondPrices = trueBillPrice[0].map((data: any) => {\n return {\n points: data?.points?.toString(),\n trueBondPrice: data?.trueBondPrice.toString(),\n discount: getRawDiscount(data?.trueBondPrice.toString(), lpPrice, earnTokenPrice),\n bonus: getRawBonus(data?.trueBondPrice.toString(), lpPrice, earnTokenPrice),\n discountWithFee: getDiscountWithFee(\n feeInPayout,\n tierBoostRate,\n data?.trueBondPrice.toString(),\n lpPrice,\n earnTokenPrice,\n ),\n bonusWithFee: getBonusWithFee(\n feeInPayout,\n tierBoostRate,\n data?.trueBondPrice.toString(),\n lpPrice,\n earnTokenPrice,\n ),\n boost: TIER_MAPPING[data?.points?.toString() as keyof typeof TIER_MAPPING],\n }\n })\n } else {\n const bonus = getRawBonus(trueBillPrice, lpPrice, earnTokenPrice)\n const bonusWithFee = getBonusWithFee(feeInPayout, tierBoostRate, trueBillPrice, lpPrice, earnTokenPrice)\n const discount = getRawDiscount(trueBillPrice, lpPrice, earnTokenPrice)\n const discountWithFee = getDiscountWithFee(feeInPayout, tierBoostRate, trueBillPrice, lpPrice, earnTokenPrice)\n trueBondPrices = [\n {\n points: '0',\n boost: 0,\n trueBondPrice: trueBillPrice.toString(),\n bonus,\n bonusWithFee,\n discount,\n discountWithFee,\n },\n ]\n }\n const cleanedData: BondsData = {\n ...bill,\n soldOut: paused[0] ? true : bill.soldOut,\n feeInPayout,\n feeInPrincipal,\n showcaseTokenName: bill?.showcaseToken?.symbol ?? bill?.earnToken.symbol ?? '',\n trueBondPrices,\n principalTokenPrice: lpPrice?.toString(),\n payoutTokenPrice: earnTokenPrice?.toString(),\n tokensRemaining:\n treasuryBalance !== null\n ? Math.min(treasuryBalance, tokensRemaining).toString()\n : tokensRemaining.toString(),\n maxTotalPayout: maxTotalPayout?.toString(),\n maxPayout: maxPayout?.toString(),\n totalPayoutGiven: totalPayoutGiven?.toString(),\n vestingTerm: typeof vestingTerm === 'number' ? vestingTerm : parseInt(vestingTerm),\n tierBoostRate: bill.tierBoostRate === undefined ? 1 : bill.tierBoostRate,\n }\n return cleanedData\n }),\n )\n return [...lpStakingBondsData, ...regularBondsData]\n } catch (e) {\n console.error(e)\n reportError({\n apiUrl,\n error: e,\n extraInfo: { type: 'getBondsData', e },\n })\n return []\n }\n}\n"],"names":["BOND_2_4_0","ERC20ABI"],"mappings":"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"}
|
|
@@ -3,13 +3,15 @@ import multicall from '../utils/multicall.js';
|
|
|
3
3
|
import { BillVersion } from '@ape.swap/apeswap-lists';
|
|
4
4
|
import { apiGet } from '../../../utils/httpClient.js';
|
|
5
5
|
import { PRICE_API_URL } from '../../../config/constants/variables.js';
|
|
6
|
+
import partition from 'lodash-es/partition.js';
|
|
7
|
+
import APE_BOND_POSITION_ADAPTER_ABI from '../../../config/abi/apeBondPositionAdapter.json.js';
|
|
6
8
|
|
|
7
9
|
const fetchUsersBondsEVM = async (chainId, account, bondData, tokenPrices) => {
|
|
8
10
|
try {
|
|
9
11
|
if (!account) {
|
|
10
12
|
return [];
|
|
11
13
|
}
|
|
12
|
-
const bonds = bondData;
|
|
14
|
+
const [lpStakingBonds, bonds] = partition(bondData, (bond) => bond.billType === 'lpStaking');
|
|
13
15
|
// Fetch and set user owned bill data without NFT Data
|
|
14
16
|
const userOwnedBills = await fetchUserOwnedBills(chainId, account, bonds, tokenPrices);
|
|
15
17
|
const mapUserOwnedBills = bonds.map((bill) => userOwnedBills.filter((b) => b.address.toLowerCase() === bill.contractAddress[bill.chainId]?.toLowerCase()));
|
|
@@ -28,13 +30,243 @@ const fetchUsersBondsEVM = async (chainId, account, bondData, tokenPrices) => {
|
|
|
28
30
|
userOwnedBills: enrichedUserBills,
|
|
29
31
|
};
|
|
30
32
|
});
|
|
31
|
-
|
|
33
|
+
const lpStakingData = lpStakingBonds.length > 0 ? await fetchUserLpStakingBonds(chainId, account, lpStakingBonds) : [];
|
|
34
|
+
return Promise.resolve([...combinedData, ...lpStakingData]);
|
|
32
35
|
}
|
|
33
36
|
catch (error) {
|
|
34
37
|
console.error('Error fetching user owned bills data:', error);
|
|
35
38
|
return Promise.reject(error);
|
|
36
39
|
}
|
|
37
40
|
};
|
|
41
|
+
// REAL's API only answers browsers from origins it allowlists, so it's called through ape.bond's proxy, which
|
|
42
|
+
// forwards to REAL's API (test stack or mainnet, set on ape.bond's side).
|
|
43
|
+
// TODO: staging proxy for now; switch to the production one (https://ape.bond/api/real-lp) once it's deployed.
|
|
44
|
+
const REAL_LP_API = 'https://staging.ape.bond/api/real-lp';
|
|
45
|
+
// A position's page on REAL's site, where its bonus and pool rewards are claimed.
|
|
46
|
+
// TODO: test site for now; REAL will send the production URL when mainnet is live.
|
|
47
|
+
const REAL_LP_DASHBOARD = 'https://staking-test.real.finance/lp/dashboard';
|
|
48
|
+
/**
|
|
49
|
+
* Raw token amounts (wei) a Uniswap v3 position holds at the pool's current tick: all token0 below its range, all
|
|
50
|
+
* token1 above it, both inside. Floating point: it's for display only.
|
|
51
|
+
*/
|
|
52
|
+
const getPositionAmounts = (liquidity, tickLower, tickUpper, currentTick) => {
|
|
53
|
+
const sqrtPrice = (tick) => Math.pow(1.0001, tick / 2);
|
|
54
|
+
const sqrtLower = sqrtPrice(tickLower);
|
|
55
|
+
const sqrtUpper = sqrtPrice(tickUpper);
|
|
56
|
+
const sqrtCurrent = sqrtPrice(Math.min(Math.max(currentTick, tickLower), tickUpper));
|
|
57
|
+
return {
|
|
58
|
+
amount0: (liquidity * (sqrtUpper - sqrtCurrent)) / (sqrtCurrent * sqrtUpper),
|
|
59
|
+
amount1: liquidity * (sqrtCurrent - sqrtLower),
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* The user's LP staking positions, shaped as purchased bonds. A position has no bill: it's a Uniswap v3 NFT staked
|
|
64
|
+
* in REAL's vault, and what ApeBond pays is its bonus, reserved in REAL's escrow until the cliff. So each position
|
|
65
|
+
* becomes one bill whose payout is that bonus, vesting all at once at the cliff (`vestingCliff` = `vestingTerm`).
|
|
66
|
+
* Claims happen on REAL's site, so the bills are marked paused (the row's claim button would call `redeem` on the
|
|
67
|
+
* vault). See docs/lp-staking-bonds/2026-10-23-real-lp-positions-rewards-api.md.
|
|
68
|
+
*/
|
|
69
|
+
const fetchUserLpStakingBonds = async (chainId, account, lpStakingBonds) => {
|
|
70
|
+
let rows;
|
|
71
|
+
let assetPriceUsd;
|
|
72
|
+
let assetIsToken0 = true;
|
|
73
|
+
let currentTick = 0;
|
|
74
|
+
let rewards;
|
|
75
|
+
try {
|
|
76
|
+
const [response, rewardsResponse] = await Promise.all([
|
|
77
|
+
apiGet(`${REAL_LP_API}/positions/${account}`),
|
|
78
|
+
// The positions still show without their pool rewards if this fails
|
|
79
|
+
apiGet(`${REAL_LP_API}/rewards/${account}`).catch((error) => {
|
|
80
|
+
console.error('Error fetching LP staking rewards:', error);
|
|
81
|
+
return undefined;
|
|
82
|
+
}),
|
|
83
|
+
]);
|
|
84
|
+
rewards = rewardsResponse;
|
|
85
|
+
rows = response?.positions ?? [];
|
|
86
|
+
assetPriceUsd = response?.current_price_usd;
|
|
87
|
+
assetIsToken0 = response?.asset_is_token0 ?? true;
|
|
88
|
+
currentTick = response?.current_tick ?? 0;
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
// Don't fail the chain's regular bonds because REAL's API is unreachable (or refuses our origin)
|
|
92
|
+
console.error('Error fetching LP staking positions:', error);
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
// All episodes of a position share its lineage_id; the one with no next episode is its current state.
|
|
96
|
+
// Only positions bought through ApeBond have an apebond block.
|
|
97
|
+
const currentPositions = rows.filter((row) => row.apebond && row.next_episode_id === null);
|
|
98
|
+
// Each campaign's bonus rate and minimum bonus, for the minimum position value that earns a bonus.
|
|
99
|
+
// campaigns() → (enabled, downTicks, upTicks, toleranceTicks, bonusCliffSeconds, bonusBps, minBonusAmount)
|
|
100
|
+
const campaigns = await multicall(chainId, APE_BOND_POSITION_ADAPTER_ABI, lpStakingBonds.map((bond) => ({
|
|
101
|
+
address: bond.lpStakingConfig.adapter,
|
|
102
|
+
name: 'campaigns',
|
|
103
|
+
params: [bond.lpStakingConfig.campaignId],
|
|
104
|
+
})));
|
|
105
|
+
return lpStakingBonds.map((bond, bondIndex) => {
|
|
106
|
+
const lpStakingConfig = bond.lpStakingConfig;
|
|
107
|
+
const campaign = campaigns?.[bondIndex];
|
|
108
|
+
const bonusDecimals = lpStakingConfig.bonusRewardToken.decimals[bond.chainId] ?? 18;
|
|
109
|
+
const bonusThreshold = campaign && Number(campaign[5]) > 0
|
|
110
|
+
? (Number(campaign[6]) / 10 ** bonusDecimals) * (10000 / Number(campaign[5]))
|
|
111
|
+
: undefined;
|
|
112
|
+
const userOwnedBills = currentPositions
|
|
113
|
+
.filter((row) => row.apebond.campaign_id.toLowerCase() === lpStakingConfig.campaignId.toLowerCase())
|
|
114
|
+
.map((row) => {
|
|
115
|
+
const { deposited_at: depositedAt, bonus } = row.apebond;
|
|
116
|
+
// No bonus when the purchase was below the campaign minimum; forfeited bonuses have amount 0
|
|
117
|
+
const amount = bonus?.amount_wei ?? '0';
|
|
118
|
+
const cliff = bonus ? bonus.unlock_at - depositedAt : 0;
|
|
119
|
+
const chainId = bond.chainId;
|
|
120
|
+
const bonusToken = lpStakingConfig.bonusRewardToken;
|
|
121
|
+
// The pool is the bonus token ($ASSET) paired with the bond's principal token (USDC)
|
|
122
|
+
const assetToken = {
|
|
123
|
+
address: bonusToken.address[chainId] ?? '',
|
|
124
|
+
symbol: bonusToken.symbol,
|
|
125
|
+
name: bonusToken.symbol,
|
|
126
|
+
decimals: bonusToken.decimals,
|
|
127
|
+
};
|
|
128
|
+
const pairedToken = {
|
|
129
|
+
address: bond.lpToken.address[chainId] ?? '',
|
|
130
|
+
symbol: bond.lpToken.symbol,
|
|
131
|
+
name: bond.lpToken.symbol,
|
|
132
|
+
decimals: bond.lpToken.decimals,
|
|
133
|
+
};
|
|
134
|
+
// Value of the position when it was staked: what the buyer paid, minus the zap fees and the change returned
|
|
135
|
+
const principalUsd = parseFloat(row.principal_usd ?? '0');
|
|
136
|
+
// Value of the position now (null once unstaked: the vault no longer holds it)
|
|
137
|
+
const valueUsdNow = parseFloat(row.value_usd_now ?? '0');
|
|
138
|
+
const assetPrice = parseFloat(assetPriceUsd ?? '0');
|
|
139
|
+
// What the staked position holds now. An unstaked position is back in the wallet, so nothing is staked.
|
|
140
|
+
// current_price_usd is $ASSET's price in USDC, and USDC is counted at $1 (as REAL's value_usd_now does).
|
|
141
|
+
const { amount0, amount1 } = row.status === 'unstaked'
|
|
142
|
+
? { amount0: 0, amount1: 0 }
|
|
143
|
+
: getPositionAmounts(parseFloat(row.liquidity_wei), row.tick_lower, row.tick_upper, currentTick);
|
|
144
|
+
const [token0, token1] = assetIsToken0 ? [assetToken, pairedToken] : [pairedToken, assetToken];
|
|
145
|
+
const toStakedToken = (token, rawAmount) => {
|
|
146
|
+
const amount = rawAmount / 10 ** (token.decimals[chainId] ?? 18);
|
|
147
|
+
return {
|
|
148
|
+
address: token.address,
|
|
149
|
+
symbol: token.symbol,
|
|
150
|
+
amount,
|
|
151
|
+
amountUsd: amount * (token === assetToken ? assetPrice : 1),
|
|
152
|
+
};
|
|
153
|
+
};
|
|
154
|
+
return {
|
|
155
|
+
// Rows are matched to their bond by contract address; for LP staking that's the vault
|
|
156
|
+
address: bond.contractAddress[bond.chainId] ?? '',
|
|
157
|
+
// The position's current NFT, the one REAL's page link uses. After a rebalance past the cliff the escrow
|
|
158
|
+
// still pays on the NFT id the position had at the cliff (bonus.token_id), which has no field here.
|
|
159
|
+
id: row.token_id,
|
|
160
|
+
// The NFT contract is the position manager. The price range (price_lower_usd / price_upper_usd,
|
|
161
|
+
// range_status_now) has no field.
|
|
162
|
+
// Neither do the position's status (an unstaked position still shows, with its bonus as the API reports
|
|
163
|
+
// it) and `finalized` (false for ~13 min after a purchase).
|
|
164
|
+
billNftAddress: lpStakingConfig.positionManager,
|
|
165
|
+
totalPayout: amount,
|
|
166
|
+
// What's left to receive: everything until it's claimed (or forfeited, where amount is 0)
|
|
167
|
+
payout: bonus?.status === 'claimed' ? '0' : amount,
|
|
168
|
+
pendingRewards: bonus?.status === 'claimable' ? amount : '0',
|
|
169
|
+
payoutClaimed: bonus?.status === 'claimed' ? amount : '0',
|
|
170
|
+
vestingStartTimestamp: depositedAt.toString(),
|
|
171
|
+
vestingTerm: cliff.toString(),
|
|
172
|
+
lastBlockTimestamp: (bonus?.claimed_at ?? depositedAt).toString(),
|
|
173
|
+
// No price per payout token: the bonus is a share of the position's value
|
|
174
|
+
truePricePaid: '0',
|
|
175
|
+
paused: true,
|
|
176
|
+
lpStakingData: {
|
|
177
|
+
token0: toStakedToken(token0, amount0),
|
|
178
|
+
token1: toStakedToken(token1, amount1),
|
|
179
|
+
bonusStatus: bonus?.status ?? null,
|
|
180
|
+
bonusThreshold,
|
|
181
|
+
// The position's page on REAL's site. The ordinal is only appended from 2 on (an NFT staked again by
|
|
182
|
+
// hand after an unstake); older ids of the lineage redirect to the current one.
|
|
183
|
+
positionUrl: `${REAL_LP_DASHBOARD}/${row.token_id}${row.stake_ordinal >= 2 ? `-${row.stake_ordinal}` : ''}`,
|
|
184
|
+
// Matched by lineage_id, shared by every episode of the position (it survives rebalances)
|
|
185
|
+
poolRewards: rewards
|
|
186
|
+
? rewards.tokens.map((rewardToken) => {
|
|
187
|
+
const positionToken = rewards.positions
|
|
188
|
+
.find((position) => position.lineage_id === row.lineage_id)
|
|
189
|
+
?.tokens.find((token) => token.token.toLowerCase() === rewardToken.token.toLowerCase());
|
|
190
|
+
// claimable_wei is what's earned and not claimed yet; $ASSET can't be claimed before
|
|
191
|
+
// claims_enabled (mainnet launch + REAL's timelock)
|
|
192
|
+
const rewardAmount = Number(positionToken?.claimable_wei ?? '0') / 10 ** rewardToken.decimals;
|
|
193
|
+
return {
|
|
194
|
+
address: rewardToken.token,
|
|
195
|
+
symbol: rewardToken.symbol,
|
|
196
|
+
amount: rewardAmount,
|
|
197
|
+
// Only $ASSET has a price (current_price_usd); REAL's API doesn't price $OVTR
|
|
198
|
+
amountUsd: rewardToken.token.toLowerCase() === assetToken.address.toLowerCase()
|
|
199
|
+
? rewardAmount * assetPrice
|
|
200
|
+
: undefined,
|
|
201
|
+
claimsEnabled: rewardToken.claims_enabled,
|
|
202
|
+
};
|
|
203
|
+
})
|
|
204
|
+
: undefined,
|
|
205
|
+
},
|
|
206
|
+
// What api-v2 provides for regular bills, here from REAL's API (useUserBonds doesn't send LP staking
|
|
207
|
+
// bills to api-v2)
|
|
208
|
+
nftData: {
|
|
209
|
+
tokenId: parseInt(row.token_id),
|
|
210
|
+
billNftId: parseInt(row.token_id),
|
|
211
|
+
processing: false,
|
|
212
|
+
// The position NFT is a Uniswap v3 position with no bond art
|
|
213
|
+
image: 'https://www.ape.bond/images/bills/hidden-bill.jpg',
|
|
214
|
+
chainId,
|
|
215
|
+
contractAddress: lpStakingConfig.positionManager,
|
|
216
|
+
data: {
|
|
217
|
+
billContract: bond.contractAddress[chainId] ?? '',
|
|
218
|
+
billNftAddress: lpStakingConfig.positionManager,
|
|
219
|
+
billNftId: parseInt(row.token_id),
|
|
220
|
+
// Not in REAL's API
|
|
221
|
+
blockNumber: 0,
|
|
222
|
+
bondArtCollection: '',
|
|
223
|
+
bondPartner: bond.bondPartner ?? '',
|
|
224
|
+
bondVersion: bond.billVersion ?? '',
|
|
225
|
+
chainId,
|
|
226
|
+
// The purchase opened the position's first episode, whose id is <token_id>-<opening tx hash>
|
|
227
|
+
createTransactionHash: row.lineage_id.split('-')[1] ?? '',
|
|
228
|
+
createdAddressOwner: account,
|
|
229
|
+
createdAt: depositedAt,
|
|
230
|
+
// The amount paid isn't in REAL's API (only in the purchase tx). The principal token is USDC, so the
|
|
231
|
+
// position's USD value at purchase stands in for it.
|
|
232
|
+
deposit: principalUsd,
|
|
233
|
+
dollarValue: principalUsd,
|
|
234
|
+
expires: depositedAt + cliff,
|
|
235
|
+
pairName: assetIsToken0
|
|
236
|
+
? `${assetToken.symbol}-${pairedToken.symbol}`
|
|
237
|
+
: `${pairedToken.symbol}-${assetToken.symbol}`,
|
|
238
|
+
// The position's current value (used by the share image), in $ASSET (the payout token) so that
|
|
239
|
+
// payout × payoutTokenPrice gives value_usd_now back. The bonus itself is in the bill's payout fields.
|
|
240
|
+
payout: assetPrice > 0 ? valueUsdNow / assetPrice : 0,
|
|
241
|
+
payoutToken: assetToken.address,
|
|
242
|
+
payoutTokenData: {
|
|
243
|
+
address: assetToken.address,
|
|
244
|
+
name: assetToken.name,
|
|
245
|
+
symbol: assetToken.symbol,
|
|
246
|
+
decimals: assetToken.decimals,
|
|
247
|
+
},
|
|
248
|
+
payoutTokenPrice: assetPriceUsd ?? '0',
|
|
249
|
+
principalToken: pairedToken.address,
|
|
250
|
+
token0: assetIsToken0 ? assetToken : pairedToken,
|
|
251
|
+
token1: assetIsToken0 ? pairedToken : assetToken,
|
|
252
|
+
type: bond.billType,
|
|
253
|
+
vestingPeriodSeconds: cliff,
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
// The bonus is paid in the bonus token, not the bond's earnToken, and only unlocks at the cliff.
|
|
257
|
+
// The $OVTR and $ASSET staking rewards (REAL's /rewards/<wallet>) have no field.
|
|
258
|
+
bond: {
|
|
259
|
+
...bond,
|
|
260
|
+
earnToken: lpStakingConfig.bonusRewardToken,
|
|
261
|
+
vestingCliff: cliff,
|
|
262
|
+
vestingTerm: cliff,
|
|
263
|
+
payoutTokenPrice: assetPriceUsd,
|
|
264
|
+
},
|
|
265
|
+
};
|
|
266
|
+
});
|
|
267
|
+
return { index: bond.index, userOwnedBills };
|
|
268
|
+
});
|
|
269
|
+
};
|
|
38
270
|
const fetchUserOwnedBills = async (chainId, account, bonds, tokenPrices) => {
|
|
39
271
|
// Maps all the bills in the list repo to make a call to each of them to get Bills Id and paused state (only for V4)
|
|
40
272
|
const billIdAndPausedCalls = bonds.flatMap((b, index) => {
|