@4mica/sdk 0.5.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.
Files changed (105) hide show
  1. package/.eslintrc.cjs +29 -0
  2. package/.github/workflows/ci.yml +31 -0
  3. package/.prettierignore +3 -0
  4. package/.prettierrc +6 -0
  5. package/LICENSE +21 -0
  6. package/README.md +444 -0
  7. package/dist/abi/core4mica.json +1605 -0
  8. package/dist/abi/erc20.json +187 -0
  9. package/dist/auth.d.ts +62 -0
  10. package/dist/auth.js +255 -0
  11. package/dist/bls.d.ts +5 -0
  12. package/dist/bls.js +58 -0
  13. package/dist/client.d.ts +58 -0
  14. package/dist/client.js +245 -0
  15. package/dist/config.d.ts +36 -0
  16. package/dist/config.js +123 -0
  17. package/dist/contract.d.ts +33 -0
  18. package/dist/contract.js +134 -0
  19. package/dist/errors.d.ts +43 -0
  20. package/dist/errors.js +62 -0
  21. package/dist/guarantee.d.ts +3 -0
  22. package/dist/guarantee.js +66 -0
  23. package/dist/index.d.ts +12 -0
  24. package/dist/index.js +28 -0
  25. package/dist/models.d.ts +150 -0
  26. package/dist/models.js +176 -0
  27. package/dist/rpc.d.ts +37 -0
  28. package/dist/rpc.js +163 -0
  29. package/dist/signing.d.ts +106 -0
  30. package/dist/signing.js +223 -0
  31. package/dist/src/abi/core4mica.json +1605 -0
  32. package/dist/src/abi/erc20.json +187 -0
  33. package/dist/src/bls.d.ts +5 -0
  34. package/dist/src/bls.js +45 -0
  35. package/dist/src/client.d.ts +55 -0
  36. package/dist/src/client.js +214 -0
  37. package/dist/src/config.d.ts +21 -0
  38. package/dist/src/config.js +76 -0
  39. package/dist/src/contract.d.ts +33 -0
  40. package/dist/src/contract.js +121 -0
  41. package/dist/src/errors.d.ts +17 -0
  42. package/dist/src/errors.js +31 -0
  43. package/dist/src/guarantee.d.ts +3 -0
  44. package/dist/src/guarantee.js +66 -0
  45. package/dist/src/index.d.ts +11 -0
  46. package/dist/src/index.js +27 -0
  47. package/dist/src/models.d.ts +119 -0
  48. package/dist/src/models.js +132 -0
  49. package/dist/src/rpc.d.ts +30 -0
  50. package/dist/src/rpc.js +122 -0
  51. package/dist/src/signing.d.ts +16 -0
  52. package/dist/src/signing.js +102 -0
  53. package/dist/src/utils.d.ts +8 -0
  54. package/dist/src/utils.js +78 -0
  55. package/dist/src/x402.d.ts +77 -0
  56. package/dist/src/x402.js +214 -0
  57. package/dist/tests/config.test.d.ts +1 -0
  58. package/dist/tests/config.test.js +26 -0
  59. package/dist/tests/guarantee.test.d.ts +1 -0
  60. package/dist/tests/guarantee.test.js +26 -0
  61. package/dist/tests/rpc.test.d.ts +1 -0
  62. package/dist/tests/rpc.test.js +44 -0
  63. package/dist/tests/signing.test.d.ts +1 -0
  64. package/dist/tests/signing.test.js +25 -0
  65. package/dist/tests/utils.test.d.ts +1 -0
  66. package/dist/tests/utils.test.js +25 -0
  67. package/dist/tests/x402.test.d.ts +1 -0
  68. package/dist/tests/x402.test.js +65 -0
  69. package/dist/utils.d.ts +8 -0
  70. package/dist/utils.js +78 -0
  71. package/dist/x402/index.d.ts +22 -0
  72. package/dist/x402/index.js +136 -0
  73. package/dist/x402/models.d.ts +80 -0
  74. package/dist/x402/models.js +2 -0
  75. package/dist/x402.d.ts +78 -0
  76. package/dist/x402.js +231 -0
  77. package/eslint.config.mjs +22 -0
  78. package/package.json +31 -0
  79. package/src/abi/core4mica.json +1605 -0
  80. package/src/abi/erc20.json +187 -0
  81. package/src/auth.ts +325 -0
  82. package/src/bls.ts +76 -0
  83. package/src/client.ts +347 -0
  84. package/src/config.ts +149 -0
  85. package/src/contract.ts +194 -0
  86. package/src/errors.ts +40 -0
  87. package/src/guarantee.ts +96 -0
  88. package/src/index.ts +12 -0
  89. package/src/models.ts +309 -0
  90. package/src/rpc.ts +225 -0
  91. package/src/signing.ts +330 -0
  92. package/src/utils.ts +75 -0
  93. package/src/x402/index.ts +192 -0
  94. package/src/x402/models.ts +94 -0
  95. package/tests/auth.integration.test.ts +97 -0
  96. package/tests/auth.test.ts +292 -0
  97. package/tests/config.test.ts +56 -0
  98. package/tests/guarantee.test.ts +26 -0
  99. package/tests/rpc.test.ts +76 -0
  100. package/tests/signing.test.ts +52 -0
  101. package/tests/utils.test.ts +35 -0
  102. package/tests/x402.test.ts +152 -0
  103. package/tsconfig.build.json +5 -0
  104. package/tsconfig.json +15 -0
  105. package/vitest.config.ts +12 -0
package/dist/client.js ADDED
@@ -0,0 +1,245 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RecipientClient = exports.UserClient = exports.Client = void 0;
4
+ const bls_1 = require("./bls");
5
+ const auth_1 = require("./auth");
6
+ const contract_1 = require("./contract");
7
+ const errors_1 = require("./errors");
8
+ const guarantee_1 = require("./guarantee");
9
+ const models_1 = require("./models");
10
+ const rpc_1 = require("./rpc");
11
+ const signing_1 = require("./signing");
12
+ const utils_1 = require("./utils");
13
+ const isNumericLike = (value) => typeof value === 'number' || typeof value === 'bigint' || typeof value === 'string';
14
+ function tabStatusFromRpc(status) {
15
+ const paid = status.paid !== undefined ? status.paid : (status.paidAmount ?? 0);
16
+ const remunerated = status.remunerated ?? status.paidOut ?? false;
17
+ const asset = status.asset ?? status.assetAddress ?? '';
18
+ return {
19
+ paid: (0, utils_1.parseU256)(paid),
20
+ remunerated: Boolean(remunerated),
21
+ asset,
22
+ };
23
+ }
24
+ class Client {
25
+ constructor(rpc, params, gateway, guaranteeDomain, signer, authSession) {
26
+ this.rpc = rpc;
27
+ this.params = params;
28
+ this.gateway = gateway;
29
+ this.guaranteeDomain = guaranteeDomain;
30
+ this.signer = signer;
31
+ this.authSession = authSession;
32
+ this.user = new UserClient(this);
33
+ this.recipient = new RecipientClient(this);
34
+ }
35
+ static async new(cfg) {
36
+ const rpc = new rpc_1.RpcProxy(cfg.rpcUrl, cfg.adminApiKey);
37
+ const params = await rpc.getPublicParams();
38
+ const gateway = Client.buildGateway(cfg, params);
39
+ await Client.validateChainId(gateway, params.chainId);
40
+ const guaranteeDomain = await gateway.getGuaranteeDomain();
41
+ const signer = new signing_1.PaymentSigner(cfg.signer);
42
+ const authEnabled = cfg.authUrl !== undefined || cfg.authRefreshMarginSecs !== undefined;
43
+ const authSession = cfg.bearerToken || !authEnabled
44
+ ? undefined
45
+ : new auth_1.AuthSession({
46
+ authUrl: cfg.authUrl ?? cfg.rpcUrl,
47
+ signer: cfg.signer,
48
+ refreshMarginSecs: cfg.authRefreshMarginSecs ?? 60,
49
+ });
50
+ if (cfg.bearerToken) {
51
+ rpc.withBearerToken(cfg.bearerToken);
52
+ }
53
+ else if (authSession) {
54
+ rpc.withTokenProvider(() => authSession.accessToken());
55
+ }
56
+ return new Client(rpc, params, gateway, guaranteeDomain, signer, authSession);
57
+ }
58
+ static buildGateway(cfg, params) {
59
+ const ethRpcUrl = cfg.ethereumHttpRpcUrl ?? params.ethereumHttpRpcUrl;
60
+ const contractAddress = cfg.contractAddress ?? params.contractAddress;
61
+ return new contract_1.ContractGateway(ethRpcUrl, cfg.walletPrivateKey, contractAddress, params.chainId);
62
+ }
63
+ static async validateChainId(gateway, expectedChainId) {
64
+ try {
65
+ const chainId = await gateway.getChainId();
66
+ if (Number(chainId) !== Number(expectedChainId)) {
67
+ throw new errors_1.ClientInitializationError(`chain id mismatch between core (${expectedChainId}) and provider (${chainId})`);
68
+ }
69
+ }
70
+ catch (err) {
71
+ const message = err instanceof Error ? err.message : String(err);
72
+ throw new errors_1.ClientInitializationError(message);
73
+ }
74
+ }
75
+ async aclose() {
76
+ await this.rpc.aclose();
77
+ }
78
+ async login() {
79
+ if (!this.authSession) {
80
+ throw new errors_1.AuthMissingConfigError('auth is not enabled');
81
+ }
82
+ return this.authSession.login();
83
+ }
84
+ }
85
+ exports.Client = Client;
86
+ class UserClient {
87
+ constructor(client) {
88
+ this.client = client;
89
+ }
90
+ get guaranteeDomain() {
91
+ return this.client.guaranteeDomain;
92
+ }
93
+ async approveErc20(token, amount) {
94
+ return this.client.gateway.approveErc20(token, amount);
95
+ }
96
+ async deposit(amount, erc20Token) {
97
+ return this.client.gateway.deposit(amount, erc20Token);
98
+ }
99
+ async getUser() {
100
+ const assets = await this.client.gateway.getUserAssets();
101
+ return assets.map((a) => ({
102
+ asset: a.asset,
103
+ collateral: (0, utils_1.parseU256)(a.collateral),
104
+ withdrawalRequestAmount: (0, utils_1.parseU256)(a.withdrawal_request_amount),
105
+ withdrawalRequestTimestamp: Number(a.withdrawal_request_timestamp),
106
+ }));
107
+ }
108
+ async getTabPaymentStatus(tabId) {
109
+ const status = await this.client.gateway.getPaymentStatus(tabId);
110
+ return tabStatusFromRpc(status);
111
+ }
112
+ async signPayment(claims, scheme = models_1.SigningScheme.EIP712) {
113
+ return this.client.signer.signRequest(this.client.params, claims, scheme);
114
+ }
115
+ async payTab(tabId, reqId, amount, recipientAddress, erc20Token) {
116
+ if (erc20Token) {
117
+ return this.client.gateway.payTabErc20(tabId, amount, erc20Token, recipientAddress);
118
+ }
119
+ return this.client.gateway.payTabEth(tabId, reqId, amount, recipientAddress);
120
+ }
121
+ async requestWithdrawal(amount, erc20Token) {
122
+ return this.client.gateway.requestWithdrawal(amount, erc20Token);
123
+ }
124
+ async cancelWithdrawal(erc20Token) {
125
+ return this.client.gateway.cancelWithdrawal(erc20Token);
126
+ }
127
+ async finalizeWithdrawal(erc20Token) {
128
+ return this.client.gateway.finalizeWithdrawal(erc20Token);
129
+ }
130
+ }
131
+ exports.UserClient = UserClient;
132
+ class RecipientClient {
133
+ constructor(client) {
134
+ this.client = client;
135
+ }
136
+ get recipientAddress() {
137
+ return (0, utils_1.normalizeAddress)(this.client.gateway.wallet.address);
138
+ }
139
+ get guaranteeDomain() {
140
+ return this.client.guaranteeDomain;
141
+ }
142
+ checkSigner(expected) {
143
+ if ((0, utils_1.normalizeAddress)(expected) !== this.recipientAddress) {
144
+ throw new errors_1.VerificationError('signer address does not match recipient address');
145
+ }
146
+ }
147
+ async createTab(userAddress, recipientAddress, erc20Token, ttl) {
148
+ this.checkSigner(recipientAddress);
149
+ const body = {
150
+ user_address: (0, utils_1.normalizeAddress)(userAddress),
151
+ recipient_address: (0, utils_1.normalizeAddress)(recipientAddress),
152
+ erc20_token: erc20Token ? (0, utils_1.normalizeAddress)(erc20Token) : null,
153
+ ttl: ttl ?? null,
154
+ };
155
+ const result = await this.client.rpc.createPaymentTab(body);
156
+ const record = result;
157
+ const tabIdRaw = record.id ?? record.tabId ?? record.tab_id;
158
+ const tabId = isNumericLike(tabIdRaw) ? tabIdRaw : 0;
159
+ return (0, utils_1.parseU256)(tabId);
160
+ }
161
+ async getTabPaymentStatus(tabId) {
162
+ const status = await this.client.gateway.getPaymentStatus(tabId);
163
+ return tabStatusFromRpc(status);
164
+ }
165
+ async issuePaymentGuarantee(claims, signature, scheme) {
166
+ this.checkSigner(claims.recipientAddress);
167
+ const payload = {
168
+ claims: {
169
+ version: 'v1',
170
+ user_address: claims.userAddress,
171
+ recipient_address: claims.recipientAddress,
172
+ tab_id: (0, utils_1.serializeU256)(claims.tabId),
173
+ req_id: (0, utils_1.serializeU256)(claims.reqId),
174
+ amount: (0, utils_1.serializeU256)(claims.amount),
175
+ asset_address: claims.assetAddress,
176
+ timestamp: Number(claims.timestamp),
177
+ },
178
+ signature,
179
+ scheme,
180
+ };
181
+ const cert = await this.client.rpc.issueGuarantee(payload);
182
+ const record = cert;
183
+ const certClaims = typeof record.claims === 'string' ? record.claims : '';
184
+ const signatureOut = typeof record.signature === 'string' ? record.signature : '';
185
+ return { claims: certClaims, signature: signatureOut };
186
+ }
187
+ verifyPaymentGuarantee(cert) {
188
+ const claims = (0, guarantee_1.decodeGuaranteeClaims)(cert.claims);
189
+ const domainHex = this.guaranteeDomain.startsWith('0x')
190
+ ? this.guaranteeDomain.slice(2)
191
+ : Buffer.from(this.guaranteeDomain).toString('hex');
192
+ const claimsHex = Buffer.from(claims.domain).toString('hex');
193
+ if (claimsHex !== domainHex) {
194
+ throw new errors_1.VerificationError('guarantee domain mismatch');
195
+ }
196
+ return claims;
197
+ }
198
+ async remunerate(cert) {
199
+ this.verifyPaymentGuarantee(cert);
200
+ const sigWords = (0, bls_1.signatureToWords)(cert.signature);
201
+ const claimsBytes = Buffer.from(cert.claims.replace(/^0x/, ''), 'hex');
202
+ return this.client.gateway.remunerate(claimsBytes, sigWords);
203
+ }
204
+ async listSettledTabs() {
205
+ const tabs = await this.client.rpc.listSettledTabs(this.recipientAddress);
206
+ return tabs.map((t) => models_1.TabInfo.fromRpc(t));
207
+ }
208
+ async listPendingRemunerations() {
209
+ const items = await this.client.rpc.listPendingRemunerations(this.recipientAddress);
210
+ return items.map((item) => models_1.PendingRemunerationInfo.fromRpc(item));
211
+ }
212
+ async getTab(tabId) {
213
+ const result = await this.client.rpc.getTab(tabId);
214
+ return result ? models_1.TabInfo.fromRpc(result) : null;
215
+ }
216
+ async listRecipientTabs(settlementStatuses) {
217
+ const tabs = await this.client.rpc.listRecipientTabs(this.recipientAddress, settlementStatuses);
218
+ return tabs.map((t) => models_1.TabInfo.fromRpc(t));
219
+ }
220
+ async getTabGuarantees(tabId) {
221
+ const guarantees = await this.client.rpc.getTabGuarantees(tabId);
222
+ return guarantees.map((g) => models_1.GuaranteeInfo.fromRpc(g));
223
+ }
224
+ async getLatestGuarantee(tabId) {
225
+ const result = await this.client.rpc.getLatestGuarantee(tabId);
226
+ return result ? models_1.GuaranteeInfo.fromRpc(result) : null;
227
+ }
228
+ async getGuarantee(tabId, reqId) {
229
+ const result = await this.client.rpc.getGuarantee(tabId, reqId);
230
+ return result ? models_1.GuaranteeInfo.fromRpc(result) : null;
231
+ }
232
+ async listRecipientPayments() {
233
+ const payments = await this.client.rpc.listRecipientPayments(this.recipientAddress);
234
+ return payments.map((p) => models_1.RecipientPaymentInfo.fromRpc(p));
235
+ }
236
+ async getCollateralEventsForTab(tabId) {
237
+ const events = await this.client.rpc.getCollateralEventsForTab(tabId);
238
+ return events.map((ev) => models_1.CollateralEventInfo.fromRpc(ev));
239
+ }
240
+ async getUserAssetBalance(userAddress, assetAddress) {
241
+ const balance = await this.client.rpc.getUserAssetBalance(userAddress, assetAddress);
242
+ return balance ? models_1.AssetBalanceInfo.fromRpc(balance) : null;
243
+ }
244
+ }
245
+ exports.RecipientClient = RecipientClient;
@@ -0,0 +1,36 @@
1
+ import { EvmSigner } from './signing';
2
+ export interface Config {
3
+ rpcUrl: string;
4
+ walletPrivateKey: string;
5
+ signer: EvmSigner;
6
+ ethereumHttpRpcUrl?: string;
7
+ contractAddress?: string;
8
+ adminApiKey?: string;
9
+ bearerToken?: string;
10
+ authUrl?: string;
11
+ authRefreshMarginSecs?: number;
12
+ }
13
+ export declare class ConfigBuilder {
14
+ private _rpcUrl;
15
+ private _walletPrivateKey;
16
+ private _signer;
17
+ private _ethereumHttpRpcUrl?;
18
+ private _contractAddress?;
19
+ private _adminApiKey?;
20
+ private _bearerToken?;
21
+ private _authEnabled;
22
+ private _authUrl?;
23
+ private _authRefreshMarginSecs?;
24
+ rpcUrl(value: string): ConfigBuilder;
25
+ walletPrivateKey(value: string): ConfigBuilder;
26
+ signer(value: EvmSigner): ConfigBuilder;
27
+ ethereumHttpRpcUrl(value: string): ConfigBuilder;
28
+ contractAddress(value: string): ConfigBuilder;
29
+ adminApiKey(value: string): ConfigBuilder;
30
+ bearerToken(value: string): ConfigBuilder;
31
+ enableAuth(): ConfigBuilder;
32
+ authUrl(value: string): ConfigBuilder;
33
+ authRefreshMarginSecs(value: number): ConfigBuilder;
34
+ fromEnv(): ConfigBuilder;
35
+ build(): Config;
36
+ }
package/dist/config.js ADDED
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ConfigBuilder = void 0;
4
+ const errors_1 = require("./errors");
5
+ const signing_1 = require("./signing");
6
+ const utils_1 = require("./utils");
7
+ class ConfigBuilder {
8
+ constructor() {
9
+ this._rpcUrl = 'http://127.0.0.1:3000';
10
+ this._authEnabled = false;
11
+ }
12
+ rpcUrl(value) {
13
+ this._rpcUrl = value;
14
+ return this;
15
+ }
16
+ walletPrivateKey(value) {
17
+ this._walletPrivateKey = value;
18
+ return this;
19
+ }
20
+ signer(value) {
21
+ this._signer = value;
22
+ return this;
23
+ }
24
+ ethereumHttpRpcUrl(value) {
25
+ this._ethereumHttpRpcUrl = value;
26
+ return this;
27
+ }
28
+ contractAddress(value) {
29
+ this._contractAddress = value;
30
+ return this;
31
+ }
32
+ adminApiKey(value) {
33
+ this._adminApiKey = value;
34
+ return this;
35
+ }
36
+ bearerToken(value) {
37
+ this._bearerToken = value;
38
+ return this;
39
+ }
40
+ enableAuth() {
41
+ this._authEnabled = true;
42
+ return this;
43
+ }
44
+ authUrl(value) {
45
+ this._authUrl = value;
46
+ this._authEnabled = true;
47
+ return this;
48
+ }
49
+ authRefreshMarginSecs(value) {
50
+ this._authRefreshMarginSecs = value;
51
+ this._authEnabled = true;
52
+ return this;
53
+ }
54
+ fromEnv() {
55
+ const env = process.env;
56
+ if (env['4MICA_RPC_URL'])
57
+ this._rpcUrl = env['4MICA_RPC_URL'];
58
+ if (env['4MICA_WALLET_PRIVATE_KEY'])
59
+ this._walletPrivateKey = env['4MICA_WALLET_PRIVATE_KEY'];
60
+ if (env['4MICA_ETHEREUM_HTTP_RPC_URL'])
61
+ this._ethereumHttpRpcUrl = env['4MICA_ETHEREUM_HTTP_RPC_URL'];
62
+ if (env['4MICA_CONTRACT_ADDRESS'])
63
+ this._contractAddress = env['4MICA_CONTRACT_ADDRESS'];
64
+ if (env['4MICA_ADMIN_API_KEY'])
65
+ this._adminApiKey = env['4MICA_ADMIN_API_KEY'];
66
+ if (env['4MICA_BEARER_TOKEN'])
67
+ this._bearerToken = env['4MICA_BEARER_TOKEN'];
68
+ if (env['4MICA_AUTH_URL']) {
69
+ this._authUrl = env['4MICA_AUTH_URL'];
70
+ this._authEnabled = true;
71
+ }
72
+ if (env['4MICA_AUTH_REFRESH_MARGIN_SECS']) {
73
+ this._authRefreshMarginSecs = Number(env['4MICA_AUTH_REFRESH_MARGIN_SECS']);
74
+ this._authEnabled = true;
75
+ }
76
+ return this;
77
+ }
78
+ build() {
79
+ if (!this._signer && !this._walletPrivateKey) {
80
+ throw new errors_1.ConfigError('missing signer or wallet_private_key');
81
+ }
82
+ if (!this._rpcUrl) {
83
+ throw new errors_1.ConfigError('missing rpc_url');
84
+ }
85
+ try {
86
+ const rpcUrl = (0, utils_1.validateUrl)(this._rpcUrl);
87
+ const walletPrivateKey = this._walletPrivateKey
88
+ ? (0, utils_1.normalizePrivateKey)(this._walletPrivateKey)
89
+ : undefined;
90
+ const signer = this._signer ?? (0, signing_1.createLocalSigner)(walletPrivateKey);
91
+ const ethereumHttpRpcUrl = this._ethereumHttpRpcUrl
92
+ ? (0, utils_1.validateUrl)(this._ethereumHttpRpcUrl)
93
+ : undefined;
94
+ const contractAddress = this._contractAddress
95
+ ? (0, utils_1.normalizeAddress)(this._contractAddress)
96
+ : undefined;
97
+ const authUrl = this._authUrl ? (0, utils_1.validateUrl)(this._authUrl) : undefined;
98
+ const refreshMargin = this._authRefreshMarginSecs !== undefined ? this._authRefreshMarginSecs : 60;
99
+ if (!Number.isFinite(refreshMargin) || refreshMargin < 0) {
100
+ throw new utils_1.ValidationError('invalid auth refresh margin');
101
+ }
102
+ const authEnabled = this._authEnabled;
103
+ return {
104
+ rpcUrl,
105
+ walletPrivateKey: walletPrivateKey ?? signer.address,
106
+ signer,
107
+ ethereumHttpRpcUrl,
108
+ contractAddress,
109
+ adminApiKey: this._adminApiKey,
110
+ bearerToken: this._bearerToken,
111
+ authUrl: authEnabled ? (authUrl ?? rpcUrl) : undefined,
112
+ authRefreshMarginSecs: authEnabled ? refreshMargin : undefined,
113
+ };
114
+ }
115
+ catch (err) {
116
+ if (err instanceof utils_1.ValidationError) {
117
+ throw new errors_1.ConfigError(err.message);
118
+ }
119
+ throw err;
120
+ }
121
+ }
122
+ }
123
+ exports.ConfigBuilder = ConfigBuilder;
@@ -0,0 +1,33 @@
1
+ import { Contract, JsonRpcProvider, Wallet } from 'ethers';
2
+ type ContractFactory = (address: string, abi: unknown, signer: Wallet) => Contract;
3
+ export declare class ContractGateway {
4
+ readonly provider: JsonRpcProvider;
5
+ readonly wallet: Wallet;
6
+ readonly contract: Contract;
7
+ private erc20Cache;
8
+ constructor(ethRpcUrl: string, privateKey: string, contractAddress: string, chainId: number | bigint, provider?: JsonRpcProvider, contractFactory?: ContractFactory);
9
+ getChainId(): Promise<number>;
10
+ private erc20;
11
+ private send;
12
+ getGuaranteeDomain(): Promise<string>;
13
+ approveErc20(token: string, amount: number | bigint | string): Promise<unknown>;
14
+ deposit(amount: number | bigint | string, erc20Token?: string): Promise<unknown>;
15
+ getUserAssets(): Promise<{
16
+ asset: string;
17
+ collateral: bigint;
18
+ withdrawal_request_timestamp: bigint;
19
+ withdrawal_request_amount: bigint;
20
+ }[]>;
21
+ getPaymentStatus(tabId: number | bigint): Promise<{
22
+ paid: bigint;
23
+ remunerated: boolean;
24
+ asset: string;
25
+ }>;
26
+ payTabEth(tabId: number | bigint, reqId: number | bigint, amount: number | bigint | string, recipient: string): Promise<unknown>;
27
+ payTabErc20(tabId: number | bigint, amount: number | bigint | string, erc20Token: string, recipient: string): Promise<unknown>;
28
+ requestWithdrawal(amount: number | bigint | string, erc20Token?: string): Promise<unknown>;
29
+ cancelWithdrawal(erc20Token?: string): Promise<unknown>;
30
+ finalizeWithdrawal(erc20Token?: string): Promise<unknown>;
31
+ remunerate(claimsBlob: Uint8Array, signatureWords: Uint8Array[]): Promise<unknown>;
32
+ }
33
+ export {};
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ContractGateway = void 0;
7
+ const ethers_1 = require("ethers");
8
+ const core4mica_json_1 = __importDefault(require("./abi/core4mica.json"));
9
+ const erc20_json_1 = __importDefault(require("./abi/erc20.json"));
10
+ const errors_1 = require("./errors");
11
+ const utils_1 = require("./utils");
12
+ class ContractGateway {
13
+ constructor(ethRpcUrl, privateKey, contractAddress, chainId, provider, contractFactory) {
14
+ this.erc20Cache = new Map();
15
+ const parsedChainId = Number(chainId);
16
+ if (!Number.isFinite(parsedChainId)) {
17
+ throw new errors_1.ContractError(`invalid chain id: ${chainId}`);
18
+ }
19
+ const networkish = { chainId: parsedChainId, name: `chain-${parsedChainId}` };
20
+ this.provider = provider ?? new ethers_1.JsonRpcProvider(ethRpcUrl, networkish);
21
+ this.wallet = new ethers_1.Wallet(privateKey, this.provider);
22
+ const factory = contractFactory ??
23
+ ((addr, abi, signer) => {
24
+ const resolvedAbi = abi.abi ?? abi;
25
+ return new ethers_1.Contract(addr, resolvedAbi, signer);
26
+ });
27
+ this.contract = factory(contractAddress, core4mica_json_1.default, this.wallet);
28
+ }
29
+ async getChainId() {
30
+ const network = await this.provider.getNetwork();
31
+ return Number(network.chainId);
32
+ }
33
+ erc20(address) {
34
+ const checksum = address;
35
+ if (!this.erc20Cache.has(checksum)) {
36
+ this.erc20Cache.set(checksum, new ethers_1.Contract(checksum, erc20_json_1.default.abi ?? erc20_json_1.default, this.wallet));
37
+ }
38
+ return this.erc20Cache.get(checksum);
39
+ }
40
+ async send(promise) {
41
+ try {
42
+ const tx = await promise;
43
+ if (typeof tx.wait === 'function') {
44
+ return await tx.wait();
45
+ }
46
+ return tx;
47
+ }
48
+ catch (err) {
49
+ const message = err instanceof Error ? err.message : String(err);
50
+ throw new errors_1.ContractError(message);
51
+ }
52
+ }
53
+ async getGuaranteeDomain() {
54
+ return this.send(this.contract.guaranteeDomainSeparator());
55
+ }
56
+ async approveErc20(token, amount) {
57
+ const erc20 = this.erc20(token);
58
+ const { target, address } = this.contract;
59
+ const spender = target ?? address ?? token;
60
+ return this.send(erc20.approve(spender, (0, utils_1.parseU256)(amount)));
61
+ }
62
+ async deposit(amount, erc20Token) {
63
+ if (erc20Token) {
64
+ return this.send(this.contract.depositStablecoin(erc20Token, (0, utils_1.parseU256)(amount)));
65
+ }
66
+ return this.send(this.contract.deposit({
67
+ value: (0, utils_1.parseU256)(amount),
68
+ }));
69
+ }
70
+ async getUserAssets() {
71
+ try {
72
+ const result = await this.contract.getUserAllAssets(this.wallet.address);
73
+ return result.map((asset) => ({
74
+ asset: asset[0],
75
+ collateral: (0, utils_1.parseU256)(asset[1]),
76
+ withdrawal_request_timestamp: (0, utils_1.parseU256)(asset[2]),
77
+ withdrawal_request_amount: (0, utils_1.parseU256)(asset[3]),
78
+ }));
79
+ }
80
+ catch (err) {
81
+ const message = err instanceof Error ? err.message : String(err);
82
+ throw new errors_1.ContractError(message);
83
+ }
84
+ }
85
+ async getPaymentStatus(tabId) {
86
+ try {
87
+ const [paid, remunerated, asset] = await this.contract.getPaymentStatus((0, utils_1.parseU256)(tabId));
88
+ return {
89
+ paid: (0, utils_1.parseU256)(paid),
90
+ remunerated: Boolean(remunerated),
91
+ asset,
92
+ };
93
+ }
94
+ catch (err) {
95
+ const message = err instanceof Error ? err.message : String(err);
96
+ throw new errors_1.ContractError(message);
97
+ }
98
+ }
99
+ async payTabEth(tabId, reqId, amount, recipient) {
100
+ const data = Buffer.from(`tab_id:${(0, ethers_1.toBeHex)((0, utils_1.parseU256)(tabId))};req_id:${(0, ethers_1.toBeHex)((0, utils_1.parseU256)(reqId))}`);
101
+ const tx = {
102
+ to: recipient,
103
+ value: (0, utils_1.parseU256)(amount),
104
+ data: (0, ethers_1.hexlify)(data),
105
+ };
106
+ return this.send(this.wallet.sendTransaction(tx));
107
+ }
108
+ async payTabErc20(tabId, amount, erc20Token, recipient) {
109
+ return this.send(this.contract.payTabInERC20Token((0, utils_1.parseU256)(tabId), erc20Token, (0, utils_1.parseU256)(amount), recipient));
110
+ }
111
+ async requestWithdrawal(amount, erc20Token) {
112
+ if (erc20Token) {
113
+ return this.send(this.contract['requestWithdrawal(address,uint256)'](erc20Token, (0, utils_1.parseU256)(amount)));
114
+ }
115
+ return this.send(this.contract['requestWithdrawal(uint256)']((0, utils_1.parseU256)(amount)));
116
+ }
117
+ async cancelWithdrawal(erc20Token) {
118
+ if (erc20Token) {
119
+ return this.send(this.contract['cancelWithdrawal(address)'](erc20Token));
120
+ }
121
+ return this.send(this.contract['cancelWithdrawal()']());
122
+ }
123
+ async finalizeWithdrawal(erc20Token) {
124
+ if (erc20Token) {
125
+ return this.send(this.contract['finalizeWithdrawal(address)'](erc20Token));
126
+ }
127
+ return this.send(this.contract['finalizeWithdrawal()']());
128
+ }
129
+ async remunerate(claimsBlob, signatureWords) {
130
+ const sigStruct = signatureWords.map((word) => (0, ethers_1.hexlify)((0, ethers_1.getBytes)(word)));
131
+ return this.send(this.contract.remunerate((0, ethers_1.hexlify)(claimsBlob), sigStruct));
132
+ }
133
+ }
134
+ exports.ContractGateway = ContractGateway;
@@ -0,0 +1,43 @@
1
+ export declare class FourMicaError extends Error {
2
+ constructor(message: string);
3
+ }
4
+ export declare class ConfigError extends FourMicaError {
5
+ }
6
+ export declare class RpcError extends FourMicaError {
7
+ readonly status?: number;
8
+ readonly body?: unknown;
9
+ constructor(message: string, options?: {
10
+ status?: number;
11
+ body?: unknown;
12
+ });
13
+ }
14
+ export declare class ClientInitializationError extends FourMicaError {
15
+ }
16
+ export declare class SigningError extends FourMicaError {
17
+ }
18
+ export declare class ContractError extends FourMicaError {
19
+ }
20
+ export declare class VerificationError extends FourMicaError {
21
+ }
22
+ export declare class X402Error extends FourMicaError {
23
+ }
24
+ export declare class AuthError extends FourMicaError {
25
+ }
26
+ export declare class AuthUrlError extends AuthError {
27
+ }
28
+ export declare class AuthTransportError extends AuthError {
29
+ }
30
+ export declare class AuthDecodeError extends AuthError {
31
+ }
32
+ export declare class AuthApiError extends AuthError {
33
+ readonly status?: number;
34
+ readonly body?: unknown;
35
+ constructor(message: string, options?: {
36
+ status?: number;
37
+ body?: unknown;
38
+ });
39
+ }
40
+ export declare class AuthConfigError extends AuthError {
41
+ }
42
+ export declare class AuthMissingConfigError extends AuthConfigError {
43
+ }
package/dist/errors.js ADDED
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AuthMissingConfigError = exports.AuthConfigError = exports.AuthApiError = exports.AuthDecodeError = exports.AuthTransportError = exports.AuthUrlError = exports.AuthError = exports.X402Error = exports.VerificationError = exports.ContractError = exports.SigningError = exports.ClientInitializationError = exports.RpcError = exports.ConfigError = exports.FourMicaError = void 0;
4
+ class FourMicaError extends Error {
5
+ constructor(message) {
6
+ super(message);
7
+ this.name = this.constructor.name;
8
+ }
9
+ }
10
+ exports.FourMicaError = FourMicaError;
11
+ class ConfigError extends FourMicaError {
12
+ }
13
+ exports.ConfigError = ConfigError;
14
+ class RpcError extends FourMicaError {
15
+ constructor(message, options) {
16
+ super(message);
17
+ this.status = options?.status;
18
+ this.body = options?.body;
19
+ }
20
+ }
21
+ exports.RpcError = RpcError;
22
+ class ClientInitializationError extends FourMicaError {
23
+ }
24
+ exports.ClientInitializationError = ClientInitializationError;
25
+ class SigningError extends FourMicaError {
26
+ }
27
+ exports.SigningError = SigningError;
28
+ class ContractError extends FourMicaError {
29
+ }
30
+ exports.ContractError = ContractError;
31
+ class VerificationError extends FourMicaError {
32
+ }
33
+ exports.VerificationError = VerificationError;
34
+ class X402Error extends FourMicaError {
35
+ }
36
+ exports.X402Error = X402Error;
37
+ class AuthError extends FourMicaError {
38
+ }
39
+ exports.AuthError = AuthError;
40
+ class AuthUrlError extends AuthError {
41
+ }
42
+ exports.AuthUrlError = AuthUrlError;
43
+ class AuthTransportError extends AuthError {
44
+ }
45
+ exports.AuthTransportError = AuthTransportError;
46
+ class AuthDecodeError extends AuthError {
47
+ }
48
+ exports.AuthDecodeError = AuthDecodeError;
49
+ class AuthApiError extends AuthError {
50
+ constructor(message, options) {
51
+ super(message);
52
+ this.status = options?.status;
53
+ this.body = options?.body;
54
+ }
55
+ }
56
+ exports.AuthApiError = AuthApiError;
57
+ class AuthConfigError extends AuthError {
58
+ }
59
+ exports.AuthConfigError = AuthConfigError;
60
+ class AuthMissingConfigError extends AuthConfigError {
61
+ }
62
+ exports.AuthMissingConfigError = AuthMissingConfigError;
@@ -0,0 +1,3 @@
1
+ import { PaymentGuaranteeClaims } from './models';
2
+ export declare function encodeGuaranteeClaims(claims: PaymentGuaranteeClaims): string;
3
+ export declare function decodeGuaranteeClaims(data: string | Uint8Array): PaymentGuaranteeClaims;