@armory-sh/base 0.2.27-alpha.23.76 → 0.2.27-alpha.23.78
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/client-hooks-runtime.d.ts +8 -0
- package/dist/encoding/x402.d.ts +1 -1
- package/dist/index.d.ts +27 -26
- package/dist/index.js +1223 -1029
- package/dist/payment-client.d.ts +1 -1
- package/dist/payment-requirements.d.ts +1 -1
- package/dist/types/api.d.ts +1 -1
- package/dist/types/hooks.d.ts +17 -1
- package/dist/types/protocol.d.ts +1 -1
- package/dist/utils/x402.d.ts +1 -1
- package/dist/validation.d.ts +1 -1
- package/package.json +14 -1
- package/src/abi/erc20.ts +84 -0
- package/src/client-hooks-runtime.ts +133 -0
- package/src/data/tokens.ts +199 -0
- package/src/eip712.ts +108 -0
- package/src/encoding/x402.ts +205 -0
- package/src/encoding.ts +98 -0
- package/src/errors.ts +23 -0
- package/src/index.ts +322 -0
- package/src/payment-client.ts +201 -0
- package/src/payment-requirements.ts +256 -0
- package/src/protocol.ts +57 -0
- package/src/types/api.ts +304 -0
- package/src/types/hooks.ts +85 -0
- package/src/types/networks.ts +175 -0
- package/src/types/protocol.ts +182 -0
- package/src/types/v2.ts +282 -0
- package/src/types/wallet.ts +30 -0
- package/src/types/x402.ts +151 -0
- package/src/utils/base64.ts +48 -0
- package/src/utils/routes.ts +240 -0
- package/src/utils/utils/index.ts +7 -0
- package/src/utils/utils/mock-facilitator.ts +184 -0
- package/src/utils/x402.ts +147 -0
- package/src/validation.ts +655 -0
package/dist/payment-client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PaymentPayload, PaymentRequirements,
|
|
1
|
+
import type { PaymentPayload, PaymentRequirements, SettlementResponse, VerifyResponse } from "./types/x402";
|
|
2
2
|
export interface FacilitatorClientConfig {
|
|
3
3
|
url: string;
|
|
4
4
|
createHeaders?: () => Record<string, string> | Promise<Record<string, string>>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { PaymentRequirementsV2, Address } from "./types/v2";
|
|
2
1
|
import type { NetworkId, TokenId, ValidationError } from "./types/api";
|
|
2
|
+
import type { Address, PaymentRequirementsV2 } from "./types/v2";
|
|
3
3
|
export interface PaymentConfig {
|
|
4
4
|
payTo: Address | string;
|
|
5
5
|
chains?: NetworkId[];
|
package/dist/types/api.d.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Simple, developer-friendly API types for Armory
|
|
3
3
|
* Focuses on DX/UX - "everything just magically works"
|
|
4
4
|
*/
|
|
5
|
+
import type { CustomToken, NetworkConfig } from "./networks";
|
|
5
6
|
import type { Address, CAIPAssetId } from "./v2";
|
|
6
|
-
import type { NetworkConfig, CustomToken } from "./networks";
|
|
7
7
|
/**
|
|
8
8
|
* Network identifier - flexible input that resolves to a chain
|
|
9
9
|
* - Network name: "base", "ethereum", "skale-base"
|
package/dist/types/hooks.d.ts
CHANGED
|
@@ -7,11 +7,13 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Hooks allow extensibility without custom code in each client package.
|
|
9
9
|
*/
|
|
10
|
-
import type {
|
|
10
|
+
import type { Address, Extensions, PaymentPayloadV2, PaymentRequirementsV2 } from "./v2";
|
|
11
11
|
export interface PaymentRequiredContext {
|
|
12
12
|
url: RequestInfo | URL;
|
|
13
13
|
requestInit: RequestInit | undefined;
|
|
14
|
+
accepts: PaymentRequirementsV2[];
|
|
14
15
|
requirements: PaymentRequirementsV2;
|
|
16
|
+
selectedRequirement?: PaymentRequirementsV2;
|
|
15
17
|
serverExtensions: Extensions | undefined;
|
|
16
18
|
fromAddress: Address;
|
|
17
19
|
nonce: `0x${string}`;
|
|
@@ -33,3 +35,17 @@ export interface HookConfig<TWallet = unknown> {
|
|
|
33
35
|
name?: string;
|
|
34
36
|
}
|
|
35
37
|
export type HookRegistry<TWallet = unknown> = Record<string, HookConfig<TWallet>>;
|
|
38
|
+
export interface ClientHookErrorContext {
|
|
39
|
+
error: unknown;
|
|
40
|
+
phase: "onPaymentRequired" | "selectRequirement" | "beforeSignPayment" | "afterPaymentResponse";
|
|
41
|
+
}
|
|
42
|
+
export interface ClientHook<TWallet = unknown> {
|
|
43
|
+
name?: string;
|
|
44
|
+
onPaymentRequired?: (context: PaymentRequiredContext) => HookResult;
|
|
45
|
+
selectRequirement?: (context: PaymentRequiredContext) => PaymentRequirementsV2 | undefined | Promise<PaymentRequirementsV2 | undefined>;
|
|
46
|
+
beforeSignPayment?: (context: PaymentPayloadContext<TWallet>) => HookResult;
|
|
47
|
+
afterPaymentResponse?: (context: PaymentPayloadContext<TWallet> & {
|
|
48
|
+
response: Response;
|
|
49
|
+
}) => HookResult;
|
|
50
|
+
onError?: (context: ClientHookErrorContext) => HookResult;
|
|
51
|
+
}
|
package/dist/types/protocol.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Simplified to support only x402 V2 format (Coinbase compatible)
|
|
5
5
|
*/
|
|
6
|
-
import type {
|
|
6
|
+
import type { Address, PaymentPayloadV2, PaymentRequiredV2, PaymentRequirementsV2, SettlementResponseV2 } from "./v2";
|
|
7
7
|
export type PaymentPayload = PaymentPayloadV2;
|
|
8
8
|
export type PaymentRequirements = PaymentRequirementsV2;
|
|
9
9
|
export type SettlementResponse = SettlementResponseV2;
|
package/dist/utils/x402.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Helper functions for nonce generation, amount conversion, and other utilities.
|
|
5
5
|
*/
|
|
6
|
-
import type {
|
|
6
|
+
import type { Address, Hex } from "../types/x402";
|
|
7
7
|
/**
|
|
8
8
|
* Generate a random 32-byte nonce as hex string
|
|
9
9
|
* Matches Coinbase SDK format: "0x" + 64 hex characters
|
package/dist/validation.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Comprehensive validation for Armory configurations
|
|
3
3
|
* Ensures networks, tokens, and facilitators are compatible
|
|
4
4
|
*/
|
|
5
|
-
import type { NetworkId,
|
|
5
|
+
import type { FacilitatorConfig, NetworkId, PaymentErrorCode, ResolvedFacilitator, ResolvedNetwork, ResolvedPaymentConfig, ResolvedToken, TokenId, ValidationError } from "./types/api";
|
|
6
6
|
export declare const createError: (code: PaymentErrorCode, message: string, details?: Partial<ValidationError>) => ValidationError;
|
|
7
7
|
export declare const normalizeNetworkName: (name: string) => string;
|
|
8
8
|
export declare const resolveNetwork: (input: unknown) => ResolvedNetwork | ValidationError;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@armory-sh/base",
|
|
3
|
-
"version": "0.2.27-alpha.23.
|
|
3
|
+
"version": "0.2.27-alpha.23.78",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Sawyer Cutler <sawyer@dirtroad.dev>",
|
|
6
6
|
"keywords": [
|
|
@@ -28,10 +28,21 @@
|
|
|
28
28
|
"bun": "./dist/index.js",
|
|
29
29
|
"default": "./dist/index.js"
|
|
30
30
|
},
|
|
31
|
+
"./types/hooks": {
|
|
32
|
+
"types": "./src/types/hooks.ts",
|
|
33
|
+
"bun": "./src/types/hooks.ts",
|
|
34
|
+
"default": "./src/types/hooks.ts"
|
|
35
|
+
},
|
|
36
|
+
"./client-hooks-runtime": {
|
|
37
|
+
"types": "./src/client-hooks-runtime.ts",
|
|
38
|
+
"bun": "./src/client-hooks-runtime.ts",
|
|
39
|
+
"default": "./src/client-hooks-runtime.ts"
|
|
40
|
+
},
|
|
31
41
|
"./dist/*": "./dist/*.js"
|
|
32
42
|
},
|
|
33
43
|
"files": [
|
|
34
44
|
"dist",
|
|
45
|
+
"src",
|
|
35
46
|
"README.md"
|
|
36
47
|
],
|
|
37
48
|
"publishConfig": {
|
|
@@ -50,6 +61,8 @@
|
|
|
50
61
|
},
|
|
51
62
|
"scripts": {
|
|
52
63
|
"build": "rm -rf dist && tsup && tsc --emitDeclarationOnly",
|
|
64
|
+
"lint": "bun run build",
|
|
65
|
+
"format": "bun run lint",
|
|
53
66
|
"test": "bun test",
|
|
54
67
|
"typecheck": "tsc --noEmit"
|
|
55
68
|
}
|
package/src/abi/erc20.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
export type TransferWithAuthorizationParams = readonly [
|
|
2
|
+
from: `0x${string}`,
|
|
3
|
+
to: `0x${string}`,
|
|
4
|
+
amount: bigint,
|
|
5
|
+
validAfter: bigint,
|
|
6
|
+
expiry: bigint,
|
|
7
|
+
v: number,
|
|
8
|
+
r: `0x${string}`,
|
|
9
|
+
s: `0x${string}`,
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
export type ReceiveWithAuthorizationParams = readonly [
|
|
13
|
+
from: `0x${string}`,
|
|
14
|
+
to: `0x${string}`,
|
|
15
|
+
amount: bigint,
|
|
16
|
+
validAfter: bigint,
|
|
17
|
+
expiry: bigint,
|
|
18
|
+
v: number,
|
|
19
|
+
r: `0x${string}`,
|
|
20
|
+
s: `0x${string}`,
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
export type BalanceOfParams = readonly [account: `0x${string}`];
|
|
24
|
+
export type BalanceOfReturnType = bigint;
|
|
25
|
+
export type NameReturnType = string;
|
|
26
|
+
export type SymbolReturnType = string;
|
|
27
|
+
|
|
28
|
+
export const ERC20_ABI = [
|
|
29
|
+
{
|
|
30
|
+
type: "function",
|
|
31
|
+
name: "transferWithAuthorization",
|
|
32
|
+
stateMutability: "nonpayable",
|
|
33
|
+
inputs: [
|
|
34
|
+
{ name: "from", type: "address" },
|
|
35
|
+
{ name: "to", type: "address" },
|
|
36
|
+
{ name: "amount", type: "uint256" },
|
|
37
|
+
{ name: "validAfter", type: "uint256" },
|
|
38
|
+
{ name: "expiry", type: "uint256" },
|
|
39
|
+
{ name: "v", type: "uint8" },
|
|
40
|
+
{ name: "r", type: "bytes32" },
|
|
41
|
+
{ name: "s", type: "bytes32" },
|
|
42
|
+
],
|
|
43
|
+
outputs: [],
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
type: "function",
|
|
47
|
+
name: "receiveWithAuthorization",
|
|
48
|
+
stateMutability: "nonpayable",
|
|
49
|
+
inputs: [
|
|
50
|
+
{ name: "from", type: "address" },
|
|
51
|
+
{ name: "to", type: "address" },
|
|
52
|
+
{ name: "amount", type: "uint256" },
|
|
53
|
+
{ name: "validAfter", type: "uint256" },
|
|
54
|
+
{ name: "expiry", type: "uint256" },
|
|
55
|
+
{ name: "v", type: "uint8" },
|
|
56
|
+
{ name: "r", type: "bytes32" },
|
|
57
|
+
{ name: "s", type: "bytes32" },
|
|
58
|
+
],
|
|
59
|
+
outputs: [],
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
type: "function",
|
|
63
|
+
name: "balanceOf",
|
|
64
|
+
stateMutability: "view",
|
|
65
|
+
inputs: [{ name: "account", type: "address" }],
|
|
66
|
+
outputs: [{ name: "balance", type: "uint256" }],
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
type: "function",
|
|
70
|
+
name: "name",
|
|
71
|
+
stateMutability: "view",
|
|
72
|
+
inputs: [],
|
|
73
|
+
outputs: [{ name: "", type: "string" }],
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
type: "function",
|
|
77
|
+
name: "symbol",
|
|
78
|
+
stateMutability: "view",
|
|
79
|
+
inputs: [],
|
|
80
|
+
outputs: [{ name: "", type: "string" }],
|
|
81
|
+
},
|
|
82
|
+
] as const;
|
|
83
|
+
|
|
84
|
+
export type ERC20Abi = typeof ERC20_ABI;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ClientHook,
|
|
3
|
+
ClientHookErrorContext,
|
|
4
|
+
PaymentPayloadContext,
|
|
5
|
+
PaymentRequiredContext,
|
|
6
|
+
} from "./types/hooks";
|
|
7
|
+
import type { PaymentRequirementsV2 } from "./types/v2";
|
|
8
|
+
|
|
9
|
+
const notifyError = async <TWallet>(
|
|
10
|
+
hooks: ClientHook<TWallet>[] | undefined,
|
|
11
|
+
context: ClientHookErrorContext,
|
|
12
|
+
): Promise<void> => {
|
|
13
|
+
if (!hooks?.length) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
for (const hook of hooks) {
|
|
18
|
+
if (!hook.onError) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
await hook.onError(context);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const runOnPaymentRequiredHooks = async <TWallet>(
|
|
26
|
+
hooks: ClientHook<TWallet>[] | undefined,
|
|
27
|
+
context: PaymentRequiredContext,
|
|
28
|
+
): Promise<void> => {
|
|
29
|
+
if (!hooks?.length) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
for (const hook of hooks) {
|
|
34
|
+
if (!hook.onPaymentRequired) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
await hook.onPaymentRequired(context);
|
|
39
|
+
} catch (error) {
|
|
40
|
+
await notifyError(hooks, { error, phase: "onPaymentRequired" });
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const selectRequirementWithHooks = async <TWallet>(
|
|
47
|
+
hooks: ClientHook<TWallet>[] | undefined,
|
|
48
|
+
context: PaymentRequiredContext,
|
|
49
|
+
): Promise<PaymentRequirementsV2> => {
|
|
50
|
+
if (!context.accepts.length) {
|
|
51
|
+
throw new Error("No payment requirements found in accepts array");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
let selected = context.accepts[0];
|
|
55
|
+
|
|
56
|
+
if (!hooks?.length) {
|
|
57
|
+
context.selectedRequirement = selected;
|
|
58
|
+
context.requirements = selected;
|
|
59
|
+
return selected;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
for (const hook of hooks) {
|
|
63
|
+
if (!hook.selectRequirement) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const override = await hook.selectRequirement({
|
|
68
|
+
...context,
|
|
69
|
+
selectedRequirement: selected,
|
|
70
|
+
requirements: selected,
|
|
71
|
+
});
|
|
72
|
+
if (!override) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const isValid = context.accepts.some((accept) => accept === override);
|
|
76
|
+
if (!isValid) {
|
|
77
|
+
throw new Error(
|
|
78
|
+
"Hook selectRequirement must return an item from accepts",
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
selected = override;
|
|
82
|
+
} catch (error) {
|
|
83
|
+
await notifyError(hooks, { error, phase: "selectRequirement" });
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
context.selectedRequirement = selected;
|
|
89
|
+
context.requirements = selected;
|
|
90
|
+
return selected;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export const runBeforeSignPaymentHooks = async <TWallet>(
|
|
94
|
+
hooks: ClientHook<TWallet>[] | undefined,
|
|
95
|
+
context: PaymentPayloadContext<TWallet>,
|
|
96
|
+
): Promise<void> => {
|
|
97
|
+
if (!hooks?.length) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
for (const hook of hooks) {
|
|
102
|
+
if (!hook.beforeSignPayment) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
await hook.beforeSignPayment(context);
|
|
107
|
+
} catch (error) {
|
|
108
|
+
await notifyError(hooks, { error, phase: "beforeSignPayment" });
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
export const runAfterPaymentResponseHooks = async <TWallet>(
|
|
115
|
+
hooks: ClientHook<TWallet>[] | undefined,
|
|
116
|
+
context: PaymentPayloadContext<TWallet> & { response: Response },
|
|
117
|
+
): Promise<void> => {
|
|
118
|
+
if (!hooks?.length) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
for (const hook of hooks) {
|
|
123
|
+
if (!hook.afterPaymentResponse) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
await hook.afterPaymentResponse(context);
|
|
128
|
+
} catch (error) {
|
|
129
|
+
await notifyError(hooks, { error, phase: "afterPaymentResponse" });
|
|
130
|
+
throw error;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
};
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import type { CustomToken } from "../types/networks";
|
|
2
|
+
|
|
3
|
+
export const USDC_BASE: CustomToken = {
|
|
4
|
+
symbol: "USDC",
|
|
5
|
+
name: "USDC",
|
|
6
|
+
version: "2",
|
|
7
|
+
contractAddress:
|
|
8
|
+
"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" as `0x${string}`,
|
|
9
|
+
chainId: 8453,
|
|
10
|
+
decimals: 6,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const EURC_BASE: CustomToken = {
|
|
14
|
+
symbol: "EURC",
|
|
15
|
+
name: "EURC",
|
|
16
|
+
version: "2",
|
|
17
|
+
contractAddress:
|
|
18
|
+
"0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42" as `0x${string}`,
|
|
19
|
+
chainId: 8453,
|
|
20
|
+
decimals: 6,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const USDC_BASE_SEPOLIA: CustomToken = {
|
|
24
|
+
symbol: "USDC",
|
|
25
|
+
name: "USDC",
|
|
26
|
+
version: "2",
|
|
27
|
+
contractAddress:
|
|
28
|
+
"0x036CbD53842c5426634e7929541eC2318f3dCF7e" as `0x${string}`,
|
|
29
|
+
chainId: 84532,
|
|
30
|
+
decimals: 6,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const USDC_SKALE_BASE: CustomToken = {
|
|
34
|
+
symbol: "USDC",
|
|
35
|
+
name: "Bridged USDC (SKALE Bridge)",
|
|
36
|
+
version: "2",
|
|
37
|
+
contractAddress:
|
|
38
|
+
"0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20" as `0x${string}`,
|
|
39
|
+
chainId: 1187947933,
|
|
40
|
+
decimals: 6,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const SKL_SKALE_BASE: CustomToken = {
|
|
44
|
+
symbol: "SKL",
|
|
45
|
+
name: "SKALE",
|
|
46
|
+
version: "1",
|
|
47
|
+
contractAddress:
|
|
48
|
+
"0xE0595a049d02b7674572b0d59cd4880Db60EDC50" as `0x${string}`,
|
|
49
|
+
chainId: 1187947933,
|
|
50
|
+
decimals: 18,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const USDT_SKALE_BASE: CustomToken = {
|
|
54
|
+
symbol: "USDT",
|
|
55
|
+
name: "Tether USD",
|
|
56
|
+
version: "1",
|
|
57
|
+
contractAddress:
|
|
58
|
+
"0x2bF5bF154b515EaA82C31a65ec11554fF5aF7fCA" as `0x${string}`,
|
|
59
|
+
chainId: 1187947933,
|
|
60
|
+
decimals: 6,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const WBTC_SKALE_BASE: CustomToken = {
|
|
64
|
+
symbol: "WBTC",
|
|
65
|
+
name: "Wrapped BTC",
|
|
66
|
+
version: "1",
|
|
67
|
+
contractAddress:
|
|
68
|
+
"0x1aeeCFE5454c83B42D8A316246CAc9739E7f690e" as `0x${string}`,
|
|
69
|
+
chainId: 1187947933,
|
|
70
|
+
decimals: 8,
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const WETH_SKALE_BASE: CustomToken = {
|
|
74
|
+
symbol: "WETH",
|
|
75
|
+
name: "Wrapped Ether",
|
|
76
|
+
version: "1",
|
|
77
|
+
contractAddress:
|
|
78
|
+
"0x7bD39ABBd0Dd13103542cAe3276C7fA332bCA486" as `0x${string}`,
|
|
79
|
+
chainId: 1187947933,
|
|
80
|
+
decimals: 18,
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export const SKL_SKALE_BASE_SEPOLIA: CustomToken = {
|
|
84
|
+
symbol: "SKL",
|
|
85
|
+
name: "SKALE",
|
|
86
|
+
version: "1",
|
|
87
|
+
contractAddress:
|
|
88
|
+
"0xaf2e0ff5b5f51553fdb34ce7f04a6c3201cee57b" as `0x${string}`,
|
|
89
|
+
chainId: 324705682,
|
|
90
|
+
decimals: 18,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export const USDC_SKALE_BASE_SEPOLIA: CustomToken = {
|
|
94
|
+
symbol: "USDC",
|
|
95
|
+
name: "Bridged USDC (SKALE Bridge)",
|
|
96
|
+
version: "2",
|
|
97
|
+
contractAddress:
|
|
98
|
+
"0x2e08028E3C4c2356572E096d8EF835cD5C6030bD" as `0x${string}`,
|
|
99
|
+
chainId: 324705682,
|
|
100
|
+
decimals: 6,
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export const USDT_SKALE_BASE_SEPOLIA: CustomToken = {
|
|
104
|
+
symbol: "USDT",
|
|
105
|
+
name: "Tether USD",
|
|
106
|
+
version: "1",
|
|
107
|
+
contractAddress:
|
|
108
|
+
"0x3ca0a49f511c2c89c4dcbbf1731120d8919050bf" as `0x${string}`,
|
|
109
|
+
chainId: 324705682,
|
|
110
|
+
decimals: 6,
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export const WBTC_SKALE_BASE_SEPOLIA: CustomToken = {
|
|
114
|
+
symbol: "WBTC",
|
|
115
|
+
name: "Wrapped BTC",
|
|
116
|
+
version: "1",
|
|
117
|
+
contractAddress:
|
|
118
|
+
"0x4512eacd4186b025186e1cf6cc0d89497c530e87" as `0x${string}`,
|
|
119
|
+
chainId: 324705682,
|
|
120
|
+
decimals: 8,
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
export const WETH_SKALE_BASE_SEPOLIA: CustomToken = {
|
|
124
|
+
symbol: "WETH",
|
|
125
|
+
name: "Wrapped Ether",
|
|
126
|
+
version: "1",
|
|
127
|
+
contractAddress:
|
|
128
|
+
"0xf94056bd7f6965db3757e1b145f200b7346b4fc0" as `0x${string}`,
|
|
129
|
+
chainId: 324705682,
|
|
130
|
+
decimals: 18,
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
export const TOKENS = {
|
|
134
|
+
USDC_BASE,
|
|
135
|
+
USDC_BASE_SEPOLIA,
|
|
136
|
+
EURC_BASE,
|
|
137
|
+
USDC_SKALE_BASE,
|
|
138
|
+
USDT_SKALE_BASE,
|
|
139
|
+
WBTC_SKALE_BASE,
|
|
140
|
+
WETH_SKALE_BASE,
|
|
141
|
+
SKL_SKALE_BASE,
|
|
142
|
+
SKL_SKALE_BASE_SEPOLIA,
|
|
143
|
+
USDC_SKALE_BASE_SEPOLIA,
|
|
144
|
+
USDT_SKALE_BASE_SEPOLIA,
|
|
145
|
+
WBTC_SKALE_BASE_SEPOLIA,
|
|
146
|
+
WETH_SKALE_BASE_SEPOLIA,
|
|
147
|
+
} as const;
|
|
148
|
+
|
|
149
|
+
function getToken(
|
|
150
|
+
chainId: number,
|
|
151
|
+
contractAddress: string,
|
|
152
|
+
): CustomToken | undefined {
|
|
153
|
+
const tokens = Object.values(TOKENS);
|
|
154
|
+
return tokens.find(
|
|
155
|
+
(t) =>
|
|
156
|
+
t.chainId === chainId &&
|
|
157
|
+
t.contractAddress.toLowerCase() === contractAddress.toLowerCase(),
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function getAllTokens(): CustomToken[] {
|
|
162
|
+
return Object.values(TOKENS);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function getTokensBySymbol(symbol: string): CustomToken[] {
|
|
166
|
+
return getAllTokens().filter(
|
|
167
|
+
(t) => t.symbol.toUpperCase() === symbol.toUpperCase(),
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function getTokensByChain(chainId: number): CustomToken[] {
|
|
172
|
+
return getAllTokens().filter((t) => t.chainId === chainId);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export function getUSDCTokens(): CustomToken[] {
|
|
176
|
+
return getTokensBySymbol("USDC");
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export function getEURCTokens(): CustomToken[] {
|
|
180
|
+
return getTokensBySymbol("EURC");
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export function getSKLTokens(): CustomToken[] {
|
|
184
|
+
return getTokensBySymbol("SKL");
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export function getUSDTTokens(): CustomToken[] {
|
|
188
|
+
return getTokensBySymbol("USDT");
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export function getWBTCTokens(): CustomToken[] {
|
|
192
|
+
return getTokensBySymbol("WBTC");
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export function getWETHTokens(): CustomToken[] {
|
|
196
|
+
return getTokensBySymbol("WETH");
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export { getToken, getAllTokens, getTokensBySymbol, getTokensByChain };
|
package/src/eip712.ts
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
export type TypedDataDomain = {
|
|
2
|
+
name?: string;
|
|
3
|
+
version?: string;
|
|
4
|
+
chainId?: number;
|
|
5
|
+
verifyingContract?: `0x${string}`;
|
|
6
|
+
salt?: `0x${string}`;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export interface EIP712Domain {
|
|
10
|
+
name: string;
|
|
11
|
+
version: string;
|
|
12
|
+
chainId: number;
|
|
13
|
+
verifyingContract: `0x${string}`;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface TransferWithAuthorization {
|
|
17
|
+
from: `0x${string}`;
|
|
18
|
+
to: `0x${string}`;
|
|
19
|
+
value: bigint;
|
|
20
|
+
validAfter: bigint;
|
|
21
|
+
validBefore: bigint;
|
|
22
|
+
nonce: `0x${string}`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type TransferWithAuthorizationRecord = TransferWithAuthorization &
|
|
26
|
+
Record<string, unknown>;
|
|
27
|
+
|
|
28
|
+
export type TypedDataField = { name: string; type: string };
|
|
29
|
+
|
|
30
|
+
export type EIP712Types = {
|
|
31
|
+
TransferWithAuthorization: TypedDataField[];
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const EIP712_TYPES = {
|
|
35
|
+
TransferWithAuthorization: [
|
|
36
|
+
{ name: "from", type: "address" },
|
|
37
|
+
{ name: "to", type: "address" },
|
|
38
|
+
{ name: "value", type: "uint256" },
|
|
39
|
+
{ name: "validAfter", type: "uint256" },
|
|
40
|
+
{ name: "validBefore", type: "uint256" },
|
|
41
|
+
{ name: "nonce", type: "bytes32" },
|
|
42
|
+
] as const,
|
|
43
|
+
} as const satisfies EIP712Types;
|
|
44
|
+
|
|
45
|
+
export const USDC_DOMAIN = {
|
|
46
|
+
NAME: "USD Coin",
|
|
47
|
+
VERSION: "2",
|
|
48
|
+
} as const;
|
|
49
|
+
|
|
50
|
+
export const createEIP712Domain = (
|
|
51
|
+
chainId: number,
|
|
52
|
+
contractAddress: `0x${string}`,
|
|
53
|
+
): EIP712Domain => ({
|
|
54
|
+
name: USDC_DOMAIN.NAME,
|
|
55
|
+
version: USDC_DOMAIN.VERSION,
|
|
56
|
+
chainId,
|
|
57
|
+
verifyingContract: contractAddress,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
export const createTransferWithAuthorization = (
|
|
61
|
+
params: Omit<
|
|
62
|
+
TransferWithAuthorization,
|
|
63
|
+
"value" | "validAfter" | "validBefore" | "nonce"
|
|
64
|
+
> & {
|
|
65
|
+
value: bigint | number;
|
|
66
|
+
validAfter: bigint | number;
|
|
67
|
+
validBefore: bigint | number;
|
|
68
|
+
nonce: `0x${string}`;
|
|
69
|
+
},
|
|
70
|
+
): TransferWithAuthorizationRecord => ({
|
|
71
|
+
from: params.from,
|
|
72
|
+
to: params.to,
|
|
73
|
+
value: BigInt(params.value),
|
|
74
|
+
validAfter: BigInt(params.validAfter),
|
|
75
|
+
validBefore: BigInt(params.validBefore),
|
|
76
|
+
nonce: params.nonce,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const isAddress = (value: string): boolean => /^0x[a-fA-F0-9]{40}$/.test(value);
|
|
80
|
+
|
|
81
|
+
const isBytes32 = (value: string): boolean => /^0x[a-fA-F0-9]{64}$/.test(value);
|
|
82
|
+
|
|
83
|
+
export const validateTransferWithAuthorization = (
|
|
84
|
+
message: TransferWithAuthorization,
|
|
85
|
+
): boolean => {
|
|
86
|
+
if (!isAddress(message.from))
|
|
87
|
+
throw new Error(`Invalid "from" address: ${message.from}`);
|
|
88
|
+
if (!isAddress(message.to))
|
|
89
|
+
throw new Error(`Invalid "to" address: ${message.to}`);
|
|
90
|
+
if (message.value < 0n)
|
|
91
|
+
throw new Error(`"value" must be non-negative: ${message.value}`);
|
|
92
|
+
if (message.validAfter < 0n)
|
|
93
|
+
throw new Error(`"validAfter" must be non-negative: ${message.validAfter}`);
|
|
94
|
+
if (message.validBefore < 0n)
|
|
95
|
+
throw new Error(
|
|
96
|
+
`"validBefore" must be non-negative: ${message.validBefore}`,
|
|
97
|
+
);
|
|
98
|
+
if (message.validAfter >= message.validBefore) {
|
|
99
|
+
throw new Error(
|
|
100
|
+
`"validAfter" (${message.validAfter}) must be before "validBefore" (${message.validBefore})`,
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
if (!isBytes32(message.nonce))
|
|
104
|
+
throw new Error(
|
|
105
|
+
`"nonce" must be a valid bytes32 hex string: ${message.nonce}`,
|
|
106
|
+
);
|
|
107
|
+
return true;
|
|
108
|
+
};
|