@t402/tezos 2.3.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/README.md +161 -0
- package/dist/exact-direct/client/index.d.cts +92 -0
- package/dist/exact-direct/client/index.d.ts +92 -0
- package/dist/exact-direct/client/index.js +204 -0
- package/dist/exact-direct/client/index.js.map +1 -0
- package/dist/exact-direct/client/index.mjs +176 -0
- package/dist/exact-direct/client/index.mjs.map +1 -0
- package/dist/exact-direct/facilitator/index.d.cts +110 -0
- package/dist/exact-direct/facilitator/index.d.ts +110 -0
- package/dist/exact-direct/facilitator/index.js +331 -0
- package/dist/exact-direct/facilitator/index.js.map +1 -0
- package/dist/exact-direct/facilitator/index.mjs +303 -0
- package/dist/exact-direct/facilitator/index.mjs.map +1 -0
- package/dist/exact-direct/server/index.d.cts +109 -0
- package/dist/exact-direct/server/index.d.ts +109 -0
- package/dist/exact-direct/server/index.js +226 -0
- package/dist/exact-direct/server/index.js.map +1 -0
- package/dist/exact-direct/server/index.mjs +198 -0
- package/dist/exact-direct/server/index.mjs.map +1 -0
- package/dist/index.d.cts +124 -0
- package/dist/index.d.ts +124 -0
- package/dist/index.js +228 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +170 -0
- package/dist/index.mjs.map +1 -0
- package/dist/types-DQMtUOa_.d.cts +125 -0
- package/dist/types-DQMtUOa_.d.ts +125 -0
- package/package.json +100 -0
- package/src/constants.ts +53 -0
- package/src/exact-direct/client/index.ts +13 -0
- package/src/exact-direct/client/register.ts +71 -0
- package/src/exact-direct/client/scheme.ts +177 -0
- package/src/exact-direct/facilitator/index.ts +13 -0
- package/src/exact-direct/facilitator/register.ts +74 -0
- package/src/exact-direct/facilitator/scheme.ts +311 -0
- package/src/exact-direct/server/index.ts +13 -0
- package/src/exact-direct/server/register.ts +64 -0
- package/src/exact-direct/server/scheme.ts +205 -0
- package/src/index.ts +32 -0
- package/src/tokens.ts +86 -0
- package/src/types.ts +160 -0
- package/src/utils.ts +128 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { Network } from '@t402/core/types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Tezos mechanism types
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Exact-direct payment payload for Tezos
|
|
9
|
+
*/
|
|
10
|
+
type ExactDirectTezosPayload = {
|
|
11
|
+
/** Operation hash (o...) */
|
|
12
|
+
opHash: string;
|
|
13
|
+
/** Sender address (tz1/tz2/tz3...) */
|
|
14
|
+
from: string;
|
|
15
|
+
/** Recipient address */
|
|
16
|
+
to: string;
|
|
17
|
+
/** Amount in smallest units */
|
|
18
|
+
amount: string;
|
|
19
|
+
/** FA2 contract address (KT1...) */
|
|
20
|
+
contractAddress: string;
|
|
21
|
+
/** Token ID within the FA2 contract */
|
|
22
|
+
tokenId: number;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Tezos signer interface for client-side operations
|
|
26
|
+
*/
|
|
27
|
+
interface TezosSigner {
|
|
28
|
+
/** Get the signer's address */
|
|
29
|
+
getAddress(): Promise<string>;
|
|
30
|
+
/**
|
|
31
|
+
* Execute an FA2 transfer
|
|
32
|
+
* @param contractAddress FA2 contract address
|
|
33
|
+
* @param tokenId Token ID
|
|
34
|
+
* @param to Recipient address
|
|
35
|
+
* @param amount Amount to transfer
|
|
36
|
+
* @returns Operation hash
|
|
37
|
+
*/
|
|
38
|
+
transfer(contractAddress: string, tokenId: number, to: string, amount: bigint): Promise<string>;
|
|
39
|
+
/**
|
|
40
|
+
* Get token balance
|
|
41
|
+
* @param contractAddress FA2 contract address
|
|
42
|
+
* @param tokenId Token ID
|
|
43
|
+
* @param address Address to check (optional, defaults to signer address)
|
|
44
|
+
* @returns Balance in smallest units
|
|
45
|
+
*/
|
|
46
|
+
getBalance(contractAddress: string, tokenId: number, address?: string): Promise<bigint>;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Tezos signer interface for facilitator operations
|
|
50
|
+
*/
|
|
51
|
+
interface FacilitatorTezosSigner {
|
|
52
|
+
/** Get facilitator addresses for a network */
|
|
53
|
+
getAddresses(network: Network): string[];
|
|
54
|
+
/**
|
|
55
|
+
* Query an operation by hash
|
|
56
|
+
* @param opHash Operation hash
|
|
57
|
+
* @returns Operation result or null if not found
|
|
58
|
+
*/
|
|
59
|
+
queryOperation(opHash: string): Promise<TezosOperationResult | null>;
|
|
60
|
+
/**
|
|
61
|
+
* Get token balance for an address
|
|
62
|
+
* @param contractAddress FA2 contract address
|
|
63
|
+
* @param tokenId Token ID
|
|
64
|
+
* @param address Address to check
|
|
65
|
+
* @returns Balance as string
|
|
66
|
+
*/
|
|
67
|
+
getBalance(contractAddress: string, tokenId: number, address: string): Promise<string>;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Tezos operation result from indexer
|
|
71
|
+
*/
|
|
72
|
+
interface TezosOperationResult {
|
|
73
|
+
/** Operation hash */
|
|
74
|
+
hash: string;
|
|
75
|
+
/** Block level */
|
|
76
|
+
level: number;
|
|
77
|
+
/** Timestamp */
|
|
78
|
+
timestamp: string;
|
|
79
|
+
/** Status: applied, failed, backtracked, skipped */
|
|
80
|
+
status: "applied" | "failed" | "backtracked" | "skipped";
|
|
81
|
+
/** Sender address */
|
|
82
|
+
sender: {
|
|
83
|
+
address: string;
|
|
84
|
+
};
|
|
85
|
+
/** Target contract (for contract calls) */
|
|
86
|
+
target?: {
|
|
87
|
+
address: string;
|
|
88
|
+
};
|
|
89
|
+
/** Entrypoint called */
|
|
90
|
+
entrypoint?: string;
|
|
91
|
+
/** Parameter value */
|
|
92
|
+
parameter?: unknown;
|
|
93
|
+
/** Amount transferred (in mutez for XTZ) */
|
|
94
|
+
amount?: number;
|
|
95
|
+
/** Errors if failed */
|
|
96
|
+
errors?: Array<{
|
|
97
|
+
type: string;
|
|
98
|
+
message?: string;
|
|
99
|
+
}>;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* FA2 transfer parameter structure
|
|
103
|
+
*/
|
|
104
|
+
interface FA2TransferParam {
|
|
105
|
+
from_: string;
|
|
106
|
+
txs: Array<{
|
|
107
|
+
to_: string;
|
|
108
|
+
token_id: number;
|
|
109
|
+
amount: string;
|
|
110
|
+
}>;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Check if a string is a valid Tezos address
|
|
114
|
+
*/
|
|
115
|
+
declare function isValidTezosAddress(address: string): boolean;
|
|
116
|
+
/**
|
|
117
|
+
* Check if a string is a valid Tezos operation hash
|
|
118
|
+
*/
|
|
119
|
+
declare function isValidOperationHash(opHash: string): boolean;
|
|
120
|
+
/**
|
|
121
|
+
* Check if a network is a Tezos network
|
|
122
|
+
*/
|
|
123
|
+
declare function isTezosNetwork(network: string): boolean;
|
|
124
|
+
|
|
125
|
+
export { type ExactDirectTezosPayload as E, type FacilitatorTezosSigner as F, type TezosSigner as T, type TezosOperationResult as a, type FA2TransferParam as b, isValidOperationHash as c, isTezosNetwork as d, isValidTezosAddress as i };
|
package/package.json
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@t402/tezos",
|
|
3
|
+
"version": "2.3.0",
|
|
4
|
+
"description": "Tezos (FA2) mechanism for T402 payment protocol",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/cjs/index.js",
|
|
7
|
+
"module": "./dist/esm/index.mjs",
|
|
8
|
+
"types": "./dist/esm/index.d.mts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/esm/index.d.mts",
|
|
13
|
+
"default": "./dist/esm/index.mjs"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/cjs/index.d.ts",
|
|
17
|
+
"default": "./dist/cjs/index.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"./exact-direct/client": {
|
|
21
|
+
"import": {
|
|
22
|
+
"types": "./dist/esm/exact-direct/client/index.d.mts",
|
|
23
|
+
"default": "./dist/esm/exact-direct/client/index.mjs"
|
|
24
|
+
},
|
|
25
|
+
"require": {
|
|
26
|
+
"types": "./dist/cjs/exact-direct/client/index.d.ts",
|
|
27
|
+
"default": "./dist/cjs/exact-direct/client/index.js"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"./exact-direct/server": {
|
|
31
|
+
"import": {
|
|
32
|
+
"types": "./dist/esm/exact-direct/server/index.d.mts",
|
|
33
|
+
"default": "./dist/esm/exact-direct/server/index.mjs"
|
|
34
|
+
},
|
|
35
|
+
"require": {
|
|
36
|
+
"types": "./dist/cjs/exact-direct/server/index.d.ts",
|
|
37
|
+
"default": "./dist/cjs/exact-direct/server/index.js"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"./exact-direct/facilitator": {
|
|
41
|
+
"import": {
|
|
42
|
+
"types": "./dist/esm/exact-direct/facilitator/index.d.mts",
|
|
43
|
+
"default": "./dist/esm/exact-direct/facilitator/index.mjs"
|
|
44
|
+
},
|
|
45
|
+
"require": {
|
|
46
|
+
"types": "./dist/cjs/exact-direct/facilitator/index.d.ts",
|
|
47
|
+
"default": "./dist/cjs/exact-direct/facilitator/index.js"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"files": [
|
|
52
|
+
"dist",
|
|
53
|
+
"src"
|
|
54
|
+
],
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"@t402/core": "2.3.0"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@types/node": "^22.15.21",
|
|
60
|
+
"tsup": "^8.5.0",
|
|
61
|
+
"typescript": "^5.8.3",
|
|
62
|
+
"vitest": "^3.2.4"
|
|
63
|
+
},
|
|
64
|
+
"peerDependencies": {
|
|
65
|
+
"@taquito/taquito": "^19.0.0"
|
|
66
|
+
},
|
|
67
|
+
"peerDependenciesMeta": {
|
|
68
|
+
"@taquito/taquito": {
|
|
69
|
+
"optional": true
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"keywords": [
|
|
73
|
+
"t402",
|
|
74
|
+
"tezos",
|
|
75
|
+
"fa2",
|
|
76
|
+
"tzip-12",
|
|
77
|
+
"usdt",
|
|
78
|
+
"payment",
|
|
79
|
+
"blockchain"
|
|
80
|
+
],
|
|
81
|
+
"author": "T402",
|
|
82
|
+
"license": "Apache-2.0",
|
|
83
|
+
"repository": {
|
|
84
|
+
"type": "git",
|
|
85
|
+
"url": "https://github.com/t402-io/t402.git",
|
|
86
|
+
"directory": "typescript/packages/mechanisms/tezos"
|
|
87
|
+
},
|
|
88
|
+
"bugs": {
|
|
89
|
+
"url": "https://github.com/t402-io/t402/issues"
|
|
90
|
+
},
|
|
91
|
+
"homepage": "https://t402.io",
|
|
92
|
+
"scripts": {
|
|
93
|
+
"build": "tsup",
|
|
94
|
+
"dev": "tsup --watch",
|
|
95
|
+
"test": "vitest run",
|
|
96
|
+
"test:watch": "vitest",
|
|
97
|
+
"typecheck": "tsc --noEmit",
|
|
98
|
+
"clean": "rm -rf dist"
|
|
99
|
+
}
|
|
100
|
+
}
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tezos mechanism constants
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Scheme identifiers
|
|
6
|
+
export const SCHEME_EXACT_DIRECT = "exact-direct";
|
|
7
|
+
|
|
8
|
+
// CAIP-2 namespace
|
|
9
|
+
export const TEZOS_CAIP2_NAMESPACE = "tezos";
|
|
10
|
+
|
|
11
|
+
// CAIP-2 network identifiers (derived from genesis block hash)
|
|
12
|
+
export const TEZOS_MAINNET_CAIP2 = "tezos:NetXdQprcVkpaWU";
|
|
13
|
+
export const TEZOS_GHOSTNET_CAIP2 = "tezos:NetXnHfVqm9iesp";
|
|
14
|
+
|
|
15
|
+
// Default RPC endpoints
|
|
16
|
+
export const DEFAULT_MAINNET_RPC = "https://mainnet.api.tez.ie";
|
|
17
|
+
export const DEFAULT_GHOSTNET_RPC = "https://ghostnet.tezos.marigold.dev";
|
|
18
|
+
|
|
19
|
+
// Default indexer API endpoints (TzKT)
|
|
20
|
+
export const DEFAULT_MAINNET_INDEXER = "https://api.tzkt.io";
|
|
21
|
+
export const DEFAULT_GHOSTNET_INDEXER = "https://api.ghostnet.tzkt.io";
|
|
22
|
+
|
|
23
|
+
// FA2 token standard (TZIP-12)
|
|
24
|
+
export const FA2_TRANSFER_ENTRYPOINT = "transfer";
|
|
25
|
+
export const FA2_BALANCE_OF_ENTRYPOINT = "balance_of";
|
|
26
|
+
export const FA2_UPDATE_OPERATORS_ENTRYPOINT = "update_operators";
|
|
27
|
+
|
|
28
|
+
// Supported networks
|
|
29
|
+
export const SUPPORTED_NETWORKS = [
|
|
30
|
+
TEZOS_MAINNET_CAIP2,
|
|
31
|
+
TEZOS_GHOSTNET_CAIP2,
|
|
32
|
+
] as const;
|
|
33
|
+
|
|
34
|
+
// Network configurations
|
|
35
|
+
export const NETWORK_CONFIGS: Record<
|
|
36
|
+
string,
|
|
37
|
+
{
|
|
38
|
+
name: string;
|
|
39
|
+
rpcUrl: string;
|
|
40
|
+
indexerUrl: string;
|
|
41
|
+
}
|
|
42
|
+
> = {
|
|
43
|
+
[TEZOS_MAINNET_CAIP2]: {
|
|
44
|
+
name: "Tezos Mainnet",
|
|
45
|
+
rpcUrl: DEFAULT_MAINNET_RPC,
|
|
46
|
+
indexerUrl: DEFAULT_MAINNET_INDEXER,
|
|
47
|
+
},
|
|
48
|
+
[TEZOS_GHOSTNET_CAIP2]: {
|
|
49
|
+
name: "Tezos Ghostnet",
|
|
50
|
+
rpcUrl: DEFAULT_GHOSTNET_RPC,
|
|
51
|
+
indexerUrl: DEFAULT_GHOSTNET_INDEXER,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registration function for Tezos Exact-Direct client
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { t402Client } from "@t402/core/client";
|
|
6
|
+
import type { Network } from "@t402/core/types";
|
|
7
|
+
import type { TezosSigner } from "../../types.js";
|
|
8
|
+
import {
|
|
9
|
+
ExactDirectTezosClient,
|
|
10
|
+
type ExactDirectTezosClientConfig,
|
|
11
|
+
} from "./scheme.js";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Configuration options for registering Tezos schemes to a t402Client
|
|
15
|
+
*/
|
|
16
|
+
export interface TezosClientConfig {
|
|
17
|
+
/**
|
|
18
|
+
* The Tezos signer for payment operations
|
|
19
|
+
*/
|
|
20
|
+
signer: TezosSigner;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Optional specific networks to register
|
|
24
|
+
* If not provided, registers wildcard support (tezos:*)
|
|
25
|
+
*/
|
|
26
|
+
networks?: Network[];
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Optional scheme configuration
|
|
30
|
+
*/
|
|
31
|
+
schemeConfig?: ExactDirectTezosClientConfig;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Registers Tezos exact-direct payment scheme to a t402Client instance.
|
|
36
|
+
*
|
|
37
|
+
* @param client - The t402Client instance to register schemes to
|
|
38
|
+
* @param config - Configuration for Tezos client registration
|
|
39
|
+
* @returns The client instance for chaining
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* import { registerExactDirectTezosClient } from "@t402/tezos/exact-direct/client";
|
|
44
|
+
* import { t402Client } from "@t402/core/client";
|
|
45
|
+
*
|
|
46
|
+
* const client = new t402Client();
|
|
47
|
+
* registerExactDirectTezosClient(client, {
|
|
48
|
+
* signer: myTezosSigner,
|
|
49
|
+
* networks: ["tezos:NetXdQprcVkpaWU"]
|
|
50
|
+
* });
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export function registerExactDirectTezosClient(
|
|
54
|
+
client: t402Client,
|
|
55
|
+
config: TezosClientConfig,
|
|
56
|
+
): t402Client {
|
|
57
|
+
const scheme = new ExactDirectTezosClient(config.signer, config.schemeConfig);
|
|
58
|
+
|
|
59
|
+
// Register scheme
|
|
60
|
+
if (config.networks && config.networks.length > 0) {
|
|
61
|
+
// Register specific networks
|
|
62
|
+
config.networks.forEach((network) => {
|
|
63
|
+
client.register(network, scheme);
|
|
64
|
+
});
|
|
65
|
+
} else {
|
|
66
|
+
// Register wildcard for all Tezos networks
|
|
67
|
+
client.register("tezos:*", scheme);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return client;
|
|
71
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tezos Exact-Direct Client Scheme
|
|
3
|
+
*
|
|
4
|
+
* The client executes the FA2 transfer directly and provides
|
|
5
|
+
* the operation hash as proof of payment.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
SchemeNetworkClient,
|
|
10
|
+
PaymentPayload,
|
|
11
|
+
PaymentRequirements,
|
|
12
|
+
} from "@t402/core/types";
|
|
13
|
+
import { SCHEME_EXACT_DIRECT, TEZOS_CAIP2_NAMESPACE } from "../../constants.js";
|
|
14
|
+
import type { TezosSigner, ExactDirectTezosPayload } from "../../types.js";
|
|
15
|
+
import { isValidTezosAddress } from "../../types.js";
|
|
16
|
+
import { getTokenBySymbol } from "../../tokens.js";
|
|
17
|
+
import { compareAddresses } from "../../utils.js";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Configuration for ExactDirectTezosClient
|
|
21
|
+
*/
|
|
22
|
+
export interface ExactDirectTezosClientConfig {
|
|
23
|
+
/**
|
|
24
|
+
* Whether to verify the operation was successful before returning
|
|
25
|
+
* @default true
|
|
26
|
+
*/
|
|
27
|
+
verifyOperation?: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Tezos Exact-Direct Client
|
|
32
|
+
*
|
|
33
|
+
* Implements the client-side payment flow where the client:
|
|
34
|
+
* 1. Receives payment requirements
|
|
35
|
+
* 2. Executes the FA2 transfer operation
|
|
36
|
+
* 3. Returns operation hash as proof
|
|
37
|
+
*/
|
|
38
|
+
export class ExactDirectTezosClient implements SchemeNetworkClient {
|
|
39
|
+
readonly scheme = SCHEME_EXACT_DIRECT;
|
|
40
|
+
|
|
41
|
+
constructor(
|
|
42
|
+
private readonly signer: TezosSigner,
|
|
43
|
+
config: ExactDirectTezosClientConfig = {},
|
|
44
|
+
) {
|
|
45
|
+
// Config reserved for future use
|
|
46
|
+
void config;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Create a payment payload by executing the transfer
|
|
51
|
+
*/
|
|
52
|
+
async createPaymentPayload(
|
|
53
|
+
t402Version: number,
|
|
54
|
+
paymentRequirements: PaymentRequirements,
|
|
55
|
+
): Promise<Pick<PaymentPayload, "t402Version" | "payload">> {
|
|
56
|
+
// Validate requirements
|
|
57
|
+
this.validateRequirements(paymentRequirements);
|
|
58
|
+
|
|
59
|
+
// Get sender address
|
|
60
|
+
const from = await this.signer.getAddress();
|
|
61
|
+
|
|
62
|
+
// Parse asset to get contract address and token ID
|
|
63
|
+
const assetInfo = this.parseAssetIdentifier(paymentRequirements.asset);
|
|
64
|
+
if (!assetInfo) {
|
|
65
|
+
throw new Error(`Invalid asset identifier: ${paymentRequirements.asset}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Get amount
|
|
69
|
+
const amount = BigInt(paymentRequirements.amount);
|
|
70
|
+
|
|
71
|
+
// Check balance
|
|
72
|
+
const balance = await this.signer.getBalance(
|
|
73
|
+
assetInfo.contractAddress,
|
|
74
|
+
assetInfo.tokenId,
|
|
75
|
+
);
|
|
76
|
+
if (balance < amount) {
|
|
77
|
+
throw new Error(
|
|
78
|
+
`Insufficient balance: have ${balance}, need ${amount}`,
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Execute transfer
|
|
83
|
+
const opHash = await this.signer.transfer(
|
|
84
|
+
assetInfo.contractAddress,
|
|
85
|
+
assetInfo.tokenId,
|
|
86
|
+
paymentRequirements.payTo,
|
|
87
|
+
amount,
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
// Create payload
|
|
91
|
+
const payload: ExactDirectTezosPayload = {
|
|
92
|
+
opHash,
|
|
93
|
+
from,
|
|
94
|
+
to: paymentRequirements.payTo,
|
|
95
|
+
amount: paymentRequirements.amount,
|
|
96
|
+
contractAddress: assetInfo.contractAddress,
|
|
97
|
+
tokenId: assetInfo.tokenId,
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
t402Version,
|
|
102
|
+
payload,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Parse CAIP-19 asset identifier for Tezos FA2
|
|
108
|
+
* Format: tezos:{chainRef}/fa2:{contractAddress}/{tokenId}
|
|
109
|
+
*/
|
|
110
|
+
private parseAssetIdentifier(
|
|
111
|
+
asset: string,
|
|
112
|
+
): { contractAddress: string; tokenId: number } | null {
|
|
113
|
+
// Try parsing CAIP-19 format
|
|
114
|
+
const caipMatch = asset.match(/^tezos:[^/]+\/fa2:([^/]+)\/(\d+)$/);
|
|
115
|
+
if (caipMatch) {
|
|
116
|
+
return {
|
|
117
|
+
contractAddress: caipMatch[1],
|
|
118
|
+
tokenId: parseInt(caipMatch[2], 10),
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Try simple format: contractAddress/tokenId or just contractAddress (default tokenId 0)
|
|
123
|
+
const simpleMatch = asset.match(/^(KT1[a-zA-Z0-9]+)(?:\/(\d+))?$/);
|
|
124
|
+
if (simpleMatch) {
|
|
125
|
+
return {
|
|
126
|
+
contractAddress: simpleMatch[1],
|
|
127
|
+
tokenId: simpleMatch[2] ? parseInt(simpleMatch[2], 10) : 0,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Validate payment requirements
|
|
136
|
+
*/
|
|
137
|
+
private validateRequirements(requirements: PaymentRequirements): void {
|
|
138
|
+
// Check scheme
|
|
139
|
+
if (requirements.scheme !== SCHEME_EXACT_DIRECT) {
|
|
140
|
+
throw new Error(
|
|
141
|
+
`Invalid scheme: expected ${SCHEME_EXACT_DIRECT}, got ${requirements.scheme}`,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Check network
|
|
146
|
+
if (!requirements.network.startsWith(`${TEZOS_CAIP2_NAMESPACE}:`)) {
|
|
147
|
+
throw new Error(`Invalid network: ${requirements.network}`);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Check payTo address
|
|
151
|
+
if (!isValidTezosAddress(requirements.payTo)) {
|
|
152
|
+
throw new Error(`Invalid payTo address: ${requirements.payTo}`);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Check amount
|
|
156
|
+
const amount = BigInt(requirements.amount);
|
|
157
|
+
if (amount <= 0n) {
|
|
158
|
+
throw new Error(`Invalid amount: ${requirements.amount}`);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Check asset
|
|
162
|
+
const assetInfo = this.parseAssetIdentifier(requirements.asset);
|
|
163
|
+
if (!assetInfo) {
|
|
164
|
+
throw new Error(`Invalid asset: ${requirements.asset}`);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Verify token is supported (warn for unknown tokens)
|
|
168
|
+
const tokenConfig = getTokenBySymbol(requirements.network, "USDt");
|
|
169
|
+
if (tokenConfig && !compareAddresses(tokenConfig.contractAddress, assetInfo.contractAddress)) {
|
|
170
|
+
console.warn(
|
|
171
|
+
`Using non-standard token: ${assetInfo.contractAddress}`,
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export default ExactDirectTezosClient;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tezos Exact-Direct Facilitator
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export {
|
|
6
|
+
ExactDirectTezosFacilitator,
|
|
7
|
+
type ExactDirectTezosFacilitatorConfig,
|
|
8
|
+
} from "./scheme.js";
|
|
9
|
+
|
|
10
|
+
export {
|
|
11
|
+
registerExactDirectTezosFacilitator,
|
|
12
|
+
type TezosFacilitatorConfig,
|
|
13
|
+
} from "./register.js";
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registration function for Tezos Exact-Direct facilitator
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { t402Facilitator } from "@t402/core/facilitator";
|
|
6
|
+
import type { Network } from "@t402/core/types";
|
|
7
|
+
import type { FacilitatorTezosSigner } from "../../types.js";
|
|
8
|
+
import {
|
|
9
|
+
ExactDirectTezosFacilitator,
|
|
10
|
+
type ExactDirectTezosFacilitatorConfig,
|
|
11
|
+
} from "./scheme.js";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Configuration options for registering Tezos schemes to a t402Facilitator
|
|
15
|
+
*/
|
|
16
|
+
export interface TezosFacilitatorConfig {
|
|
17
|
+
/**
|
|
18
|
+
* The Tezos signer for facilitator operations (verify and settle)
|
|
19
|
+
*/
|
|
20
|
+
signer: FacilitatorTezosSigner;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Optional specific networks to register
|
|
24
|
+
* If not provided, registers wildcard support (tezos:*)
|
|
25
|
+
*/
|
|
26
|
+
networks?: Network[];
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Optional scheme configuration
|
|
30
|
+
*/
|
|
31
|
+
schemeConfig?: ExactDirectTezosFacilitatorConfig;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Registers Tezos exact-direct payment schemes to a t402Facilitator instance.
|
|
36
|
+
*
|
|
37
|
+
* @param facilitator - The t402Facilitator instance to register schemes to
|
|
38
|
+
* @param config - Configuration for Tezos facilitator registration
|
|
39
|
+
* @returns The facilitator instance for chaining
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* import { registerExactDirectTezosFacilitator } from "@t402/tezos/exact-direct/facilitator";
|
|
44
|
+
* import { t402Facilitator } from "@t402/core/facilitator";
|
|
45
|
+
*
|
|
46
|
+
* const facilitator = new t402Facilitator();
|
|
47
|
+
* registerExactDirectTezosFacilitator(facilitator, {
|
|
48
|
+
* signer: myTezosSigner,
|
|
49
|
+
* networks: ["tezos:NetXdQprcVkpaWU"]
|
|
50
|
+
* });
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export function registerExactDirectTezosFacilitator(
|
|
54
|
+
facilitator: t402Facilitator,
|
|
55
|
+
config: TezosFacilitatorConfig,
|
|
56
|
+
): t402Facilitator {
|
|
57
|
+
const scheme = new ExactDirectTezosFacilitator(
|
|
58
|
+
config.signer,
|
|
59
|
+
config.schemeConfig,
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
// Register scheme
|
|
63
|
+
if (config.networks && config.networks.length > 0) {
|
|
64
|
+
// Register specific networks
|
|
65
|
+
config.networks.forEach((network) => {
|
|
66
|
+
facilitator.register(network, scheme);
|
|
67
|
+
});
|
|
68
|
+
} else {
|
|
69
|
+
// Register wildcard for all Tezos networks
|
|
70
|
+
facilitator.register("tezos:*", scheme);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return facilitator;
|
|
74
|
+
}
|