@ember-finance/sdk 1.1.4 → 1.2.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/README.md +169 -2
- package/dist/src/abis/ERC20Token.json +196 -2
- package/dist/src/abis/EmberVault.json +90 -7
- package/dist/src/evm-vaults/interfaces/index.d.ts +13 -0
- package/dist/src/evm-vaults/on-chain-calls/tx-builder.d.ts +19 -1
- package/dist/src/evm-vaults/on-chain-calls/tx-builder.js +50 -0
- package/dist/src/evm-vaults/on-chain-calls/user.d.ts +74 -4
- package/dist/src/evm-vaults/on-chain-calls/user.js +81 -3
- package/dist/src/evm-vaults/utils/index.d.ts +1 -0
- package/dist/src/evm-vaults/utils/index.js +1 -0
- package/dist/src/evm-vaults/utils/permit-utils.d.ts +134 -0
- package/dist/src/evm-vaults/utils/permit-utils.js +263 -0
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Signer, Provider } from "ethers";
|
|
2
2
|
import { EVMOnChainCalls } from "./onchain-calls";
|
|
3
|
-
import { IEvmDeployment, IUserCallOptions, IEvmCallOptions, EvmOnChainCallResponse } from "../interfaces";
|
|
3
|
+
import { IEvmDeployment, IUserCallOptions, IEvmCallOptions, EvmOnChainCallResponse, IPermitSignature } from "../interfaces";
|
|
4
4
|
import { NumStr } from "../../common/types";
|
|
5
5
|
/**
|
|
6
6
|
* User Calls for Ember Protocol on EVM (ERC-4626 Compatible)
|
|
@@ -10,7 +10,9 @@ import { NumStr } from "../../common/types";
|
|
|
10
10
|
*
|
|
11
11
|
* Users can:
|
|
12
12
|
* - deposit: Deposit assets and receive shares (ERC-4626)
|
|
13
|
+
* - depositWithPermit: Deposit assets using EIP-2612 permit (no separate approval needed)
|
|
13
14
|
* - mint: Mint a specific number of shares by depositing assets (ERC-4626)
|
|
15
|
+
* - mintWithPermit: Mint shares using EIP-2612 permit (no separate approval needed)
|
|
14
16
|
* - redeemShares: Initiate a withdrawal request by redeeming shares
|
|
15
17
|
* - cancelPendingWithdrawalRequest: Cancel a pending withdrawal
|
|
16
18
|
*
|
|
@@ -28,12 +30,14 @@ import { NumStr } from "../../common/types";
|
|
|
28
30
|
*
|
|
29
31
|
* const userCalls = new EVMUserCalls(deployment, signer, provider);
|
|
30
32
|
*
|
|
31
|
-
* // Approve token spending first
|
|
33
|
+
* // Traditional approach: Approve token spending first, then deposit
|
|
32
34
|
* await userCalls.approveToken(underlyingAsset, vaultAddress, amount);
|
|
33
|
-
*
|
|
34
|
-
* // Deposit assets (receiver defaults to caller)
|
|
35
35
|
* await userCalls.deposit(vaultAddress, amount);
|
|
36
36
|
*
|
|
37
|
+
* // New approach: Use permit to deposit in single transaction (no approval needed)
|
|
38
|
+
* const permitSig = await signPermit(signer, tokenAddress, vaultAddress, amount, deadline);
|
|
39
|
+
* await userCalls.depositWithPermit(vaultAddress, amount, permitSig);
|
|
40
|
+
*
|
|
37
41
|
* // Deposit assets to a different receiver
|
|
38
42
|
* await userCalls.deposit(vaultAddress, amount, { receiver: otherAddress });
|
|
39
43
|
*
|
|
@@ -58,6 +62,39 @@ export declare class EVMUserCalls extends EVMOnChainCalls {
|
|
|
58
62
|
* @returns EvmOnChainCallResponse
|
|
59
63
|
*/
|
|
60
64
|
deposit(vaultAddress: string, assets: NumStr, options?: IUserCallOptions): Promise<EvmOnChainCallResponse>;
|
|
65
|
+
/**
|
|
66
|
+
* Deposit assets into a vault using EIP-2612 permit (no separate approval needed)
|
|
67
|
+
*
|
|
68
|
+
* This method allows depositing in a single transaction by including a permit signature.
|
|
69
|
+
* The permit signature authorizes the vault to spend the underlying asset without requiring
|
|
70
|
+
* a separate approve transaction.
|
|
71
|
+
*
|
|
72
|
+
* @param vaultAddress The address of the vault
|
|
73
|
+
* @param assets The amount of assets to deposit
|
|
74
|
+
* @param permitSignature The EIP-2612 permit signature components
|
|
75
|
+
* @param options Optional tx execution params (includes optional receiver, defaults to caller)
|
|
76
|
+
* @returns EvmOnChainCallResponse
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```typescript
|
|
80
|
+
* // Generate permit signature (see signPermit utility)
|
|
81
|
+
* const permitSig = await signPermit(
|
|
82
|
+
* signer,
|
|
83
|
+
* tokenAddress,
|
|
84
|
+
* vaultAddress,
|
|
85
|
+
* amount,
|
|
86
|
+
* deadline
|
|
87
|
+
* );
|
|
88
|
+
*
|
|
89
|
+
* // Deposit with permit in single transaction
|
|
90
|
+
* await userCalls.depositWithPermit(
|
|
91
|
+
* vaultAddress,
|
|
92
|
+
* amount,
|
|
93
|
+
* permitSig
|
|
94
|
+
* );
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
depositWithPermit(vaultAddress: string, assets: NumStr, permitSignature: IPermitSignature, options?: IUserCallOptions): Promise<EvmOnChainCallResponse>;
|
|
61
98
|
/**
|
|
62
99
|
* Mint a specific number of shares by depositing assets (ERC-4626 standard)
|
|
63
100
|
*
|
|
@@ -70,6 +107,39 @@ export declare class EVMUserCalls extends EVMOnChainCalls {
|
|
|
70
107
|
* @returns EvmOnChainCallResponse
|
|
71
108
|
*/
|
|
72
109
|
mint(vaultAddress: string, shares: NumStr, options?: IUserCallOptions): Promise<EvmOnChainCallResponse>;
|
|
110
|
+
/**
|
|
111
|
+
* Mint a specific number of shares using EIP-2612 permit (no separate approval needed)
|
|
112
|
+
*
|
|
113
|
+
* This method allows minting shares in a single transaction by including a permit signature.
|
|
114
|
+
* The permit signature authorizes the vault to spend the required underlying assets without
|
|
115
|
+
* requiring a separate approve transaction.
|
|
116
|
+
*
|
|
117
|
+
* @param vaultAddress The address of the vault
|
|
118
|
+
* @param shares The number of shares to mint
|
|
119
|
+
* @param permitSignature The EIP-2612 permit signature components
|
|
120
|
+
* @param options Optional tx execution params (includes optional receiver, defaults to caller)
|
|
121
|
+
* @returns EvmOnChainCallResponse
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```typescript
|
|
125
|
+
* // Generate permit signature (see signPermit utility)
|
|
126
|
+
* const permitSig = await signPermit(
|
|
127
|
+
* signer,
|
|
128
|
+
* tokenAddress,
|
|
129
|
+
* vaultAddress,
|
|
130
|
+
* maxAmount, // Use high amount or max for mint since exact amount is calculated by vault
|
|
131
|
+
* deadline
|
|
132
|
+
* );
|
|
133
|
+
*
|
|
134
|
+
* // Mint shares with permit in single transaction
|
|
135
|
+
* await userCalls.mintWithPermit(
|
|
136
|
+
* vaultAddress,
|
|
137
|
+
* shares,
|
|
138
|
+
* permitSig
|
|
139
|
+
* );
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
mintWithPermit(vaultAddress: string, shares: NumStr, permitSignature: IPermitSignature, options?: IUserCallOptions): Promise<EvmOnChainCallResponse>;
|
|
73
143
|
/**
|
|
74
144
|
* Redeem shares to initiate a withdrawal request
|
|
75
145
|
*
|
|
@@ -15,7 +15,9 @@ const EmberVault_json_1 = __importDefault(require("../../abis/EmberVault.json"))
|
|
|
15
15
|
*
|
|
16
16
|
* Users can:
|
|
17
17
|
* - deposit: Deposit assets and receive shares (ERC-4626)
|
|
18
|
+
* - depositWithPermit: Deposit assets using EIP-2612 permit (no separate approval needed)
|
|
18
19
|
* - mint: Mint a specific number of shares by depositing assets (ERC-4626)
|
|
20
|
+
* - mintWithPermit: Mint shares using EIP-2612 permit (no separate approval needed)
|
|
19
21
|
* - redeemShares: Initiate a withdrawal request by redeeming shares
|
|
20
22
|
* - cancelPendingWithdrawalRequest: Cancel a pending withdrawal
|
|
21
23
|
*
|
|
@@ -33,12 +35,14 @@ const EmberVault_json_1 = __importDefault(require("../../abis/EmberVault.json"))
|
|
|
33
35
|
*
|
|
34
36
|
* const userCalls = new EVMUserCalls(deployment, signer, provider);
|
|
35
37
|
*
|
|
36
|
-
* // Approve token spending first
|
|
38
|
+
* // Traditional approach: Approve token spending first, then deposit
|
|
37
39
|
* await userCalls.approveToken(underlyingAsset, vaultAddress, amount);
|
|
38
|
-
*
|
|
39
|
-
* // Deposit assets (receiver defaults to caller)
|
|
40
40
|
* await userCalls.deposit(vaultAddress, amount);
|
|
41
41
|
*
|
|
42
|
+
* // New approach: Use permit to deposit in single transaction (no approval needed)
|
|
43
|
+
* const permitSig = await signPermit(signer, tokenAddress, vaultAddress, amount, deadline);
|
|
44
|
+
* await userCalls.depositWithPermit(vaultAddress, amount, permitSig);
|
|
45
|
+
*
|
|
42
46
|
* // Deposit assets to a different receiver
|
|
43
47
|
* await userCalls.deposit(vaultAddress, amount, { receiver: otherAddress });
|
|
44
48
|
*
|
|
@@ -72,6 +76,43 @@ class EVMUserCalls extends onchain_calls_1.EVMOnChainCalls {
|
|
|
72
76
|
const txCall = this.txBuilder.deposit(vaultAddress, assets, receiver);
|
|
73
77
|
return this.execCall(txCall, options);
|
|
74
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* Deposit assets into a vault using EIP-2612 permit (no separate approval needed)
|
|
81
|
+
*
|
|
82
|
+
* This method allows depositing in a single transaction by including a permit signature.
|
|
83
|
+
* The permit signature authorizes the vault to spend the underlying asset without requiring
|
|
84
|
+
* a separate approve transaction.
|
|
85
|
+
*
|
|
86
|
+
* @param vaultAddress The address of the vault
|
|
87
|
+
* @param assets The amount of assets to deposit
|
|
88
|
+
* @param permitSignature The EIP-2612 permit signature components
|
|
89
|
+
* @param options Optional tx execution params (includes optional receiver, defaults to caller)
|
|
90
|
+
* @returns EvmOnChainCallResponse
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```typescript
|
|
94
|
+
* // Generate permit signature (see signPermit utility)
|
|
95
|
+
* const permitSig = await signPermit(
|
|
96
|
+
* signer,
|
|
97
|
+
* tokenAddress,
|
|
98
|
+
* vaultAddress,
|
|
99
|
+
* amount,
|
|
100
|
+
* deadline
|
|
101
|
+
* );
|
|
102
|
+
*
|
|
103
|
+
* // Deposit with permit in single transaction
|
|
104
|
+
* await userCalls.depositWithPermit(
|
|
105
|
+
* vaultAddress,
|
|
106
|
+
* amount,
|
|
107
|
+
* permitSig
|
|
108
|
+
* );
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
async depositWithPermit(vaultAddress, assets, permitSignature, options) {
|
|
112
|
+
const receiver = options?.receiver ?? (await this.getWalletAddress());
|
|
113
|
+
const txCall = this.txBuilder.depositWithPermit(vaultAddress, assets, receiver, permitSignature);
|
|
114
|
+
return this.execCall(txCall, options);
|
|
115
|
+
}
|
|
75
116
|
// ============================================
|
|
76
117
|
// Mint Methods (ERC-4626)
|
|
77
118
|
// ============================================
|
|
@@ -91,6 +132,43 @@ class EVMUserCalls extends onchain_calls_1.EVMOnChainCalls {
|
|
|
91
132
|
const txCall = this.txBuilder.mint(vaultAddress, shares, receiver);
|
|
92
133
|
return this.execCall(txCall, options);
|
|
93
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* Mint a specific number of shares using EIP-2612 permit (no separate approval needed)
|
|
137
|
+
*
|
|
138
|
+
* This method allows minting shares in a single transaction by including a permit signature.
|
|
139
|
+
* The permit signature authorizes the vault to spend the required underlying assets without
|
|
140
|
+
* requiring a separate approve transaction.
|
|
141
|
+
*
|
|
142
|
+
* @param vaultAddress The address of the vault
|
|
143
|
+
* @param shares The number of shares to mint
|
|
144
|
+
* @param permitSignature The EIP-2612 permit signature components
|
|
145
|
+
* @param options Optional tx execution params (includes optional receiver, defaults to caller)
|
|
146
|
+
* @returns EvmOnChainCallResponse
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```typescript
|
|
150
|
+
* // Generate permit signature (see signPermit utility)
|
|
151
|
+
* const permitSig = await signPermit(
|
|
152
|
+
* signer,
|
|
153
|
+
* tokenAddress,
|
|
154
|
+
* vaultAddress,
|
|
155
|
+
* maxAmount, // Use high amount or max for mint since exact amount is calculated by vault
|
|
156
|
+
* deadline
|
|
157
|
+
* );
|
|
158
|
+
*
|
|
159
|
+
* // Mint shares with permit in single transaction
|
|
160
|
+
* await userCalls.mintWithPermit(
|
|
161
|
+
* vaultAddress,
|
|
162
|
+
* shares,
|
|
163
|
+
* permitSig
|
|
164
|
+
* );
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
async mintWithPermit(vaultAddress, shares, permitSignature, options) {
|
|
168
|
+
const receiver = options?.receiver ?? (await this.getWalletAddress());
|
|
169
|
+
const txCall = this.txBuilder.mintWithPermit(vaultAddress, shares, receiver, permitSignature);
|
|
170
|
+
return this.execCall(txCall, options);
|
|
171
|
+
}
|
|
94
172
|
// ============================================
|
|
95
173
|
// Redemption Methods
|
|
96
174
|
// ============================================
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { Signer } from "ethers";
|
|
2
|
+
import { IPermitSignature } from "../interfaces";
|
|
3
|
+
import { NumStr } from "../../common/types";
|
|
4
|
+
/**
|
|
5
|
+
* Signs an EIP-2612 permit message
|
|
6
|
+
*
|
|
7
|
+
* This creates an off-chain signature that authorizes a spender (vault) to spend
|
|
8
|
+
* tokens on behalf of the owner without requiring a separate approval transaction.
|
|
9
|
+
*
|
|
10
|
+
* @param signer The ethers.js signer
|
|
11
|
+
* @param tokenAddress The address of the ERC20 token (must support EIP-2612)
|
|
12
|
+
* @param tokenName The name of the token (for domain separator)
|
|
13
|
+
* @param spender The address authorized to spend (usually the vault address)
|
|
14
|
+
* @param value The amount of tokens to approve
|
|
15
|
+
* @param deadline The deadline timestamp (in seconds) for the permit
|
|
16
|
+
* @param nonce The current permit nonce for the owner (fetch from token.nonces(owner))
|
|
17
|
+
* @param chainId The chain ID
|
|
18
|
+
* @param version Optional version string for the domain separator (fetched from token if not provided)
|
|
19
|
+
* @returns The permit signature components
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* import { signPermit } from "@ember-finance/sdk";
|
|
24
|
+
*
|
|
25
|
+
* const deadline = Math.floor(Date.now() / 1000) + 3600; // 1 hour from now
|
|
26
|
+
* const tokenContract = new ethers.Contract(tokenAddress, erc20Abi, provider);
|
|
27
|
+
* const nonce = await tokenContract.nonces(await signer.getAddress());
|
|
28
|
+
*
|
|
29
|
+
* const permitSig = await signPermit(
|
|
30
|
+
* signer,
|
|
31
|
+
* tokenAddress,
|
|
32
|
+
* "USD Coin", // token name
|
|
33
|
+
* vaultAddress,
|
|
34
|
+
* amount,
|
|
35
|
+
* BigInt(deadline),
|
|
36
|
+
* nonce,
|
|
37
|
+
* BigInt(1) // Ethereum mainnet
|
|
38
|
+
* );
|
|
39
|
+
*
|
|
40
|
+
* // Use with depositWithPermit
|
|
41
|
+
* await userCalls.depositWithPermit(vaultAddress, amount, permitSig);
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export declare function signPermit(signer: Signer, tokenAddress: string, tokenName: string, spender: string, value: NumStr, deadline: bigint, nonce: bigint, chainId: bigint, version?: string): Promise<IPermitSignature>;
|
|
45
|
+
/**
|
|
46
|
+
* Helper function to get the permit version from an EIP-2612 token
|
|
47
|
+
*
|
|
48
|
+
* @param tokenAddress The address of the ERC20 token
|
|
49
|
+
* @param provider An ethers.js provider
|
|
50
|
+
* @returns The version string (e.g., "1", "2"), defaults to "1" if version() not implemented
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* import { getPermitVersion } from "@ember-finance/sdk";
|
|
55
|
+
*
|
|
56
|
+
* const version = await getPermitVersion(tokenAddress, provider);
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare function getPermitVersion(tokenAddress: string, provider: import("ethers").Provider): Promise<string>;
|
|
60
|
+
/**
|
|
61
|
+
* Helper function to check if a token supports EIP-5267
|
|
62
|
+
*
|
|
63
|
+
* EIP-5267 defines a standard way to retrieve EIP-712 domain information
|
|
64
|
+
* via the eip712Domain() method. This is useful for tokens that want to
|
|
65
|
+
* expose their domain separator parameters in a standardized way.
|
|
66
|
+
*
|
|
67
|
+
* @param tokenAddress The address of the ERC20 token
|
|
68
|
+
* @param provider An ethers.js provider
|
|
69
|
+
* @returns True if the token supports EIP-5267, false otherwise
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* import { supportsEIP5267 } from "@ember-finance/sdk";
|
|
74
|
+
*
|
|
75
|
+
* const supports = await supportsEIP5267(tokenAddress, provider);
|
|
76
|
+
* if (supports) {
|
|
77
|
+
* console.log("Token supports EIP-5267");
|
|
78
|
+
* }
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export declare function supportsEIP5267(tokenAddress: string, provider: import("ethers").Provider): Promise<boolean>;
|
|
82
|
+
/**
|
|
83
|
+
* Helper function to get the current nonce for a user from an EIP-2612 token
|
|
84
|
+
*
|
|
85
|
+
* @param tokenAddress The address of the ERC20 token
|
|
86
|
+
* @param ownerAddress The address of the token owner
|
|
87
|
+
* @param provider An ethers.js provider
|
|
88
|
+
* @returns The current nonce
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```typescript
|
|
92
|
+
* import { getPermitNonce } from "@ember-finance/sdk";
|
|
93
|
+
*
|
|
94
|
+
* const nonce = await getPermitNonce(
|
|
95
|
+
* tokenAddress,
|
|
96
|
+
* await signer.getAddress(),
|
|
97
|
+
* provider
|
|
98
|
+
* );
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
export declare function getPermitNonce(tokenAddress: string, ownerAddress: string, provider: import("ethers").Provider): Promise<bigint>;
|
|
102
|
+
/**
|
|
103
|
+
* Helper function to create a permit signature with sensible defaults
|
|
104
|
+
*
|
|
105
|
+
* This is a convenience function that:
|
|
106
|
+
* - Fetches the current nonce automatically
|
|
107
|
+
* - Fetches the version from the token contract
|
|
108
|
+
* - Sets a deadline of 1 hour from now
|
|
109
|
+
* - Gets the chain ID from the signer
|
|
110
|
+
*
|
|
111
|
+
* @param signer The ethers.js signer (must be connected to a provider)
|
|
112
|
+
* @param tokenAddress The address of the ERC20 token (must support EIP-2612)
|
|
113
|
+
* @param tokenName The name of the token (for domain separator)
|
|
114
|
+
* @param spender The address authorized to spend (usually the vault address)
|
|
115
|
+
* @param value The amount of tokens to approve
|
|
116
|
+
* @returns The permit signature components
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```typescript
|
|
120
|
+
* import { signPermitSimple } from "@ember-finance/sdk";
|
|
121
|
+
*
|
|
122
|
+
* // Simplified permit signing (fetches nonce, version, sets 1 hour deadline automatically)
|
|
123
|
+
* const permitSig = await signPermitSimple(
|
|
124
|
+
* signer,
|
|
125
|
+
* tokenAddress,
|
|
126
|
+
* "USD Coin",
|
|
127
|
+
* vaultAddress,
|
|
128
|
+
* amount
|
|
129
|
+
* );
|
|
130
|
+
*
|
|
131
|
+
* await userCalls.depositWithPermit(vaultAddress, amount, permitSig);
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
export declare function signPermitSimple(signer: Signer, tokenAddress: string, tokenName: string, spender: string, value: NumStr): Promise<IPermitSignature>;
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.signPermit = signPermit;
|
|
37
|
+
exports.getPermitVersion = getPermitVersion;
|
|
38
|
+
exports.supportsEIP5267 = supportsEIP5267;
|
|
39
|
+
exports.getPermitNonce = getPermitNonce;
|
|
40
|
+
exports.signPermitSimple = signPermitSimple;
|
|
41
|
+
/**
|
|
42
|
+
* Signs an EIP-2612 permit message
|
|
43
|
+
*
|
|
44
|
+
* This creates an off-chain signature that authorizes a spender (vault) to spend
|
|
45
|
+
* tokens on behalf of the owner without requiring a separate approval transaction.
|
|
46
|
+
*
|
|
47
|
+
* @param signer The ethers.js signer
|
|
48
|
+
* @param tokenAddress The address of the ERC20 token (must support EIP-2612)
|
|
49
|
+
* @param tokenName The name of the token (for domain separator)
|
|
50
|
+
* @param spender The address authorized to spend (usually the vault address)
|
|
51
|
+
* @param value The amount of tokens to approve
|
|
52
|
+
* @param deadline The deadline timestamp (in seconds) for the permit
|
|
53
|
+
* @param nonce The current permit nonce for the owner (fetch from token.nonces(owner))
|
|
54
|
+
* @param chainId The chain ID
|
|
55
|
+
* @param version Optional version string for the domain separator (fetched from token if not provided)
|
|
56
|
+
* @returns The permit signature components
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```typescript
|
|
60
|
+
* import { signPermit } from "@ember-finance/sdk";
|
|
61
|
+
*
|
|
62
|
+
* const deadline = Math.floor(Date.now() / 1000) + 3600; // 1 hour from now
|
|
63
|
+
* const tokenContract = new ethers.Contract(tokenAddress, erc20Abi, provider);
|
|
64
|
+
* const nonce = await tokenContract.nonces(await signer.getAddress());
|
|
65
|
+
*
|
|
66
|
+
* const permitSig = await signPermit(
|
|
67
|
+
* signer,
|
|
68
|
+
* tokenAddress,
|
|
69
|
+
* "USD Coin", // token name
|
|
70
|
+
* vaultAddress,
|
|
71
|
+
* amount,
|
|
72
|
+
* BigInt(deadline),
|
|
73
|
+
* nonce,
|
|
74
|
+
* BigInt(1) // Ethereum mainnet
|
|
75
|
+
* );
|
|
76
|
+
*
|
|
77
|
+
* // Use with depositWithPermit
|
|
78
|
+
* await userCalls.depositWithPermit(vaultAddress, amount, permitSig);
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
async function signPermit(signer, tokenAddress, tokenName, spender, value, deadline, nonce, chainId, version) {
|
|
82
|
+
const owner = await signer.getAddress();
|
|
83
|
+
// If version not provided, fetch it from the token contract
|
|
84
|
+
let permitVersion = version;
|
|
85
|
+
if (!permitVersion) {
|
|
86
|
+
const provider = signer.provider;
|
|
87
|
+
if (!provider) {
|
|
88
|
+
throw new Error("Signer must be connected to a provider to fetch version");
|
|
89
|
+
}
|
|
90
|
+
permitVersion = await getPermitVersion(tokenAddress, provider);
|
|
91
|
+
}
|
|
92
|
+
// EIP-2612 domain
|
|
93
|
+
const domain = {
|
|
94
|
+
name: tokenName,
|
|
95
|
+
version: permitVersion,
|
|
96
|
+
chainId: chainId,
|
|
97
|
+
verifyingContract: tokenAddress
|
|
98
|
+
};
|
|
99
|
+
// EIP-2612 Permit type
|
|
100
|
+
const types = {
|
|
101
|
+
Permit: [
|
|
102
|
+
{ name: "owner", type: "address" },
|
|
103
|
+
{ name: "spender", type: "address" },
|
|
104
|
+
{ name: "value", type: "uint256" },
|
|
105
|
+
{ name: "nonce", type: "uint256" },
|
|
106
|
+
{ name: "deadline", type: "uint256" }
|
|
107
|
+
]
|
|
108
|
+
};
|
|
109
|
+
// Permit message
|
|
110
|
+
const message = {
|
|
111
|
+
owner,
|
|
112
|
+
spender,
|
|
113
|
+
value: BigInt(value),
|
|
114
|
+
nonce,
|
|
115
|
+
deadline
|
|
116
|
+
};
|
|
117
|
+
// Sign the typed data
|
|
118
|
+
const signature = await signer.signTypedData(domain, types, message);
|
|
119
|
+
// Split signature into v, r, s components
|
|
120
|
+
const r = signature.slice(0, 66);
|
|
121
|
+
const s = "0x" + signature.slice(66, 130);
|
|
122
|
+
const v = parseInt(signature.slice(130, 132), 16);
|
|
123
|
+
return {
|
|
124
|
+
deadline,
|
|
125
|
+
v,
|
|
126
|
+
r,
|
|
127
|
+
s
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Helper function to get the permit version from an EIP-2612 token
|
|
132
|
+
*
|
|
133
|
+
* @param tokenAddress The address of the ERC20 token
|
|
134
|
+
* @param provider An ethers.js provider
|
|
135
|
+
* @returns The version string (e.g., "1", "2"), defaults to "1" if version() not implemented
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```typescript
|
|
139
|
+
* import { getPermitVersion } from "@ember-finance/sdk";
|
|
140
|
+
*
|
|
141
|
+
* const version = await getPermitVersion(tokenAddress, provider);
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
async function getPermitVersion(tokenAddress, provider) {
|
|
145
|
+
try {
|
|
146
|
+
const { Contract } = await Promise.resolve().then(() => __importStar(require("ethers")));
|
|
147
|
+
const tokenContract = new Contract(tokenAddress, ["function version() view returns (string)"], provider);
|
|
148
|
+
return await tokenContract.version();
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
// TODO: change this to "1" when we have a token that supports version "1"
|
|
152
|
+
// If version() is not implemented, default to "2"
|
|
153
|
+
// Most EIP-2612 tokens use version "2" unless specified otherwise
|
|
154
|
+
return "2";
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Helper function to check if a token supports EIP-5267
|
|
159
|
+
*
|
|
160
|
+
* EIP-5267 defines a standard way to retrieve EIP-712 domain information
|
|
161
|
+
* via the eip712Domain() method. This is useful for tokens that want to
|
|
162
|
+
* expose their domain separator parameters in a standardized way.
|
|
163
|
+
*
|
|
164
|
+
* @param tokenAddress The address of the ERC20 token
|
|
165
|
+
* @param provider An ethers.js provider
|
|
166
|
+
* @returns True if the token supports EIP-5267, false otherwise
|
|
167
|
+
*
|
|
168
|
+
* @example
|
|
169
|
+
* ```typescript
|
|
170
|
+
* import { supportsEIP5267 } from "@ember-finance/sdk";
|
|
171
|
+
*
|
|
172
|
+
* const supports = await supportsEIP5267(tokenAddress, provider);
|
|
173
|
+
* if (supports) {
|
|
174
|
+
* console.log("Token supports EIP-5267");
|
|
175
|
+
* }
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
async function supportsEIP5267(tokenAddress, provider) {
|
|
179
|
+
try {
|
|
180
|
+
const { Contract } = await Promise.resolve().then(() => __importStar(require("ethers")));
|
|
181
|
+
const tokenContract = new Contract(tokenAddress, [
|
|
182
|
+
"function eip712Domain() view returns (bytes1 fields, string name, string version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] extensions)"
|
|
183
|
+
], provider);
|
|
184
|
+
// Try to call the method - if it succeeds, the token supports EIP-5267
|
|
185
|
+
await tokenContract.eip712Domain();
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
// If the call fails, the token does not support EIP-5267
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Helper function to get the current nonce for a user from an EIP-2612 token
|
|
195
|
+
*
|
|
196
|
+
* @param tokenAddress The address of the ERC20 token
|
|
197
|
+
* @param ownerAddress The address of the token owner
|
|
198
|
+
* @param provider An ethers.js provider
|
|
199
|
+
* @returns The current nonce
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* ```typescript
|
|
203
|
+
* import { getPermitNonce } from "@ember-finance/sdk";
|
|
204
|
+
*
|
|
205
|
+
* const nonce = await getPermitNonce(
|
|
206
|
+
* tokenAddress,
|
|
207
|
+
* await signer.getAddress(),
|
|
208
|
+
* provider
|
|
209
|
+
* );
|
|
210
|
+
* ```
|
|
211
|
+
*/
|
|
212
|
+
async function getPermitNonce(tokenAddress, ownerAddress, provider) {
|
|
213
|
+
const { Contract } = await Promise.resolve().then(() => __importStar(require("ethers")));
|
|
214
|
+
const tokenContract = new Contract(tokenAddress, ["function nonces(address owner) view returns (uint256)"], provider);
|
|
215
|
+
return await tokenContract.nonces(ownerAddress);
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Helper function to create a permit signature with sensible defaults
|
|
219
|
+
*
|
|
220
|
+
* This is a convenience function that:
|
|
221
|
+
* - Fetches the current nonce automatically
|
|
222
|
+
* - Fetches the version from the token contract
|
|
223
|
+
* - Sets a deadline of 1 hour from now
|
|
224
|
+
* - Gets the chain ID from the signer
|
|
225
|
+
*
|
|
226
|
+
* @param signer The ethers.js signer (must be connected to a provider)
|
|
227
|
+
* @param tokenAddress The address of the ERC20 token (must support EIP-2612)
|
|
228
|
+
* @param tokenName The name of the token (for domain separator)
|
|
229
|
+
* @param spender The address authorized to spend (usually the vault address)
|
|
230
|
+
* @param value The amount of tokens to approve
|
|
231
|
+
* @returns The permit signature components
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* ```typescript
|
|
235
|
+
* import { signPermitSimple } from "@ember-finance/sdk";
|
|
236
|
+
*
|
|
237
|
+
* // Simplified permit signing (fetches nonce, version, sets 1 hour deadline automatically)
|
|
238
|
+
* const permitSig = await signPermitSimple(
|
|
239
|
+
* signer,
|
|
240
|
+
* tokenAddress,
|
|
241
|
+
* "USD Coin",
|
|
242
|
+
* vaultAddress,
|
|
243
|
+
* amount
|
|
244
|
+
* );
|
|
245
|
+
*
|
|
246
|
+
* await userCalls.depositWithPermit(vaultAddress, amount, permitSig);
|
|
247
|
+
* ```
|
|
248
|
+
*/
|
|
249
|
+
async function signPermitSimple(signer, tokenAddress, tokenName, spender, value) {
|
|
250
|
+
const provider = signer.provider;
|
|
251
|
+
if (!provider) {
|
|
252
|
+
throw new Error("Signer must be connected to a provider");
|
|
253
|
+
}
|
|
254
|
+
const ownerAddress = await signer.getAddress();
|
|
255
|
+
const network = await provider.getNetwork();
|
|
256
|
+
const chainId = network.chainId;
|
|
257
|
+
// Get current nonce and version from token contract
|
|
258
|
+
const nonce = await getPermitNonce(tokenAddress, ownerAddress, provider);
|
|
259
|
+
const version = await getPermitVersion(tokenAddress, provider);
|
|
260
|
+
// Set deadline to 1 hour from now
|
|
261
|
+
const deadline = BigInt(Math.floor(Date.now() / 1000) + 3600);
|
|
262
|
+
return signPermit(signer, tokenAddress, tokenName, spender, value, deadline, nonce, chainId, version);
|
|
263
|
+
}
|