@4mica/sdk 1.2.14 → 1.2.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@4mica/sdk",
3
- "version": "1.2.14",
3
+ "version": "1.2.16",
4
4
  "description": "TypeScript SDK for interacting with the 4Mica payment network",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -59,13 +59,13 @@ export declare class UserClient {
59
59
  /**
60
60
  * List all tabs where the current signer is the payer.
61
61
  *
62
- * @param recipientAddress - Address of the recipient to query tabs from.
62
+ * @param settlementStatuses - Optional filter on settlement status (e.g. `['pending']`).
63
63
  * @returns Array of tabs belonging to the current signer.
64
64
  */
65
- listTabs(recipientAddress: string): Promise<TabInfo[]>;
65
+ listTabs(settlementStatuses?: string[]): Promise<TabInfo[]>;
66
66
  /**
67
- * Pay a tab on-chain. Automatically resolves the recipient, asset, and amount
68
- * from the tab and its latest guarantee.
67
+ * Pay the remaining tab balance on-chain. Automatically resolves the recipient,
68
+ * asset, and remaining amount from the tab and its latest guarantee.
69
69
  *
70
70
  * @param tabId - Tab identifier.
71
71
  * @param waitOptions - Optional timeout/polling overrides.
@@ -81,15 +81,13 @@ class UserClient {
81
81
  /**
82
82
  * List all tabs where the current signer is the payer.
83
83
  *
84
- * @param recipientAddress - Address of the recipient to query tabs from.
84
+ * @param settlementStatuses - Optional filter on settlement status (e.g. `['pending']`).
85
85
  * @returns Array of tabs belonging to the current signer.
86
86
  */
87
- async listTabs(recipientAddress) {
87
+ async listTabs(settlementStatuses) {
88
88
  const myAddress = (0, utils_1.normalizeAddress)(this.client.signer.signer.address);
89
- const raw = await this.client.rpc.listRecipientTabs(recipientAddress);
90
- return raw
91
- .map((t) => models_1.TabInfo.fromRpc(t))
92
- .filter((t) => (0, utils_1.normalizeAddress)(t.userAddress) === myAddress);
89
+ const raw = await this.client.rpc.listUserTabs(myAddress, settlementStatuses);
90
+ return raw.map((t) => models_1.TabInfo.fromRpc(t));
93
91
  }
94
92
  async payTab(tabId, reqIdOrWaitOptions, amount, recipientAddress, erc20Token, waitOptions) {
95
93
  // Simple overload: auto-resolve from tab + latest guarantee
@@ -104,10 +102,14 @@ class UserClient {
104
102
  const guarantee = await this.client.recipient.getLatestGuarantee(tabId);
105
103
  if (!guarantee)
106
104
  throw new Error(`Tab ${tabId} has no guarantee`);
105
+ const remaining = tab.totalAmount > tab.paidAmount ? tab.totalAmount - tab.paidAmount : 0n;
106
+ if (remaining === 0n) {
107
+ throw new Error(`Tab ${tabId} is already fully paid`);
108
+ }
107
109
  const isEth = tab.assetAddress === '0x0000000000000000000000000000000000000000';
108
110
  return isEth
109
- ? this.client.gateway.payTabEth(tabId, guarantee.reqId, guarantee.amount, tab.recipientAddress, opts)
110
- : this.client.gateway.payTabErc20(tabId, guarantee.amount, tab.assetAddress, tab.recipientAddress, opts);
111
+ ? this.client.gateway.payTabEth(tabId, guarantee.reqId, remaining, tab.recipientAddress, opts)
112
+ : this.client.gateway.payTabErc20(tabId, remaining, tab.assetAddress, tab.recipientAddress, opts);
111
113
  }
112
114
  // Explicit overload
113
115
  const reqId = reqIdOrWaitOptions;
@@ -172,7 +172,9 @@ export declare class TabInfo {
172
172
  settlementStatus: string;
173
173
  createdAt: number;
174
174
  updatedAt: number;
175
- constructor(tabId: bigint, userAddress: string, recipientAddress: string, assetAddress: string, startTimestamp: number, ttlSeconds: number, status: string, settlementStatus: string, createdAt: number, updatedAt: number);
175
+ totalAmount: bigint;
176
+ paidAmount: bigint;
177
+ constructor(tabId: bigint, userAddress: string, recipientAddress: string, assetAddress: string, startTimestamp: number, ttlSeconds: number, status: string, settlementStatus: string, createdAt: number, updatedAt: number, totalAmount?: bigint, paidAmount?: bigint);
176
178
  static fromRpc(raw: Record<string, unknown>): TabInfo;
177
179
  }
178
180
  export declare class GuaranteeInfo {
@@ -153,7 +153,9 @@ class TabInfo {
153
153
  settlementStatus;
154
154
  createdAt;
155
155
  updatedAt;
156
- constructor(tabId, userAddress, recipientAddress, assetAddress, startTimestamp, ttlSeconds, status, settlementStatus, createdAt, updatedAt) {
156
+ totalAmount;
157
+ paidAmount;
158
+ constructor(tabId, userAddress, recipientAddress, assetAddress, startTimestamp, ttlSeconds, status, settlementStatus, createdAt, updatedAt, totalAmount = 0n, paidAmount = 0n) {
157
159
  this.tabId = tabId;
158
160
  this.userAddress = userAddress;
159
161
  this.recipientAddress = recipientAddress;
@@ -164,9 +166,11 @@ class TabInfo {
164
166
  this.settlementStatus = settlementStatus;
165
167
  this.createdAt = createdAt;
166
168
  this.updatedAt = updatedAt;
169
+ this.totalAmount = totalAmount;
170
+ this.paidAmount = paidAmount;
167
171
  }
168
172
  static fromRpc(raw) {
169
- return new TabInfo((0, utils_1.parseU256)(((0, serde_1.getAny)(raw, 'tab_id', 'tabId') ?? 0)), ((0, serde_1.getAny)(raw, 'user_address', 'userAddress') ?? ''), ((0, serde_1.getAny)(raw, 'recipient_address', 'recipientAddress') ?? ''), ((0, serde_1.getAny)(raw, 'asset_address', 'assetAddress') ?? ''), Number((0, serde_1.getAny)(raw, 'start_timestamp', 'startTimestamp')), Number((0, serde_1.getAny)(raw, 'ttl_seconds', 'ttlSeconds')), ((0, serde_1.getAny)(raw, 'status') ?? ''), ((0, serde_1.getAny)(raw, 'settlement_status', 'settlementStatus') ?? ''), Number((0, serde_1.getAny)(raw, 'created_at', 'createdAt')), Number((0, serde_1.getAny)(raw, 'updated_at', 'updatedAt')));
173
+ return new TabInfo((0, utils_1.parseU256)(((0, serde_1.getAny)(raw, 'tab_id', 'tabId') ?? 0)), ((0, serde_1.getAny)(raw, 'user_address', 'userAddress') ?? ''), ((0, serde_1.getAny)(raw, 'recipient_address', 'recipientAddress') ?? ''), ((0, serde_1.getAny)(raw, 'asset_address', 'assetAddress') ?? ''), Number((0, serde_1.getAny)(raw, 'start_timestamp', 'startTimestamp')), Number((0, serde_1.getAny)(raw, 'ttl_seconds', 'ttlSeconds')), ((0, serde_1.getAny)(raw, 'status') ?? ''), ((0, serde_1.getAny)(raw, 'settlement_status', 'settlementStatus') ?? ''), Number((0, serde_1.getAny)(raw, 'created_at', 'createdAt')), Number((0, serde_1.getAny)(raw, 'updated_at', 'updatedAt')), (0, utils_1.parseU256)(((0, serde_1.getAny)(raw, 'total_amount', 'totalAmount') ?? 0)), (0, utils_1.parseU256)(((0, serde_1.getAny)(raw, 'paid_amount', 'paidAmount') ?? 0)));
170
174
  }
171
175
  }
172
176
  exports.TabInfo = TabInfo;
package/dist/src/rpc.d.ts CHANGED
@@ -24,6 +24,7 @@ export declare class RpcProxy {
24
24
  listPendingRemunerations(recipientAddress: string): Promise<Record<string, unknown>[]>;
25
25
  getTab(tabId: number | bigint): Promise<Record<string, unknown> | null>;
26
26
  listRecipientTabs(recipientAddress: string, settlementStatuses?: string[]): Promise<Record<string, unknown>[]>;
27
+ listUserTabs(userAddress: string, settlementStatuses?: string[]): Promise<Record<string, unknown>[]>;
27
28
  getTabGuarantees(tabId: number | bigint): Promise<Record<string, unknown>[]>;
28
29
  getLatestGuarantee(tabId: number | bigint): Promise<Record<string, unknown> | null>;
29
30
  getGuarantee(tabId: number | bigint, reqId: number | bigint): Promise<Record<string, unknown> | null>;
package/dist/src/rpc.js CHANGED
@@ -113,6 +113,14 @@ class RpcProxy {
113
113
  }
114
114
  return this.get(`/core/recipients/${recipientAddress}/tabs${query}`);
115
115
  }
116
+ async listUserTabs(userAddress, settlementStatuses) {
117
+ let query = '';
118
+ if (settlementStatuses?.length) {
119
+ query =
120
+ '?' + settlementStatuses.map((s) => `settlement_status=${encodeURIComponent(s)}`).join('&');
121
+ }
122
+ return this.get(`/core/users/${userAddress}/tabs${query}`);
123
+ }
116
124
  async getTabGuarantees(tabId) {
117
125
  return this.get(`/core/tabs/${serializeTabId(tabId)}/guarantees`);
118
126
  }
@@ -4,6 +4,8 @@ export interface CdpAccountConfig {
4
4
  apiKeyId: string;
5
5
  /** CDP API key secret from the Coinbase Developer Platform dashboard. */
6
6
  apiKeySecret: string;
7
+ /** CDP wallet secret — required for account creation/signing operations. */
8
+ walletSecret: string;
7
9
  /** Idempotency name — getOrCreateAccount always returns the same wallet for a given name. */
8
10
  name: string;
9
11
  }
@@ -42,6 +42,7 @@ async function createCdpAccount(config) {
42
42
  const cdp = new CdpClient({
43
43
  apiKeyId: config.apiKeyId,
44
44
  apiKeySecret: config.apiKeySecret,
45
+ walletSecret: config.walletSecret,
45
46
  });
46
47
  const evmAccount = await cdp.evm.getOrCreateAccount({ name: config.name });
47
48
  const address = evmAccount.address;
@@ -56,18 +57,10 @@ async function createCdpAccount(config) {
56
57
  return result.signature;
57
58
  }
58
59
  async function signTypedData(parameters) {
59
- const { domain, types, primaryType, message } = parameters;
60
- if (domain && types && primaryType && message) {
61
- try {
62
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
63
- const payload = { address, domain, types, primaryType, message };
64
- const result = await cdp.evm.signTypedData(payload);
65
- return result.signature;
66
- }
67
- catch {
68
- // Fall back to hash-then-sign if CDP rejects the typed-data structure.
69
- }
70
- }
60
+ // Always hash locally with viem (guaranteed correct EIP-712 encoding including
61
+ // non-standard types like uint64) and sign only the hash via CDP.
62
+ // CDP's native signTypedData can silently produce a wrong hash for custom types,
63
+ // which would pass without error but fail signature verification on the core side.
71
64
  const hash = (0, viem_1.hashTypedData)(parameters);
72
65
  const result = await cdp.evm.signHash({ address, hash });
73
66
  return result.signature;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@4mica/sdk",
3
- "version": "1.2.14",
3
+ "version": "1.2.17",
4
4
  "description": "TypeScript SDK for interacting with the 4Mica payment network",
5
5
  "license": "MIT",
6
6
  "repository": {