@wopr-network/platform-core 1.49.5 → 1.50.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/dist/billing/crypto/__tests__/key-server.test.js +4 -0
- package/dist/billing/crypto/client.d.ts +1 -0
- package/dist/billing/crypto/key-server.js +16 -1
- package/dist/billing/crypto/payment-method-store.d.ts +12 -0
- package/dist/billing/crypto/payment-method-store.js +16 -0
- package/dist/db/schema/crypto.d.ts +17 -0
- package/dist/db/schema/crypto.js +1 -0
- package/drizzle/migrations/0019_icon_url_column.sql +4 -0
- package/drizzle/migrations/meta/_journal.json +7 -0
- package/package.json +1 -1
- package/src/billing/crypto/__tests__/key-server.test.ts +4 -0
- package/src/billing/crypto/client.ts +1 -0
- package/src/billing/crypto/key-server.ts +24 -1
- package/src/billing/crypto/payment-method-store.ts +24 -0
- package/src/db/schema/crypto.ts +1 -0
|
@@ -67,6 +67,7 @@ function mockDeps() {
|
|
|
67
67
|
displayName: "Bitcoin",
|
|
68
68
|
contractAddress: null,
|
|
69
69
|
confirmations: 6,
|
|
70
|
+
iconUrl: null,
|
|
70
71
|
},
|
|
71
72
|
{
|
|
72
73
|
id: "base-usdc",
|
|
@@ -76,6 +77,7 @@ function mockDeps() {
|
|
|
76
77
|
displayName: "USDC on Base",
|
|
77
78
|
contractAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
78
79
|
confirmations: 12,
|
|
80
|
+
iconUrl: null,
|
|
79
81
|
},
|
|
80
82
|
]),
|
|
81
83
|
listAll: vi.fn(),
|
|
@@ -91,12 +93,14 @@ function mockDeps() {
|
|
|
91
93
|
oracleAddress: "0x64c911996D3c6aC71f9b455B1E8E7266BcbD848F",
|
|
92
94
|
xpub: null,
|
|
93
95
|
displayOrder: 0,
|
|
96
|
+
iconUrl: null,
|
|
94
97
|
enabled: true,
|
|
95
98
|
rpcUrl: null,
|
|
96
99
|
}),
|
|
97
100
|
listByType: vi.fn(),
|
|
98
101
|
upsert: vi.fn().mockResolvedValue(undefined),
|
|
99
102
|
setEnabled: vi.fn().mockResolvedValue(undefined),
|
|
103
|
+
patchMetadata: vi.fn().mockResolvedValue(true),
|
|
100
104
|
};
|
|
101
105
|
return {
|
|
102
106
|
db: createMockDb(),
|
|
@@ -218,6 +218,7 @@ export function createKeyServerApp(deps) {
|
|
|
218
218
|
displayName: m.displayName,
|
|
219
219
|
contractAddress: m.contractAddress,
|
|
220
220
|
confirmations: m.confirmations,
|
|
221
|
+
iconUrl: m.iconUrl,
|
|
221
222
|
})));
|
|
222
223
|
});
|
|
223
224
|
// --- Admin API ---
|
|
@@ -282,7 +283,8 @@ export function createKeyServerApp(deps) {
|
|
|
282
283
|
decimals: body.decimals,
|
|
283
284
|
displayName: body.display_name ?? `${body.token} on ${body.network}`,
|
|
284
285
|
enabled: true,
|
|
285
|
-
displayOrder: 0,
|
|
286
|
+
displayOrder: body.display_order ?? 0,
|
|
287
|
+
iconUrl: body.icon_url ?? null,
|
|
286
288
|
rpcUrl: body.rpc_url,
|
|
287
289
|
oracleAddress: body.oracle_address ?? null,
|
|
288
290
|
xpub: body.xpub,
|
|
@@ -291,6 +293,19 @@ export function createKeyServerApp(deps) {
|
|
|
291
293
|
});
|
|
292
294
|
return c.json({ id: body.id, path: `m/44'/${body.coin_type}'/${body.account_index}'` }, 201);
|
|
293
295
|
});
|
|
296
|
+
/** PATCH /admin/chains/:id — update metadata (icon_url, display_order, display_name) */
|
|
297
|
+
app.patch("/admin/chains/:id", async (c) => {
|
|
298
|
+
const id = c.req.param("id");
|
|
299
|
+
const body = await c.req.json();
|
|
300
|
+
const updated = await deps.methodStore.patchMetadata(id, {
|
|
301
|
+
iconUrl: body.icon_url,
|
|
302
|
+
displayOrder: body.display_order,
|
|
303
|
+
displayName: body.display_name,
|
|
304
|
+
});
|
|
305
|
+
if (!updated)
|
|
306
|
+
return c.json({ id, updated: false }, 200);
|
|
307
|
+
return c.json({ id, updated: true });
|
|
308
|
+
});
|
|
294
309
|
/** DELETE /admin/chains/:id — soft disable */
|
|
295
310
|
app.delete("/admin/chains/:id", async (c) => {
|
|
296
311
|
await deps.methodStore.setEnabled(c.req.param("id"), false);
|
|
@@ -9,6 +9,7 @@ export interface PaymentMethodRecord {
|
|
|
9
9
|
displayName: string;
|
|
10
10
|
enabled: boolean;
|
|
11
11
|
displayOrder: number;
|
|
12
|
+
iconUrl: string | null;
|
|
12
13
|
rpcUrl: string | null;
|
|
13
14
|
oracleAddress: string | null;
|
|
14
15
|
xpub: string | null;
|
|
@@ -28,6 +29,12 @@ export interface IPaymentMethodStore {
|
|
|
28
29
|
upsert(method: PaymentMethodRecord): Promise<void>;
|
|
29
30
|
/** Enable or disable a payment method (admin). */
|
|
30
31
|
setEnabled(id: string, enabled: boolean): Promise<void>;
|
|
32
|
+
/** Partial update of metadata fields (no read-modify-write needed). */
|
|
33
|
+
patchMetadata(id: string, patch: {
|
|
34
|
+
iconUrl?: string | null;
|
|
35
|
+
displayOrder?: number;
|
|
36
|
+
displayName?: string;
|
|
37
|
+
}): Promise<boolean>;
|
|
31
38
|
}
|
|
32
39
|
export declare class DrizzlePaymentMethodStore implements IPaymentMethodStore {
|
|
33
40
|
private readonly db;
|
|
@@ -38,4 +45,9 @@ export declare class DrizzlePaymentMethodStore implements IPaymentMethodStore {
|
|
|
38
45
|
listByType(type: string): Promise<PaymentMethodRecord[]>;
|
|
39
46
|
upsert(method: PaymentMethodRecord): Promise<void>;
|
|
40
47
|
setEnabled(id: string, enabled: boolean): Promise<void>;
|
|
48
|
+
patchMetadata(id: string, patch: {
|
|
49
|
+
iconUrl?: string | null;
|
|
50
|
+
displayOrder?: number;
|
|
51
|
+
displayName?: string;
|
|
52
|
+
}): Promise<boolean>;
|
|
41
53
|
}
|
|
@@ -42,6 +42,7 @@ export class DrizzlePaymentMethodStore {
|
|
|
42
42
|
displayName: method.displayName,
|
|
43
43
|
enabled: method.enabled,
|
|
44
44
|
displayOrder: method.displayOrder,
|
|
45
|
+
iconUrl: method.iconUrl,
|
|
45
46
|
rpcUrl: method.rpcUrl,
|
|
46
47
|
oracleAddress: method.oracleAddress,
|
|
47
48
|
xpub: method.xpub,
|
|
@@ -59,6 +60,7 @@ export class DrizzlePaymentMethodStore {
|
|
|
59
60
|
displayName: method.displayName,
|
|
60
61
|
enabled: method.enabled,
|
|
61
62
|
displayOrder: method.displayOrder,
|
|
63
|
+
iconUrl: method.iconUrl,
|
|
62
64
|
rpcUrl: method.rpcUrl,
|
|
63
65
|
oracleAddress: method.oracleAddress,
|
|
64
66
|
xpub: method.xpub,
|
|
@@ -70,6 +72,19 @@ export class DrizzlePaymentMethodStore {
|
|
|
70
72
|
async setEnabled(id, enabled) {
|
|
71
73
|
await this.db.update(paymentMethods).set({ enabled }).where(eq(paymentMethods.id, id));
|
|
72
74
|
}
|
|
75
|
+
async patchMetadata(id, patch) {
|
|
76
|
+
const set = {};
|
|
77
|
+
if (patch.iconUrl !== undefined)
|
|
78
|
+
set.iconUrl = patch.iconUrl;
|
|
79
|
+
if (patch.displayOrder !== undefined)
|
|
80
|
+
set.displayOrder = patch.displayOrder;
|
|
81
|
+
if (patch.displayName !== undefined)
|
|
82
|
+
set.displayName = patch.displayName;
|
|
83
|
+
if (Object.keys(set).length === 0)
|
|
84
|
+
return false;
|
|
85
|
+
const result = (await this.db.update(paymentMethods).set(set).where(eq(paymentMethods.id, id)));
|
|
86
|
+
return result.rowCount > 0;
|
|
87
|
+
}
|
|
73
88
|
}
|
|
74
89
|
function toRecord(row) {
|
|
75
90
|
return {
|
|
@@ -82,6 +97,7 @@ function toRecord(row) {
|
|
|
82
97
|
displayName: row.displayName,
|
|
83
98
|
enabled: row.enabled,
|
|
84
99
|
displayOrder: row.displayOrder,
|
|
100
|
+
iconUrl: row.iconUrl,
|
|
85
101
|
rpcUrl: row.rpcUrl,
|
|
86
102
|
oracleAddress: row.oracleAddress,
|
|
87
103
|
xpub: row.xpub,
|
|
@@ -597,6 +597,23 @@ export declare const paymentMethods: import("drizzle-orm/pg-core").PgTableWithCo
|
|
|
597
597
|
identity: undefined;
|
|
598
598
|
generated: undefined;
|
|
599
599
|
}, {}, {}>;
|
|
600
|
+
iconUrl: import("drizzle-orm/pg-core").PgColumn<{
|
|
601
|
+
name: "icon_url";
|
|
602
|
+
tableName: "payment_methods";
|
|
603
|
+
dataType: "string";
|
|
604
|
+
columnType: "PgText";
|
|
605
|
+
data: string;
|
|
606
|
+
driverParam: string;
|
|
607
|
+
notNull: false;
|
|
608
|
+
hasDefault: false;
|
|
609
|
+
isPrimaryKey: false;
|
|
610
|
+
isAutoincrement: false;
|
|
611
|
+
hasRuntimeDefault: false;
|
|
612
|
+
enumValues: [string, ...string[]];
|
|
613
|
+
baseColumn: never;
|
|
614
|
+
identity: undefined;
|
|
615
|
+
generated: undefined;
|
|
616
|
+
}, {}, {}>;
|
|
600
617
|
rpcUrl: import("drizzle-orm/pg-core").PgColumn<{
|
|
601
618
|
name: "rpc_url";
|
|
602
619
|
tableName: "payment_methods";
|
package/dist/db/schema/crypto.js
CHANGED
|
@@ -71,6 +71,7 @@ export const paymentMethods = pgTable("payment_methods", {
|
|
|
71
71
|
displayName: text("display_name").notNull(),
|
|
72
72
|
enabled: boolean("enabled").notNull().default(true),
|
|
73
73
|
displayOrder: integer("display_order").notNull().default(0),
|
|
74
|
+
iconUrl: text("icon_url"),
|
|
74
75
|
rpcUrl: text("rpc_url"), // chain node RPC endpoint
|
|
75
76
|
oracleAddress: text("oracle_address"), // Chainlink feed address for price (null = 1:1 stablecoin)
|
|
76
77
|
xpub: text("xpub"), // HD wallet extended public key for deposit address derivation
|
|
@@ -134,6 +134,13 @@
|
|
|
134
134
|
"when": 1743177600000,
|
|
135
135
|
"tag": "0018_address_type_column",
|
|
136
136
|
"breakpoints": true
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"idx": 19,
|
|
140
|
+
"version": "7",
|
|
141
|
+
"when": 1743264000000,
|
|
142
|
+
"tag": "0019_icon_url_column",
|
|
143
|
+
"breakpoints": true
|
|
137
144
|
}
|
|
138
145
|
]
|
|
139
146
|
}
|
package/package.json
CHANGED
|
@@ -76,6 +76,7 @@ function mockDeps(): KeyServerDeps & {
|
|
|
76
76
|
displayName: "Bitcoin",
|
|
77
77
|
contractAddress: null,
|
|
78
78
|
confirmations: 6,
|
|
79
|
+
iconUrl: null,
|
|
79
80
|
},
|
|
80
81
|
{
|
|
81
82
|
id: "base-usdc",
|
|
@@ -85,6 +86,7 @@ function mockDeps(): KeyServerDeps & {
|
|
|
85
86
|
displayName: "USDC on Base",
|
|
86
87
|
contractAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
87
88
|
confirmations: 12,
|
|
89
|
+
iconUrl: null,
|
|
88
90
|
},
|
|
89
91
|
]),
|
|
90
92
|
listAll: vi.fn(),
|
|
@@ -100,12 +102,14 @@ function mockDeps(): KeyServerDeps & {
|
|
|
100
102
|
oracleAddress: "0x64c911996D3c6aC71f9b455B1E8E7266BcbD848F",
|
|
101
103
|
xpub: null,
|
|
102
104
|
displayOrder: 0,
|
|
105
|
+
iconUrl: null,
|
|
103
106
|
enabled: true,
|
|
104
107
|
rpcUrl: null,
|
|
105
108
|
}),
|
|
106
109
|
listByType: vi.fn(),
|
|
107
110
|
upsert: vi.fn().mockResolvedValue(undefined),
|
|
108
111
|
setEnabled: vi.fn().mockResolvedValue(undefined),
|
|
112
|
+
patchMetadata: vi.fn().mockResolvedValue(true),
|
|
109
113
|
};
|
|
110
114
|
return {
|
|
111
115
|
db: createMockDb() as never,
|
|
@@ -266,6 +266,7 @@ export function createKeyServerApp(deps: KeyServerDeps): Hono {
|
|
|
266
266
|
displayName: m.displayName,
|
|
267
267
|
contractAddress: m.contractAddress,
|
|
268
268
|
confirmations: m.confirmations,
|
|
269
|
+
iconUrl: m.iconUrl,
|
|
269
270
|
})),
|
|
270
271
|
);
|
|
271
272
|
});
|
|
@@ -328,6 +329,8 @@ export function createKeyServerApp(deps: KeyServerDeps): Hono {
|
|
|
328
329
|
display_name?: string;
|
|
329
330
|
oracle_address?: string;
|
|
330
331
|
address_type?: string;
|
|
332
|
+
icon_url?: string;
|
|
333
|
+
display_order?: number;
|
|
331
334
|
}>();
|
|
332
335
|
|
|
333
336
|
if (!body.id || !body.xpub || !body.token) {
|
|
@@ -362,7 +365,8 @@ export function createKeyServerApp(deps: KeyServerDeps): Hono {
|
|
|
362
365
|
decimals: body.decimals,
|
|
363
366
|
displayName: body.display_name ?? `${body.token} on ${body.network}`,
|
|
364
367
|
enabled: true,
|
|
365
|
-
displayOrder: 0,
|
|
368
|
+
displayOrder: body.display_order ?? 0,
|
|
369
|
+
iconUrl: body.icon_url ?? null,
|
|
366
370
|
rpcUrl: body.rpc_url,
|
|
367
371
|
oracleAddress: body.oracle_address ?? null,
|
|
368
372
|
xpub: body.xpub,
|
|
@@ -373,6 +377,25 @@ export function createKeyServerApp(deps: KeyServerDeps): Hono {
|
|
|
373
377
|
return c.json({ id: body.id, path: `m/44'/${body.coin_type}'/${body.account_index}'` }, 201);
|
|
374
378
|
});
|
|
375
379
|
|
|
380
|
+
/** PATCH /admin/chains/:id — update metadata (icon_url, display_order, display_name) */
|
|
381
|
+
app.patch("/admin/chains/:id", async (c) => {
|
|
382
|
+
const id = c.req.param("id");
|
|
383
|
+
const body = await c.req.json<{
|
|
384
|
+
icon_url?: string | null;
|
|
385
|
+
display_order?: number;
|
|
386
|
+
display_name?: string;
|
|
387
|
+
}>();
|
|
388
|
+
|
|
389
|
+
const updated = await deps.methodStore.patchMetadata(id, {
|
|
390
|
+
iconUrl: body.icon_url,
|
|
391
|
+
displayOrder: body.display_order,
|
|
392
|
+
displayName: body.display_name,
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
if (!updated) return c.json({ id, updated: false }, 200);
|
|
396
|
+
return c.json({ id, updated: true });
|
|
397
|
+
});
|
|
398
|
+
|
|
376
399
|
/** DELETE /admin/chains/:id — soft disable */
|
|
377
400
|
app.delete("/admin/chains/:id", async (c) => {
|
|
378
401
|
await deps.methodStore.setEnabled(c.req.param("id"), false);
|
|
@@ -12,6 +12,7 @@ export interface PaymentMethodRecord {
|
|
|
12
12
|
displayName: string;
|
|
13
13
|
enabled: boolean;
|
|
14
14
|
displayOrder: number;
|
|
15
|
+
iconUrl: string | null;
|
|
15
16
|
rpcUrl: string | null;
|
|
16
17
|
oracleAddress: string | null;
|
|
17
18
|
xpub: string | null;
|
|
@@ -32,6 +33,11 @@ export interface IPaymentMethodStore {
|
|
|
32
33
|
upsert(method: PaymentMethodRecord): Promise<void>;
|
|
33
34
|
/** Enable or disable a payment method (admin). */
|
|
34
35
|
setEnabled(id: string, enabled: boolean): Promise<void>;
|
|
36
|
+
/** Partial update of metadata fields (no read-modify-write needed). */
|
|
37
|
+
patchMetadata(
|
|
38
|
+
id: string,
|
|
39
|
+
patch: { iconUrl?: string | null; displayOrder?: number; displayName?: string },
|
|
40
|
+
): Promise<boolean>;
|
|
35
41
|
}
|
|
36
42
|
|
|
37
43
|
export class DrizzlePaymentMethodStore implements IPaymentMethodStore {
|
|
@@ -78,6 +84,7 @@ export class DrizzlePaymentMethodStore implements IPaymentMethodStore {
|
|
|
78
84
|
displayName: method.displayName,
|
|
79
85
|
enabled: method.enabled,
|
|
80
86
|
displayOrder: method.displayOrder,
|
|
87
|
+
iconUrl: method.iconUrl,
|
|
81
88
|
rpcUrl: method.rpcUrl,
|
|
82
89
|
oracleAddress: method.oracleAddress,
|
|
83
90
|
xpub: method.xpub,
|
|
@@ -95,6 +102,7 @@ export class DrizzlePaymentMethodStore implements IPaymentMethodStore {
|
|
|
95
102
|
displayName: method.displayName,
|
|
96
103
|
enabled: method.enabled,
|
|
97
104
|
displayOrder: method.displayOrder,
|
|
105
|
+
iconUrl: method.iconUrl,
|
|
98
106
|
rpcUrl: method.rpcUrl,
|
|
99
107
|
oracleAddress: method.oracleAddress,
|
|
100
108
|
xpub: method.xpub,
|
|
@@ -107,6 +115,21 @@ export class DrizzlePaymentMethodStore implements IPaymentMethodStore {
|
|
|
107
115
|
async setEnabled(id: string, enabled: boolean): Promise<void> {
|
|
108
116
|
await this.db.update(paymentMethods).set({ enabled }).where(eq(paymentMethods.id, id));
|
|
109
117
|
}
|
|
118
|
+
|
|
119
|
+
async patchMetadata(
|
|
120
|
+
id: string,
|
|
121
|
+
patch: { iconUrl?: string | null; displayOrder?: number; displayName?: string },
|
|
122
|
+
): Promise<boolean> {
|
|
123
|
+
const set: Record<string, unknown> = {};
|
|
124
|
+
if (patch.iconUrl !== undefined) set.iconUrl = patch.iconUrl;
|
|
125
|
+
if (patch.displayOrder !== undefined) set.displayOrder = patch.displayOrder;
|
|
126
|
+
if (patch.displayName !== undefined) set.displayName = patch.displayName;
|
|
127
|
+
if (Object.keys(set).length === 0) return false;
|
|
128
|
+
const result = (await this.db.update(paymentMethods).set(set).where(eq(paymentMethods.id, id))) as {
|
|
129
|
+
rowCount: number;
|
|
130
|
+
};
|
|
131
|
+
return result.rowCount > 0;
|
|
132
|
+
}
|
|
110
133
|
}
|
|
111
134
|
|
|
112
135
|
function toRecord(row: typeof paymentMethods.$inferSelect): PaymentMethodRecord {
|
|
@@ -120,6 +143,7 @@ function toRecord(row: typeof paymentMethods.$inferSelect): PaymentMethodRecord
|
|
|
120
143
|
displayName: row.displayName,
|
|
121
144
|
enabled: row.enabled,
|
|
122
145
|
displayOrder: row.displayOrder,
|
|
146
|
+
iconUrl: row.iconUrl,
|
|
123
147
|
rpcUrl: row.rpcUrl,
|
|
124
148
|
oracleAddress: row.oracleAddress,
|
|
125
149
|
xpub: row.xpub,
|
package/src/db/schema/crypto.ts
CHANGED
|
@@ -78,6 +78,7 @@ export const paymentMethods = pgTable("payment_methods", {
|
|
|
78
78
|
displayName: text("display_name").notNull(),
|
|
79
79
|
enabled: boolean("enabled").notNull().default(true),
|
|
80
80
|
displayOrder: integer("display_order").notNull().default(0),
|
|
81
|
+
iconUrl: text("icon_url"),
|
|
81
82
|
rpcUrl: text("rpc_url"), // chain node RPC endpoint
|
|
82
83
|
oracleAddress: text("oracle_address"), // Chainlink feed address for price (null = 1:1 stablecoin)
|
|
83
84
|
xpub: text("xpub"), // HD wallet extended public key for deposit address derivation
|