@wopr-network/platform-core 1.42.2 → 1.43.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/.github/workflows/key-server-image.yml +35 -0
- package/Dockerfile.key-server +20 -0
- package/GATEWAY_BILLING_RESEARCH.md +430 -0
- package/biome.json +2 -9
- package/dist/billing/crypto/__tests__/key-server.test.d.ts +1 -0
- package/dist/billing/crypto/__tests__/key-server.test.js +225 -0
- package/dist/billing/crypto/client.d.ts +84 -20
- package/dist/billing/crypto/client.js +76 -46
- package/dist/billing/crypto/client.test.js +76 -83
- package/dist/billing/crypto/index.d.ts +4 -2
- package/dist/billing/crypto/index.js +2 -1
- package/dist/billing/crypto/key-server-entry.d.ts +1 -0
- package/dist/billing/crypto/key-server-entry.js +43 -0
- package/dist/billing/crypto/key-server.d.ts +18 -0
- package/dist/billing/crypto/key-server.js +239 -0
- package/dist/db/schema/crypto.d.ts +247 -0
- package/dist/db/schema/crypto.js +35 -4
- package/dist/fleet/instance.d.ts +2 -0
- package/dist/fleet/instance.js +15 -0
- package/drizzle/migrations/0014_crypto_key_server.sql +60 -0
- package/drizzle/migrations/meta/_journal.json +21 -0
- package/package.json +2 -1
- package/src/billing/crypto/__tests__/key-server.test.ts +247 -0
- package/src/billing/crypto/client.test.ts +80 -96
- package/src/billing/crypto/client.ts +138 -58
- package/src/billing/crypto/index.ts +11 -2
- package/src/billing/crypto/key-server-entry.ts +52 -0
- package/src/billing/crypto/key-server.ts +315 -0
- package/src/db/schema/crypto.ts +45 -4
- package/src/fleet/instance.ts +16 -0
|
@@ -300,6 +300,9 @@ export declare const watcherCursors: import("drizzle-orm/pg-core").PgTableWithCo
|
|
|
300
300
|
* Payment method registry — runtime-configurable tokens/chains.
|
|
301
301
|
* Admin inserts a row to enable a new payment method. No deploy needed.
|
|
302
302
|
* Contract addresses are immutable on-chain but configurable here.
|
|
303
|
+
*
|
|
304
|
+
* nextIndex is an atomic counter for HD derivation — never reuses an index.
|
|
305
|
+
* Increment via UPDATE ... SET next_index = next_index + 1 RETURNING next_index.
|
|
303
306
|
*/
|
|
304
307
|
export declare const paymentMethods: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
305
308
|
name: "payment_methods";
|
|
@@ -373,6 +376,23 @@ export declare const paymentMethods: import("drizzle-orm/pg-core").PgTableWithCo
|
|
|
373
376
|
identity: undefined;
|
|
374
377
|
generated: undefined;
|
|
375
378
|
}, {}, {}>;
|
|
379
|
+
network: import("drizzle-orm/pg-core").PgColumn<{
|
|
380
|
+
name: "network";
|
|
381
|
+
tableName: "payment_methods";
|
|
382
|
+
dataType: "string";
|
|
383
|
+
columnType: "PgText";
|
|
384
|
+
data: string;
|
|
385
|
+
driverParam: string;
|
|
386
|
+
notNull: true;
|
|
387
|
+
hasDefault: true;
|
|
388
|
+
isPrimaryKey: false;
|
|
389
|
+
isAutoincrement: false;
|
|
390
|
+
hasRuntimeDefault: false;
|
|
391
|
+
enumValues: [string, ...string[]];
|
|
392
|
+
baseColumn: never;
|
|
393
|
+
identity: undefined;
|
|
394
|
+
generated: undefined;
|
|
395
|
+
}, {}, {}>;
|
|
376
396
|
contractAddress: import("drizzle-orm/pg-core").PgColumn<{
|
|
377
397
|
name: "contract_address";
|
|
378
398
|
tableName: "payment_methods";
|
|
@@ -526,6 +546,23 @@ export declare const paymentMethods: import("drizzle-orm/pg-core").PgTableWithCo
|
|
|
526
546
|
identity: undefined;
|
|
527
547
|
generated: undefined;
|
|
528
548
|
}, {}, {}>;
|
|
549
|
+
nextIndex: import("drizzle-orm/pg-core").PgColumn<{
|
|
550
|
+
name: "next_index";
|
|
551
|
+
tableName: "payment_methods";
|
|
552
|
+
dataType: "number";
|
|
553
|
+
columnType: "PgInteger";
|
|
554
|
+
data: number;
|
|
555
|
+
driverParam: string | number;
|
|
556
|
+
notNull: true;
|
|
557
|
+
hasDefault: true;
|
|
558
|
+
isPrimaryKey: false;
|
|
559
|
+
isAutoincrement: false;
|
|
560
|
+
hasRuntimeDefault: false;
|
|
561
|
+
enumValues: undefined;
|
|
562
|
+
baseColumn: never;
|
|
563
|
+
identity: undefined;
|
|
564
|
+
generated: undefined;
|
|
565
|
+
}, {}, {}>;
|
|
529
566
|
createdAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
530
567
|
name: "created_at";
|
|
531
568
|
tableName: "payment_methods";
|
|
@@ -546,6 +583,216 @@ export declare const paymentMethods: import("drizzle-orm/pg-core").PgTableWithCo
|
|
|
546
583
|
};
|
|
547
584
|
dialect: "pg";
|
|
548
585
|
}>;
|
|
586
|
+
/**
|
|
587
|
+
* BIP-44 path allocation registry — tracks which derivation paths are in use.
|
|
588
|
+
* The server knows which paths are allocated so you never collide.
|
|
589
|
+
* The seed phrase never touches the server — only xpubs.
|
|
590
|
+
*/
|
|
591
|
+
export declare const pathAllocations: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
592
|
+
name: "path_allocations";
|
|
593
|
+
schema: undefined;
|
|
594
|
+
columns: {
|
|
595
|
+
coinType: import("drizzle-orm/pg-core").PgColumn<{
|
|
596
|
+
name: "coin_type";
|
|
597
|
+
tableName: "path_allocations";
|
|
598
|
+
dataType: "number";
|
|
599
|
+
columnType: "PgInteger";
|
|
600
|
+
data: number;
|
|
601
|
+
driverParam: string | number;
|
|
602
|
+
notNull: true;
|
|
603
|
+
hasDefault: false;
|
|
604
|
+
isPrimaryKey: false;
|
|
605
|
+
isAutoincrement: false;
|
|
606
|
+
hasRuntimeDefault: false;
|
|
607
|
+
enumValues: undefined;
|
|
608
|
+
baseColumn: never;
|
|
609
|
+
identity: undefined;
|
|
610
|
+
generated: undefined;
|
|
611
|
+
}, {}, {}>;
|
|
612
|
+
accountIndex: import("drizzle-orm/pg-core").PgColumn<{
|
|
613
|
+
name: "account_index";
|
|
614
|
+
tableName: "path_allocations";
|
|
615
|
+
dataType: "number";
|
|
616
|
+
columnType: "PgInteger";
|
|
617
|
+
data: number;
|
|
618
|
+
driverParam: string | number;
|
|
619
|
+
notNull: true;
|
|
620
|
+
hasDefault: false;
|
|
621
|
+
isPrimaryKey: false;
|
|
622
|
+
isAutoincrement: false;
|
|
623
|
+
hasRuntimeDefault: false;
|
|
624
|
+
enumValues: undefined;
|
|
625
|
+
baseColumn: never;
|
|
626
|
+
identity: undefined;
|
|
627
|
+
generated: undefined;
|
|
628
|
+
}, {}, {}>;
|
|
629
|
+
chainId: import("drizzle-orm/pg-core").PgColumn<{
|
|
630
|
+
name: "chain_id";
|
|
631
|
+
tableName: "path_allocations";
|
|
632
|
+
dataType: "string";
|
|
633
|
+
columnType: "PgText";
|
|
634
|
+
data: string;
|
|
635
|
+
driverParam: string;
|
|
636
|
+
notNull: false;
|
|
637
|
+
hasDefault: false;
|
|
638
|
+
isPrimaryKey: false;
|
|
639
|
+
isAutoincrement: false;
|
|
640
|
+
hasRuntimeDefault: false;
|
|
641
|
+
enumValues: [string, ...string[]];
|
|
642
|
+
baseColumn: never;
|
|
643
|
+
identity: undefined;
|
|
644
|
+
generated: undefined;
|
|
645
|
+
}, {}, {}>;
|
|
646
|
+
xpub: import("drizzle-orm/pg-core").PgColumn<{
|
|
647
|
+
name: "xpub";
|
|
648
|
+
tableName: "path_allocations";
|
|
649
|
+
dataType: "string";
|
|
650
|
+
columnType: "PgText";
|
|
651
|
+
data: string;
|
|
652
|
+
driverParam: string;
|
|
653
|
+
notNull: true;
|
|
654
|
+
hasDefault: false;
|
|
655
|
+
isPrimaryKey: false;
|
|
656
|
+
isAutoincrement: false;
|
|
657
|
+
hasRuntimeDefault: false;
|
|
658
|
+
enumValues: [string, ...string[]];
|
|
659
|
+
baseColumn: never;
|
|
660
|
+
identity: undefined;
|
|
661
|
+
generated: undefined;
|
|
662
|
+
}, {}, {}>;
|
|
663
|
+
allocatedAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
664
|
+
name: "allocated_at";
|
|
665
|
+
tableName: "path_allocations";
|
|
666
|
+
dataType: "string";
|
|
667
|
+
columnType: "PgText";
|
|
668
|
+
data: string;
|
|
669
|
+
driverParam: string;
|
|
670
|
+
notNull: true;
|
|
671
|
+
hasDefault: true;
|
|
672
|
+
isPrimaryKey: false;
|
|
673
|
+
isAutoincrement: false;
|
|
674
|
+
hasRuntimeDefault: false;
|
|
675
|
+
enumValues: [string, ...string[]];
|
|
676
|
+
baseColumn: never;
|
|
677
|
+
identity: undefined;
|
|
678
|
+
generated: undefined;
|
|
679
|
+
}, {}, {}>;
|
|
680
|
+
};
|
|
681
|
+
dialect: "pg";
|
|
682
|
+
}>;
|
|
683
|
+
/**
|
|
684
|
+
* Every address ever derived — immutable append-only log.
|
|
685
|
+
* Used for auditing and ensuring no address is ever reused.
|
|
686
|
+
*/
|
|
687
|
+
export declare const derivedAddresses: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
688
|
+
name: "derived_addresses";
|
|
689
|
+
schema: undefined;
|
|
690
|
+
columns: {
|
|
691
|
+
id: import("drizzle-orm/pg-core").PgColumn<{
|
|
692
|
+
name: "id";
|
|
693
|
+
tableName: "derived_addresses";
|
|
694
|
+
dataType: "number";
|
|
695
|
+
columnType: "PgInteger";
|
|
696
|
+
data: number;
|
|
697
|
+
driverParam: string | number;
|
|
698
|
+
notNull: true;
|
|
699
|
+
hasDefault: true;
|
|
700
|
+
isPrimaryKey: true;
|
|
701
|
+
isAutoincrement: false;
|
|
702
|
+
hasRuntimeDefault: false;
|
|
703
|
+
enumValues: undefined;
|
|
704
|
+
baseColumn: never;
|
|
705
|
+
identity: "always";
|
|
706
|
+
generated: undefined;
|
|
707
|
+
}, {}, {}>;
|
|
708
|
+
chainId: import("drizzle-orm/pg-core").PgColumn<{
|
|
709
|
+
name: "chain_id";
|
|
710
|
+
tableName: "derived_addresses";
|
|
711
|
+
dataType: "string";
|
|
712
|
+
columnType: "PgText";
|
|
713
|
+
data: string;
|
|
714
|
+
driverParam: string;
|
|
715
|
+
notNull: true;
|
|
716
|
+
hasDefault: false;
|
|
717
|
+
isPrimaryKey: false;
|
|
718
|
+
isAutoincrement: false;
|
|
719
|
+
hasRuntimeDefault: false;
|
|
720
|
+
enumValues: [string, ...string[]];
|
|
721
|
+
baseColumn: never;
|
|
722
|
+
identity: undefined;
|
|
723
|
+
generated: undefined;
|
|
724
|
+
}, {}, {}>;
|
|
725
|
+
derivationIndex: import("drizzle-orm/pg-core").PgColumn<{
|
|
726
|
+
name: "derivation_index";
|
|
727
|
+
tableName: "derived_addresses";
|
|
728
|
+
dataType: "number";
|
|
729
|
+
columnType: "PgInteger";
|
|
730
|
+
data: number;
|
|
731
|
+
driverParam: string | number;
|
|
732
|
+
notNull: true;
|
|
733
|
+
hasDefault: false;
|
|
734
|
+
isPrimaryKey: false;
|
|
735
|
+
isAutoincrement: false;
|
|
736
|
+
hasRuntimeDefault: false;
|
|
737
|
+
enumValues: undefined;
|
|
738
|
+
baseColumn: never;
|
|
739
|
+
identity: undefined;
|
|
740
|
+
generated: undefined;
|
|
741
|
+
}, {}, {}>;
|
|
742
|
+
address: import("drizzle-orm/pg-core").PgColumn<{
|
|
743
|
+
name: "address";
|
|
744
|
+
tableName: "derived_addresses";
|
|
745
|
+
dataType: "string";
|
|
746
|
+
columnType: "PgText";
|
|
747
|
+
data: string;
|
|
748
|
+
driverParam: string;
|
|
749
|
+
notNull: true;
|
|
750
|
+
hasDefault: false;
|
|
751
|
+
isPrimaryKey: false;
|
|
752
|
+
isAutoincrement: false;
|
|
753
|
+
hasRuntimeDefault: false;
|
|
754
|
+
enumValues: [string, ...string[]];
|
|
755
|
+
baseColumn: never;
|
|
756
|
+
identity: undefined;
|
|
757
|
+
generated: undefined;
|
|
758
|
+
}, {}, {}>;
|
|
759
|
+
tenantId: import("drizzle-orm/pg-core").PgColumn<{
|
|
760
|
+
name: "tenant_id";
|
|
761
|
+
tableName: "derived_addresses";
|
|
762
|
+
dataType: "string";
|
|
763
|
+
columnType: "PgText";
|
|
764
|
+
data: string;
|
|
765
|
+
driverParam: string;
|
|
766
|
+
notNull: false;
|
|
767
|
+
hasDefault: false;
|
|
768
|
+
isPrimaryKey: false;
|
|
769
|
+
isAutoincrement: false;
|
|
770
|
+
hasRuntimeDefault: false;
|
|
771
|
+
enumValues: [string, ...string[]];
|
|
772
|
+
baseColumn: never;
|
|
773
|
+
identity: undefined;
|
|
774
|
+
generated: undefined;
|
|
775
|
+
}, {}, {}>;
|
|
776
|
+
createdAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
777
|
+
name: "created_at";
|
|
778
|
+
tableName: "derived_addresses";
|
|
779
|
+
dataType: "string";
|
|
780
|
+
columnType: "PgText";
|
|
781
|
+
data: string;
|
|
782
|
+
driverParam: string;
|
|
783
|
+
notNull: true;
|
|
784
|
+
hasDefault: true;
|
|
785
|
+
isPrimaryKey: false;
|
|
786
|
+
isAutoincrement: false;
|
|
787
|
+
hasRuntimeDefault: false;
|
|
788
|
+
enumValues: [string, ...string[]];
|
|
789
|
+
baseColumn: never;
|
|
790
|
+
identity: undefined;
|
|
791
|
+
generated: undefined;
|
|
792
|
+
}, {}, {}>;
|
|
793
|
+
};
|
|
794
|
+
dialect: "pg";
|
|
795
|
+
}>;
|
|
549
796
|
/** Processed transaction IDs for watchers without block cursors (e.g. BTC). */
|
|
550
797
|
export declare const watcherProcessed: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
551
798
|
name: "watcher_processed";
|
package/dist/db/schema/crypto.js
CHANGED
|
@@ -43,12 +43,16 @@ export const watcherCursors = pgTable("watcher_cursors", {
|
|
|
43
43
|
* Payment method registry — runtime-configurable tokens/chains.
|
|
44
44
|
* Admin inserts a row to enable a new payment method. No deploy needed.
|
|
45
45
|
* Contract addresses are immutable on-chain but configurable here.
|
|
46
|
+
*
|
|
47
|
+
* nextIndex is an atomic counter for HD derivation — never reuses an index.
|
|
48
|
+
* Increment via UPDATE ... SET next_index = next_index + 1 RETURNING next_index.
|
|
46
49
|
*/
|
|
47
50
|
export const paymentMethods = pgTable("payment_methods", {
|
|
48
|
-
id: text("id").primaryKey(), // "
|
|
49
|
-
type: text("type").notNull(), // "
|
|
50
|
-
token: text("token").notNull(), // "USDC", "ETH", "BTC"
|
|
51
|
-
chain: text("chain").notNull(), // "base", "ethereum", "bitcoin"
|
|
51
|
+
id: text("id").primaryKey(), // "btc", "base-usdc", "arb-usdc", "doge"
|
|
52
|
+
type: text("type").notNull(), // "erc20", "native", "btc"
|
|
53
|
+
token: text("token").notNull(), // "USDC", "ETH", "BTC", "DOGE"
|
|
54
|
+
chain: text("chain").notNull(), // "base", "ethereum", "bitcoin", "arbitrum"
|
|
55
|
+
network: text("network").notNull().default("mainnet"), // "mainnet", "base", "arbitrum"
|
|
52
56
|
contractAddress: text("contract_address"), // null for native (ETH, BTC)
|
|
53
57
|
decimals: integer("decimals").notNull(),
|
|
54
58
|
displayName: text("display_name").notNull(),
|
|
@@ -58,8 +62,35 @@ export const paymentMethods = pgTable("payment_methods", {
|
|
|
58
62
|
oracleAddress: text("oracle_address"), // Chainlink feed address for price (null = 1:1 stablecoin)
|
|
59
63
|
xpub: text("xpub"), // HD wallet extended public key for deposit address derivation
|
|
60
64
|
confirmations: integer("confirmations").notNull().default(1),
|
|
65
|
+
nextIndex: integer("next_index").notNull().default(0), // atomic derivation counter, never reuses
|
|
61
66
|
createdAt: text("created_at").notNull().default(sql `(now())`),
|
|
62
67
|
});
|
|
68
|
+
/**
|
|
69
|
+
* BIP-44 path allocation registry — tracks which derivation paths are in use.
|
|
70
|
+
* The server knows which paths are allocated so you never collide.
|
|
71
|
+
* The seed phrase never touches the server — only xpubs.
|
|
72
|
+
*/
|
|
73
|
+
export const pathAllocations = pgTable("path_allocations", {
|
|
74
|
+
coinType: integer("coin_type").notNull(), // BIP44 coin type (0=BTC, 60=ETH, 3=DOGE, 501=SOL)
|
|
75
|
+
accountIndex: integer("account_index").notNull(), // m/44'/{coin_type}'/{index}'
|
|
76
|
+
chainId: text("chain_id").references(() => paymentMethods.id),
|
|
77
|
+
xpub: text("xpub").notNull(),
|
|
78
|
+
allocatedAt: text("allocated_at").notNull().default(sql `(now())`),
|
|
79
|
+
}, (table) => [primaryKey({ columns: [table.coinType, table.accountIndex] })]);
|
|
80
|
+
/**
|
|
81
|
+
* Every address ever derived — immutable append-only log.
|
|
82
|
+
* Used for auditing and ensuring no address is ever reused.
|
|
83
|
+
*/
|
|
84
|
+
export const derivedAddresses = pgTable("derived_addresses", {
|
|
85
|
+
id: integer("id").primaryKey().generatedAlwaysAsIdentity(),
|
|
86
|
+
chainId: text("chain_id")
|
|
87
|
+
.notNull()
|
|
88
|
+
.references(() => paymentMethods.id),
|
|
89
|
+
derivationIndex: integer("derivation_index").notNull(),
|
|
90
|
+
address: text("address").notNull().unique(),
|
|
91
|
+
tenantId: text("tenant_id"),
|
|
92
|
+
createdAt: text("created_at").notNull().default(sql `(now())`),
|
|
93
|
+
}, (table) => [index("idx_derived_addresses_chain").on(table.chainId)]);
|
|
63
94
|
/** Processed transaction IDs for watchers without block cursors (e.g. BTC). */
|
|
64
95
|
export const watcherProcessed = pgTable("watcher_processed", {
|
|
65
96
|
watcherId: text("watcher_id").notNull(),
|
package/dist/fleet/instance.d.ts
CHANGED
|
@@ -39,6 +39,8 @@ export declare class Instance {
|
|
|
39
39
|
/** Simple per-instance mutex to serialize start/stop/restart/remove. */
|
|
40
40
|
private lockPromise;
|
|
41
41
|
constructor(deps: InstanceDeps);
|
|
42
|
+
/** Serialize to a plain object safe for JSON.stringify / tRPC responses. */
|
|
43
|
+
toJSON(): Record<string, unknown>;
|
|
42
44
|
/**
|
|
43
45
|
* Remote instances have containerId like "remote:node-3".
|
|
44
46
|
* Local Docker operations are not supported — callers (e.g. wopr-platform)
|
package/dist/fleet/instance.js
CHANGED
|
@@ -25,6 +25,21 @@ export class Instance {
|
|
|
25
25
|
this.eventEmitter = deps.eventEmitter;
|
|
26
26
|
this.botMetricsTracker = deps.botMetricsTracker;
|
|
27
27
|
}
|
|
28
|
+
/** Serialize to a plain object safe for JSON.stringify / tRPC responses. */
|
|
29
|
+
toJSON() {
|
|
30
|
+
return {
|
|
31
|
+
id: this.id,
|
|
32
|
+
containerId: this.containerId,
|
|
33
|
+
containerName: this.containerName,
|
|
34
|
+
url: this.url,
|
|
35
|
+
name: this.profile.name,
|
|
36
|
+
image: this.profile.image,
|
|
37
|
+
tenantId: this.profile.tenantId,
|
|
38
|
+
env: this.profile.env,
|
|
39
|
+
restartPolicy: this.profile.restartPolicy,
|
|
40
|
+
nodeId: this.profile.nodeId,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
28
43
|
/**
|
|
29
44
|
* Remote instances have containerId like "remote:node-3".
|
|
30
45
|
* Local Docker operations are not supported — callers (e.g. wopr-platform)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
-- Crypto Key Server schema additions.
|
|
2
|
+
-- Adds atomic derivation counter + path registry + address log.
|
|
3
|
+
|
|
4
|
+
-- 1. Add network column to payment_methods (parallel to chain)
|
|
5
|
+
ALTER TABLE "payment_methods" ADD COLUMN "network" text NOT NULL DEFAULT 'mainnet';
|
|
6
|
+
--> statement-breakpoint
|
|
7
|
+
|
|
8
|
+
-- 2. Add next_index atomic counter to payment_methods
|
|
9
|
+
ALTER TABLE "payment_methods" ADD COLUMN "next_index" integer NOT NULL DEFAULT 0;
|
|
10
|
+
--> statement-breakpoint
|
|
11
|
+
|
|
12
|
+
-- 3. BIP-44 path allocation registry
|
|
13
|
+
CREATE TABLE IF NOT EXISTS "path_allocations" (
|
|
14
|
+
"coin_type" integer NOT NULL,
|
|
15
|
+
"account_index" integer NOT NULL,
|
|
16
|
+
"chain_id" text REFERENCES "payment_methods"("id"),
|
|
17
|
+
"xpub" text NOT NULL,
|
|
18
|
+
"allocated_at" text NOT NULL DEFAULT (now()),
|
|
19
|
+
CONSTRAINT "path_allocations_pkey" PRIMARY KEY("coin_type","account_index")
|
|
20
|
+
);
|
|
21
|
+
--> statement-breakpoint
|
|
22
|
+
|
|
23
|
+
-- 4. Immutable derived address log
|
|
24
|
+
CREATE TABLE IF NOT EXISTS "derived_addresses" (
|
|
25
|
+
"id" integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
|
|
26
|
+
"chain_id" text NOT NULL REFERENCES "payment_methods"("id"),
|
|
27
|
+
"derivation_index" integer NOT NULL,
|
|
28
|
+
"address" text NOT NULL UNIQUE,
|
|
29
|
+
"tenant_id" text,
|
|
30
|
+
"created_at" text NOT NULL DEFAULT (now())
|
|
31
|
+
);
|
|
32
|
+
--> statement-breakpoint
|
|
33
|
+
|
|
34
|
+
CREATE INDEX IF NOT EXISTS "idx_derived_addresses_chain" ON "derived_addresses" ("chain_id");
|
|
35
|
+
--> statement-breakpoint
|
|
36
|
+
|
|
37
|
+
-- 5. Backfill next_index + derived_addresses from existing crypto_charges.
|
|
38
|
+
-- Guarded: only runs if crypto_charges table exists (fresh deploys won't have it).
|
|
39
|
+
DO $$
|
|
40
|
+
BEGIN
|
|
41
|
+
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'crypto_charges') THEN
|
|
42
|
+
UPDATE "payment_methods" pm
|
|
43
|
+
SET "next_index" = sub.max_idx + 1
|
|
44
|
+
FROM (
|
|
45
|
+
SELECT "chain", MAX("derivation_index") AS max_idx
|
|
46
|
+
FROM "crypto_charges"
|
|
47
|
+
WHERE "derivation_index" IS NOT NULL
|
|
48
|
+
GROUP BY "chain"
|
|
49
|
+
) sub
|
|
50
|
+
WHERE pm."chain" = sub."chain" AND sub.max_idx >= pm."next_index";
|
|
51
|
+
|
|
52
|
+
INSERT INTO "derived_addresses" ("chain_id", "derivation_index", "address", "tenant_id", "created_at")
|
|
53
|
+
SELECT cc."chain", cc."derivation_index", cc."deposit_address", cc."tenant_id", cc."created_at"
|
|
54
|
+
FROM "crypto_charges" cc
|
|
55
|
+
WHERE cc."deposit_address" IS NOT NULL
|
|
56
|
+
AND cc."derivation_index" IS NOT NULL
|
|
57
|
+
AND cc."chain" IS NOT NULL
|
|
58
|
+
ON CONFLICT ("address") DO NOTHING;
|
|
59
|
+
END IF;
|
|
60
|
+
END $$;
|
|
@@ -85,6 +85,27 @@
|
|
|
85
85
|
"when": 1742572800000,
|
|
86
86
|
"tag": "0011_notification_templates",
|
|
87
87
|
"breakpoints": true
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"idx": 12,
|
|
91
|
+
"version": "7",
|
|
92
|
+
"when": 1742659200000,
|
|
93
|
+
"tag": "0012_seed_popular_tokens",
|
|
94
|
+
"breakpoints": true
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"idx": 13,
|
|
98
|
+
"version": "7",
|
|
99
|
+
"when": 1742745600000,
|
|
100
|
+
"tag": "0013_platform_service_tenant_type",
|
|
101
|
+
"breakpoints": true
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"idx": 14,
|
|
105
|
+
"version": "7",
|
|
106
|
+
"when": 1742832000000,
|
|
107
|
+
"tag": "0014_crypto_key_server",
|
|
108
|
+
"breakpoints": true
|
|
88
109
|
}
|
|
89
110
|
]
|
|
90
111
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wopr-network/platform-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.43.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -128,6 +128,7 @@
|
|
|
128
128
|
},
|
|
129
129
|
"packageManager": "pnpm@10.31.0",
|
|
130
130
|
"dependencies": {
|
|
131
|
+
"@hono/node-server": "^1.19.11",
|
|
131
132
|
"@noble/hashes": "^2.0.1",
|
|
132
133
|
"@scure/base": "^2.0.0",
|
|
133
134
|
"@scure/bip32": "^2.0.1",
|