payment-kit 1.25.2 → 1.25.4
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/api/src/libs/payment.ts
CHANGED
|
@@ -253,6 +253,15 @@ export async function isDelegationSufficientForPayment(args: {
|
|
|
253
253
|
}
|
|
254
254
|
}
|
|
255
255
|
|
|
256
|
+
// Log delegation check context for debugging
|
|
257
|
+
logger.info('isDelegationSufficientForPayment: checking delegation', {
|
|
258
|
+
originalUserDid: userDid,
|
|
259
|
+
resolvedDelegator: delegator,
|
|
260
|
+
delegatorChanged: userDid !== delegator,
|
|
261
|
+
walletAddress: wallet.address,
|
|
262
|
+
paymentMethodApiHost: paymentMethod.settings?.arcblock?.api_host,
|
|
263
|
+
});
|
|
264
|
+
|
|
256
265
|
const client = paymentMethod.getOcapClient();
|
|
257
266
|
|
|
258
267
|
// have delegated before? Use migration-aware fallback query
|
|
@@ -263,6 +272,12 @@ export async function isDelegationSufficientForPayment(args: {
|
|
|
263
272
|
client,
|
|
264
273
|
});
|
|
265
274
|
if (!delegationResult) {
|
|
275
|
+
logger.error('isDelegationSufficientForPayment: no delegation address found', {
|
|
276
|
+
delegator,
|
|
277
|
+
storedDelegationAddress,
|
|
278
|
+
subscriptionDelegationAddress: subscription?.payment_details?.arcblock?.delegation_address,
|
|
279
|
+
subscriptionId: subscription?.id,
|
|
280
|
+
});
|
|
266
281
|
return { sufficient: false, reason: 'NO_DELEGATION' };
|
|
267
282
|
}
|
|
268
283
|
|
|
@@ -15,17 +15,21 @@ import { wallet } from './auth';
|
|
|
15
15
|
import logger from './logger';
|
|
16
16
|
import { Subscription } from '../store/models';
|
|
17
17
|
|
|
18
|
-
// Cache for migratedFrom list (
|
|
18
|
+
// Cache for migratedFrom list (keyed by wallet.address + chain host)
|
|
19
19
|
let cachedMigratedFrom: string[] | null = null;
|
|
20
20
|
let cachedWalletAddress: string | null = null;
|
|
21
|
+
let cachedChainHost: string | null = null;
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* Get the migratedFrom list for the current app wallet (with caching)
|
|
24
|
-
* The cache is invalidated when wallet.address changes
|
|
25
|
+
* The cache is invalidated when wallet.address or chain host changes
|
|
25
26
|
*/
|
|
26
27
|
export async function getMigratedFromList(client: OcapClient): Promise<string[]> {
|
|
27
|
-
//
|
|
28
|
-
|
|
28
|
+
// @ts-ignore - OcapClient has host property
|
|
29
|
+
const chainHost = client.host || client.endpoint || 'unknown';
|
|
30
|
+
|
|
31
|
+
// If wallet address and chain host haven't changed, use cached value
|
|
32
|
+
if (wallet.address === cachedWalletAddress && chainHost === cachedChainHost && cachedMigratedFrom !== null) {
|
|
29
33
|
return cachedMigratedFrom;
|
|
30
34
|
}
|
|
31
35
|
|
|
@@ -34,17 +38,23 @@ export async function getMigratedFromList(client: OcapClient): Promise<string[]>
|
|
|
34
38
|
const { state } = await client.getAccountState({ address: wallet.address });
|
|
35
39
|
cachedMigratedFrom = state?.migratedFrom || [];
|
|
36
40
|
cachedWalletAddress = wallet.address;
|
|
41
|
+
cachedChainHost = chainHost;
|
|
37
42
|
|
|
38
43
|
if (cachedMigratedFrom.length > 0) {
|
|
39
44
|
logger.info('wallet-migration: loaded migratedFrom list', {
|
|
40
45
|
walletAddress: wallet.address,
|
|
46
|
+
chainHost,
|
|
41
47
|
migratedFrom: cachedMigratedFrom,
|
|
42
48
|
});
|
|
43
49
|
}
|
|
44
50
|
|
|
45
51
|
return cachedMigratedFrom;
|
|
46
52
|
} catch (err) {
|
|
47
|
-
logger.error('wallet-migration: failed to get migratedFrom list', {
|
|
53
|
+
logger.error('wallet-migration: failed to get migratedFrom list', {
|
|
54
|
+
walletAddress: wallet.address,
|
|
55
|
+
chainHost,
|
|
56
|
+
error: err,
|
|
57
|
+
});
|
|
48
58
|
return [];
|
|
49
59
|
}
|
|
50
60
|
}
|
|
@@ -54,6 +64,7 @@ export async function getMigratedFromList(client: OcapClient): Promise<string[]>
|
|
|
54
64
|
*/
|
|
55
65
|
export function clearMigratedFromCache(): void {
|
|
56
66
|
cachedMigratedFrom = null;
|
|
67
|
+
cachedChainHost = null;
|
|
57
68
|
cachedWalletAddress = null;
|
|
58
69
|
}
|
|
59
70
|
|
|
@@ -85,19 +96,46 @@ export async function getDelegationAddressWithFallback({
|
|
|
85
96
|
delegator,
|
|
86
97
|
client,
|
|
87
98
|
}: GetDelegationAddressParams): Promise<AddressWithFallbackResult | null> {
|
|
88
|
-
// 1. Check stored delegation_address first
|
|
99
|
+
// 1. Check stored delegation_address first - but verify it has valid state
|
|
89
100
|
if (storedAddress) {
|
|
90
|
-
|
|
101
|
+
try {
|
|
102
|
+
const { state: storedState } = await client.getDelegateState({ address: storedAddress });
|
|
103
|
+
if (storedState?.ops?.length > 0) {
|
|
104
|
+
return { address: storedAddress, needsBackfill: false, source: 'stored' };
|
|
105
|
+
}
|
|
106
|
+
logger.warn('wallet-migration: stored delegation address has no valid state, falling back', {
|
|
107
|
+
storedAddress,
|
|
108
|
+
delegator,
|
|
109
|
+
hasState: !!storedState,
|
|
110
|
+
opsCount: storedState?.ops?.length || 0,
|
|
111
|
+
});
|
|
112
|
+
} catch (err) {
|
|
113
|
+
logger.warn('wallet-migration: failed to query stored delegation address, falling back', {
|
|
114
|
+
storedAddress,
|
|
115
|
+
delegator,
|
|
116
|
+
error: err,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
// Continue to fallback instead of returning early
|
|
91
120
|
}
|
|
92
121
|
|
|
93
122
|
// 2. Try current wallet.address
|
|
94
123
|
const currentAddress = toDelegateAddress(delegator, wallet.address);
|
|
124
|
+
let currentStateResult: { hasState: boolean; opsCount: number; error?: string } = {
|
|
125
|
+
hasState: false,
|
|
126
|
+
opsCount: 0,
|
|
127
|
+
};
|
|
95
128
|
try {
|
|
96
129
|
const { state: currentState } = await client.getDelegateState({ address: currentAddress });
|
|
130
|
+
currentStateResult = {
|
|
131
|
+
hasState: !!currentState,
|
|
132
|
+
opsCount: currentState?.ops?.length || 0,
|
|
133
|
+
};
|
|
97
134
|
if (currentState?.ops?.length > 0) {
|
|
98
135
|
return { address: currentAddress, needsBackfill: true, source: 'current' };
|
|
99
136
|
}
|
|
100
137
|
} catch (err) {
|
|
138
|
+
currentStateResult.error = String(err);
|
|
101
139
|
logger.warn('wallet-migration: failed to query current delegation state', {
|
|
102
140
|
address: currentAddress,
|
|
103
141
|
error: err,
|
|
@@ -106,11 +144,24 @@ export async function getDelegationAddressWithFallback({
|
|
|
106
144
|
|
|
107
145
|
// 3. Fallback to migratedFrom addresses
|
|
108
146
|
const migratedFrom = await getMigratedFromList(client);
|
|
147
|
+
const migratedResults: Array<{
|
|
148
|
+
appDid: string;
|
|
149
|
+
address: string;
|
|
150
|
+
hasState: boolean;
|
|
151
|
+
opsCount: number;
|
|
152
|
+
error?: string;
|
|
153
|
+
}> = [];
|
|
109
154
|
for (const oldAppDid of migratedFrom) {
|
|
110
155
|
const oldAddress = toDelegateAddress(delegator, oldAppDid);
|
|
111
156
|
try {
|
|
112
157
|
// eslint-disable-next-line no-await-in-loop
|
|
113
158
|
const { state: oldState } = await client.getDelegateState({ address: oldAddress });
|
|
159
|
+
migratedResults.push({
|
|
160
|
+
appDid: oldAppDid,
|
|
161
|
+
address: oldAddress,
|
|
162
|
+
hasState: !!oldState,
|
|
163
|
+
opsCount: oldState?.ops?.length || 0,
|
|
164
|
+
});
|
|
114
165
|
if (oldState?.ops?.length > 0) {
|
|
115
166
|
logger.info('wallet-migration: found delegation in migratedFrom', {
|
|
116
167
|
delegator,
|
|
@@ -120,6 +171,13 @@ export async function getDelegationAddressWithFallback({
|
|
|
120
171
|
return { address: oldAddress, needsBackfill: true, source: 'migrated' };
|
|
121
172
|
}
|
|
122
173
|
} catch (err) {
|
|
174
|
+
migratedResults.push({
|
|
175
|
+
appDid: oldAppDid,
|
|
176
|
+
address: oldAddress,
|
|
177
|
+
hasState: false,
|
|
178
|
+
opsCount: 0,
|
|
179
|
+
error: String(err),
|
|
180
|
+
});
|
|
123
181
|
logger.warn('wallet-migration: failed to query migrated delegation state', {
|
|
124
182
|
address: oldAddress,
|
|
125
183
|
oldAppDid,
|
|
@@ -128,7 +186,15 @@ export async function getDelegationAddressWithFallback({
|
|
|
128
186
|
}
|
|
129
187
|
}
|
|
130
188
|
|
|
131
|
-
// Not found
|
|
189
|
+
// Not found - log detailed search results
|
|
190
|
+
logger.error('wallet-migration: no delegation found after full search', {
|
|
191
|
+
delegator,
|
|
192
|
+
currentWalletAddress: wallet.address,
|
|
193
|
+
currentDelegationAddress: currentAddress,
|
|
194
|
+
currentStateResult,
|
|
195
|
+
migratedFromCount: migratedFrom.length,
|
|
196
|
+
migratedResults,
|
|
197
|
+
});
|
|
132
198
|
return null;
|
|
133
199
|
}
|
|
134
200
|
|
|
@@ -25,6 +25,7 @@ jest.mock('../../src/libs/logger', () => ({
|
|
|
25
25
|
describe('wallet-migration', () => {
|
|
26
26
|
// Mock OcapClient
|
|
27
27
|
const createMockClient = (overrides: any = {}) => ({
|
|
28
|
+
host: 'https://main.abtnetwork.io/api',
|
|
28
29
|
getAccountState: jest.fn().mockResolvedValue({
|
|
29
30
|
state: {
|
|
30
31
|
migratedFrom: ['zNKq13Dr2TBHELpLDUJFGxepiGP7YHbAVxPn', 'zNKq6yG8AVbwdRBDJSNCDVJJUQD1AXdkK7Wp'],
|
|
@@ -76,8 +77,15 @@ describe('wallet-migration', () => {
|
|
|
76
77
|
const currentWalletAddress = 'zNKcF7wyrvAvn4YaADjr4p9gpFUSHnW2aQJa';
|
|
77
78
|
const oldAppDid = 'zNKq13Dr2TBHELpLDUJFGxepiGP7YHbAVxPn';
|
|
78
79
|
|
|
79
|
-
it('should return stored address if available', async () => {
|
|
80
|
-
const mockClient = createMockClient(
|
|
80
|
+
it('should return stored address if available and valid', async () => {
|
|
81
|
+
const mockClient = createMockClient({
|
|
82
|
+
getDelegateState: jest.fn().mockImplementation(({ address }) => {
|
|
83
|
+
if (address === 'stored_delegation_address') {
|
|
84
|
+
return { state: { ops: [{ key: 'fg:x:transfer' }] } };
|
|
85
|
+
}
|
|
86
|
+
return { state: null };
|
|
87
|
+
}),
|
|
88
|
+
});
|
|
81
89
|
|
|
82
90
|
const result = await getDelegationAddressWithFallback({
|
|
83
91
|
storedAddress: 'stored_delegation_address',
|
|
@@ -90,8 +98,34 @@ describe('wallet-migration', () => {
|
|
|
90
98
|
needsBackfill: false,
|
|
91
99
|
source: 'stored',
|
|
92
100
|
});
|
|
93
|
-
// Should
|
|
94
|
-
expect(mockClient.getDelegateState).
|
|
101
|
+
// Should verify stored address
|
|
102
|
+
expect(mockClient.getDelegateState).toHaveBeenCalledWith({ address: 'stored_delegation_address' });
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should fallback if stored address has no valid state', async () => {
|
|
106
|
+
const oldAddress = toDelegateAddress(delegator, oldAppDid);
|
|
107
|
+
const mockClient = createMockClient({
|
|
108
|
+
getDelegateState: jest.fn().mockImplementation(({ address }) => {
|
|
109
|
+
// stored address has no state, but migratedFrom address has
|
|
110
|
+
if (address === oldAddress) {
|
|
111
|
+
return { state: { ops: [{ key: 'fg:x:transfer' }] } };
|
|
112
|
+
}
|
|
113
|
+
return { state: null };
|
|
114
|
+
}),
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
const result = await getDelegationAddressWithFallback({
|
|
118
|
+
storedAddress: 'invalid_stored_address',
|
|
119
|
+
delegator,
|
|
120
|
+
client: mockClient as any,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Should fallback to migratedFrom
|
|
124
|
+
expect(result).toEqual({
|
|
125
|
+
address: oldAddress,
|
|
126
|
+
needsBackfill: true,
|
|
127
|
+
source: 'migrated',
|
|
128
|
+
});
|
|
95
129
|
});
|
|
96
130
|
|
|
97
131
|
it('should return current address if delegation exists on current wallet', async () => {
|
package/blocklet.yml
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payment-kit",
|
|
3
|
-
"version": "1.25.
|
|
3
|
+
"version": "1.25.4",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "blocklet dev --open",
|
|
6
6
|
"prelint": "npm run types",
|
|
@@ -59,9 +59,9 @@
|
|
|
59
59
|
"@blocklet/error": "^0.3.5",
|
|
60
60
|
"@blocklet/js-sdk": "^1.17.8-beta-20260104-120132-cb5b1914",
|
|
61
61
|
"@blocklet/logger": "^1.17.8-beta-20260104-120132-cb5b1914",
|
|
62
|
-
"@blocklet/payment-broker-client": "1.25.
|
|
63
|
-
"@blocklet/payment-react": "1.25.
|
|
64
|
-
"@blocklet/payment-vendor": "1.25.
|
|
62
|
+
"@blocklet/payment-broker-client": "1.25.4",
|
|
63
|
+
"@blocklet/payment-react": "1.25.4",
|
|
64
|
+
"@blocklet/payment-vendor": "1.25.4",
|
|
65
65
|
"@blocklet/sdk": "^1.17.8-beta-20260104-120132-cb5b1914",
|
|
66
66
|
"@blocklet/ui-react": "^3.4.7",
|
|
67
67
|
"@blocklet/uploader": "^0.3.19",
|
|
@@ -132,7 +132,7 @@
|
|
|
132
132
|
"devDependencies": {
|
|
133
133
|
"@abtnode/types": "^1.17.8-beta-20260104-120132-cb5b1914",
|
|
134
134
|
"@arcblock/eslint-config-ts": "^0.3.3",
|
|
135
|
-
"@blocklet/payment-types": "1.25.
|
|
135
|
+
"@blocklet/payment-types": "1.25.4",
|
|
136
136
|
"@types/cookie-parser": "^1.4.9",
|
|
137
137
|
"@types/cors": "^2.8.19",
|
|
138
138
|
"@types/debug": "^4.1.12",
|
|
@@ -179,5 +179,5 @@
|
|
|
179
179
|
"parser": "typescript"
|
|
180
180
|
}
|
|
181
181
|
},
|
|
182
|
-
"gitHead": "
|
|
182
|
+
"gitHead": "e551d0dd9b08432ff880a33d859fa9a00c8ff649"
|
|
183
183
|
}
|