@oydual31/more-vaults-sdk 0.3.0 → 0.3.2
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/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +1 -1
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.js.map +1 -1
- package/dist/{spokeRoutes-FgKCJQYa.d.cts → spokeRoutes-DK7cIW4z.d.cts} +4 -0
- package/dist/{spokeRoutes-FgKCJQYa.d.ts → spokeRoutes-DK7cIW4z.d.ts} +4 -0
- package/dist/viem/index.cjs +450 -5
- package/dist/viem/index.cjs.map +1 -1
- package/dist/viem/index.d.cts +396 -3
- package/dist/viem/index.d.ts +396 -3
- package/dist/viem/index.js +438 -7
- package/dist/viem/index.js.map +1 -1
- package/package.json +1 -1
- package/src/viem/abis.ts +51 -0
- package/src/viem/chains.ts +17 -0
- package/src/viem/curatorMulticall.ts +299 -0
- package/src/viem/curatorStatus.ts +197 -2
- package/src/viem/curatorSwaps.ts +239 -0
- package/src/viem/index.ts +22 -1
- package/src/viem/types.ts +38 -0
- package/src/viem/userHelpers.ts +22 -6
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Curator swap helpers for Uniswap V3-compatible DEXes.
|
|
3
|
+
*
|
|
4
|
+
* Provides typed helpers to build CuratorAction objects and raw calldata for
|
|
5
|
+
* Uniswap V3 exactInputSingle swaps, automatically resolving the correct router
|
|
6
|
+
* and ABI variant (SwapRouter vs SwapRouter02) per chain.
|
|
7
|
+
*
|
|
8
|
+
* Supported chains and routers:
|
|
9
|
+
* - Base (8453): SwapRouter02 0x2626... — NO deadline field
|
|
10
|
+
* - Ethereum (1): SwapRouter 0xE592... — HAS deadline field
|
|
11
|
+
* - Arbitrum (42161): SwapRouter 0xE592... — HAS deadline field
|
|
12
|
+
* - Optimism (10): SwapRouter 0xE592... — HAS deadline field
|
|
13
|
+
* - Flow EVM (747): FlowSwap V3 0xeEDC... — HAS deadline field
|
|
14
|
+
*
|
|
15
|
+
* @module curatorSwaps
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { type Address, encodeFunctionData } from 'viem'
|
|
19
|
+
import { UNISWAP_V3_ROUTERS } from './chains.js'
|
|
20
|
+
import type { CuratorAction } from './types.js'
|
|
21
|
+
|
|
22
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
23
|
+
// ABI constants
|
|
24
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Uniswap V3 SwapRouter exactInputSingle ABI.
|
|
28
|
+
* Used for: Ethereum (1), Arbitrum (42161), Optimism (10), Flow EVM (747).
|
|
29
|
+
* Struct includes `deadline` field.
|
|
30
|
+
*/
|
|
31
|
+
const UNISWAP_V3_SWAP_ROUTER_ABI = [
|
|
32
|
+
{
|
|
33
|
+
type: 'function',
|
|
34
|
+
name: 'exactInputSingle',
|
|
35
|
+
inputs: [
|
|
36
|
+
{
|
|
37
|
+
type: 'tuple',
|
|
38
|
+
name: 'params',
|
|
39
|
+
components: [
|
|
40
|
+
{ name: 'tokenIn', type: 'address' },
|
|
41
|
+
{ name: 'tokenOut', type: 'address' },
|
|
42
|
+
{ name: 'fee', type: 'uint24' },
|
|
43
|
+
{ name: 'recipient', type: 'address' },
|
|
44
|
+
{ name: 'deadline', type: 'uint256' },
|
|
45
|
+
{ name: 'amountIn', type: 'uint256' },
|
|
46
|
+
{ name: 'amountOutMinimum', type: 'uint256' },
|
|
47
|
+
{ name: 'sqrtPriceLimitX96', type: 'uint160' },
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
outputs: [{ name: 'amountOut', type: 'uint256' }],
|
|
52
|
+
stateMutability: 'payable',
|
|
53
|
+
},
|
|
54
|
+
] as const
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Uniswap V3 SwapRouter02 exactInputSingle ABI.
|
|
58
|
+
* Used for: Base (8453).
|
|
59
|
+
* Struct does NOT include `deadline` field — SwapRouter02 removed it.
|
|
60
|
+
*/
|
|
61
|
+
const UNISWAP_V3_SWAP_ROUTER02_ABI = [
|
|
62
|
+
{
|
|
63
|
+
type: 'function',
|
|
64
|
+
name: 'exactInputSingle',
|
|
65
|
+
inputs: [
|
|
66
|
+
{
|
|
67
|
+
type: 'tuple',
|
|
68
|
+
name: 'params',
|
|
69
|
+
components: [
|
|
70
|
+
{ name: 'tokenIn', type: 'address' },
|
|
71
|
+
{ name: 'tokenOut', type: 'address' },
|
|
72
|
+
{ name: 'fee', type: 'uint24' },
|
|
73
|
+
{ name: 'recipient', type: 'address' },
|
|
74
|
+
{ name: 'amountIn', type: 'uint256' },
|
|
75
|
+
{ name: 'amountOutMinimum', type: 'uint256' },
|
|
76
|
+
{ name: 'sqrtPriceLimitX96', type: 'uint160' },
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
outputs: [{ name: 'amountOut', type: 'uint256' }],
|
|
81
|
+
stateMutability: 'payable',
|
|
82
|
+
},
|
|
83
|
+
] as const
|
|
84
|
+
|
|
85
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
86
|
+
// Chain variant detection
|
|
87
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Chains that use SwapRouter02 (no deadline in struct).
|
|
91
|
+
* All other chains in UNISWAP_V3_ROUTERS use the original SwapRouter.
|
|
92
|
+
*/
|
|
93
|
+
const SWAP_ROUTER02_CHAINS = new Set([8453])
|
|
94
|
+
|
|
95
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
96
|
+
// Calldata encoding
|
|
97
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Encode Uniswap V3 exactInputSingle calldata directly.
|
|
101
|
+
* For curators who want raw calldata without the CuratorAction wrapper.
|
|
102
|
+
*
|
|
103
|
+
* Automatically selects the correct ABI variant (SwapRouter vs SwapRouter02)
|
|
104
|
+
* based on the chainId. The deadline (for SwapRouter chains) is set to
|
|
105
|
+
* `now + 20 minutes` to prevent stale transactions from executing.
|
|
106
|
+
*
|
|
107
|
+
* @param params.chainId EVM chain ID — must be present in UNISWAP_V3_ROUTERS
|
|
108
|
+
* @param params.tokenIn Input token address
|
|
109
|
+
* @param params.tokenOut Output token address
|
|
110
|
+
* @param params.fee Pool fee tier: 100, 500, 3000, or 10000
|
|
111
|
+
* @param params.amountIn Exact input amount (in tokenIn units)
|
|
112
|
+
* @param params.minAmountOut Minimum acceptable output (slippage protection)
|
|
113
|
+
* @param params.recipient Address to receive the output tokens (usually the vault)
|
|
114
|
+
* @returns The router contract address and ABI-encoded calldata
|
|
115
|
+
* @throws If no router is configured for the given chainId
|
|
116
|
+
*/
|
|
117
|
+
export function encodeUniswapV3SwapCalldata(params: {
|
|
118
|
+
chainId: number
|
|
119
|
+
tokenIn: Address
|
|
120
|
+
tokenOut: Address
|
|
121
|
+
fee: number
|
|
122
|
+
amountIn: bigint
|
|
123
|
+
minAmountOut: bigint
|
|
124
|
+
recipient: Address
|
|
125
|
+
}): { targetContract: Address; swapCallData: `0x${string}` } {
|
|
126
|
+
const { chainId, tokenIn, tokenOut, fee, amountIn, minAmountOut, recipient } = params
|
|
127
|
+
|
|
128
|
+
const router = UNISWAP_V3_ROUTERS[chainId]
|
|
129
|
+
if (!router) {
|
|
130
|
+
throw new Error(
|
|
131
|
+
`[MoreVaults] No Uniswap V3 router configured for chainId ${chainId}. ` +
|
|
132
|
+
`Supported chains: ${Object.keys(UNISWAP_V3_ROUTERS).join(', ')}`
|
|
133
|
+
)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
let swapCallData: `0x${string}`
|
|
137
|
+
|
|
138
|
+
if (SWAP_ROUTER02_CHAINS.has(chainId)) {
|
|
139
|
+
// SwapRouter02 (Base) — no deadline field
|
|
140
|
+
swapCallData = encodeFunctionData({
|
|
141
|
+
abi: UNISWAP_V3_SWAP_ROUTER02_ABI,
|
|
142
|
+
functionName: 'exactInputSingle',
|
|
143
|
+
args: [
|
|
144
|
+
{
|
|
145
|
+
tokenIn,
|
|
146
|
+
tokenOut,
|
|
147
|
+
fee,
|
|
148
|
+
recipient,
|
|
149
|
+
amountIn,
|
|
150
|
+
amountOutMinimum: minAmountOut,
|
|
151
|
+
sqrtPriceLimitX96: 0n,
|
|
152
|
+
},
|
|
153
|
+
],
|
|
154
|
+
})
|
|
155
|
+
} else {
|
|
156
|
+
// Original SwapRouter (Eth/Arb/Op/Flow EVM) — has deadline field
|
|
157
|
+
const deadline = BigInt(Math.floor(Date.now() / 1000) + 1200) // now + 20 minutes
|
|
158
|
+
swapCallData = encodeFunctionData({
|
|
159
|
+
abi: UNISWAP_V3_SWAP_ROUTER_ABI,
|
|
160
|
+
functionName: 'exactInputSingle',
|
|
161
|
+
args: [
|
|
162
|
+
{
|
|
163
|
+
tokenIn,
|
|
164
|
+
tokenOut,
|
|
165
|
+
fee,
|
|
166
|
+
recipient,
|
|
167
|
+
deadline,
|
|
168
|
+
amountIn,
|
|
169
|
+
amountOutMinimum: minAmountOut,
|
|
170
|
+
sqrtPriceLimitX96: 0n,
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
})
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return { targetContract: router, swapCallData }
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
180
|
+
// CuratorAction builder
|
|
181
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Build a CuratorAction for a Uniswap V3 exactInputSingle swap.
|
|
185
|
+
*
|
|
186
|
+
* Automatically resolves the router address from UNISWAP_V3_ROUTERS and
|
|
187
|
+
* selects the correct ABI struct (with or without deadline) based on chainId.
|
|
188
|
+
*
|
|
189
|
+
* The returned action is a `swap` variant ready to be passed to
|
|
190
|
+
* `buildCuratorBatch` and then `submitActions`.
|
|
191
|
+
*
|
|
192
|
+
* @param params.chainId EVM chain ID — must be present in UNISWAP_V3_ROUTERS
|
|
193
|
+
* @param params.tokenIn Input token address
|
|
194
|
+
* @param params.tokenOut Output token address
|
|
195
|
+
* @param params.fee Pool fee tier: 100, 500, 3000, or 10000
|
|
196
|
+
* @param params.amountIn Exact input amount (in tokenIn units)
|
|
197
|
+
* @param params.minAmountOut Minimum acceptable output (slippage protection)
|
|
198
|
+
* @param params.recipient Address to receive output tokens (usually the vault)
|
|
199
|
+
* @returns A typed CuratorAction ready for buildCuratorBatch
|
|
200
|
+
* @throws If no router is configured for the given chainId
|
|
201
|
+
*
|
|
202
|
+
* @example
|
|
203
|
+
* ```typescript
|
|
204
|
+
* const action = buildUniswapV3Swap({
|
|
205
|
+
* chainId: 8453,
|
|
206
|
+
* tokenIn: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC
|
|
207
|
+
* tokenOut: '0x4200000000000000000000000000000000000006', // WETH
|
|
208
|
+
* fee: 500, // 0.05% pool
|
|
209
|
+
* amountIn: 150_000n, // 0.15 USDC (6 decimals)
|
|
210
|
+
* minAmountOut: 1n, // accept any amount (set properly in production)
|
|
211
|
+
* recipient: VAULT,
|
|
212
|
+
* })
|
|
213
|
+
* const batch = buildCuratorBatch([action])
|
|
214
|
+
* await submitActions(walletClient, publicClient, vault, batch)
|
|
215
|
+
* ```
|
|
216
|
+
*/
|
|
217
|
+
export function buildUniswapV3Swap(params: {
|
|
218
|
+
chainId: number
|
|
219
|
+
tokenIn: Address
|
|
220
|
+
tokenOut: Address
|
|
221
|
+
fee: number
|
|
222
|
+
amountIn: bigint
|
|
223
|
+
minAmountOut: bigint
|
|
224
|
+
recipient: Address
|
|
225
|
+
}): CuratorAction {
|
|
226
|
+
const { targetContract, swapCallData } = encodeUniswapV3SwapCalldata(params)
|
|
227
|
+
|
|
228
|
+
return {
|
|
229
|
+
type: 'swap',
|
|
230
|
+
params: {
|
|
231
|
+
targetContract,
|
|
232
|
+
tokenIn: params.tokenIn,
|
|
233
|
+
tokenOut: params.tokenOut,
|
|
234
|
+
maxAmountIn: params.amountIn,
|
|
235
|
+
minAmountOut: params.minAmountOut,
|
|
236
|
+
swapCallData,
|
|
237
|
+
},
|
|
238
|
+
}
|
|
239
|
+
}
|
package/src/viem/index.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Provides typed helpers for all deposit, redeem, and cross-chain vault flows.
|
|
3
3
|
|
|
4
4
|
// --- Chain constants ---
|
|
5
|
-
export { CHAIN_IDS, LZ_EIDS, EID_TO_CHAIN_ID, CHAIN_ID_TO_EID, OFT_ROUTES, STARGATE_TAXI_CMD, USDC_STARGATE_OFT, USDC_TOKEN, LZ_TIMEOUTS } from './chains'
|
|
5
|
+
export { CHAIN_IDS, LZ_EIDS, EID_TO_CHAIN_ID, CHAIN_ID_TO_EID, OFT_ROUTES, STARGATE_TAXI_CMD, USDC_STARGATE_OFT, USDC_TOKEN, LZ_TIMEOUTS, UNISWAP_V3_ROUTERS } from './chains'
|
|
6
6
|
|
|
7
7
|
// --- ABIs ---
|
|
8
8
|
export {
|
|
@@ -17,8 +17,11 @@ export {
|
|
|
17
17
|
DEX_ABI,
|
|
18
18
|
BRIDGE_FACET_ABI,
|
|
19
19
|
ERC7540_FACET_ABI,
|
|
20
|
+
ERC4626_FACET_ABI,
|
|
20
21
|
CURATOR_CONFIG_ABI,
|
|
21
22
|
LZ_ADAPTER_ABI,
|
|
23
|
+
VAULT_ANALYSIS_ABI,
|
|
24
|
+
REGISTRY_ABI,
|
|
22
25
|
} from './abis'
|
|
23
26
|
|
|
24
27
|
// --- Types ---
|
|
@@ -38,6 +41,10 @@ export type {
|
|
|
38
41
|
SubmitActionsResult,
|
|
39
42
|
CuratorAction,
|
|
40
43
|
CuratorVaultStatus,
|
|
44
|
+
AssetInfo,
|
|
45
|
+
AssetBalance,
|
|
46
|
+
VaultAnalysis,
|
|
47
|
+
VaultAssetBreakdown,
|
|
41
48
|
} from './types'
|
|
42
49
|
export { ActionType } from './types'
|
|
43
50
|
|
|
@@ -155,7 +162,21 @@ export {
|
|
|
155
162
|
getCuratorVaultStatus,
|
|
156
163
|
getPendingActions,
|
|
157
164
|
isCurator,
|
|
165
|
+
getVaultAnalysis,
|
|
166
|
+
checkProtocolWhitelist,
|
|
167
|
+
getVaultAssetBreakdown,
|
|
158
168
|
} from './curatorStatus'
|
|
169
|
+
export {
|
|
170
|
+
encodeCuratorAction,
|
|
171
|
+
buildCuratorBatch,
|
|
172
|
+
submitActions,
|
|
173
|
+
executeActions,
|
|
174
|
+
vetoActions,
|
|
175
|
+
} from './curatorMulticall'
|
|
176
|
+
export {
|
|
177
|
+
buildUniswapV3Swap,
|
|
178
|
+
encodeUniswapV3SwapCalldata,
|
|
179
|
+
} from './curatorSwaps'
|
|
159
180
|
|
|
160
181
|
// --- wagmi compatibility ---
|
|
161
182
|
// Re-export viem's PublicClient type for wagmi compatibility.
|
package/src/viem/types.ts
CHANGED
|
@@ -155,3 +155,41 @@ export interface CuratorVaultStatus {
|
|
|
155
155
|
lzAdapter: Address
|
|
156
156
|
paused: boolean
|
|
157
157
|
}
|
|
158
|
+
|
|
159
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
160
|
+
// Vault Analysis Types
|
|
161
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
162
|
+
|
|
163
|
+
export interface AssetInfo {
|
|
164
|
+
address: Address
|
|
165
|
+
symbol: string
|
|
166
|
+
name: string
|
|
167
|
+
decimals: number
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export interface VaultAnalysis {
|
|
171
|
+
/** All tokens the vault can hold/swap (curator-managed) */
|
|
172
|
+
availableAssets: AssetInfo[]
|
|
173
|
+
/** Tokens users can deposit */
|
|
174
|
+
depositableAssets: AssetInfo[]
|
|
175
|
+
/** Whether deposit whitelist is enabled (restricts who can deposit) */
|
|
176
|
+
depositWhitelistEnabled: boolean
|
|
177
|
+
/** Registry address for global protocol whitelist checks */
|
|
178
|
+
registryAddress: Address | null
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export interface AssetBalance extends AssetInfo {
|
|
182
|
+
/** Raw balance held by the vault */
|
|
183
|
+
balance: bigint
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export interface VaultAssetBreakdown {
|
|
187
|
+
/** Per-asset balances held by the vault on the hub chain */
|
|
188
|
+
assets: AssetBalance[]
|
|
189
|
+
/** totalAssets() as reported by the vault (all positions converted to underlying) */
|
|
190
|
+
totalAssets: bigint
|
|
191
|
+
/** totalSupply() of vault shares */
|
|
192
|
+
totalSupply: bigint
|
|
193
|
+
/** Vault underlying token decimals */
|
|
194
|
+
underlyingDecimals: number
|
|
195
|
+
}
|
package/src/viem/userHelpers.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Address, type PublicClient, getAddress } from 'viem'
|
|
2
|
-
import { BRIDGE_ABI, CONFIG_ABI, ERC20_ABI, VAULT_ABI, METADATA_ABI, OFT_ABI } from './abis'
|
|
2
|
+
import { BRIDGE_ABI, CONFIG_ABI, ERC20_ABI, VAULT_ABI, METADATA_ABI, OFT_ABI, VAULT_ANALYSIS_ABI } from './abis'
|
|
3
3
|
import type { CrossChainRequestInfo } from './types'
|
|
4
4
|
import { getVaultStatus } from './utils'
|
|
5
5
|
import type { VaultStatus } from './utils'
|
|
@@ -140,6 +140,10 @@ export type DepositBlockReason = 'paused' | 'capacity-full' | 'not-whitelisted'
|
|
|
140
140
|
export interface DepositEligibility {
|
|
141
141
|
allowed: boolean
|
|
142
142
|
reason: DepositBlockReason
|
|
143
|
+
/** Max deposit amount for this user (0n if capacity full or not whitelisted) */
|
|
144
|
+
maxDeposit?: bigint
|
|
145
|
+
/** Whether the vault restricts deposits to whitelisted addresses */
|
|
146
|
+
whitelistEnabled?: boolean
|
|
143
147
|
}
|
|
144
148
|
|
|
145
149
|
/**
|
|
@@ -167,15 +171,27 @@ export async function canDeposit(
|
|
|
167
171
|
allowFailure: false,
|
|
168
172
|
})
|
|
169
173
|
|
|
174
|
+
// Read whitelist status (may revert on older vaults — default to false)
|
|
175
|
+
let whitelistEnabled = false
|
|
176
|
+
try {
|
|
177
|
+
whitelistEnabled = await publicClient.readContract({
|
|
178
|
+
address: v,
|
|
179
|
+
abi: VAULT_ANALYSIS_ABI,
|
|
180
|
+
functionName: 'isDepositWhitelistEnabled',
|
|
181
|
+
}) as boolean
|
|
182
|
+
} catch {
|
|
183
|
+
// Older vaults may not have this function
|
|
184
|
+
}
|
|
185
|
+
|
|
170
186
|
if (isPaused) {
|
|
171
|
-
return { allowed: false, reason: 'paused' }
|
|
187
|
+
return { allowed: false, reason: 'paused', whitelistEnabled }
|
|
172
188
|
}
|
|
173
189
|
|
|
174
190
|
// Cross-chain async hubs revert on maxDeposit — this is expected, not a whitelist block.
|
|
175
191
|
// The vault accepts deposits via initVaultActionRequest instead of the standard ERC-4626 path.
|
|
176
192
|
const isCrossChainAsync = isHub && !oraclesEnabled
|
|
177
193
|
if (isCrossChainAsync) {
|
|
178
|
-
return { allowed: true, reason: 'ok' }
|
|
194
|
+
return { allowed: true, reason: 'ok', whitelistEnabled }
|
|
179
195
|
}
|
|
180
196
|
|
|
181
197
|
// maxDeposit(user) can REVERT on vaults with whitelist/ACL
|
|
@@ -189,13 +205,13 @@ export async function canDeposit(
|
|
|
189
205
|
})
|
|
190
206
|
} catch {
|
|
191
207
|
// Revert means the vault has whitelist/ACL and this user is not approved
|
|
192
|
-
return { allowed: false, reason: 'not-whitelisted' }
|
|
208
|
+
return { allowed: false, reason: 'not-whitelisted', maxDeposit: 0n, whitelistEnabled }
|
|
193
209
|
}
|
|
194
210
|
|
|
195
211
|
if (maxDepositAmount === 0n) {
|
|
196
|
-
return { allowed: false, reason: 'capacity-full' }
|
|
212
|
+
return { allowed: false, reason: 'capacity-full', maxDeposit: 0n, whitelistEnabled }
|
|
197
213
|
}
|
|
198
|
-
return { allowed: true, reason: 'ok' }
|
|
214
|
+
return { allowed: true, reason: 'ok', maxDeposit: maxDepositAmount, whitelistEnabled }
|
|
199
215
|
}
|
|
200
216
|
|
|
201
217
|
// ─────────────────────────────────────────────────────────────────────────────
|