@armory-sh/base 0.2.28 → 0.2.30
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 +304 -28
- package/dist/client-hooks-runtime.d.ts +9 -0
- package/dist/encoding/x402.d.ts +1 -1
- package/dist/errors.d.ts +10 -0
- package/dist/facilitator-capabilities.d.ts +9 -0
- package/dist/index.d.ts +30 -22
- package/dist/index.js +1198 -650
- package/dist/payment-client.d.ts +1 -1
- package/dist/payment-requirements.d.ts +35 -0
- package/dist/protocol.d.ts +33 -0
- 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/types/wallet.d.ts +24 -0
- package/dist/utils/base64.d.ts +4 -0
- package/dist/utils/x402.d.ts +1 -1
- package/dist/validation.d.ts +1 -1
- package/package.json +15 -2
- package/src/abi/erc20.ts +84 -0
- package/src/client-hooks-runtime.ts +153 -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/facilitator-capabilities.ts +125 -0
- package/src/index.ts +330 -0
- package/src/payment-client.ts +201 -0
- package/src/payment-requirements.ts +354 -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 +654 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extension Hook System Types
|
|
3
|
+
*
|
|
4
|
+
* Provides a generic hook system for x402 clients to register
|
|
5
|
+
* extension handlers that can modify payment payloads or respond
|
|
6
|
+
* to payment requirements.
|
|
7
|
+
*
|
|
8
|
+
* Hooks allow extensibility without custom code in each client package.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type {
|
|
12
|
+
Address,
|
|
13
|
+
Extensions,
|
|
14
|
+
PaymentPayloadV2,
|
|
15
|
+
PaymentRequirementsV2,
|
|
16
|
+
} from "./v2";
|
|
17
|
+
|
|
18
|
+
export interface PaymentRequiredContext {
|
|
19
|
+
url: RequestInfo | URL;
|
|
20
|
+
requestInit: RequestInit | undefined;
|
|
21
|
+
accepts: PaymentRequirementsV2[];
|
|
22
|
+
requirements: PaymentRequirementsV2;
|
|
23
|
+
selectedRequirement?: PaymentRequirementsV2;
|
|
24
|
+
serverExtensions: Extensions | undefined;
|
|
25
|
+
fromAddress: Address;
|
|
26
|
+
nonce: `0x${string}`;
|
|
27
|
+
validBefore: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface PaymentPayloadContext<TWallet = unknown> {
|
|
31
|
+
payload: PaymentPayloadV2;
|
|
32
|
+
requirements: PaymentRequirementsV2;
|
|
33
|
+
wallet: TWallet;
|
|
34
|
+
paymentContext: PaymentRequiredContext;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export type HookResult = void | Promise<void>;
|
|
38
|
+
|
|
39
|
+
export type OnPaymentRequiredHook<TWallet = unknown> = (
|
|
40
|
+
context: PaymentRequiredContext,
|
|
41
|
+
) => HookResult;
|
|
42
|
+
|
|
43
|
+
export type BeforePaymentHook<TWallet = unknown> = (
|
|
44
|
+
context: PaymentPayloadContext<TWallet>,
|
|
45
|
+
) => HookResult;
|
|
46
|
+
|
|
47
|
+
export type ExtensionHook<TWallet = unknown> =
|
|
48
|
+
| OnPaymentRequiredHook<TWallet>
|
|
49
|
+
| BeforePaymentHook<TWallet>;
|
|
50
|
+
|
|
51
|
+
export interface HookConfig<TWallet = unknown> {
|
|
52
|
+
hook: ExtensionHook<TWallet>;
|
|
53
|
+
priority?: number;
|
|
54
|
+
name?: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export type HookRegistry<TWallet = unknown> = Record<
|
|
58
|
+
string,
|
|
59
|
+
HookConfig<TWallet>
|
|
60
|
+
>;
|
|
61
|
+
|
|
62
|
+
export interface ClientHookErrorContext {
|
|
63
|
+
error: unknown;
|
|
64
|
+
phase:
|
|
65
|
+
| "onPaymentRequired"
|
|
66
|
+
| "selectRequirement"
|
|
67
|
+
| "beforeSignPayment"
|
|
68
|
+
| "afterPaymentResponse";
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface ClientHook<TWallet = unknown> {
|
|
72
|
+
name?: string;
|
|
73
|
+
onPaymentRequired?: (context: PaymentRequiredContext) => HookResult;
|
|
74
|
+
selectRequirement?: (
|
|
75
|
+
context: PaymentRequiredContext,
|
|
76
|
+
) =>
|
|
77
|
+
| PaymentRequirementsV2
|
|
78
|
+
| undefined
|
|
79
|
+
| Promise<PaymentRequirementsV2 | undefined>;
|
|
80
|
+
beforeSignPayment?: (context: PaymentPayloadContext<TWallet>) => HookResult;
|
|
81
|
+
afterPaymentResponse?: (
|
|
82
|
+
context: PaymentPayloadContext<TWallet> & { response: Response },
|
|
83
|
+
) => HookResult;
|
|
84
|
+
onError?: (context: ClientHookErrorContext) => HookResult;
|
|
85
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
const isEvmAddress = (value: string): boolean =>
|
|
2
|
+
/^0x[a-fA-F0-9]{40}$/.test(value);
|
|
3
|
+
|
|
4
|
+
export interface NetworkConfig {
|
|
5
|
+
name: string;
|
|
6
|
+
chainId: number;
|
|
7
|
+
usdcAddress: `0x${string}`;
|
|
8
|
+
rpcUrl: string;
|
|
9
|
+
caip2Id: string;
|
|
10
|
+
caipAssetId: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface CustomToken {
|
|
14
|
+
symbol: string;
|
|
15
|
+
name: string;
|
|
16
|
+
version: string;
|
|
17
|
+
contractAddress: `0x${string}`;
|
|
18
|
+
chainId: number;
|
|
19
|
+
decimals?: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const tokenRegistry = new Map<string, CustomToken>();
|
|
23
|
+
const tokenKey = (chainId: number, contractAddress: string): string =>
|
|
24
|
+
`${chainId}:${contractAddress.toLowerCase()}`;
|
|
25
|
+
|
|
26
|
+
export const NETWORKS: Record<string, NetworkConfig> = {
|
|
27
|
+
ethereum: {
|
|
28
|
+
name: "Ethereum Mainnet",
|
|
29
|
+
chainId: 1,
|
|
30
|
+
usdcAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" as const,
|
|
31
|
+
rpcUrl: "https://eth.llamarpc.com",
|
|
32
|
+
caip2Id: "eip155:1",
|
|
33
|
+
caipAssetId: "eip155:1/erc20:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
34
|
+
},
|
|
35
|
+
base: {
|
|
36
|
+
name: "Base Mainnet",
|
|
37
|
+
chainId: 8453,
|
|
38
|
+
usdcAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" as const,
|
|
39
|
+
rpcUrl: "https://mainnet.base.org",
|
|
40
|
+
caip2Id: "eip155:8453",
|
|
41
|
+
caipAssetId: "eip155:8453/erc20:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
42
|
+
},
|
|
43
|
+
"base-sepolia": {
|
|
44
|
+
name: "Base Sepolia",
|
|
45
|
+
chainId: 84532,
|
|
46
|
+
usdcAddress: "0x036CbD53842c5426634e7929541eC2318f3dCF7e" as const,
|
|
47
|
+
rpcUrl: "https://sepolia.base.org",
|
|
48
|
+
caip2Id: "eip155:84532",
|
|
49
|
+
caipAssetId:
|
|
50
|
+
"eip155:84532/erc20:0x036CbD53842c5426634e7929541eC2318f3dCF7e",
|
|
51
|
+
},
|
|
52
|
+
"skale-base": {
|
|
53
|
+
name: "SKALE Base",
|
|
54
|
+
chainId: 1187947933,
|
|
55
|
+
usdcAddress: "0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20" as const,
|
|
56
|
+
rpcUrl: "https://skale-base.skalenodes.com/v1/base",
|
|
57
|
+
caip2Id: "eip155:1187947933",
|
|
58
|
+
caipAssetId:
|
|
59
|
+
"eip155:1187947933/erc20:0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20",
|
|
60
|
+
},
|
|
61
|
+
"skale-base-sepolia": {
|
|
62
|
+
name: "SKALE Base Sepolia",
|
|
63
|
+
chainId: 324705682,
|
|
64
|
+
usdcAddress: "0x2e08028E3C4c2356572E096d8EF835cD5C6030bD" as const,
|
|
65
|
+
rpcUrl:
|
|
66
|
+
"https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha",
|
|
67
|
+
caip2Id: "eip155:324705682",
|
|
68
|
+
caipAssetId:
|
|
69
|
+
"eip155:324705682/erc20:0x2e08028E3C4c2356572E096d8EF835cD5C6030bD",
|
|
70
|
+
},
|
|
71
|
+
"ethereum-sepolia": {
|
|
72
|
+
name: "Ethereum Sepolia",
|
|
73
|
+
chainId: 11155111,
|
|
74
|
+
usdcAddress: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238" as const,
|
|
75
|
+
rpcUrl: "https://rpc.sepolia.org",
|
|
76
|
+
caip2Id: "eip155:11155111",
|
|
77
|
+
caipAssetId:
|
|
78
|
+
"eip155:11155111/erc20:0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export const getNetworkConfig = (name: string): NetworkConfig | undefined =>
|
|
83
|
+
NETWORKS[name];
|
|
84
|
+
export const getNetworkByChainId = (
|
|
85
|
+
chainId: number,
|
|
86
|
+
): NetworkConfig | undefined =>
|
|
87
|
+
Object.values(NETWORKS).find((c) => c.chainId === chainId);
|
|
88
|
+
export const getMainnets = (): NetworkConfig[] =>
|
|
89
|
+
Object.values(NETWORKS).filter(
|
|
90
|
+
(c) => !c.name.toLowerCase().includes("sepolia"),
|
|
91
|
+
);
|
|
92
|
+
export const getTestnets = (): NetworkConfig[] =>
|
|
93
|
+
Object.values(NETWORKS).filter((c) =>
|
|
94
|
+
c.name.toLowerCase().includes("sepolia"),
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
export const registerToken = (token: unknown): CustomToken => {
|
|
98
|
+
if (typeof token !== "object" || token === null) {
|
|
99
|
+
throw new Error("Invalid token: must be an object");
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const t = token as Record<string, unknown>;
|
|
103
|
+
|
|
104
|
+
if (typeof t.symbol !== "string") {
|
|
105
|
+
throw new Error("Invalid token: symbol must be a string");
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (typeof t.name !== "string") {
|
|
109
|
+
throw new Error("Invalid token: name must be a string");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (typeof t.version !== "string") {
|
|
113
|
+
throw new Error("Invalid token: version must be a string");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (
|
|
117
|
+
typeof t.contractAddress !== "string" ||
|
|
118
|
+
!isEvmAddress(t.contractAddress)
|
|
119
|
+
) {
|
|
120
|
+
throw new Error(
|
|
121
|
+
"Invalid token: contractAddress must be a valid EVM address",
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (
|
|
126
|
+
typeof t.chainId !== "number" ||
|
|
127
|
+
!Number.isInteger(t.chainId) ||
|
|
128
|
+
t.chainId <= 0
|
|
129
|
+
) {
|
|
130
|
+
throw new Error("Invalid token: chainId must be a positive integer");
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (
|
|
134
|
+
t.decimals !== undefined &&
|
|
135
|
+
(typeof t.decimals !== "number" ||
|
|
136
|
+
!Number.isInteger(t.decimals) ||
|
|
137
|
+
t.decimals < 0)
|
|
138
|
+
) {
|
|
139
|
+
throw new Error("Invalid token: decimals must be a non-negative integer");
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const validated: CustomToken = {
|
|
143
|
+
symbol: t.symbol,
|
|
144
|
+
name: t.name,
|
|
145
|
+
version: t.version,
|
|
146
|
+
contractAddress: t.contractAddress as `0x${string}`,
|
|
147
|
+
chainId: t.chainId,
|
|
148
|
+
decimals: t.decimals,
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
tokenRegistry.set(
|
|
152
|
+
tokenKey(validated.chainId, validated.contractAddress),
|
|
153
|
+
validated,
|
|
154
|
+
);
|
|
155
|
+
return validated;
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
export const getCustomToken = (
|
|
159
|
+
chainId: number,
|
|
160
|
+
contractAddress: string,
|
|
161
|
+
): CustomToken | undefined =>
|
|
162
|
+
tokenRegistry.get(tokenKey(chainId, contractAddress));
|
|
163
|
+
|
|
164
|
+
export const getAllCustomTokens = (): CustomToken[] =>
|
|
165
|
+
Array.from(tokenRegistry.values());
|
|
166
|
+
|
|
167
|
+
export const unregisterToken = (
|
|
168
|
+
chainId: number,
|
|
169
|
+
contractAddress: string,
|
|
170
|
+
): boolean => tokenRegistry.delete(tokenKey(chainId, contractAddress));
|
|
171
|
+
|
|
172
|
+
export const isCustomToken = (
|
|
173
|
+
chainId: number,
|
|
174
|
+
contractAddress: string,
|
|
175
|
+
): boolean => tokenRegistry.has(tokenKey(chainId, contractAddress));
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Protocol Types - x402 V2 Only
|
|
3
|
+
*
|
|
4
|
+
* Simplified to support only x402 V2 format (Coinbase compatible)
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type {
|
|
8
|
+
Address,
|
|
9
|
+
PaymentPayloadV2,
|
|
10
|
+
PaymentRequiredV2,
|
|
11
|
+
PaymentRequirementsV2,
|
|
12
|
+
SettlementResponseV2,
|
|
13
|
+
} from "./v2";
|
|
14
|
+
|
|
15
|
+
// ============================================================================
|
|
16
|
+
// Type Aliases for V2 Only
|
|
17
|
+
// ============================================================================
|
|
18
|
+
|
|
19
|
+
export type PaymentPayload = PaymentPayloadV2;
|
|
20
|
+
export type PaymentRequirements = PaymentRequirementsV2;
|
|
21
|
+
export type SettlementResponse = SettlementResponseV2;
|
|
22
|
+
export type PaymentRequired = PaymentRequiredV2;
|
|
23
|
+
|
|
24
|
+
// ============================================================================
|
|
25
|
+
// Facilitator Communication Types (shared across middleware packages)
|
|
26
|
+
// ============================================================================
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Configuration for connecting to a facilitator service
|
|
30
|
+
*/
|
|
31
|
+
export interface FacilitatorConfig {
|
|
32
|
+
url: string;
|
|
33
|
+
createHeaders?: () => Record<string, string>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Result from facilitator verification
|
|
38
|
+
*/
|
|
39
|
+
export interface FacilitatorVerifyResult {
|
|
40
|
+
success: boolean;
|
|
41
|
+
payerAddress?: string;
|
|
42
|
+
balance?: string;
|
|
43
|
+
requiredAmount?: string;
|
|
44
|
+
error?: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Result from facilitator settlement
|
|
49
|
+
*/
|
|
50
|
+
export interface FacilitatorSettleResult {
|
|
51
|
+
success: boolean;
|
|
52
|
+
txHash?: string;
|
|
53
|
+
error?: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Settlement mode - verify only, settle only, or both
|
|
58
|
+
*/
|
|
59
|
+
export type SettlementMode = "verify" | "settle" | "async";
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Payment destination - address, CAIP-2 chain ID, or CAIP asset ID
|
|
63
|
+
*/
|
|
64
|
+
export type PayToAddress = Address | CAIP2ChainId | CAIPAssetId;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* CAIP-2 chain ID type (e.g., eip155:8453)
|
|
68
|
+
*/
|
|
69
|
+
export type CAIP2ChainId = `eip155:${string}`;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* CAIP-2 asset ID type (e.g., eip155:8453/erc20:0xa0b8691...)
|
|
73
|
+
*/
|
|
74
|
+
export type CAIPAssetId = `eip155:${string}/erc20:${string}`;
|
|
75
|
+
|
|
76
|
+
// ============================================================================
|
|
77
|
+
// Type Guards
|
|
78
|
+
// ============================================================================
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Check if payload is x402 V2 format (Coinbase format)
|
|
82
|
+
*/
|
|
83
|
+
export function isX402V2Payload(obj: unknown): obj is PaymentPayloadV2 {
|
|
84
|
+
return (
|
|
85
|
+
typeof obj === "object" &&
|
|
86
|
+
obj !== null &&
|
|
87
|
+
"x402Version" in obj &&
|
|
88
|
+
(obj as PaymentPayloadV2).x402Version === 2 &&
|
|
89
|
+
"accepted" in obj &&
|
|
90
|
+
"payload" in obj
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Check if requirements is x402 V2 format
|
|
96
|
+
*/
|
|
97
|
+
export function isX402V2Requirements(
|
|
98
|
+
obj: unknown,
|
|
99
|
+
): obj is PaymentRequirementsV2 {
|
|
100
|
+
return (
|
|
101
|
+
typeof obj === "object" &&
|
|
102
|
+
obj !== null &&
|
|
103
|
+
"scheme" in obj &&
|
|
104
|
+
(obj as PaymentRequirementsV2).scheme === "exact" &&
|
|
105
|
+
"network" in obj &&
|
|
106
|
+
typeof (obj as PaymentRequirementsV2).network === "string" &&
|
|
107
|
+
(obj as PaymentRequirementsV2).network.startsWith("eip155:") && // CAIP-2 format
|
|
108
|
+
"amount" in obj &&
|
|
109
|
+
"asset" in obj &&
|
|
110
|
+
"payTo" in obj &&
|
|
111
|
+
"maxTimeoutSeconds" in obj
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Check if settlement response is x402 V2 format
|
|
117
|
+
*/
|
|
118
|
+
export function isX402V2Settlement(obj: unknown): obj is SettlementResponseV2 {
|
|
119
|
+
return (
|
|
120
|
+
typeof obj === "object" &&
|
|
121
|
+
obj !== null &&
|
|
122
|
+
"success" in obj &&
|
|
123
|
+
typeof (obj as SettlementResponseV2).success === "boolean" &&
|
|
124
|
+
"network" in obj &&
|
|
125
|
+
typeof (obj as SettlementResponseV2).network === "string" &&
|
|
126
|
+
(obj as SettlementResponseV2).network.startsWith("eip155:") // CAIP-2 format
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Check if payment required is x402 V2 format
|
|
132
|
+
*/
|
|
133
|
+
export function isX402V2PaymentRequired(
|
|
134
|
+
obj: unknown,
|
|
135
|
+
): obj is PaymentRequiredV2 {
|
|
136
|
+
return (
|
|
137
|
+
typeof obj === "object" &&
|
|
138
|
+
obj !== null &&
|
|
139
|
+
"x402Version" in obj &&
|
|
140
|
+
(obj as PaymentRequiredV2).x402Version === 2 &&
|
|
141
|
+
"resource" in obj &&
|
|
142
|
+
"accepts" in obj
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ============================================================================
|
|
147
|
+
// Header Names (V2 Hardcoded)
|
|
148
|
+
// ============================================================================
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* x402 V2 payment header name
|
|
152
|
+
*/
|
|
153
|
+
export const PAYMENT_SIGNATURE_HEADER = "PAYMENT-SIGNATURE" as const;
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* x402 V2 payment response header name
|
|
157
|
+
*/
|
|
158
|
+
export const PAYMENT_RESPONSE_HEADER = "PAYMENT-RESPONSE" as const;
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* x402 V2 payment required header name
|
|
162
|
+
*/
|
|
163
|
+
export const PAYMENT_REQUIRED_HEADER = "PAYMENT-REQUIRED" as const;
|
|
164
|
+
|
|
165
|
+
// ============================================================================
|
|
166
|
+
// Utility Functions
|
|
167
|
+
// ============================================================================
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Check if settlement was successful
|
|
171
|
+
*/
|
|
172
|
+
export function isSettlementSuccessful(response: SettlementResponse): boolean {
|
|
173
|
+
return "success" in response ? response.success : false;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Get transaction hash from settlement response (V2 only)
|
|
178
|
+
*/
|
|
179
|
+
export function getTxHash(response: SettlementResponse): string | undefined {
|
|
180
|
+
if ("transaction" in response) return response.transaction;
|
|
181
|
+
return undefined;
|
|
182
|
+
}
|