@armory-sh/base 0.2.0
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/LICENSE +21 -0
- package/README.md +28 -0
- package/dist/abi/erc20.d.ts +116 -0
- package/dist/eip712.d.ts +61 -0
- package/dist/encoding.d.ts +22 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +730 -0
- package/dist/types/networks.d.ts +26 -0
- package/dist/types/protocol.d.ts +15 -0
- package/dist/types/simple.d.ts +147 -0
- package/dist/types/v1.d.ts +34 -0
- package/dist/types/v2.d.ts +50 -0
- package/dist/validation.d.ts +54 -0
- package/package.json +41 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sawyer Cutler
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# @armory-sh/base
|
|
2
|
+
|
|
3
|
+
Core types and utilities for Armory payment protocol.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add @armory-sh/base
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Use
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import type { PaymentRequest, PaymentResponse } from '@armory-sh/base'
|
|
15
|
+
import { calculateExpiry } from '@armory-sh/base'
|
|
16
|
+
|
|
17
|
+
const payment: PaymentRequest = {
|
|
18
|
+
to: '0x...',
|
|
19
|
+
amount: 1000000n,
|
|
20
|
+
expiry: calculateExpiry(3600),
|
|
21
|
+
chainId: 'eip155:8453',
|
|
22
|
+
assetId: 'eip155:8453/erc20:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
MIT License | Sawyer Cutler 2026 | Provided "AS IS" without warranty
|
|
@@ -0,0 +1,116 @@
|
|
|
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
|
+
export type ReceiveWithAuthorizationParams = readonly [
|
|
12
|
+
from: `0x${string}`,
|
|
13
|
+
to: `0x${string}`,
|
|
14
|
+
amount: bigint,
|
|
15
|
+
validAfter: bigint,
|
|
16
|
+
expiry: bigint,
|
|
17
|
+
v: number,
|
|
18
|
+
r: `0x${string}`,
|
|
19
|
+
s: `0x${string}`
|
|
20
|
+
];
|
|
21
|
+
export type BalanceOfParams = readonly [account: `0x${string}`];
|
|
22
|
+
export type BalanceOfReturnType = bigint;
|
|
23
|
+
export type NameReturnType = string;
|
|
24
|
+
export type SymbolReturnType = string;
|
|
25
|
+
export declare const ERC20_ABI: readonly [{
|
|
26
|
+
readonly type: "function";
|
|
27
|
+
readonly name: "transferWithAuthorization";
|
|
28
|
+
readonly stateMutability: "nonpayable";
|
|
29
|
+
readonly inputs: readonly [{
|
|
30
|
+
readonly name: "from";
|
|
31
|
+
readonly type: "address";
|
|
32
|
+
}, {
|
|
33
|
+
readonly name: "to";
|
|
34
|
+
readonly type: "address";
|
|
35
|
+
}, {
|
|
36
|
+
readonly name: "amount";
|
|
37
|
+
readonly type: "uint256";
|
|
38
|
+
}, {
|
|
39
|
+
readonly name: "validAfter";
|
|
40
|
+
readonly type: "uint256";
|
|
41
|
+
}, {
|
|
42
|
+
readonly name: "expiry";
|
|
43
|
+
readonly type: "uint256";
|
|
44
|
+
}, {
|
|
45
|
+
readonly name: "v";
|
|
46
|
+
readonly type: "uint8";
|
|
47
|
+
}, {
|
|
48
|
+
readonly name: "r";
|
|
49
|
+
readonly type: "bytes32";
|
|
50
|
+
}, {
|
|
51
|
+
readonly name: "s";
|
|
52
|
+
readonly type: "bytes32";
|
|
53
|
+
}];
|
|
54
|
+
readonly outputs: readonly [];
|
|
55
|
+
}, {
|
|
56
|
+
readonly type: "function";
|
|
57
|
+
readonly name: "receiveWithAuthorization";
|
|
58
|
+
readonly stateMutability: "nonpayable";
|
|
59
|
+
readonly inputs: readonly [{
|
|
60
|
+
readonly name: "from";
|
|
61
|
+
readonly type: "address";
|
|
62
|
+
}, {
|
|
63
|
+
readonly name: "to";
|
|
64
|
+
readonly type: "address";
|
|
65
|
+
}, {
|
|
66
|
+
readonly name: "amount";
|
|
67
|
+
readonly type: "uint256";
|
|
68
|
+
}, {
|
|
69
|
+
readonly name: "validAfter";
|
|
70
|
+
readonly type: "uint256";
|
|
71
|
+
}, {
|
|
72
|
+
readonly name: "expiry";
|
|
73
|
+
readonly type: "uint256";
|
|
74
|
+
}, {
|
|
75
|
+
readonly name: "v";
|
|
76
|
+
readonly type: "uint8";
|
|
77
|
+
}, {
|
|
78
|
+
readonly name: "r";
|
|
79
|
+
readonly type: "bytes32";
|
|
80
|
+
}, {
|
|
81
|
+
readonly name: "s";
|
|
82
|
+
readonly type: "bytes32";
|
|
83
|
+
}];
|
|
84
|
+
readonly outputs: readonly [];
|
|
85
|
+
}, {
|
|
86
|
+
readonly type: "function";
|
|
87
|
+
readonly name: "balanceOf";
|
|
88
|
+
readonly stateMutability: "view";
|
|
89
|
+
readonly inputs: readonly [{
|
|
90
|
+
readonly name: "account";
|
|
91
|
+
readonly type: "address";
|
|
92
|
+
}];
|
|
93
|
+
readonly outputs: readonly [{
|
|
94
|
+
readonly name: "balance";
|
|
95
|
+
readonly type: "uint256";
|
|
96
|
+
}];
|
|
97
|
+
}, {
|
|
98
|
+
readonly type: "function";
|
|
99
|
+
readonly name: "name";
|
|
100
|
+
readonly stateMutability: "view";
|
|
101
|
+
readonly inputs: readonly [];
|
|
102
|
+
readonly outputs: readonly [{
|
|
103
|
+
readonly name: "";
|
|
104
|
+
readonly type: "string";
|
|
105
|
+
}];
|
|
106
|
+
}, {
|
|
107
|
+
readonly type: "function";
|
|
108
|
+
readonly name: "symbol";
|
|
109
|
+
readonly stateMutability: "view";
|
|
110
|
+
readonly inputs: readonly [];
|
|
111
|
+
readonly outputs: readonly [{
|
|
112
|
+
readonly name: "";
|
|
113
|
+
readonly type: "string";
|
|
114
|
+
}];
|
|
115
|
+
}];
|
|
116
|
+
export type ERC20Abi = typeof ERC20_ABI;
|
package/dist/eip712.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export type TypedDataDomain = {
|
|
2
|
+
name?: string;
|
|
3
|
+
version?: string;
|
|
4
|
+
chainId?: number;
|
|
5
|
+
verifyingContract?: `0x${string}`;
|
|
6
|
+
salt?: `0x${string}`;
|
|
7
|
+
};
|
|
8
|
+
export interface EIP712Domain {
|
|
9
|
+
name: string;
|
|
10
|
+
version: string;
|
|
11
|
+
chainId: number;
|
|
12
|
+
verifyingContract: `0x${string}`;
|
|
13
|
+
}
|
|
14
|
+
export interface TransferWithAuthorization {
|
|
15
|
+
from: `0x${string}`;
|
|
16
|
+
to: `0x${string}`;
|
|
17
|
+
value: bigint;
|
|
18
|
+
validAfter: bigint;
|
|
19
|
+
validBefore: bigint;
|
|
20
|
+
nonce: bigint;
|
|
21
|
+
}
|
|
22
|
+
export type TypedDataField = {
|
|
23
|
+
name: string;
|
|
24
|
+
type: string;
|
|
25
|
+
};
|
|
26
|
+
export type EIP712Types = {
|
|
27
|
+
TransferWithAuthorization: TypedDataField[];
|
|
28
|
+
};
|
|
29
|
+
export declare const EIP712_TYPES: {
|
|
30
|
+
readonly TransferWithAuthorization: [{
|
|
31
|
+
readonly name: "from";
|
|
32
|
+
readonly type: "address";
|
|
33
|
+
}, {
|
|
34
|
+
readonly name: "to";
|
|
35
|
+
readonly type: "address";
|
|
36
|
+
}, {
|
|
37
|
+
readonly name: "value";
|
|
38
|
+
readonly type: "uint256";
|
|
39
|
+
}, {
|
|
40
|
+
readonly name: "validAfter";
|
|
41
|
+
readonly type: "uint256";
|
|
42
|
+
}, {
|
|
43
|
+
readonly name: "validBefore";
|
|
44
|
+
readonly type: "uint256";
|
|
45
|
+
}, {
|
|
46
|
+
readonly name: "nonce";
|
|
47
|
+
readonly type: "uint256";
|
|
48
|
+
}];
|
|
49
|
+
};
|
|
50
|
+
export declare const USDC_DOMAIN: {
|
|
51
|
+
readonly NAME: "USD Coin";
|
|
52
|
+
readonly VERSION: "2";
|
|
53
|
+
};
|
|
54
|
+
export declare const createEIP712Domain: (chainId: number, contractAddress: `0x${string}`) => EIP712Domain;
|
|
55
|
+
export declare const createTransferWithAuthorization: (params: Omit<TransferWithAuthorization, "value" | "validAfter" | "validBefore" | "nonce"> & {
|
|
56
|
+
value: bigint | number;
|
|
57
|
+
validAfter: bigint | number;
|
|
58
|
+
validBefore: bigint | number;
|
|
59
|
+
nonce: bigint | number;
|
|
60
|
+
}) => TransferWithAuthorization;
|
|
61
|
+
export declare const validateTransferWithAuthorization: (message: TransferWithAuthorization) => boolean;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { PaymentPayloadV1, SettlementResponseV1 } from "./types/v1";
|
|
2
|
+
import { V1_HEADERS } from "./types/v1";
|
|
3
|
+
import type { PaymentPayloadV2, SettlementResponseV2 } from "./types/v2";
|
|
4
|
+
import { V2_HEADERS } from "./types/v2";
|
|
5
|
+
export { V1_HEADERS, V2_HEADERS };
|
|
6
|
+
export type PaymentPayload = PaymentPayloadV1 | PaymentPayloadV2;
|
|
7
|
+
export type SettlementResponse = SettlementResponseV1 | SettlementResponseV2;
|
|
8
|
+
export declare const encodePaymentV1: (payload: PaymentPayloadV1) => string;
|
|
9
|
+
export declare const decodePaymentV1: (encoded: string) => PaymentPayloadV1;
|
|
10
|
+
export declare const encodeSettlementV1: (response: SettlementResponseV1) => string;
|
|
11
|
+
export declare const decodeSettlementV1: (encoded: string) => SettlementResponseV1;
|
|
12
|
+
export declare const encodePaymentV2: (payload: PaymentPayloadV2) => string;
|
|
13
|
+
export declare const decodePaymentV2: (encoded: string) => PaymentPayloadV2;
|
|
14
|
+
export declare const encodeSettlementV2: (response: SettlementResponseV2) => string;
|
|
15
|
+
export declare const decodeSettlementV2: (encoded: string) => SettlementResponseV2;
|
|
16
|
+
export declare const detectPaymentVersion: (headers: Headers) => 1 | 2 | null;
|
|
17
|
+
export declare const decodePayment: (headers: Headers) => PaymentPayload;
|
|
18
|
+
export declare const decodeSettlement: (headers: Headers) => SettlementResponse;
|
|
19
|
+
export declare const isPaymentV1: (payload: PaymentPayload) => payload is PaymentPayloadV1;
|
|
20
|
+
export declare const isPaymentV2: (payload: PaymentPayload) => payload is PaymentPayloadV2;
|
|
21
|
+
export declare const isSettlementV1: (response: SettlementResponse) => response is SettlementResponseV1;
|
|
22
|
+
export declare const isSettlementV2: (response: SettlementResponse) => response is SettlementResponseV2;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type { PaymentPayloadV1, PaymentRequirementsV1, SettlementResponseV1, } from "./types/v1";
|
|
2
|
+
export { V1_HEADERS, encodePaymentPayload, decodePaymentPayload, encodeSettlementResponse, decodeSettlementResponse, } from "./types/v1";
|
|
3
|
+
export type { CAIP2ChainId, CAIPAssetId, Address, Signature, PayToV2, Extensions, PaymentPayloadV2, PaymentRequirementsV2, SettlementResponseV2, } from "./types/v2";
|
|
4
|
+
export { V2_HEADERS, isCAIP2ChainId, isCAIPAssetId, isAddress, } from "./types/v2";
|
|
5
|
+
export type { PaymentPayload, PaymentRequirements, SettlementResponse, } from "./types/protocol";
|
|
6
|
+
export { isV1, isV2, getPaymentVersion as getPaymentVersionFromPayload, getRequirementsVersion, getSettlementVersion, getPaymentHeaderName, getPaymentResponseHeaderName, getPaymentRequiredHeaderName, isSettlementSuccessful, getTxHash, } from "./types/protocol";
|
|
7
|
+
export type { NetworkConfig, CustomToken } from "./types/networks";
|
|
8
|
+
export { NETWORKS, getNetworkConfig, getNetworkByChainId, getMainnets, getTestnets, registerToken, getCustomToken, getAllCustomTokens, unregisterToken, isCustomToken, } from "./types/networks";
|
|
9
|
+
export type { TransferWithAuthorizationParams, ReceiveWithAuthorizationParams, BalanceOfParams, BalanceOfReturnType, NameReturnType, SymbolReturnType, ERC20Abi, } from "./abi/erc20";
|
|
10
|
+
export { ERC20_ABI } from "./abi/erc20";
|
|
11
|
+
export type { PaymentPayload as EncodingPaymentPayload, SettlementResponse as EncodingSettlementResponse, } from "./encoding";
|
|
12
|
+
export { encodePaymentV1, decodePaymentV1, encodeSettlementV1, decodeSettlementV1, encodePaymentV2, decodePaymentV2, encodeSettlementV2, decodeSettlementV2, detectPaymentVersion, decodePayment, decodeSettlement, isPaymentV1, isPaymentV2, isSettlementV1, isSettlementV2, } from "./encoding";
|
|
13
|
+
export type { TypedDataDomain, EIP712Domain, TransferWithAuthorization, TypedDataField, EIP712Types, } from "./eip712";
|
|
14
|
+
export { EIP712_TYPES, USDC_DOMAIN, createEIP712Domain, createTransferWithAuthorization, validateTransferWithAuthorization, } from "./eip712";
|
|
15
|
+
export { resolveNetwork, resolveToken, resolveFacilitator, checkFacilitatorSupport, validatePaymentConfig, validateAcceptConfig, getAvailableNetworks, getAvailableTokens, isValidationError, isResolvedNetwork, isResolvedToken, createError, } from "./validation";
|
|
16
|
+
export type { NetworkId, TokenId, FacilitatorConfig, AcceptPaymentOptions, PaymentResult, PaymentError, PaymentErrorCode, ArmoryPaymentResult, ResolvedNetwork, ResolvedToken, ResolvedFacilitator, ResolvedPaymentConfig, ValidationError, } from "./types/simple";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,730 @@
|
|
|
1
|
+
// src/types/v1.ts
|
|
2
|
+
var V1_HEADERS = {
|
|
3
|
+
PAYMENT: "X-PAYMENT",
|
|
4
|
+
PAYMENT_RESPONSE: "X-PAYMENT-RESPONSE"
|
|
5
|
+
};
|
|
6
|
+
function encodePaymentPayload(payload) {
|
|
7
|
+
return Buffer.from(JSON.stringify(payload)).toString("base64");
|
|
8
|
+
}
|
|
9
|
+
function decodePaymentPayload(encoded) {
|
|
10
|
+
return JSON.parse(Buffer.from(encoded, "base64").toString("utf-8"));
|
|
11
|
+
}
|
|
12
|
+
function encodeSettlementResponse(response) {
|
|
13
|
+
return Buffer.from(JSON.stringify(response)).toString("base64");
|
|
14
|
+
}
|
|
15
|
+
function decodeSettlementResponse(encoded) {
|
|
16
|
+
return JSON.parse(Buffer.from(encoded, "base64").toString("utf-8"));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// src/types/v2.ts
|
|
20
|
+
var V2_HEADERS = {
|
|
21
|
+
PAYMENT_SIGNATURE: "PAYMENT-SIGNATURE",
|
|
22
|
+
PAYMENT_REQUIRED: "PAYMENT-REQUIRED",
|
|
23
|
+
PAYMENT_RESPONSE: "PAYMENT-RESPONSE"
|
|
24
|
+
};
|
|
25
|
+
function isCAIP2ChainId(value) {
|
|
26
|
+
return /^eip155:\d+$/.test(value);
|
|
27
|
+
}
|
|
28
|
+
function isCAIPAssetId(value) {
|
|
29
|
+
return /^eip155:\d+\/erc20:0x[a-fA-F0-9]+$/.test(value);
|
|
30
|
+
}
|
|
31
|
+
function isAddress(value) {
|
|
32
|
+
return /^0x[a-fA-F0-9]{40}$/.test(value);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// src/types/protocol.ts
|
|
36
|
+
var isV1 = (payload) => "contractAddress" in payload && "network" in payload && "v" in payload;
|
|
37
|
+
var isV2 = (payload) => "chainId" in payload && "assetId" in payload && "signature" in payload;
|
|
38
|
+
var getPaymentVersion = (payload) => isV1(payload) ? 1 : 2;
|
|
39
|
+
var getRequirementsVersion = (requirements) => "contractAddress" in requirements && "network" in requirements ? 1 : 2;
|
|
40
|
+
var getSettlementVersion = (response) => "success" in response ? 1 : 2;
|
|
41
|
+
var getPaymentHeaderName = (version) => version === 1 ? "X-PAYMENT" : "PAYMENT-SIGNATURE";
|
|
42
|
+
var getPaymentResponseHeaderName = (version) => version === 1 ? "X-PAYMENT-RESPONSE" : "PAYMENT-RESPONSE";
|
|
43
|
+
var getPaymentRequiredHeaderName = (version) => version === 1 ? "X-PAYMENT-REQUIRED" : "PAYMENT-REQUIRED";
|
|
44
|
+
var isSettlementSuccessful = (response) => "success" in response ? response.success : response.status === "success";
|
|
45
|
+
var getTxHash = (response) => response.txHash;
|
|
46
|
+
|
|
47
|
+
// src/types/networks.ts
|
|
48
|
+
var tokenRegistry = /* @__PURE__ */ new Map();
|
|
49
|
+
var tokenKey = (chainId, contractAddress) => `${chainId}:${contractAddress.toLowerCase()}`;
|
|
50
|
+
var NETWORKS = {
|
|
51
|
+
ethereum: {
|
|
52
|
+
name: "Ethereum Mainnet",
|
|
53
|
+
chainId: 1,
|
|
54
|
+
usdcAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
55
|
+
rpcUrl: "https://eth.llamarpc.com",
|
|
56
|
+
caip2Id: "eip155:1",
|
|
57
|
+
caipAssetId: "eip155:1/erc20:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
|
|
58
|
+
},
|
|
59
|
+
base: {
|
|
60
|
+
name: "Base Mainnet",
|
|
61
|
+
chainId: 8453,
|
|
62
|
+
usdcAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
63
|
+
rpcUrl: "https://mainnet.base.org",
|
|
64
|
+
caip2Id: "eip155:8453",
|
|
65
|
+
caipAssetId: "eip155:8453/erc20:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
|
|
66
|
+
},
|
|
67
|
+
"base-sepolia": {
|
|
68
|
+
name: "Base Sepolia",
|
|
69
|
+
chainId: 84532,
|
|
70
|
+
usdcAddress: "0x036CbD53842c5426634e7929541eA237834d2D14",
|
|
71
|
+
rpcUrl: "https://sepolia.base.org",
|
|
72
|
+
caip2Id: "eip155:84532",
|
|
73
|
+
caipAssetId: "eip155:84532/erc20:0x036CbD53842c5426634e7929541eA237834d2D14"
|
|
74
|
+
},
|
|
75
|
+
"skale-base": {
|
|
76
|
+
name: "SKALE Base",
|
|
77
|
+
chainId: 1187947933,
|
|
78
|
+
usdcAddress: "0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20",
|
|
79
|
+
rpcUrl: "https://skale-base.skalenodes.com/v1/base",
|
|
80
|
+
caip2Id: "eip155:1187947933",
|
|
81
|
+
caipAssetId: "eip155:1187947933/erc20:0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20"
|
|
82
|
+
},
|
|
83
|
+
"skale-base-sepolia": {
|
|
84
|
+
name: "SKALE Base Sepolia",
|
|
85
|
+
chainId: 324705682,
|
|
86
|
+
usdcAddress: "0x2e08028E3C4c2356572E096d8EF835cD5C6030bD",
|
|
87
|
+
rpcUrl: "https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha",
|
|
88
|
+
caip2Id: "eip155:324705682",
|
|
89
|
+
caipAssetId: "eip155:324705682/erc20:0x2e08028E3C4c2356572E096d8EF835cD5C6030bD"
|
|
90
|
+
},
|
|
91
|
+
"ethereum-sepolia": {
|
|
92
|
+
name: "Ethereum Sepolia",
|
|
93
|
+
chainId: 11155111,
|
|
94
|
+
usdcAddress: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
|
|
95
|
+
rpcUrl: "https://rpc.sepolia.org",
|
|
96
|
+
caip2Id: "eip155:11155111",
|
|
97
|
+
caipAssetId: "eip155:11155111/erc20:0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
var getNetworkConfig = (name) => NETWORKS[name];
|
|
101
|
+
var getNetworkByChainId = (chainId) => Object.values(NETWORKS).find((c) => c.chainId === chainId);
|
|
102
|
+
var getMainnets = () => Object.values(NETWORKS).filter((c) => !c.name.toLowerCase().includes("sepolia"));
|
|
103
|
+
var getTestnets = () => Object.values(NETWORKS).filter((c) => c.name.toLowerCase().includes("sepolia"));
|
|
104
|
+
var registerToken = (token) => {
|
|
105
|
+
tokenRegistry.set(tokenKey(token.chainId, token.contractAddress), token);
|
|
106
|
+
return token;
|
|
107
|
+
};
|
|
108
|
+
var getCustomToken = (chainId, contractAddress) => tokenRegistry.get(tokenKey(chainId, contractAddress));
|
|
109
|
+
var getAllCustomTokens = () => Array.from(tokenRegistry.values());
|
|
110
|
+
var unregisterToken = (chainId, contractAddress) => tokenRegistry.delete(tokenKey(chainId, contractAddress));
|
|
111
|
+
var isCustomToken = (chainId, contractAddress) => tokenRegistry.has(tokenKey(chainId, contractAddress));
|
|
112
|
+
|
|
113
|
+
// src/abi/erc20.ts
|
|
114
|
+
var ERC20_ABI = [
|
|
115
|
+
{
|
|
116
|
+
type: "function",
|
|
117
|
+
name: "transferWithAuthorization",
|
|
118
|
+
stateMutability: "nonpayable",
|
|
119
|
+
inputs: [
|
|
120
|
+
{ name: "from", type: "address" },
|
|
121
|
+
{ name: "to", type: "address" },
|
|
122
|
+
{ name: "amount", type: "uint256" },
|
|
123
|
+
{ name: "validAfter", type: "uint256" },
|
|
124
|
+
{ name: "expiry", type: "uint256" },
|
|
125
|
+
{ name: "v", type: "uint8" },
|
|
126
|
+
{ name: "r", type: "bytes32" },
|
|
127
|
+
{ name: "s", type: "bytes32" }
|
|
128
|
+
],
|
|
129
|
+
outputs: []
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
type: "function",
|
|
133
|
+
name: "receiveWithAuthorization",
|
|
134
|
+
stateMutability: "nonpayable",
|
|
135
|
+
inputs: [
|
|
136
|
+
{ name: "from", type: "address" },
|
|
137
|
+
{ name: "to", type: "address" },
|
|
138
|
+
{ name: "amount", type: "uint256" },
|
|
139
|
+
{ name: "validAfter", type: "uint256" },
|
|
140
|
+
{ name: "expiry", type: "uint256" },
|
|
141
|
+
{ name: "v", type: "uint8" },
|
|
142
|
+
{ name: "r", type: "bytes32" },
|
|
143
|
+
{ name: "s", type: "bytes32" }
|
|
144
|
+
],
|
|
145
|
+
outputs: []
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
type: "function",
|
|
149
|
+
name: "balanceOf",
|
|
150
|
+
stateMutability: "view",
|
|
151
|
+
inputs: [{ name: "account", type: "address" }],
|
|
152
|
+
outputs: [{ name: "balance", type: "uint256" }]
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
type: "function",
|
|
156
|
+
name: "name",
|
|
157
|
+
stateMutability: "view",
|
|
158
|
+
inputs: [],
|
|
159
|
+
outputs: [{ name: "", type: "string" }]
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
type: "function",
|
|
163
|
+
name: "symbol",
|
|
164
|
+
stateMutability: "view",
|
|
165
|
+
inputs: [],
|
|
166
|
+
outputs: [{ name: "", type: "string" }]
|
|
167
|
+
}
|
|
168
|
+
];
|
|
169
|
+
|
|
170
|
+
// src/encoding.ts
|
|
171
|
+
var base64Encode = (data) => Buffer.from(JSON.stringify(data)).toString("base64");
|
|
172
|
+
var base64Decode = (encoded) => JSON.parse(Buffer.from(encoded, "base64").toString("utf-8"));
|
|
173
|
+
var jsonEncode = (data) => JSON.stringify(data);
|
|
174
|
+
var jsonDecode = (encoded) => JSON.parse(encoded);
|
|
175
|
+
var encodePaymentV1 = (payload) => base64Encode(payload);
|
|
176
|
+
var decodePaymentV1 = (encoded) => base64Decode(encoded);
|
|
177
|
+
var encodeSettlementV1 = (response) => base64Encode(response);
|
|
178
|
+
var decodeSettlementV1 = (encoded) => base64Decode(encoded);
|
|
179
|
+
var encodePaymentV2 = (payload) => jsonEncode(payload);
|
|
180
|
+
var decodePaymentV2 = (encoded) => jsonDecode(encoded);
|
|
181
|
+
var encodeSettlementV2 = (response) => jsonEncode(response);
|
|
182
|
+
var decodeSettlementV2 = (encoded) => jsonDecode(encoded);
|
|
183
|
+
var detectPaymentVersion = (headers) => {
|
|
184
|
+
if (headers.has(V1_HEADERS.PAYMENT)) return 1;
|
|
185
|
+
if (headers.has(V2_HEADERS.PAYMENT_SIGNATURE)) return 2;
|
|
186
|
+
return null;
|
|
187
|
+
};
|
|
188
|
+
var decodePayment = (headers) => {
|
|
189
|
+
const version = detectPaymentVersion(headers);
|
|
190
|
+
if (version === null) {
|
|
191
|
+
throw new Error("No valid payment headers found. Expected X-PAYMENT (v1) or PAYMENT-SIGNATURE (v2)");
|
|
192
|
+
}
|
|
193
|
+
const headerName = version === 1 ? V1_HEADERS.PAYMENT : V2_HEADERS.PAYMENT_SIGNATURE;
|
|
194
|
+
const encoded = headers.get(headerName);
|
|
195
|
+
if (!encoded) throw new Error(`Header ${headerName} is empty`);
|
|
196
|
+
return version === 1 ? decodePaymentV1(encoded) : decodePaymentV2(encoded);
|
|
197
|
+
};
|
|
198
|
+
var decodeSettlement = (headers) => {
|
|
199
|
+
const v1Response = headers.get(V1_HEADERS.PAYMENT_RESPONSE);
|
|
200
|
+
if (v1Response) return decodeSettlementV1(v1Response);
|
|
201
|
+
const v2Response = headers.get(V2_HEADERS.PAYMENT_RESPONSE);
|
|
202
|
+
if (v2Response) return decodeSettlementV2(v2Response);
|
|
203
|
+
throw new Error("No valid settlement response headers found. Expected X-PAYMENT-RESPONSE (v1) or PAYMENT-RESPONSE (v2)");
|
|
204
|
+
};
|
|
205
|
+
var isPaymentV1 = (payload) => "v" in payload && typeof payload.v === "number";
|
|
206
|
+
var isPaymentV2 = (payload) => "signature" in payload && typeof payload.signature === "object";
|
|
207
|
+
var isSettlementV1 = (response) => "success" in response;
|
|
208
|
+
var isSettlementV2 = (response) => "status" in response;
|
|
209
|
+
|
|
210
|
+
// src/eip712.ts
|
|
211
|
+
var EIP712_TYPES = {
|
|
212
|
+
TransferWithAuthorization: [
|
|
213
|
+
{ name: "from", type: "address" },
|
|
214
|
+
{ name: "to", type: "address" },
|
|
215
|
+
{ name: "value", type: "uint256" },
|
|
216
|
+
{ name: "validAfter", type: "uint256" },
|
|
217
|
+
{ name: "validBefore", type: "uint256" },
|
|
218
|
+
{ name: "nonce", type: "uint256" }
|
|
219
|
+
]
|
|
220
|
+
};
|
|
221
|
+
var USDC_DOMAIN = {
|
|
222
|
+
NAME: "USD Coin",
|
|
223
|
+
VERSION: "2"
|
|
224
|
+
};
|
|
225
|
+
var createEIP712Domain = (chainId, contractAddress) => ({
|
|
226
|
+
name: USDC_DOMAIN.NAME,
|
|
227
|
+
version: USDC_DOMAIN.VERSION,
|
|
228
|
+
chainId,
|
|
229
|
+
verifyingContract: contractAddress
|
|
230
|
+
});
|
|
231
|
+
var createTransferWithAuthorization = (params) => ({
|
|
232
|
+
from: params.from,
|
|
233
|
+
to: params.to,
|
|
234
|
+
value: BigInt(params.value),
|
|
235
|
+
validAfter: BigInt(params.validAfter),
|
|
236
|
+
validBefore: BigInt(params.validBefore),
|
|
237
|
+
nonce: BigInt(params.nonce)
|
|
238
|
+
});
|
|
239
|
+
var isAddress2 = (value) => /^0x[a-fA-F0-9]{40}$/.test(value);
|
|
240
|
+
var validateTransferWithAuthorization = (message) => {
|
|
241
|
+
if (!isAddress2(message.from)) throw new Error(`Invalid "from" address: ${message.from}`);
|
|
242
|
+
if (!isAddress2(message.to)) throw new Error(`Invalid "to" address: ${message.to}`);
|
|
243
|
+
if (message.value < 0n) throw new Error(`"value" must be non-negative: ${message.value}`);
|
|
244
|
+
if (message.validAfter < 0n) throw new Error(`"validAfter" must be non-negative: ${message.validAfter}`);
|
|
245
|
+
if (message.validBefore < 0n) throw new Error(`"validBefore" must be non-negative: ${message.validBefore}`);
|
|
246
|
+
if (message.validAfter >= message.validBefore) {
|
|
247
|
+
throw new Error(`"validAfter" (${message.validAfter}) must be before "validBefore" (${message.validBefore})`);
|
|
248
|
+
}
|
|
249
|
+
if (message.nonce < 0n) throw new Error(`"nonce" must be non-negative: ${message.nonce}`);
|
|
250
|
+
return true;
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
// src/validation.ts
|
|
254
|
+
var createError = (code, message, details) => ({
|
|
255
|
+
code,
|
|
256
|
+
message,
|
|
257
|
+
...details
|
|
258
|
+
});
|
|
259
|
+
var normalizeNetworkName = (name) => name.toLowerCase().replace(/\s+/g, "-").replace("-mainnet", "").replace(/-mainnet/, "").replace("mainnet-", "").replace(/-sepolia$/, "-sepolia").replace(/^-|-$/g, "");
|
|
260
|
+
var resolveNetwork = (input) => {
|
|
261
|
+
if (typeof input === "object" && input !== null && "chainId" in input) {
|
|
262
|
+
const config = input;
|
|
263
|
+
if (!config.chainId || !config.usdcAddress || !config.caip2Id) {
|
|
264
|
+
return createError("INVALID_CAIP_FORMAT", "Invalid network config", { value: config });
|
|
265
|
+
}
|
|
266
|
+
return {
|
|
267
|
+
input,
|
|
268
|
+
config,
|
|
269
|
+
caip2: config.caip2Id
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
if (typeof input === "number") {
|
|
273
|
+
const config = getNetworkByChainId(input);
|
|
274
|
+
if (!config) {
|
|
275
|
+
const validChainIds = Object.values(NETWORKS).map((n) => n.chainId);
|
|
276
|
+
return createError(
|
|
277
|
+
"UNKNOWN_NETWORK",
|
|
278
|
+
`Unknown chain ID: ${input}`,
|
|
279
|
+
{ value: input, validOptions: validChainIds.map(String) }
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
return {
|
|
283
|
+
input,
|
|
284
|
+
config,
|
|
285
|
+
caip2: config.caip2Id
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
if (typeof input === "string") {
|
|
289
|
+
if (input.startsWith("eip155:")) {
|
|
290
|
+
const parts = input.split(":");
|
|
291
|
+
if (parts.length !== 2 || isNaN(Number(parts[1]))) {
|
|
292
|
+
return createError("INVALID_CAIP_FORMAT", `Invalid CAIP-2 format: ${input}`, { value: input });
|
|
293
|
+
}
|
|
294
|
+
const chainId = Number(parts[1]);
|
|
295
|
+
const config2 = getNetworkByChainId(chainId);
|
|
296
|
+
if (!config2) {
|
|
297
|
+
return createError("UNKNOWN_NETWORK", `Unknown CAIP-2 network: ${input}`, { value: input });
|
|
298
|
+
}
|
|
299
|
+
return {
|
|
300
|
+
input,
|
|
301
|
+
config: config2,
|
|
302
|
+
caip2: input
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
const normalizedName = normalizeNetworkName(input);
|
|
306
|
+
const config = getNetworkConfig(normalizedName);
|
|
307
|
+
if (!config) {
|
|
308
|
+
const validNames = Object.keys(NETWORKS);
|
|
309
|
+
return createError(
|
|
310
|
+
"UNKNOWN_NETWORK",
|
|
311
|
+
`Unknown network: "${input}"`,
|
|
312
|
+
{ value: input, validOptions: validNames }
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
return {
|
|
316
|
+
input,
|
|
317
|
+
config,
|
|
318
|
+
caip2: config.caip2Id
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
return createError("UNKNOWN_NETWORK", `Invalid network identifier type: ${typeof input}`, { value: input });
|
|
322
|
+
};
|
|
323
|
+
var getAvailableNetworks = () => Object.keys(NETWORKS);
|
|
324
|
+
var normalizeTokenSymbol = (symbol) => symbol.toUpperCase();
|
|
325
|
+
var isEvmAddress = (value) => /^0x[a-fA-F0-9]{40}$/.test(value);
|
|
326
|
+
var resolveToken = (input, network) => {
|
|
327
|
+
if (typeof input === "object" && input !== null && "contractAddress" in input) {
|
|
328
|
+
const config = input;
|
|
329
|
+
if (!config.chainId || !config.contractAddress || !config.symbol) {
|
|
330
|
+
return createError("VALIDATION_FAILED", "Invalid token config", { value: config });
|
|
331
|
+
}
|
|
332
|
+
if (network && config.chainId !== network.config.chainId) {
|
|
333
|
+
return createError(
|
|
334
|
+
"TOKEN_NOT_ON_NETWORK",
|
|
335
|
+
`Token ${config.symbol} is on chain ${config.chainId}, but expected chain ${network.config.chainId}`,
|
|
336
|
+
{ value: config }
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
const tokenNetwork = resolveNetwork(config.chainId);
|
|
340
|
+
if ("code" in tokenNetwork) {
|
|
341
|
+
return tokenNetwork;
|
|
342
|
+
}
|
|
343
|
+
const caipAsset = `eip155:${config.chainId}/erc20:${config.contractAddress}`;
|
|
344
|
+
return {
|
|
345
|
+
input,
|
|
346
|
+
config,
|
|
347
|
+
caipAsset,
|
|
348
|
+
network: tokenNetwork
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
if (typeof input === "string") {
|
|
352
|
+
if (isEvmAddress(input)) {
|
|
353
|
+
const contractAddress = input;
|
|
354
|
+
if (network) {
|
|
355
|
+
const customToken = getCustomToken(network.config.chainId, contractAddress);
|
|
356
|
+
const config = customToken || {
|
|
357
|
+
symbol: "CUSTOM",
|
|
358
|
+
name: "Custom Token",
|
|
359
|
+
version: "1",
|
|
360
|
+
chainId: network.config.chainId,
|
|
361
|
+
contractAddress,
|
|
362
|
+
decimals: 18
|
|
363
|
+
};
|
|
364
|
+
const caipAsset = `eip155:${network.config.chainId}/erc20:${contractAddress}`;
|
|
365
|
+
return {
|
|
366
|
+
input,
|
|
367
|
+
config,
|
|
368
|
+
caipAsset,
|
|
369
|
+
network
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
const customTokens2 = getAllCustomTokens();
|
|
373
|
+
const matchingToken2 = customTokens2.find(
|
|
374
|
+
(t) => t.contractAddress.toLowerCase() === contractAddress.toLowerCase()
|
|
375
|
+
);
|
|
376
|
+
if (matchingToken2) {
|
|
377
|
+
const tokenNetwork = resolveNetwork(matchingToken2.chainId);
|
|
378
|
+
if ("code" in tokenNetwork) {
|
|
379
|
+
return tokenNetwork;
|
|
380
|
+
}
|
|
381
|
+
const caipAsset = `eip155:${matchingToken2.chainId}/erc20:${contractAddress}`;
|
|
382
|
+
return {
|
|
383
|
+
input,
|
|
384
|
+
config: matchingToken2,
|
|
385
|
+
caipAsset,
|
|
386
|
+
network: tokenNetwork
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
return createError(
|
|
390
|
+
"UNKNOWN_TOKEN",
|
|
391
|
+
`Token address "${contractAddress}" not found in registry. Please specify a network.`,
|
|
392
|
+
{ value: input, validOptions: ["Specify network parameter"] }
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
if (input.includes("/erc20:")) {
|
|
396
|
+
const parts = input.split("/");
|
|
397
|
+
if (parts.length !== 2) {
|
|
398
|
+
return createError("INVALID_CAIP_FORMAT", `Invalid CAIP Asset ID format: ${input}`, { value: input });
|
|
399
|
+
}
|
|
400
|
+
const chainId = Number(parts[0].split(":")[1]);
|
|
401
|
+
const contractAddress = parts[1].split(":")[1];
|
|
402
|
+
const tokenNetwork = resolveNetwork(chainId);
|
|
403
|
+
if ("code" in tokenNetwork) {
|
|
404
|
+
return tokenNetwork;
|
|
405
|
+
}
|
|
406
|
+
const customToken = getCustomToken(chainId, contractAddress);
|
|
407
|
+
const config = customToken || {
|
|
408
|
+
symbol: "CUSTOM",
|
|
409
|
+
name: "Custom Token",
|
|
410
|
+
version: "1",
|
|
411
|
+
chainId,
|
|
412
|
+
contractAddress,
|
|
413
|
+
decimals: 18
|
|
414
|
+
};
|
|
415
|
+
return {
|
|
416
|
+
input,
|
|
417
|
+
config,
|
|
418
|
+
caipAsset: input,
|
|
419
|
+
network: tokenNetwork
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
const normalizedSymbol = normalizeTokenSymbol(input);
|
|
423
|
+
if (network) {
|
|
424
|
+
const customTokens2 = getAllCustomTokens();
|
|
425
|
+
const matchingToken2 = customTokens2.find(
|
|
426
|
+
(t) => t.symbol.toUpperCase() === normalizedSymbol && t.chainId === network.config.chainId
|
|
427
|
+
);
|
|
428
|
+
if (matchingToken2) {
|
|
429
|
+
return {
|
|
430
|
+
input,
|
|
431
|
+
config: matchingToken2,
|
|
432
|
+
caipAsset: `eip155:${matchingToken2.chainId}/erc20:${matchingToken2.contractAddress}`,
|
|
433
|
+
network
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
return {
|
|
437
|
+
input,
|
|
438
|
+
config: {
|
|
439
|
+
symbol: normalizedSymbol,
|
|
440
|
+
name: network.config.name + " " + normalizedSymbol,
|
|
441
|
+
version: "2",
|
|
442
|
+
chainId: network.config.chainId,
|
|
443
|
+
contractAddress: network.config.usdcAddress,
|
|
444
|
+
decimals: 6
|
|
445
|
+
},
|
|
446
|
+
caipAsset: network.config.caipAssetId,
|
|
447
|
+
network
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
const customTokens = getAllCustomTokens();
|
|
451
|
+
const matchingToken = customTokens.find((t) => t.symbol.toUpperCase() === normalizedSymbol);
|
|
452
|
+
if (matchingToken) {
|
|
453
|
+
const tokenNetwork = resolveNetwork(matchingToken.chainId);
|
|
454
|
+
if ("code" in tokenNetwork) {
|
|
455
|
+
return tokenNetwork;
|
|
456
|
+
}
|
|
457
|
+
return {
|
|
458
|
+
input,
|
|
459
|
+
config: matchingToken,
|
|
460
|
+
caipAsset: `eip155:${matchingToken.chainId}/erc20:${matchingToken.contractAddress}`,
|
|
461
|
+
network: tokenNetwork
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
const baseNetwork = resolveNetwork("base");
|
|
465
|
+
if ("code" in baseNetwork) {
|
|
466
|
+
return baseNetwork;
|
|
467
|
+
}
|
|
468
|
+
return {
|
|
469
|
+
input,
|
|
470
|
+
config: {
|
|
471
|
+
symbol: normalizedSymbol,
|
|
472
|
+
name: "USD Coin",
|
|
473
|
+
version: "2",
|
|
474
|
+
chainId: 8453,
|
|
475
|
+
contractAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
476
|
+
decimals: 6
|
|
477
|
+
},
|
|
478
|
+
caipAsset: baseNetwork.config.caipAssetId,
|
|
479
|
+
network: baseNetwork
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
return createError("UNKNOWN_TOKEN", `Invalid token identifier type: ${typeof input}`, { value: input });
|
|
483
|
+
};
|
|
484
|
+
var getAvailableTokens = () => {
|
|
485
|
+
const customTokens = getAllCustomTokens();
|
|
486
|
+
const symbols = new Set(customTokens.map((t) => t.symbol.toUpperCase()));
|
|
487
|
+
return Array.from(symbols);
|
|
488
|
+
};
|
|
489
|
+
var resolveFacilitator = (input, supportedNetworks, supportedTokens) => {
|
|
490
|
+
try {
|
|
491
|
+
new URL(input.url);
|
|
492
|
+
} catch {
|
|
493
|
+
return createError("VALIDATION_FAILED", `Invalid facilitator URL: ${input.url}`, { value: input.url });
|
|
494
|
+
}
|
|
495
|
+
const networks = [];
|
|
496
|
+
if (input.networks) {
|
|
497
|
+
for (const network of input.networks) {
|
|
498
|
+
const resolved = resolveNetwork(network);
|
|
499
|
+
if ("code" in resolved) {
|
|
500
|
+
return resolved;
|
|
501
|
+
}
|
|
502
|
+
networks.push(resolved);
|
|
503
|
+
}
|
|
504
|
+
} else if (supportedNetworks) {
|
|
505
|
+
networks.push(...supportedNetworks);
|
|
506
|
+
}
|
|
507
|
+
const tokens = [];
|
|
508
|
+
if (input.tokens) {
|
|
509
|
+
for (const token of input.tokens) {
|
|
510
|
+
for (const network of networks.length > 0 ? networks : supportedNetworks || []) {
|
|
511
|
+
const resolved = resolveToken(token, network);
|
|
512
|
+
if ("code" in resolved) {
|
|
513
|
+
continue;
|
|
514
|
+
}
|
|
515
|
+
tokens.push(resolved);
|
|
516
|
+
break;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
} else if (supportedTokens) {
|
|
520
|
+
tokens.push(...supportedTokens);
|
|
521
|
+
}
|
|
522
|
+
return {
|
|
523
|
+
input,
|
|
524
|
+
url: input.url,
|
|
525
|
+
networks,
|
|
526
|
+
tokens
|
|
527
|
+
};
|
|
528
|
+
};
|
|
529
|
+
var checkFacilitatorSupport = (facilitator, network, token) => {
|
|
530
|
+
if (facilitator.networks.length > 0) {
|
|
531
|
+
const networkSupported = facilitator.networks.some(
|
|
532
|
+
(n) => n.config.chainId === network.config.chainId
|
|
533
|
+
);
|
|
534
|
+
if (!networkSupported) {
|
|
535
|
+
const supportedNames = facilitator.networks.map((n) => n.config.name);
|
|
536
|
+
return createError(
|
|
537
|
+
"FACILITATOR_NO_NETWORK_SUPPORT",
|
|
538
|
+
`Facilitator "${facilitator.url}" does not support network "${network.config.name}" (chain ${network.config.chainId}). Supported: ${supportedNames.join(", ")}`,
|
|
539
|
+
{
|
|
540
|
+
value: { facilitator: facilitator.url, network: network.config.name },
|
|
541
|
+
validOptions: supportedNames
|
|
542
|
+
}
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
if (facilitator.tokens.length > 0) {
|
|
547
|
+
const tokenSupported = facilitator.tokens.some(
|
|
548
|
+
(t) => t.config.contractAddress.toLowerCase() === token.config.contractAddress.toLowerCase() && t.network.config.chainId === token.network.config.chainId
|
|
549
|
+
);
|
|
550
|
+
if (!tokenSupported) {
|
|
551
|
+
const supportedTokens = facilitator.tokens.map((t) => `${t.config.symbol} (${t.network.config.name})`);
|
|
552
|
+
return createError(
|
|
553
|
+
"FACILITATOR_NO_TOKEN_SUPPORT",
|
|
554
|
+
`Facilitator "${facilitator.url}" does not support token "${token.config.symbol}" on "${token.network.config.name}". Supported: ${supportedTokens.join(", ")}`,
|
|
555
|
+
{
|
|
556
|
+
value: { facilitator: facilitator.url, token: token.config.symbol, network: token.network.config.name },
|
|
557
|
+
validOptions: supportedTokens
|
|
558
|
+
}
|
|
559
|
+
);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
return { supported: true };
|
|
563
|
+
};
|
|
564
|
+
var validatePaymentConfig = (network, token, facilitators, payTo = "0x0000000000000000000000000000000000000000", amount = "1.0") => {
|
|
565
|
+
const resolvedNetwork = resolveNetwork(network);
|
|
566
|
+
if ("code" in resolvedNetwork) {
|
|
567
|
+
return resolvedNetwork;
|
|
568
|
+
}
|
|
569
|
+
const resolvedToken = resolveToken(token, resolvedNetwork);
|
|
570
|
+
if ("code" in resolvedToken) {
|
|
571
|
+
return resolvedToken;
|
|
572
|
+
}
|
|
573
|
+
const resolvedFacilitators = [];
|
|
574
|
+
if (facilitators) {
|
|
575
|
+
const facilitatorArray = Array.isArray(facilitators) ? facilitators : [facilitators];
|
|
576
|
+
for (const facilitator of facilitatorArray) {
|
|
577
|
+
const resolved = resolveFacilitator(facilitator, [resolvedNetwork], [resolvedToken]);
|
|
578
|
+
if ("code" in resolved) {
|
|
579
|
+
return resolved;
|
|
580
|
+
}
|
|
581
|
+
const supportCheck = checkFacilitatorSupport(resolved, resolvedNetwork, resolvedToken);
|
|
582
|
+
if ("code" in supportCheck) {
|
|
583
|
+
return supportCheck;
|
|
584
|
+
}
|
|
585
|
+
resolvedFacilitators.push(resolved);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
return {
|
|
589
|
+
network: resolvedNetwork,
|
|
590
|
+
token: resolvedToken,
|
|
591
|
+
facilitators: resolvedFacilitators,
|
|
592
|
+
version: "auto",
|
|
593
|
+
payTo,
|
|
594
|
+
amount
|
|
595
|
+
};
|
|
596
|
+
};
|
|
597
|
+
var validateAcceptConfig = (options, payTo, amount) => {
|
|
598
|
+
const { networks: networkInputs, tokens: tokenInputs, facilitators, version = "auto" } = options;
|
|
599
|
+
const networkIds = networkInputs?.length ? networkInputs : Object.keys(NETWORKS);
|
|
600
|
+
const tokenIds = tokenInputs?.length ? tokenInputs : ["usdc"];
|
|
601
|
+
const networks = [];
|
|
602
|
+
for (const networkId of networkIds) {
|
|
603
|
+
const resolved = resolveNetwork(networkId);
|
|
604
|
+
if ("code" in resolved) {
|
|
605
|
+
return { success: false, error: resolved };
|
|
606
|
+
}
|
|
607
|
+
networks.push(resolved);
|
|
608
|
+
}
|
|
609
|
+
const tokens = [];
|
|
610
|
+
for (const tokenId of tokenIds) {
|
|
611
|
+
let found = false;
|
|
612
|
+
for (const network of networks) {
|
|
613
|
+
const resolved = resolveToken(tokenId, network);
|
|
614
|
+
if ("code" in resolved) {
|
|
615
|
+
continue;
|
|
616
|
+
}
|
|
617
|
+
tokens.push(resolved);
|
|
618
|
+
found = true;
|
|
619
|
+
break;
|
|
620
|
+
}
|
|
621
|
+
if (!found) {
|
|
622
|
+
return {
|
|
623
|
+
success: false,
|
|
624
|
+
error: createError(
|
|
625
|
+
"TOKEN_NOT_ON_NETWORK",
|
|
626
|
+
`Token "${String(tokenId)}" not found on any of the specified networks`,
|
|
627
|
+
{ value: tokenId, validOptions: networks.map((n) => n.config.name) }
|
|
628
|
+
)
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
const facilitatorArray = facilitators ? Array.isArray(facilitators) ? facilitators : [facilitators] : [];
|
|
633
|
+
const resolvedFacilitators = [];
|
|
634
|
+
for (const facilitator of facilitatorArray) {
|
|
635
|
+
const resolved = resolveFacilitator(facilitator, networks, tokens);
|
|
636
|
+
if ("code" in resolved) {
|
|
637
|
+
return { success: false, error: resolved };
|
|
638
|
+
}
|
|
639
|
+
resolvedFacilitators.push(resolved);
|
|
640
|
+
}
|
|
641
|
+
const configs = [];
|
|
642
|
+
for (const network of networks) {
|
|
643
|
+
for (const token of tokens) {
|
|
644
|
+
if (token.network.config.chainId === network.config.chainId) {
|
|
645
|
+
configs.push({
|
|
646
|
+
network,
|
|
647
|
+
token,
|
|
648
|
+
facilitators: resolvedFacilitators,
|
|
649
|
+
version,
|
|
650
|
+
payTo,
|
|
651
|
+
amount
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
return { success: true, config: configs };
|
|
657
|
+
};
|
|
658
|
+
var isValidationError = (value) => {
|
|
659
|
+
return typeof value === "object" && value !== null && "code" in value;
|
|
660
|
+
};
|
|
661
|
+
var isResolvedNetwork = (value) => {
|
|
662
|
+
return typeof value === "object" && value !== null && "config" in value && "caip2" in value;
|
|
663
|
+
};
|
|
664
|
+
var isResolvedToken = (value) => {
|
|
665
|
+
return typeof value === "object" && value !== null && "config" in value && "caipAsset" in value;
|
|
666
|
+
};
|
|
667
|
+
export {
|
|
668
|
+
EIP712_TYPES,
|
|
669
|
+
ERC20_ABI,
|
|
670
|
+
NETWORKS,
|
|
671
|
+
USDC_DOMAIN,
|
|
672
|
+
V1_HEADERS,
|
|
673
|
+
V2_HEADERS,
|
|
674
|
+
checkFacilitatorSupport,
|
|
675
|
+
createEIP712Domain,
|
|
676
|
+
createError,
|
|
677
|
+
createTransferWithAuthorization,
|
|
678
|
+
decodePayment,
|
|
679
|
+
decodePaymentPayload,
|
|
680
|
+
decodePaymentV1,
|
|
681
|
+
decodePaymentV2,
|
|
682
|
+
decodeSettlement,
|
|
683
|
+
decodeSettlementResponse,
|
|
684
|
+
decodeSettlementV1,
|
|
685
|
+
decodeSettlementV2,
|
|
686
|
+
detectPaymentVersion,
|
|
687
|
+
encodePaymentPayload,
|
|
688
|
+
encodePaymentV1,
|
|
689
|
+
encodePaymentV2,
|
|
690
|
+
encodeSettlementResponse,
|
|
691
|
+
encodeSettlementV1,
|
|
692
|
+
encodeSettlementV2,
|
|
693
|
+
getAllCustomTokens,
|
|
694
|
+
getAvailableNetworks,
|
|
695
|
+
getAvailableTokens,
|
|
696
|
+
getCustomToken,
|
|
697
|
+
getMainnets,
|
|
698
|
+
getNetworkByChainId,
|
|
699
|
+
getNetworkConfig,
|
|
700
|
+
getPaymentHeaderName,
|
|
701
|
+
getPaymentRequiredHeaderName,
|
|
702
|
+
getPaymentResponseHeaderName,
|
|
703
|
+
getPaymentVersion as getPaymentVersionFromPayload,
|
|
704
|
+
getRequirementsVersion,
|
|
705
|
+
getSettlementVersion,
|
|
706
|
+
getTestnets,
|
|
707
|
+
getTxHash,
|
|
708
|
+
isAddress,
|
|
709
|
+
isCAIP2ChainId,
|
|
710
|
+
isCAIPAssetId,
|
|
711
|
+
isCustomToken,
|
|
712
|
+
isPaymentV1,
|
|
713
|
+
isPaymentV2,
|
|
714
|
+
isResolvedNetwork,
|
|
715
|
+
isResolvedToken,
|
|
716
|
+
isSettlementSuccessful,
|
|
717
|
+
isSettlementV1,
|
|
718
|
+
isSettlementV2,
|
|
719
|
+
isV1,
|
|
720
|
+
isV2,
|
|
721
|
+
isValidationError,
|
|
722
|
+
registerToken,
|
|
723
|
+
resolveFacilitator,
|
|
724
|
+
resolveNetwork,
|
|
725
|
+
resolveToken,
|
|
726
|
+
unregisterToken,
|
|
727
|
+
validateAcceptConfig,
|
|
728
|
+
validatePaymentConfig,
|
|
729
|
+
validateTransferWithAuthorization
|
|
730
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface NetworkConfig {
|
|
2
|
+
name: string;
|
|
3
|
+
chainId: number;
|
|
4
|
+
usdcAddress: `0x${string}`;
|
|
5
|
+
rpcUrl: string;
|
|
6
|
+
caip2Id: string;
|
|
7
|
+
caipAssetId: string;
|
|
8
|
+
}
|
|
9
|
+
export interface CustomToken {
|
|
10
|
+
symbol: string;
|
|
11
|
+
name: string;
|
|
12
|
+
version: string;
|
|
13
|
+
contractAddress: `0x${string}`;
|
|
14
|
+
chainId: number;
|
|
15
|
+
decimals: number;
|
|
16
|
+
}
|
|
17
|
+
export declare const NETWORKS: Record<string, NetworkConfig>;
|
|
18
|
+
export declare const getNetworkConfig: (name: string) => NetworkConfig | undefined;
|
|
19
|
+
export declare const getNetworkByChainId: (chainId: number) => NetworkConfig | undefined;
|
|
20
|
+
export declare const getMainnets: () => NetworkConfig[];
|
|
21
|
+
export declare const getTestnets: () => NetworkConfig[];
|
|
22
|
+
export declare const registerToken: (token: CustomToken) => CustomToken;
|
|
23
|
+
export declare const getCustomToken: (chainId: number, contractAddress: string) => CustomToken | undefined;
|
|
24
|
+
export declare const getAllCustomTokens: () => CustomToken[];
|
|
25
|
+
export declare const unregisterToken: (chainId: number, contractAddress: string) => boolean;
|
|
26
|
+
export declare const isCustomToken: (chainId: number, contractAddress: string) => boolean;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { PaymentPayloadV1, PaymentRequirementsV1, SettlementResponseV1 } from "./v1";
|
|
2
|
+
import type { PaymentPayloadV2, PaymentRequirementsV2, SettlementResponseV2 } from "./v2";
|
|
3
|
+
export type PaymentPayload = PaymentPayloadV1 | PaymentPayloadV2;
|
|
4
|
+
export type PaymentRequirements = PaymentRequirementsV1 | PaymentRequirementsV2;
|
|
5
|
+
export type SettlementResponse = SettlementResponseV1 | SettlementResponseV2;
|
|
6
|
+
export declare const isV1: (payload: PaymentPayload) => payload is PaymentPayloadV1;
|
|
7
|
+
export declare const isV2: (payload: PaymentPayload) => payload is PaymentPayloadV2;
|
|
8
|
+
export declare const getPaymentVersion: (payload: PaymentPayload) => 1 | 2;
|
|
9
|
+
export declare const getRequirementsVersion: (requirements: PaymentRequirements) => 1 | 2;
|
|
10
|
+
export declare const getSettlementVersion: (response: SettlementResponse) => 1 | 2;
|
|
11
|
+
export declare const getPaymentHeaderName: (version: 1 | 2) => string;
|
|
12
|
+
export declare const getPaymentResponseHeaderName: (version: 1 | 2) => string;
|
|
13
|
+
export declare const getPaymentRequiredHeaderName: (version: 1 | 2) => string;
|
|
14
|
+
export declare const isSettlementSuccessful: (response: SettlementResponse) => boolean;
|
|
15
|
+
export declare const getTxHash: (response: SettlementResponse) => string | undefined;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple, developer-friendly API types for Armory
|
|
3
|
+
* Focuses on DX/UX - "everything just magically works"
|
|
4
|
+
*/
|
|
5
|
+
import type { Address, CAIPAssetId } from "./v2";
|
|
6
|
+
import type { NetworkConfig, CustomToken } from "./networks";
|
|
7
|
+
/**
|
|
8
|
+
* Network identifier - flexible input that resolves to a chain
|
|
9
|
+
* - Network name: "base", "ethereum", "skale-base"
|
|
10
|
+
* - CAIP-2: "eip155:8453"
|
|
11
|
+
* - Chain ID: 8453
|
|
12
|
+
*/
|
|
13
|
+
export type NetworkId = string | number;
|
|
14
|
+
/**
|
|
15
|
+
* Token identifier - flexible input that resolves to a token
|
|
16
|
+
* - Symbol: "usdc", "eurc", "usdt" (case-insensitive)
|
|
17
|
+
* - CAIP Asset ID: "eip155:8453/erc20:0x..."
|
|
18
|
+
* - Full token config object
|
|
19
|
+
*/
|
|
20
|
+
export type TokenId = string | CustomToken;
|
|
21
|
+
/**
|
|
22
|
+
* Facilitator configuration
|
|
23
|
+
*/
|
|
24
|
+
export interface FacilitatorConfig {
|
|
25
|
+
/** Facilitator URL for verification/settlement */
|
|
26
|
+
url: string;
|
|
27
|
+
/** Optional authentication headers */
|
|
28
|
+
headers?: () => Record<string, string>;
|
|
29
|
+
/** Networks this facilitator supports (auto-detected if not provided) */
|
|
30
|
+
networks?: NetworkId[];
|
|
31
|
+
/** Tokens this facilitator supports (optional) */
|
|
32
|
+
tokens?: TokenId[];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Payment accept options for merchants (v2 multi-support)
|
|
36
|
+
*/
|
|
37
|
+
export interface AcceptPaymentOptions {
|
|
38
|
+
/** Networks to accept payments on */
|
|
39
|
+
networks?: NetworkId[];
|
|
40
|
+
/** Tokens to accept (defaults to ["usdc"]) */
|
|
41
|
+
tokens?: TokenId[];
|
|
42
|
+
/** Facilitator(s) for payment verification/settlement */
|
|
43
|
+
facilitators?: FacilitatorConfig | FacilitatorConfig[];
|
|
44
|
+
/** Protocol version (default: auto-detect) */
|
|
45
|
+
version?: 1 | 2 | "auto";
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Result of a payment attempt
|
|
49
|
+
*/
|
|
50
|
+
export interface PaymentResult<T = unknown> {
|
|
51
|
+
/** Payment successful */
|
|
52
|
+
success: true;
|
|
53
|
+
/** Response data */
|
|
54
|
+
data: T;
|
|
55
|
+
/** Transaction hash (if settled) */
|
|
56
|
+
txHash?: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Payment error result
|
|
60
|
+
*/
|
|
61
|
+
export interface PaymentError {
|
|
62
|
+
/** Payment failed */
|
|
63
|
+
success: false;
|
|
64
|
+
/** Error code */
|
|
65
|
+
code: PaymentErrorCode;
|
|
66
|
+
/** Human-readable error message */
|
|
67
|
+
message: string;
|
|
68
|
+
/** Underlying error details */
|
|
69
|
+
details?: unknown;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Payment error codes
|
|
73
|
+
*/
|
|
74
|
+
export type PaymentErrorCode = "UNKNOWN_NETWORK" | "UNKNOWN_TOKEN" | "TOKEN_NOT_ON_NETWORK" | "FACILITATOR_UNSUPPORTED" | "FACILITATOR_NO_NETWORK_SUPPORT" | "FACILITATOR_NO_TOKEN_SUPPORT" | "INVALID_CAIP_FORMAT" | "CHAIN_MISMATCH" | "PAYMENT_REQUIRED" | "PAYMENT_DECLINED" | "SIGNING_FAILED" | "NETWORK_ERROR" | "VALIDATION_FAILED";
|
|
75
|
+
/**
|
|
76
|
+
* Combined payment result type
|
|
77
|
+
*/
|
|
78
|
+
export type ArmoryPaymentResult<T = unknown> = PaymentResult<T> | PaymentError;
|
|
79
|
+
/**
|
|
80
|
+
* Fully resolved network configuration
|
|
81
|
+
*/
|
|
82
|
+
export interface ResolvedNetwork {
|
|
83
|
+
/** Original input */
|
|
84
|
+
input: NetworkId;
|
|
85
|
+
/** Network config */
|
|
86
|
+
config: NetworkConfig;
|
|
87
|
+
/** CAIP-2 ID */
|
|
88
|
+
caip2: `eip155:${string}`;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Fully resolved token configuration
|
|
92
|
+
*/
|
|
93
|
+
export interface ResolvedToken {
|
|
94
|
+
/** Original input */
|
|
95
|
+
input: TokenId;
|
|
96
|
+
/** Token config */
|
|
97
|
+
config: CustomToken;
|
|
98
|
+
/** CAIP Asset ID */
|
|
99
|
+
caipAsset: CAIPAssetId;
|
|
100
|
+
/** Network this token is on */
|
|
101
|
+
network: ResolvedNetwork;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Fully resolved facilitator configuration
|
|
105
|
+
*/
|
|
106
|
+
export interface ResolvedFacilitator {
|
|
107
|
+
/** Original input */
|
|
108
|
+
input: FacilitatorConfig;
|
|
109
|
+
/** URL */
|
|
110
|
+
url: string;
|
|
111
|
+
/** Supported networks (resolved) */
|
|
112
|
+
networks: ResolvedNetwork[];
|
|
113
|
+
/** Supported tokens (resolved) */
|
|
114
|
+
tokens: ResolvedToken[];
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Fully resolved payment configuration
|
|
118
|
+
*/
|
|
119
|
+
export interface ResolvedPaymentConfig {
|
|
120
|
+
/** Network to use */
|
|
121
|
+
network: ResolvedNetwork;
|
|
122
|
+
/** Token to use */
|
|
123
|
+
token: ResolvedToken;
|
|
124
|
+
/** Facilitator(s) to use */
|
|
125
|
+
facilitators: ResolvedFacilitator[];
|
|
126
|
+
/** Protocol version */
|
|
127
|
+
version: 1 | 2 | "auto";
|
|
128
|
+
/** Recipient address */
|
|
129
|
+
payTo: Address;
|
|
130
|
+
/** Amount to charge */
|
|
131
|
+
amount: string;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Validation error details
|
|
135
|
+
*/
|
|
136
|
+
export interface ValidationError {
|
|
137
|
+
/** Error code */
|
|
138
|
+
code: PaymentErrorCode;
|
|
139
|
+
/** Error message */
|
|
140
|
+
message: string;
|
|
141
|
+
/** Path to the invalid value */
|
|
142
|
+
path?: string;
|
|
143
|
+
/** Invalid value */
|
|
144
|
+
value?: unknown;
|
|
145
|
+
/** Valid options */
|
|
146
|
+
validOptions?: string[];
|
|
147
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export interface PaymentPayloadV1 {
|
|
2
|
+
from: string;
|
|
3
|
+
to: string;
|
|
4
|
+
amount: string;
|
|
5
|
+
nonce: string;
|
|
6
|
+
expiry: number;
|
|
7
|
+
v: number;
|
|
8
|
+
r: string;
|
|
9
|
+
s: string;
|
|
10
|
+
chainId: number;
|
|
11
|
+
contractAddress: string;
|
|
12
|
+
network: string;
|
|
13
|
+
}
|
|
14
|
+
export interface PaymentRequirementsV1 {
|
|
15
|
+
amount: string;
|
|
16
|
+
network: string;
|
|
17
|
+
contractAddress: string;
|
|
18
|
+
payTo: string;
|
|
19
|
+
expiry: number;
|
|
20
|
+
}
|
|
21
|
+
export interface SettlementResponseV1 {
|
|
22
|
+
success: boolean;
|
|
23
|
+
txHash?: string;
|
|
24
|
+
error?: string;
|
|
25
|
+
timestamp: number;
|
|
26
|
+
}
|
|
27
|
+
export declare const V1_HEADERS: {
|
|
28
|
+
readonly PAYMENT: "X-PAYMENT";
|
|
29
|
+
readonly PAYMENT_RESPONSE: "X-PAYMENT-RESPONSE";
|
|
30
|
+
};
|
|
31
|
+
export declare function encodePaymentPayload(payload: PaymentPayloadV1): string;
|
|
32
|
+
export declare function decodePaymentPayload(encoded: string): PaymentPayloadV1;
|
|
33
|
+
export declare function encodeSettlementResponse(response: SettlementResponseV1): string;
|
|
34
|
+
export declare function decodeSettlementResponse(encoded: string): SettlementResponseV1;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export type CAIP2ChainId = `eip155:${string}`;
|
|
2
|
+
export type CAIPAssetId = `eip155:${string}/erc20:${string}`;
|
|
3
|
+
export type Address = `0x${string}`;
|
|
4
|
+
export interface Signature {
|
|
5
|
+
v: number;
|
|
6
|
+
r: string;
|
|
7
|
+
s: string;
|
|
8
|
+
}
|
|
9
|
+
export type PayToV2 = Address | {
|
|
10
|
+
role?: string;
|
|
11
|
+
callback?: string;
|
|
12
|
+
};
|
|
13
|
+
export interface Extensions {
|
|
14
|
+
[key: string]: unknown;
|
|
15
|
+
}
|
|
16
|
+
export interface PaymentPayloadV2 {
|
|
17
|
+
from: Address;
|
|
18
|
+
to: PayToV2;
|
|
19
|
+
amount: string;
|
|
20
|
+
nonce: string;
|
|
21
|
+
expiry: number;
|
|
22
|
+
signature: Signature;
|
|
23
|
+
chainId: CAIP2ChainId;
|
|
24
|
+
assetId: CAIPAssetId;
|
|
25
|
+
extensions?: Extensions;
|
|
26
|
+
}
|
|
27
|
+
export interface PaymentRequirementsV2 {
|
|
28
|
+
amount: string;
|
|
29
|
+
to: PayToV2;
|
|
30
|
+
chainId: CAIP2ChainId;
|
|
31
|
+
assetId: CAIPAssetId;
|
|
32
|
+
nonce: string;
|
|
33
|
+
expiry: number;
|
|
34
|
+
extensions?: Extensions;
|
|
35
|
+
}
|
|
36
|
+
export interface SettlementResponseV2 {
|
|
37
|
+
status: "success" | "pending" | "failed";
|
|
38
|
+
txHash?: string;
|
|
39
|
+
txId?: string;
|
|
40
|
+
timestamp: number;
|
|
41
|
+
extensions?: Extensions;
|
|
42
|
+
}
|
|
43
|
+
export declare const V2_HEADERS: {
|
|
44
|
+
readonly PAYMENT_SIGNATURE: "PAYMENT-SIGNATURE";
|
|
45
|
+
readonly PAYMENT_REQUIRED: "PAYMENT-REQUIRED";
|
|
46
|
+
readonly PAYMENT_RESPONSE: "PAYMENT-RESPONSE";
|
|
47
|
+
};
|
|
48
|
+
export declare function isCAIP2ChainId(value: string): value is CAIP2ChainId;
|
|
49
|
+
export declare function isCAIPAssetId(value: string): value is CAIPAssetId;
|
|
50
|
+
export declare function isAddress(value: string): value is Address;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comprehensive validation for Armory configurations
|
|
3
|
+
* Ensures networks, tokens, and facilitators are compatible
|
|
4
|
+
*/
|
|
5
|
+
import type { NetworkId, TokenId, FacilitatorConfig, ResolvedNetwork, ResolvedToken, ResolvedFacilitator, ResolvedPaymentConfig, ValidationError, PaymentErrorCode } from "./types/simple.js";
|
|
6
|
+
export declare const createError: (code: PaymentErrorCode, message: string, details?: Partial<ValidationError>) => ValidationError;
|
|
7
|
+
/**
|
|
8
|
+
* Resolve a network identifier to a network config
|
|
9
|
+
*/
|
|
10
|
+
export declare const resolveNetwork: (input: NetworkId) => ResolvedNetwork | ValidationError;
|
|
11
|
+
/**
|
|
12
|
+
* Get all available network names
|
|
13
|
+
*/
|
|
14
|
+
export declare const getAvailableNetworks: () => string[];
|
|
15
|
+
/**
|
|
16
|
+
* Resolve a token identifier to a token config
|
|
17
|
+
*/
|
|
18
|
+
export declare const resolveToken: (input: TokenId, network?: ResolvedNetwork) => ResolvedToken | ValidationError;
|
|
19
|
+
/**
|
|
20
|
+
* Get all available token symbols
|
|
21
|
+
*/
|
|
22
|
+
export declare const getAvailableTokens: () => string[];
|
|
23
|
+
/**
|
|
24
|
+
* Resolve a facilitator configuration
|
|
25
|
+
*/
|
|
26
|
+
export declare const resolveFacilitator: (input: FacilitatorConfig, supportedNetworks?: ResolvedNetwork[], supportedTokens?: ResolvedToken[]) => ResolvedFacilitator | ValidationError;
|
|
27
|
+
/**
|
|
28
|
+
* Check if a facilitator supports a specific network/token combination
|
|
29
|
+
*/
|
|
30
|
+
export declare const checkFacilitatorSupport: (facilitator: ResolvedFacilitator, network: ResolvedNetwork, token: ResolvedToken) => ValidationError | {
|
|
31
|
+
supported: true;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Validate a complete payment configuration
|
|
35
|
+
*/
|
|
36
|
+
export declare const validatePaymentConfig: (network: NetworkId, token: TokenId, facilitators?: FacilitatorConfig | FacilitatorConfig[], payTo?: string, amount?: string) => ResolvedPaymentConfig | ValidationError;
|
|
37
|
+
/**
|
|
38
|
+
* Validate multi-accept configuration (for merchants)
|
|
39
|
+
*/
|
|
40
|
+
export declare const validateAcceptConfig: (options: {
|
|
41
|
+
networks?: NetworkId[];
|
|
42
|
+
tokens?: TokenId[];
|
|
43
|
+
facilitators?: FacilitatorConfig | FacilitatorConfig[];
|
|
44
|
+
version?: 1 | 2 | "auto";
|
|
45
|
+
}, payTo: string, amount: string) => {
|
|
46
|
+
success: true;
|
|
47
|
+
config: ResolvedPaymentConfig[];
|
|
48
|
+
} | {
|
|
49
|
+
success: false;
|
|
50
|
+
error: ValidationError;
|
|
51
|
+
};
|
|
52
|
+
export declare const isValidationError: (value: unknown) => value is ValidationError;
|
|
53
|
+
export declare const isResolvedNetwork: (value: unknown) => value is ResolvedNetwork;
|
|
54
|
+
export declare const isResolvedToken: (value: unknown) => value is ResolvedToken;
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@armory-sh/base",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"author": "Sawyer Cutler <sawyer@dirtroad.dev>",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"bun": "./src/index.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./dist/*": "./dist/*.js"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/thegreataxios/armory.git",
|
|
27
|
+
"directory": "packages/core"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"viem": "2.45.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/node": "^25.2.1",
|
|
34
|
+
"bun-types": "latest",
|
|
35
|
+
"typescript": "5.9.3"
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsup && tsc --emitDeclarationOnly",
|
|
39
|
+
"test": "bun test"
|
|
40
|
+
}
|
|
41
|
+
}
|