@partylayer/conformance-runner 0.2.8 → 0.2.10
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/cip0103-tests.d.ts +9 -6
- package/dist/cip0103-tests.js +209 -256
- package/dist/cip0103-tests.js.map +1 -1
- package/dist/index.d.ts +0 -7
- package/dist/index.js +573 -85
- package/dist/index.js.map +1 -1
- package/package.json +8 -5
- package/CHANGELOG.md +0 -168
- package/dist/cip0103-tests.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/loader.d.ts +0 -11
- package/dist/loader.d.ts.map +0 -1
- package/dist/loader.js +0 -65
- package/dist/loader.js.map +0 -1
- package/dist/report.d.ts +0 -39
- package/dist/report.d.ts.map +0 -1
- package/dist/report.js +0 -72
- package/dist/report.js.map +0 -1
- package/dist/tests.d.ts +0 -50
- package/dist/tests.d.ts.map +0 -1
- package/dist/tests.js +0 -233
- package/dist/tests.js.map +0 -1
- package/src/cip0103-tests.ts +0 -340
- package/src/index.ts +0 -116
- package/src/loader.ts +0 -78
- package/src/report.ts +0 -107
- package/src/tests.test.ts +0 -74
- package/src/tests.ts +0 -277
- package/tsconfig.esm.json +0 -10
- package/tsconfig.esm.tsbuildinfo +0 -1
- package/tsconfig.json +0 -14
- package/tsconfig.tsbuildinfo +0 -1
package/dist/tests.js
DELETED
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Adapter Conformance Tests
|
|
3
|
-
*
|
|
4
|
-
* Standard contract tests that all adapters must pass.
|
|
5
|
-
*/
|
|
6
|
-
import { CapabilityNotSupportedError, } from '@partylayer/core';
|
|
7
|
-
/**
|
|
8
|
-
* Create mock adapter context
|
|
9
|
-
*/
|
|
10
|
-
export function createMockContext() {
|
|
11
|
-
return {
|
|
12
|
-
appName: 'Conformance Test',
|
|
13
|
-
origin: 'https://test.example.com',
|
|
14
|
-
network: 'devnet',
|
|
15
|
-
logger: {
|
|
16
|
-
debug: () => { },
|
|
17
|
-
info: () => { },
|
|
18
|
-
warn: () => { },
|
|
19
|
-
error: () => { },
|
|
20
|
-
},
|
|
21
|
-
telemetry: undefined,
|
|
22
|
-
registry: {
|
|
23
|
-
getWallet: async () => ({}),
|
|
24
|
-
},
|
|
25
|
-
crypto: {
|
|
26
|
-
encrypt: async (data) => data,
|
|
27
|
-
decrypt: async (data) => data,
|
|
28
|
-
generateKey: async () => 'test-key',
|
|
29
|
-
},
|
|
30
|
-
storage: {
|
|
31
|
-
get: async () => null,
|
|
32
|
-
set: async () => { },
|
|
33
|
-
remove: async () => { },
|
|
34
|
-
clear: async () => { },
|
|
35
|
-
},
|
|
36
|
-
timeout: async (ms) => {
|
|
37
|
-
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
38
|
-
throw new Error('Timeout');
|
|
39
|
-
},
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Run conformance tests
|
|
44
|
-
*/
|
|
45
|
-
export async function runConformanceTests(adapter, context) {
|
|
46
|
-
const results = [];
|
|
47
|
-
// Test 1: Adapter has required properties
|
|
48
|
-
results.push({
|
|
49
|
-
name: 'Adapter has walletId',
|
|
50
|
-
passed: typeof adapter.walletId === 'string' && adapter.walletId.length > 0,
|
|
51
|
-
details: { walletId: adapter.walletId },
|
|
52
|
-
});
|
|
53
|
-
results.push({
|
|
54
|
-
name: 'Adapter has name',
|
|
55
|
-
passed: typeof adapter.name === 'string' && adapter.name.length > 0,
|
|
56
|
-
details: { name: adapter.name },
|
|
57
|
-
});
|
|
58
|
-
// Test 2: getCapabilities returns valid array
|
|
59
|
-
let capabilities;
|
|
60
|
-
try {
|
|
61
|
-
capabilities = adapter.getCapabilities();
|
|
62
|
-
results.push({
|
|
63
|
-
name: 'getCapabilities returns array',
|
|
64
|
-
passed: Array.isArray(capabilities),
|
|
65
|
-
details: { capabilities },
|
|
66
|
-
});
|
|
67
|
-
// Check for required capabilities
|
|
68
|
-
const hasConnect = capabilities.includes('connect');
|
|
69
|
-
results.push({
|
|
70
|
-
name: 'Capabilities include "connect"',
|
|
71
|
-
passed: hasConnect,
|
|
72
|
-
details: { capabilities },
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
catch (err) {
|
|
76
|
-
results.push({
|
|
77
|
-
name: 'getCapabilities throws error',
|
|
78
|
-
passed: false,
|
|
79
|
-
error: err instanceof Error ? err.message : String(err),
|
|
80
|
-
});
|
|
81
|
-
return results; // Can't continue without capabilities
|
|
82
|
-
}
|
|
83
|
-
// Test 3: detectInstalled returns valid result
|
|
84
|
-
try {
|
|
85
|
-
const detect = await adapter.detectInstalled();
|
|
86
|
-
results.push({
|
|
87
|
-
name: 'detectInstalled returns valid result',
|
|
88
|
-
passed: typeof detect === 'object' &&
|
|
89
|
-
typeof detect.installed === 'boolean' &&
|
|
90
|
-
(detect.installed || typeof detect.reason === 'string'),
|
|
91
|
-
details: { detect },
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
catch (err) {
|
|
95
|
-
results.push({
|
|
96
|
-
name: 'detectInstalled throws error',
|
|
97
|
-
passed: false,
|
|
98
|
-
error: err instanceof Error ? err.message : String(err),
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
// Test 4: If detectInstalled returns false, connect should throw WalletNotInstalledError
|
|
102
|
-
// (This test requires mocking detectInstalled - skip for now or use mock adapter)
|
|
103
|
-
// Test 5: Capability checks
|
|
104
|
-
if (capabilities.includes('signMessage')) {
|
|
105
|
-
if (typeof adapter.signMessage !== 'function') {
|
|
106
|
-
results.push({
|
|
107
|
-
name: 'signMessage capability declared but method missing',
|
|
108
|
-
passed: false,
|
|
109
|
-
error: 'signMessage capability declared but method not implemented',
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
else {
|
|
114
|
-
// If signMessage not in capabilities, calling it should throw CapabilityNotSupportedError
|
|
115
|
-
if (typeof adapter.signMessage === 'function') {
|
|
116
|
-
try {
|
|
117
|
-
await adapter.signMessage(context, {}, { message: 'test' });
|
|
118
|
-
results.push({
|
|
119
|
-
name: 'signMessage throws CapabilityNotSupportedError when not supported',
|
|
120
|
-
passed: false,
|
|
121
|
-
error: 'signMessage did not throw error',
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
catch (err) {
|
|
125
|
-
const passed = err instanceof CapabilityNotSupportedError;
|
|
126
|
-
results.push({
|
|
127
|
-
name: 'signMessage throws CapabilityNotSupportedError when not supported',
|
|
128
|
-
passed,
|
|
129
|
-
error: passed ? undefined : err instanceof Error ? err.message : String(err),
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
// Similar tests for signTransaction and submitTransaction
|
|
135
|
-
if (capabilities.includes('signTransaction')) {
|
|
136
|
-
if (typeof adapter.signTransaction !== 'function') {
|
|
137
|
-
results.push({
|
|
138
|
-
name: 'signTransaction capability declared but method missing',
|
|
139
|
-
passed: false,
|
|
140
|
-
error: 'signTransaction capability declared but method not implemented',
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
if (capabilities.includes('submitTransaction')) {
|
|
145
|
-
if (typeof adapter.submitTransaction !== 'function') {
|
|
146
|
-
results.push({
|
|
147
|
-
name: 'submitTransaction capability declared but method missing',
|
|
148
|
-
passed: false,
|
|
149
|
-
error: 'submitTransaction capability declared but method not implemented',
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
// Test 5b: restore capability <-> method symmetry.
|
|
154
|
-
//
|
|
155
|
-
// We had a real bug where 3 of 5 adapters implemented restore() but did
|
|
156
|
-
// not declare the 'restore' capability in getCapabilities(). The SDK
|
|
157
|
-
// checks method presence at runtime so session persistence still worked,
|
|
158
|
-
// but `wallet.capabilities.includes('restore')` returned false, which
|
|
159
|
-
// misleads docs consumers and anyone programmatically inspecting caps.
|
|
160
|
-
//
|
|
161
|
-
// Enforce both directions:
|
|
162
|
-
// - declared-but-missing: capability listed, no method → broken promise
|
|
163
|
-
// - implemented-but-undeclared: method exists, capability missing →
|
|
164
|
-
// silent drift that hides a feature from consumers
|
|
165
|
-
{
|
|
166
|
-
const hasRestoreMethod = typeof adapter.restore === 'function';
|
|
167
|
-
const declaresRestore = capabilities.includes('restore');
|
|
168
|
-
if (declaresRestore && !hasRestoreMethod) {
|
|
169
|
-
results.push({
|
|
170
|
-
name: 'restore capability declared but method missing',
|
|
171
|
-
passed: false,
|
|
172
|
-
error: `${adapter.name}: declares 'restore' capability but does not implement restore()`,
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
else if (hasRestoreMethod && !declaresRestore) {
|
|
176
|
-
results.push({
|
|
177
|
-
name: 'restore method implemented but capability not declared',
|
|
178
|
-
passed: false,
|
|
179
|
-
error: `${adapter.name}: implements restore() but getCapabilities() does not include 'restore'. ` +
|
|
180
|
-
`Add 'restore' to the returned array so consumers can discover the feature.`,
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
else {
|
|
184
|
-
results.push({
|
|
185
|
-
name: 'restore capability / method symmetry',
|
|
186
|
-
passed: true,
|
|
187
|
-
details: { hasRestoreMethod, declaresRestore },
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
// Test 6: Error mapping
|
|
192
|
-
// Verify adapter uses mapUnknownErrorToPartyLayerError
|
|
193
|
-
// (This is a code inspection test - hard to test at runtime)
|
|
194
|
-
return results;
|
|
195
|
-
}
|
|
196
|
-
/**
|
|
197
|
-
* Network-truthfulness contract.
|
|
198
|
-
*
|
|
199
|
-
* An adapter's `connect()` MUST surface the wallet's EFFECTIVE network in
|
|
200
|
-
* `session.network` (so the SDK can detect a wallet/dApp network mismatch) —
|
|
201
|
-
* not merely echo the requested `context.network`.
|
|
202
|
-
*
|
|
203
|
-
* Drive it with a context whose `.network` differs from the network the wallet
|
|
204
|
-
* actually reports (`walletReportedNetwork`); a compliant adapter returns
|
|
205
|
-
* `session.network === walletReportedNetwork`. An adapter that echoes
|
|
206
|
-
* `context.network` fails the contract.
|
|
207
|
-
*
|
|
208
|
-
* Adapters that genuinely cannot read the wallet's network must NOT claim to
|
|
209
|
-
* (leave `session.network = context.network`) and must be recorded as
|
|
210
|
-
* "network-reported: no" in the support matrix — they are out of scope for this
|
|
211
|
-
* contract rather than silently passing it.
|
|
212
|
-
*/
|
|
213
|
-
export async function checkNetworkTruthfulness(adapter, context, walletReportedNetwork) {
|
|
214
|
-
const name = 'connect() session.network is the wallet effective network';
|
|
215
|
-
try {
|
|
216
|
-
const result = await adapter.connect(context);
|
|
217
|
-
const got = result.session.network;
|
|
218
|
-
const passed = got === walletReportedNetwork;
|
|
219
|
-
return {
|
|
220
|
-
name,
|
|
221
|
-
passed,
|
|
222
|
-
error: passed
|
|
223
|
-
? undefined
|
|
224
|
-
: `expected session.network='${walletReportedNetwork}' (wallet-reported), got '${String(got)}'` +
|
|
225
|
-
(got === context.network ? ' — merely echoed context.network' : ''),
|
|
226
|
-
details: { expected: walletReportedNetwork, got, ctxNetwork: context.network },
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
catch (err) {
|
|
230
|
-
return { name, passed: false, error: err instanceof Error ? err.message : String(err) };
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
//# sourceMappingURL=tests.js.map
|
package/dist/tests.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tests.js","sourceRoot":"","sources":["../src/tests.ts"],"names":[],"mappings":"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"}
|
package/src/cip0103-tests.ts
DELETED
|
@@ -1,340 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CIP-0103 Conformance Test Suite
|
|
3
|
-
*
|
|
4
|
-
* Validates that a Provider implementation conforms to CIP-0103:
|
|
5
|
-
* - Interface shape (request, on, emit, removeListener)
|
|
6
|
-
* - All 10 mandatory methods are handled
|
|
7
|
-
* - Event subscription returns Provider for chaining
|
|
8
|
-
* - Error responses use ProviderRpcError with numeric codes
|
|
9
|
-
*
|
|
10
|
-
* This suite can be run against:
|
|
11
|
-
* - PartyLayerProvider (native path)
|
|
12
|
-
* - createProviderBridge() (bridge path)
|
|
13
|
-
* - Any third-party CIP-0103 Provider
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import type { CIP0103Provider } from '@partylayer/core';
|
|
17
|
-
import { CIP0103_MANDATORY_METHODS, CIP0103_EVENTS } from '@partylayer/core';
|
|
18
|
-
|
|
19
|
-
// ─── Types ──────────────────────────────────────────────────────────────────
|
|
20
|
-
|
|
21
|
-
export interface CIP0103TestResult {
|
|
22
|
-
name: string;
|
|
23
|
-
category: 'interface' | 'method' | 'event' | 'error' | 'lifecycle';
|
|
24
|
-
passed: boolean;
|
|
25
|
-
error?: string;
|
|
26
|
-
details?: Record<string, unknown>;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface CIP0103ConformanceReport {
|
|
30
|
-
total: number;
|
|
31
|
-
passed: number;
|
|
32
|
-
failed: number;
|
|
33
|
-
results: CIP0103TestResult[];
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// ─── Runner ─────────────────────────────────────────────────────────────────
|
|
37
|
-
|
|
38
|
-
export async function runCIP0103ConformanceTests(
|
|
39
|
-
provider: CIP0103Provider,
|
|
40
|
-
): Promise<CIP0103ConformanceReport> {
|
|
41
|
-
const results: CIP0103TestResult[] = [];
|
|
42
|
-
|
|
43
|
-
// ── Interface shape tests ─────────────────────────────────────────────
|
|
44
|
-
|
|
45
|
-
results.push({
|
|
46
|
-
name: 'Provider has request() method',
|
|
47
|
-
category: 'interface',
|
|
48
|
-
passed: typeof provider.request === 'function',
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
results.push({
|
|
52
|
-
name: 'Provider has on() method',
|
|
53
|
-
category: 'interface',
|
|
54
|
-
passed: typeof provider.on === 'function',
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
results.push({
|
|
58
|
-
name: 'Provider has emit() method',
|
|
59
|
-
category: 'interface',
|
|
60
|
-
passed: typeof provider.emit === 'function',
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
results.push({
|
|
64
|
-
name: 'Provider has removeListener() method',
|
|
65
|
-
category: 'interface',
|
|
66
|
-
passed: typeof provider.removeListener === 'function',
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
// ── Method presence tests ─────────────────────────────────────────────
|
|
70
|
-
|
|
71
|
-
for (const method of CIP0103_MANDATORY_METHODS) {
|
|
72
|
-
try {
|
|
73
|
-
await provider.request({ method, params: {} });
|
|
74
|
-
results.push({
|
|
75
|
-
name: `Method "${method}" is handled`,
|
|
76
|
-
category: 'method',
|
|
77
|
-
passed: true,
|
|
78
|
-
});
|
|
79
|
-
} catch (err: unknown) {
|
|
80
|
-
// A valid ProviderRpcError means the method IS handled
|
|
81
|
-
// (it just may not be authorized / connected yet)
|
|
82
|
-
const isValidError = isNumericCodeError(err);
|
|
83
|
-
results.push({
|
|
84
|
-
name: `Method "${method}" is handled`,
|
|
85
|
-
category: 'method',
|
|
86
|
-
passed: isValidError,
|
|
87
|
-
error: isValidError
|
|
88
|
-
? undefined
|
|
89
|
-
: `Expected ProviderRpcError with numeric code, got: ${String(err)}`,
|
|
90
|
-
details: isValidError
|
|
91
|
-
? { code: (err as { code: number }).code }
|
|
92
|
-
: undefined,
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// ── Event chaining tests ──────────────────────────────────────────────
|
|
98
|
-
|
|
99
|
-
const noopHandler = () => {};
|
|
100
|
-
|
|
101
|
-
const onResult = provider.on('statusChanged', noopHandler);
|
|
102
|
-
results.push({
|
|
103
|
-
name: 'on() returns Provider for chaining',
|
|
104
|
-
category: 'event',
|
|
105
|
-
passed: onResult === provider,
|
|
106
|
-
error:
|
|
107
|
-
onResult === provider
|
|
108
|
-
? undefined
|
|
109
|
-
: 'on() did not return the Provider instance',
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
const removeResult = provider.removeListener('statusChanged', noopHandler);
|
|
113
|
-
results.push({
|
|
114
|
-
name: 'removeListener() returns Provider for chaining',
|
|
115
|
-
category: 'event',
|
|
116
|
-
passed: removeResult === provider,
|
|
117
|
-
error:
|
|
118
|
-
removeResult === provider
|
|
119
|
-
? undefined
|
|
120
|
-
: 'removeListener() did not return the Provider instance',
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
// ── Error code validation ─────────────────────────────────────────────
|
|
124
|
-
|
|
125
|
-
try {
|
|
126
|
-
await provider.request({ method: '__cip0103_conformance_nonexistent__' });
|
|
127
|
-
results.push({
|
|
128
|
-
name: 'Unsupported method returns ProviderRpcError',
|
|
129
|
-
category: 'error',
|
|
130
|
-
passed: false,
|
|
131
|
-
error: 'Expected error for unsupported method, got success',
|
|
132
|
-
});
|
|
133
|
-
} catch (err: unknown) {
|
|
134
|
-
const hasNumericCode = isNumericCodeError(err);
|
|
135
|
-
results.push({
|
|
136
|
-
name: 'Unsupported method returns error with numeric code',
|
|
137
|
-
category: 'error',
|
|
138
|
-
passed: hasNumericCode,
|
|
139
|
-
error: hasNumericCode
|
|
140
|
-
? undefined
|
|
141
|
-
: `Expected numeric code, got: ${String(err)}`,
|
|
142
|
-
details: hasNumericCode
|
|
143
|
-
? { code: (err as { code: number }).code }
|
|
144
|
-
: undefined,
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
if (hasNumericCode) {
|
|
148
|
-
const code = (err as { code: number }).code;
|
|
149
|
-
// Should be 4200 (UNSUPPORTED_METHOD) or -32601 (METHOD_NOT_FOUND)
|
|
150
|
-
const isCorrectCode = code === 4200 || code === -32601;
|
|
151
|
-
results.push({
|
|
152
|
-
name: 'Unsupported method uses code 4200 or -32601',
|
|
153
|
-
category: 'error',
|
|
154
|
-
passed: isCorrectCode,
|
|
155
|
-
error: isCorrectCode
|
|
156
|
-
? undefined
|
|
157
|
-
: `Expected code 4200 or -32601, got ${code}`,
|
|
158
|
-
details: { code },
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// ── emit() returns boolean ────────────────────────────────────────────
|
|
164
|
-
|
|
165
|
-
const emitResult = provider.emit('__cip0103_conformance_test__');
|
|
166
|
-
results.push({
|
|
167
|
-
name: 'emit() returns boolean',
|
|
168
|
-
category: 'interface',
|
|
169
|
-
passed: typeof emitResult === 'boolean',
|
|
170
|
-
error:
|
|
171
|
-
typeof emitResult === 'boolean'
|
|
172
|
-
? undefined
|
|
173
|
-
: `emit() returned ${typeof emitResult}`,
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
// ── Transaction lifecycle tests ─────────────────────────────────────
|
|
177
|
-
|
|
178
|
-
{
|
|
179
|
-
const txEvents: unknown[] = [];
|
|
180
|
-
const txHandler = (...args: unknown[]) => txEvents.push(...args);
|
|
181
|
-
provider.on(CIP0103_EVENTS.TX_CHANGED, txHandler);
|
|
182
|
-
|
|
183
|
-
try {
|
|
184
|
-
await provider.request({
|
|
185
|
-
method: 'prepareExecute',
|
|
186
|
-
params: { tx: { _conformance: true } },
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
// Check that 'pending' was emitted
|
|
190
|
-
results.push({
|
|
191
|
-
name: 'prepareExecute emits txChanged with "pending"',
|
|
192
|
-
category: 'lifecycle',
|
|
193
|
-
passed: txEvents.some(
|
|
194
|
-
(e) => typeof e === 'object' && e !== null && (e as Record<string, unknown>).status === 'pending',
|
|
195
|
-
),
|
|
196
|
-
error: txEvents.length === 0 ? 'No txChanged events emitted' : undefined,
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
// Check that 'signed' was emitted
|
|
200
|
-
const signedEvent = txEvents.find(
|
|
201
|
-
(e) => typeof e === 'object' && e !== null && (e as Record<string, unknown>).status === 'signed',
|
|
202
|
-
) as Record<string, unknown> | undefined;
|
|
203
|
-
results.push({
|
|
204
|
-
name: 'prepareExecute emits txChanged with "signed"',
|
|
205
|
-
category: 'lifecycle',
|
|
206
|
-
passed: !!signedEvent,
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
// Validate 'signed' payload shape
|
|
210
|
-
if (signedEvent) {
|
|
211
|
-
const payload = signedEvent.payload as Record<string, unknown> | undefined;
|
|
212
|
-
results.push({
|
|
213
|
-
name: 'signed event has payload.signature (string)',
|
|
214
|
-
category: 'lifecycle',
|
|
215
|
-
passed: typeof payload?.signature === 'string',
|
|
216
|
-
});
|
|
217
|
-
results.push({
|
|
218
|
-
name: 'signed event has payload.signedBy (string)',
|
|
219
|
-
category: 'lifecycle',
|
|
220
|
-
passed: typeof payload?.signedBy === 'string',
|
|
221
|
-
});
|
|
222
|
-
results.push({
|
|
223
|
-
name: 'signed event has payload.party (string)',
|
|
224
|
-
category: 'lifecycle',
|
|
225
|
-
passed: typeof payload?.party === 'string',
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Check that a terminal state was reached
|
|
230
|
-
const hasTerminal = txEvents.some(
|
|
231
|
-
(e) =>
|
|
232
|
-
typeof e === 'object' &&
|
|
233
|
-
e !== null &&
|
|
234
|
-
((e as Record<string, unknown>).status === 'executed' ||
|
|
235
|
-
(e as Record<string, unknown>).status === 'failed'),
|
|
236
|
-
);
|
|
237
|
-
results.push({
|
|
238
|
-
name: 'prepareExecute reaches terminal tx state (executed or failed)',
|
|
239
|
-
category: 'lifecycle',
|
|
240
|
-
passed: hasTerminal,
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
// Validate 'executed' payload shape
|
|
244
|
-
const executedEvent = txEvents.find(
|
|
245
|
-
(e) => typeof e === 'object' && e !== null && (e as Record<string, unknown>).status === 'executed',
|
|
246
|
-
) as Record<string, unknown> | undefined;
|
|
247
|
-
if (executedEvent) {
|
|
248
|
-
const payload = executedEvent.payload as Record<string, unknown> | undefined;
|
|
249
|
-
results.push({
|
|
250
|
-
name: 'executed event has payload.updateId (string)',
|
|
251
|
-
category: 'lifecycle',
|
|
252
|
-
passed: typeof payload?.updateId === 'string',
|
|
253
|
-
});
|
|
254
|
-
results.push({
|
|
255
|
-
name: 'executed event has payload.completionOffset (number)',
|
|
256
|
-
category: 'lifecycle',
|
|
257
|
-
passed: typeof payload?.completionOffset === 'number',
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
} catch {
|
|
261
|
-
// prepareExecute may throw — still check if events were emitted
|
|
262
|
-
results.push({
|
|
263
|
-
name: 'prepareExecute emits txChanged events (despite error)',
|
|
264
|
-
category: 'lifecycle',
|
|
265
|
-
passed: txEvents.length > 0,
|
|
266
|
-
error: txEvents.length === 0 ? 'No txChanged events emitted before error' : undefined,
|
|
267
|
-
});
|
|
268
|
-
} finally {
|
|
269
|
-
provider.removeListener(CIP0103_EVENTS.TX_CHANGED, txHandler);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// ── ledgerApi handling test ────────────────────────────────────────
|
|
274
|
-
|
|
275
|
-
try {
|
|
276
|
-
await provider.request({
|
|
277
|
-
method: 'ledgerApi',
|
|
278
|
-
params: { requestMethod: 'GET', resource: '/v1/state/acs' },
|
|
279
|
-
});
|
|
280
|
-
results.push({
|
|
281
|
-
name: 'ledgerApi returns result (supported)',
|
|
282
|
-
category: 'method',
|
|
283
|
-
passed: true,
|
|
284
|
-
});
|
|
285
|
-
} catch (err: unknown) {
|
|
286
|
-
// ProviderRpcError with numeric code = method is recognized
|
|
287
|
-
const isHandled = isNumericCodeError(err);
|
|
288
|
-
results.push({
|
|
289
|
-
name: 'ledgerApi is handled (returns result or ProviderRpcError)',
|
|
290
|
-
category: 'method',
|
|
291
|
-
passed: isHandled,
|
|
292
|
-
error: isHandled ? undefined : `Unexpected error type: ${String(err)}`,
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
// ── Summary ───────────────────────────────────────────────────────────
|
|
297
|
-
|
|
298
|
-
const passed = results.filter((r) => r.passed).length;
|
|
299
|
-
return {
|
|
300
|
-
total: results.length,
|
|
301
|
-
passed,
|
|
302
|
-
failed: results.length - passed,
|
|
303
|
-
results,
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
308
|
-
|
|
309
|
-
function isNumericCodeError(err: unknown): boolean {
|
|
310
|
-
if (typeof err !== 'object' || err === null) return false;
|
|
311
|
-
return typeof (err as Record<string, unknown>).code === 'number';
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
// ─── Formatting ─────────────────────────────────────────────────────────────
|
|
315
|
-
|
|
316
|
-
export function formatCIP0103Report(report: CIP0103ConformanceReport): string {
|
|
317
|
-
const lines: string[] = [
|
|
318
|
-
'═══ CIP-0103 Conformance Report ═══',
|
|
319
|
-
'',
|
|
320
|
-
`Total: ${report.total} Passed: ${report.passed} Failed: ${report.failed}`,
|
|
321
|
-
'',
|
|
322
|
-
];
|
|
323
|
-
|
|
324
|
-
const categories = ['interface', 'method', 'event', 'error', 'lifecycle'] as const;
|
|
325
|
-
for (const cat of categories) {
|
|
326
|
-
const catResults = report.results.filter((r) => r.category === cat);
|
|
327
|
-
if (catResults.length === 0) continue;
|
|
328
|
-
lines.push(`── ${cat.toUpperCase()} ──`);
|
|
329
|
-
for (const r of catResults) {
|
|
330
|
-
const icon = r.passed ? '✓' : '✗';
|
|
331
|
-
lines.push(` ${icon} ${r.name}`);
|
|
332
|
-
if (r.error) {
|
|
333
|
-
lines.push(` → ${r.error}`);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
lines.push('');
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
return lines.join('\n');
|
|
340
|
-
}
|