@wopr-network/crypto-plugins 1.0.1
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/ci.yml +33 -0
- package/.github/workflows/publish.yml +12 -0
- package/biome.json +23 -0
- package/dist/__tests__/bitcoin-encoder.test.d.ts +2 -0
- package/dist/__tests__/bitcoin-encoder.test.d.ts.map +1 -0
- package/dist/__tests__/bitcoin-encoder.test.js +97 -0
- package/dist/__tests__/bitcoin-encoder.test.js.map +1 -0
- package/dist/__tests__/dogecoin-encoder.test.d.ts +2 -0
- package/dist/__tests__/dogecoin-encoder.test.d.ts.map +1 -0
- package/dist/__tests__/dogecoin-encoder.test.js +57 -0
- package/dist/__tests__/dogecoin-encoder.test.js.map +1 -0
- package/dist/__tests__/litecoin-encoder.test.d.ts +2 -0
- package/dist/__tests__/litecoin-encoder.test.d.ts.map +1 -0
- package/dist/__tests__/litecoin-encoder.test.js +44 -0
- package/dist/__tests__/litecoin-encoder.test.js.map +1 -0
- package/dist/__tests__/registry.test.d.ts +2 -0
- package/dist/__tests__/registry.test.d.ts.map +1 -0
- package/dist/__tests__/registry.test.js +75 -0
- package/dist/__tests__/registry.test.js.map +1 -0
- package/dist/__tests__/rpc.test.d.ts +2 -0
- package/dist/__tests__/rpc.test.d.ts.map +1 -0
- package/dist/__tests__/rpc.test.js +31 -0
- package/dist/__tests__/rpc.test.js.map +1 -0
- package/dist/__tests__/solana-encoder.test.d.ts +2 -0
- package/dist/__tests__/solana-encoder.test.d.ts.map +1 -0
- package/dist/__tests__/solana-encoder.test.js +85 -0
- package/dist/__tests__/solana-encoder.test.js.map +1 -0
- package/dist/__tests__/solana-watcher.test.d.ts +2 -0
- package/dist/__tests__/solana-watcher.test.d.ts.map +1 -0
- package/dist/__tests__/solana-watcher.test.js +281 -0
- package/dist/__tests__/solana-watcher.test.js.map +1 -0
- package/dist/__tests__/sweep-key-parity.test.d.ts +2 -0
- package/dist/__tests__/sweep-key-parity.test.d.ts.map +1 -0
- package/dist/__tests__/sweep-key-parity.test.js +236 -0
- package/dist/__tests__/sweep-key-parity.test.js.map +1 -0
- package/dist/__tests__/tron-encoder.test.d.ts +2 -0
- package/dist/__tests__/tron-encoder.test.d.ts.map +1 -0
- package/dist/__tests__/tron-encoder.test.js +93 -0
- package/dist/__tests__/tron-encoder.test.js.map +1 -0
- package/dist/__tests__/utxo-watcher.test.d.ts +2 -0
- package/dist/__tests__/utxo-watcher.test.d.ts.map +1 -0
- package/dist/__tests__/utxo-watcher.test.js +218 -0
- package/dist/__tests__/utxo-watcher.test.js.map +1 -0
- package/dist/bitcoin/encoder.d.ts +15 -0
- package/dist/bitcoin/encoder.d.ts.map +1 -0
- package/dist/bitcoin/encoder.js +286 -0
- package/dist/bitcoin/encoder.js.map +1 -0
- package/dist/bitcoin/index.d.ts +4 -0
- package/dist/bitcoin/index.d.ts.map +1 -0
- package/dist/bitcoin/index.js +20 -0
- package/dist/bitcoin/index.js.map +1 -0
- package/dist/dogecoin/encoder.d.ts +19 -0
- package/dist/dogecoin/encoder.d.ts.map +1 -0
- package/dist/dogecoin/encoder.js +145 -0
- package/dist/dogecoin/encoder.js.map +1 -0
- package/dist/dogecoin/index.d.ts +4 -0
- package/dist/dogecoin/index.d.ts.map +1 -0
- package/dist/dogecoin/index.js +20 -0
- package/dist/dogecoin/index.js.map +1 -0
- package/dist/evm/encoder.d.ts +7 -0
- package/dist/evm/encoder.d.ts.map +1 -0
- package/dist/evm/encoder.js +43 -0
- package/dist/evm/encoder.js.map +1 -0
- package/dist/evm/eth-watcher.d.ts +38 -0
- package/dist/evm/eth-watcher.d.ts.map +1 -0
- package/dist/evm/eth-watcher.js +138 -0
- package/dist/evm/eth-watcher.js.map +1 -0
- package/dist/evm/index.d.ts +16 -0
- package/dist/evm/index.d.ts.map +1 -0
- package/dist/evm/index.js +34 -0
- package/dist/evm/index.js.map +1 -0
- package/dist/evm/types.d.ts +43 -0
- package/dist/evm/types.d.ts.map +1 -0
- package/dist/evm/types.js +101 -0
- package/dist/evm/types.js.map +1 -0
- package/dist/evm/watcher.d.ts +42 -0
- package/dist/evm/watcher.d.ts.map +1 -0
- package/dist/evm/watcher.js +162 -0
- package/dist/evm/watcher.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/litecoin/encoder.d.ts +8 -0
- package/dist/litecoin/encoder.d.ts.map +1 -0
- package/dist/litecoin/encoder.js +16 -0
- package/dist/litecoin/encoder.js.map +1 -0
- package/dist/litecoin/index.d.ts +4 -0
- package/dist/litecoin/index.d.ts.map +1 -0
- package/dist/litecoin/index.js +20 -0
- package/dist/litecoin/index.js.map +1 -0
- package/dist/shared/test-helpers/index.d.ts +9 -0
- package/dist/shared/test-helpers/index.d.ts.map +1 -0
- package/dist/shared/test-helpers/index.js +30 -0
- package/dist/shared/test-helpers/index.js.map +1 -0
- package/dist/shared/utxo/index.d.ts +5 -0
- package/dist/shared/utxo/index.d.ts.map +1 -0
- package/dist/shared/utxo/index.js +3 -0
- package/dist/shared/utxo/index.js.map +1 -0
- package/dist/shared/utxo/rpc.d.ts +24 -0
- package/dist/shared/utxo/rpc.d.ts.map +1 -0
- package/dist/shared/utxo/rpc.js +75 -0
- package/dist/shared/utxo/rpc.js.map +1 -0
- package/dist/shared/utxo/types.d.ts +40 -0
- package/dist/shared/utxo/types.d.ts.map +1 -0
- package/dist/shared/utxo/types.js +2 -0
- package/dist/shared/utxo/types.js.map +1 -0
- package/dist/shared/utxo/watcher.d.ts +55 -0
- package/dist/shared/utxo/watcher.d.ts.map +1 -0
- package/dist/shared/utxo/watcher.js +150 -0
- package/dist/shared/utxo/watcher.js.map +1 -0
- package/dist/solana/encoder.d.ts +13 -0
- package/dist/solana/encoder.d.ts.map +1 -0
- package/dist/solana/encoder.js +62 -0
- package/dist/solana/encoder.js.map +1 -0
- package/dist/solana/index.d.ts +17 -0
- package/dist/solana/index.d.ts.map +1 -0
- package/dist/solana/index.js +32 -0
- package/dist/solana/index.js.map +1 -0
- package/dist/solana/sweeper.d.ts +47 -0
- package/dist/solana/sweeper.d.ts.map +1 -0
- package/dist/solana/sweeper.js +151 -0
- package/dist/solana/sweeper.js.map +1 -0
- package/dist/solana/types.d.ts +49 -0
- package/dist/solana/types.d.ts.map +1 -0
- package/dist/solana/types.js +2 -0
- package/dist/solana/types.js.map +1 -0
- package/dist/solana/watcher.d.ts +59 -0
- package/dist/solana/watcher.d.ts.map +1 -0
- package/dist/solana/watcher.js +251 -0
- package/dist/solana/watcher.js.map +1 -0
- package/dist/sweep/evm-sweeper.d.ts +31 -0
- package/dist/sweep/evm-sweeper.d.ts.map +1 -0
- package/dist/sweep/evm-sweeper.js +229 -0
- package/dist/sweep/evm-sweeper.js.map +1 -0
- package/dist/sweep/index.d.ts +22 -0
- package/dist/sweep/index.d.ts.map +1 -0
- package/dist/sweep/index.js +290 -0
- package/dist/sweep/index.js.map +1 -0
- package/dist/sweep/tron-sweeper.d.ts +40 -0
- package/dist/sweep/tron-sweeper.d.ts.map +1 -0
- package/dist/sweep/tron-sweeper.js +363 -0
- package/dist/sweep/tron-sweeper.js.map +1 -0
- package/dist/sweep/utxo-sweeper.d.ts +14 -0
- package/dist/sweep/utxo-sweeper.d.ts.map +1 -0
- package/dist/sweep/utxo-sweeper.js +13 -0
- package/dist/sweep/utxo-sweeper.js.map +1 -0
- package/dist/tron/address-convert.d.ts +15 -0
- package/dist/tron/address-convert.d.ts.map +1 -0
- package/dist/tron/address-convert.js +95 -0
- package/dist/tron/address-convert.js.map +1 -0
- package/dist/tron/encoder.d.ts +20 -0
- package/dist/tron/encoder.d.ts.map +1 -0
- package/dist/tron/encoder.js +67 -0
- package/dist/tron/encoder.js.map +1 -0
- package/dist/tron/index.d.ts +6 -0
- package/dist/tron/index.d.ts.map +1 -0
- package/dist/tron/index.js +20 -0
- package/dist/tron/index.js.map +1 -0
- package/dist/tron/sha256.d.ts +6 -0
- package/dist/tron/sha256.d.ts.map +1 -0
- package/dist/tron/sha256.js +90 -0
- package/dist/tron/sha256.js.map +1 -0
- package/dist/tron/watcher.d.ts +42 -0
- package/dist/tron/watcher.d.ts.map +1 -0
- package/dist/tron/watcher.js +168 -0
- package/dist/tron/watcher.js.map +1 -0
- package/package.json +47 -0
- package/src/__tests__/bitcoin-encoder.test.ts +115 -0
- package/src/__tests__/dogecoin-encoder.test.ts +66 -0
- package/src/__tests__/litecoin-encoder.test.ts +51 -0
- package/src/__tests__/registry.test.ts +91 -0
- package/src/__tests__/rpc.test.ts +36 -0
- package/src/__tests__/solana-encoder.test.ts +103 -0
- package/src/__tests__/solana-watcher.test.ts +316 -0
- package/src/__tests__/sweep-key-parity.test.ts +302 -0
- package/src/__tests__/tron-encoder.test.ts +108 -0
- package/src/__tests__/utxo-watcher.test.ts +252 -0
- package/src/bitcoin/encoder.ts +320 -0
- package/src/bitcoin/index.ts +23 -0
- package/src/dogecoin/encoder.ts +161 -0
- package/src/dogecoin/index.ts +23 -0
- package/src/evm/encoder.ts +49 -0
- package/src/evm/eth-watcher.ts +168 -0
- package/src/evm/index.ts +46 -0
- package/src/evm/types.ts +146 -0
- package/src/evm/watcher.ts +189 -0
- package/src/index.ts +21 -0
- package/src/litecoin/encoder.ts +18 -0
- package/src/litecoin/index.ts +23 -0
- package/src/shared/test-helpers/index.ts +36 -0
- package/src/shared/utxo/index.ts +12 -0
- package/src/shared/utxo/rpc.ts +80 -0
- package/src/shared/utxo/types.ts +43 -0
- package/src/shared/utxo/watcher.ts +195 -0
- package/src/solana/encoder.ts +72 -0
- package/src/solana/index.ts +36 -0
- package/src/solana/sweeper.ts +196 -0
- package/src/solana/types.ts +52 -0
- package/src/solana/watcher.ts +282 -0
- package/src/sweep/evm-sweeper.ts +296 -0
- package/src/sweep/index.ts +353 -0
- package/src/sweep/tron-sweeper.ts +467 -0
- package/src/sweep/utxo-sweeper.ts +23 -0
- package/src/tron/address-convert.ts +91 -0
- package/src/tron/encoder.ts +74 -0
- package/src/tron/index.ts +23 -0
- package/src/tron/sha256.ts +100 -0
- package/src/tron/watcher.ts +208 -0
- package/tsconfig.json +17 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert raw native units to USD cents using microdollar pricing.
|
|
3
|
+
*
|
|
4
|
+
* priceMicros = microdollars (10^-6 USD) per 1 whole coin.
|
|
5
|
+
* rawAmount is in the smallest unit (sats for BTC, litoshis for LTC, etc).
|
|
6
|
+
* decimals = number of decimal places (8 for BTC/LTC/DOGE).
|
|
7
|
+
*
|
|
8
|
+
* Formula: (rawAmount * priceMicros) / (10_000 * 10^decimals)
|
|
9
|
+
* where 10_000 converts microdollars to cents (1 cent = 10,000 microdollars).
|
|
10
|
+
*/
|
|
11
|
+
function nativeToCents(rawAmount, priceMicros, decimals) {
|
|
12
|
+
if (rawAmount < 0n)
|
|
13
|
+
throw new Error("rawAmount must be non-negative");
|
|
14
|
+
if (!Number.isInteger(priceMicros) || priceMicros <= 0) {
|
|
15
|
+
throw new Error(`priceMicros must be a positive integer, got ${priceMicros}`);
|
|
16
|
+
}
|
|
17
|
+
const MICROS_PER_CENT = 10000n;
|
|
18
|
+
return Number((rawAmount * BigInt(priceMicros)) / (MICROS_PER_CENT * 10n ** BigInt(decimals)));
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Generic UTXO chain watcher that works with any bitcoind-compatible node.
|
|
22
|
+
* Polls listreceivedbyaddress for payments and tracks confirmations.
|
|
23
|
+
*
|
|
24
|
+
* Reusable for BTC, LTC, and DOGE.
|
|
25
|
+
*/
|
|
26
|
+
export class UtxoWatcher {
|
|
27
|
+
rpc;
|
|
28
|
+
addresses = new Set();
|
|
29
|
+
token;
|
|
30
|
+
chain;
|
|
31
|
+
decimals;
|
|
32
|
+
minConfirmations;
|
|
33
|
+
oracle;
|
|
34
|
+
cursorStore;
|
|
35
|
+
watcherId;
|
|
36
|
+
cursor = 0;
|
|
37
|
+
stopped = false;
|
|
38
|
+
constructor(config) {
|
|
39
|
+
this.rpc = config.rpc;
|
|
40
|
+
this.token = config.token;
|
|
41
|
+
this.chain = config.chain;
|
|
42
|
+
this.decimals = config.decimals;
|
|
43
|
+
this.minConfirmations = config.confirmations;
|
|
44
|
+
this.oracle = config.oracle;
|
|
45
|
+
this.cursorStore = config.cursorStore;
|
|
46
|
+
this.watcherId = `${config.chain}:${config.token}`;
|
|
47
|
+
}
|
|
48
|
+
async init() {
|
|
49
|
+
// Load persisted cursor (block height not used for UTXO, but kept for interface compat)
|
|
50
|
+
const saved = await this.cursorStore.get(this.watcherId);
|
|
51
|
+
if (saved !== null)
|
|
52
|
+
this.cursor = saved;
|
|
53
|
+
}
|
|
54
|
+
setWatchedAddresses(addresses) {
|
|
55
|
+
this.addresses.clear();
|
|
56
|
+
for (const a of addresses)
|
|
57
|
+
this.addresses.add(a);
|
|
58
|
+
}
|
|
59
|
+
getCursor() {
|
|
60
|
+
return this.cursor;
|
|
61
|
+
}
|
|
62
|
+
stop() {
|
|
63
|
+
this.stopped = true;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Import an address into the node's wallet (watch-only).
|
|
67
|
+
* Uses importdescriptors (modern) with fallback to importaddress (legacy).
|
|
68
|
+
*/
|
|
69
|
+
async importAddress(address) {
|
|
70
|
+
try {
|
|
71
|
+
const info = (await this.rpc("getdescriptorinfo", [`addr(${address})`]));
|
|
72
|
+
const result = (await this.rpc("importdescriptors", [
|
|
73
|
+
[{ desc: info.descriptor, timestamp: 0 }],
|
|
74
|
+
]));
|
|
75
|
+
if (result[0] && !result[0].success) {
|
|
76
|
+
throw new Error(result[0].error?.message ?? "importdescriptors failed");
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// Fallback: legacy importaddress
|
|
81
|
+
await this.rpc("importaddress", [address, "", false]);
|
|
82
|
+
}
|
|
83
|
+
this.addresses.add(address);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Poll for payments to watched addresses.
|
|
87
|
+
* Returns PaymentEvent[] for each new or updated confirmation.
|
|
88
|
+
*/
|
|
89
|
+
async poll() {
|
|
90
|
+
if (this.stopped || this.addresses.size === 0)
|
|
91
|
+
return [];
|
|
92
|
+
const events = [];
|
|
93
|
+
// Poll with minconf=0 to see unconfirmed txs
|
|
94
|
+
const received = (await this.rpc("listreceivedbyaddress", [
|
|
95
|
+
0, // minconf=0: see ALL txs including unconfirmed
|
|
96
|
+
false, // include_empty
|
|
97
|
+
true, // include_watchonly
|
|
98
|
+
]));
|
|
99
|
+
const { priceMicros } = await this.oracle.getPrice(this.token);
|
|
100
|
+
for (const entry of received) {
|
|
101
|
+
if (!this.addresses.has(entry.address))
|
|
102
|
+
continue;
|
|
103
|
+
for (const txid of entry.txids) {
|
|
104
|
+
// Skip fully-processed txids
|
|
105
|
+
const confirmCount = await this.cursorStore.getConfirmationCount(this.watcherId, txid);
|
|
106
|
+
// Get transaction details for the exact amount
|
|
107
|
+
const tx = (await this.rpc("gettransaction", [txid, true]));
|
|
108
|
+
const detail = tx.details.find((d) => d.address === entry.address && d.category === "receive");
|
|
109
|
+
if (!detail)
|
|
110
|
+
continue;
|
|
111
|
+
// Check if confirmations have increased since last seen
|
|
112
|
+
if (confirmCount !== null && tx.confirmations <= confirmCount)
|
|
113
|
+
continue;
|
|
114
|
+
// Skip if already at or past threshold on a previous poll
|
|
115
|
+
if (confirmCount !== null && confirmCount >= this.minConfirmations)
|
|
116
|
+
continue;
|
|
117
|
+
const rawAmount = BigInt(Math.round(detail.amount * 10 ** this.decimals));
|
|
118
|
+
const amountUsdCents = nativeToCents(rawAmount, priceMicros, this.decimals);
|
|
119
|
+
events.push({
|
|
120
|
+
chain: this.chain,
|
|
121
|
+
token: this.token,
|
|
122
|
+
from: "", // UTXO chains don't have a single sender
|
|
123
|
+
to: entry.address,
|
|
124
|
+
rawAmount: rawAmount.toString(),
|
|
125
|
+
amountUsdCents,
|
|
126
|
+
txHash: txid,
|
|
127
|
+
blockNumber: 0, // UTXO chains use txid-based tracking, not block numbers
|
|
128
|
+
confirmations: tx.confirmations,
|
|
129
|
+
confirmationsRequired: this.minConfirmations,
|
|
130
|
+
});
|
|
131
|
+
// Persist confirmation count
|
|
132
|
+
await this.cursorStore.saveConfirmationCount(this.watcherId, txid, tx.confirmations);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return events;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/** Create a UtxoWatcher from the standard WatcherOpts interface. */
|
|
139
|
+
export function createUtxoWatcher(opts, rpc) {
|
|
140
|
+
return new UtxoWatcher({
|
|
141
|
+
rpc,
|
|
142
|
+
token: opts.token,
|
|
143
|
+
chain: opts.chain,
|
|
144
|
+
decimals: opts.decimals,
|
|
145
|
+
confirmations: opts.confirmations,
|
|
146
|
+
oracle: opts.oracle,
|
|
147
|
+
cursorStore: opts.cursorStore,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=watcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watcher.js","sourceRoot":"","sources":["../../../src/shared/utxo/watcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { EncodingParams, IAddressEncoder } from "@wopr-network/platform-core/crypto-plugin";
|
|
2
|
+
/**
|
|
3
|
+
* Encode a Uint8Array as a Base58 string (Bitcoin/Solana alphabet).
|
|
4
|
+
*
|
|
5
|
+
* This is a standalone implementation — no external dependency needed.
|
|
6
|
+
*/
|
|
7
|
+
export declare function base58Encode(bytes: Uint8Array): string;
|
|
8
|
+
/** Solana address encoder implementing IAddressEncoder. */
|
|
9
|
+
export declare class SolanaAddressEncoder implements IAddressEncoder {
|
|
10
|
+
encode(publicKey: Uint8Array, _params: EncodingParams): string;
|
|
11
|
+
encodingType(): string;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=encoder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encoder.d.ts","sourceRoot":"","sources":["../../src/solana/encoder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,2CAA2C,CAAC;AAKjG;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAqCtD;AAeD,2DAA2D;AAC3D,qBAAa,oBAAqB,YAAW,eAAe;IAC3D,MAAM,CAAC,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,cAAc,GAAG,MAAM;IAI9D,YAAY,IAAI,MAAM;CAGtB"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/** Base58 alphabet used by Bitcoin/Solana. */
|
|
2
|
+
const ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
3
|
+
/**
|
|
4
|
+
* Encode a Uint8Array as a Base58 string (Bitcoin/Solana alphabet).
|
|
5
|
+
*
|
|
6
|
+
* This is a standalone implementation — no external dependency needed.
|
|
7
|
+
*/
|
|
8
|
+
export function base58Encode(bytes) {
|
|
9
|
+
// Count leading zeros
|
|
10
|
+
let zeros = 0;
|
|
11
|
+
for (let i = 0; i < bytes.length && bytes[i] === 0; i++) {
|
|
12
|
+
zeros++;
|
|
13
|
+
}
|
|
14
|
+
// Convert to base58
|
|
15
|
+
// Allocate enough space in big-endian base58 representation
|
|
16
|
+
const size = Math.ceil((bytes.length * 138) / 100) + 1;
|
|
17
|
+
const b58 = new Uint8Array(size);
|
|
18
|
+
for (let i = zeros; i < bytes.length; i++) {
|
|
19
|
+
let carry = bytes[i];
|
|
20
|
+
for (let j = size - 1; j >= 0; j--) {
|
|
21
|
+
carry += 256 * b58[j];
|
|
22
|
+
b58[j] = carry % 58;
|
|
23
|
+
carry = Math.floor(carry / 58);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
// Skip leading zeros in base58 result
|
|
27
|
+
let start = 0;
|
|
28
|
+
while (start < size && b58[start] === 0) {
|
|
29
|
+
start++;
|
|
30
|
+
}
|
|
31
|
+
// Build string: leading '1's for zero bytes + base58 digits
|
|
32
|
+
let result = "";
|
|
33
|
+
for (let i = 0; i < zeros; i++) {
|
|
34
|
+
result += ALPHABET[0];
|
|
35
|
+
}
|
|
36
|
+
for (let i = start; i < size; i++) {
|
|
37
|
+
result += ALPHABET[b58[i]];
|
|
38
|
+
}
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Derive a Solana address from a raw 32-byte Ed25519 public key.
|
|
43
|
+
*
|
|
44
|
+
* Solana addresses are simply the Base58 encoding of the raw public key.
|
|
45
|
+
* No hashing, no version byte, no checksum.
|
|
46
|
+
*/
|
|
47
|
+
function encodeSolana(pubkey) {
|
|
48
|
+
if (pubkey.length !== 32) {
|
|
49
|
+
throw new Error(`Solana address requires 32-byte Ed25519 public key, got ${pubkey.length} bytes`);
|
|
50
|
+
}
|
|
51
|
+
return base58Encode(pubkey);
|
|
52
|
+
}
|
|
53
|
+
/** Solana address encoder implementing IAddressEncoder. */
|
|
54
|
+
export class SolanaAddressEncoder {
|
|
55
|
+
encode(publicKey, _params) {
|
|
56
|
+
return encodeSolana(publicKey);
|
|
57
|
+
}
|
|
58
|
+
encodingType() {
|
|
59
|
+
return "base58-solana";
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=encoder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encoder.js","sourceRoot":"","sources":["../../src/solana/encoder.ts"],"names":[],"mappings":"AAEA,8CAA8C;AAC9C,MAAM,QAAQ,GAAG,4DAA4D,CAAC;AAE9E;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,KAAiB;IAC7C,sBAAsB;IACtB,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACzD,KAAK,EAAE,CAAC;IACT,CAAC;IAED,oBAAoB;IACpB,4DAA4D;IAC5D,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;IACvD,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC;IAEjC,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,IAAI,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACrB,KAAK,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YACpC,KAAK,IAAI,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;YACtB,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;YACpB,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC;QAChC,CAAC;IACF,CAAC;IAED,sCAAsC;IACtC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,OAAO,KAAK,GAAG,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QACzC,KAAK,EAAE,CAAC;IACT,CAAC;IAED,4DAA4D;IAC5D,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QAChC,MAAM,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC;IACD,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;QACnC,MAAM,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,MAAM,CAAC;AACf,CAAC;AAED;;;;;GAKG;AACH,SAAS,YAAY,CAAC,MAAkB;IACvC,IAAI,MAAM,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,2DAA2D,MAAM,CAAC,MAAM,QAAQ,CAAC,CAAC;IACnG,CAAC;IACD,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC;AAC7B,CAAC;AAED,2DAA2D;AAC3D,MAAM,OAAO,oBAAoB;IAChC,MAAM,CAAC,SAAqB,EAAE,OAAuB;QACpD,OAAO,YAAY,CAAC,SAAS,CAAC,CAAC;IAChC,CAAC;IAED,YAAY;QACX,OAAO,eAAe,CAAC;IACxB,CAAC;CACD"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { IChainPlugin } from "@wopr-network/platform-core/crypto-plugin";
|
|
2
|
+
export { base58Encode, SolanaAddressEncoder } from "./encoder.js";
|
|
3
|
+
export { SolanaSweeper } from "./sweeper.js";
|
|
4
|
+
export type { SignatureInfo, SolanaRpcCall, SolanaTransaction, TokenBalance, TransactionMeta } from "./types.js";
|
|
5
|
+
export { createSolanaRpcCaller, SolanaWatcher } from "./watcher.js";
|
|
6
|
+
/**
|
|
7
|
+
* Solana chain plugin.
|
|
8
|
+
*
|
|
9
|
+
* Supports native SOL watching and SPL token watching (e.g. USDC).
|
|
10
|
+
* Uses Ed25519 curve for key derivation. Addresses are Base58-encoded
|
|
11
|
+
* raw 32-byte public keys (no hashing, no checksum).
|
|
12
|
+
*
|
|
13
|
+
* The watcher detects incoming transfers by scanning transaction history
|
|
14
|
+
* for each watched address via getSignaturesForAddress + getTransaction.
|
|
15
|
+
*/
|
|
16
|
+
export declare const solanaPlugin: IChainPlugin;
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/solana/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAA4B,MAAM,2CAA2C,CAAC;AAKxG,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,iBAAiB,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AACjH,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAIpE;;;;;;;;;GASG;AACH,eAAO,MAAM,YAAY,EAAE,YAa1B,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { SolanaAddressEncoder } from "./encoder.js";
|
|
2
|
+
import { SolanaSweeper } from "./sweeper.js";
|
|
3
|
+
import { SolanaWatcher } from "./watcher.js";
|
|
4
|
+
export { base58Encode, SolanaAddressEncoder } from "./encoder.js";
|
|
5
|
+
export { SolanaSweeper } from "./sweeper.js";
|
|
6
|
+
export { createSolanaRpcCaller, SolanaWatcher } from "./watcher.js";
|
|
7
|
+
const encoder = new SolanaAddressEncoder();
|
|
8
|
+
/**
|
|
9
|
+
* Solana chain plugin.
|
|
10
|
+
*
|
|
11
|
+
* Supports native SOL watching and SPL token watching (e.g. USDC).
|
|
12
|
+
* Uses Ed25519 curve for key derivation. Addresses are Base58-encoded
|
|
13
|
+
* raw 32-byte public keys (no hashing, no checksum).
|
|
14
|
+
*
|
|
15
|
+
* The watcher detects incoming transfers by scanning transaction history
|
|
16
|
+
* for each watched address via getSignaturesForAddress + getTransaction.
|
|
17
|
+
*/
|
|
18
|
+
export const solanaPlugin = {
|
|
19
|
+
pluginId: "solana",
|
|
20
|
+
supportedCurve: "ed25519",
|
|
21
|
+
encoders: {
|
|
22
|
+
"base58-solana": encoder,
|
|
23
|
+
},
|
|
24
|
+
createWatcher(opts) {
|
|
25
|
+
return new SolanaWatcher(opts);
|
|
26
|
+
},
|
|
27
|
+
createSweeper(opts) {
|
|
28
|
+
return new SolanaSweeper(opts);
|
|
29
|
+
},
|
|
30
|
+
version: 1,
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/solana/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAEpE,MAAM,OAAO,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAE3C;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,YAAY,GAAiB;IACzC,QAAQ,EAAE,QAAQ;IAClB,cAAc,EAAE,SAAS;IACzB,QAAQ,EAAE;QACT,eAAe,EAAE,OAAO;KACxB;IACD,aAAa,CAAC,IAAiB;QAC9B,OAAO,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IACD,aAAa,CAAC,IAAiB;QAC9B,OAAO,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,EAAE,CAAC;CACV,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { DepositInfo, ISweepStrategy, KeyPair, SweeperOpts, SweepResult } from "@wopr-network/platform-core/crypto-plugin";
|
|
2
|
+
/**
|
|
3
|
+
* Solana sweep strategy.
|
|
4
|
+
*
|
|
5
|
+
* Scans deposit addresses for SOL balances and SPL token balances,
|
|
6
|
+
* then creates transfer transactions to sweep funds to the treasury.
|
|
7
|
+
*/
|
|
8
|
+
export declare class SolanaSweeper implements ISweepStrategy {
|
|
9
|
+
private readonly rpc;
|
|
10
|
+
private readonly token;
|
|
11
|
+
private readonly chain;
|
|
12
|
+
private readonly contractAddress?;
|
|
13
|
+
private readonly decimals;
|
|
14
|
+
constructor(opts: SweeperOpts);
|
|
15
|
+
/**
|
|
16
|
+
* Scan deposit addresses for balances.
|
|
17
|
+
*
|
|
18
|
+
* For each key:
|
|
19
|
+
* - Check native SOL balance via getBalance
|
|
20
|
+
* - Check SPL token balances via getTokenAccountsByOwner
|
|
21
|
+
*/
|
|
22
|
+
scan(keys: KeyPair[], _treasury: string): Promise<DepositInfo[]>;
|
|
23
|
+
/**
|
|
24
|
+
* Sweep funds from deposit addresses to treasury.
|
|
25
|
+
*
|
|
26
|
+
* For native SOL: transfers balance minus fee.
|
|
27
|
+
* For SPL tokens: transfers full token balance using token transfer instruction.
|
|
28
|
+
*
|
|
29
|
+
* In dry-run mode, returns what would be swept without broadcasting.
|
|
30
|
+
*/
|
|
31
|
+
sweep(keys: KeyPair[], treasury: string, dryRun: boolean): Promise<SweepResult[]>;
|
|
32
|
+
/**
|
|
33
|
+
* Submit a native SOL transfer.
|
|
34
|
+
*
|
|
35
|
+
* Builds a SystemProgram.transfer instruction, signs with the deposit keypair,
|
|
36
|
+
* and submits via sendTransaction.
|
|
37
|
+
*/
|
|
38
|
+
private submitSolTransfer;
|
|
39
|
+
/**
|
|
40
|
+
* Submit an SPL token transfer.
|
|
41
|
+
*
|
|
42
|
+
* Builds a TokenProgram.transfer instruction for the given mint,
|
|
43
|
+
* signs with the deposit keypair, and submits via sendTransaction.
|
|
44
|
+
*/
|
|
45
|
+
private submitSplTransfer;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=sweeper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sweeper.d.ts","sourceRoot":"","sources":["../../src/solana/sweeper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,WAAW,EACX,cAAc,EACd,OAAO,EACP,WAAW,EACX,WAAW,EACX,MAAM,2CAA2C,CAAC;AAOnD;;;;;GAKG;AACH,qBAAa,aAAc,YAAW,cAAc;IACnD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAgB;IACpC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,IAAI,EAAE,WAAW;IAQ7B;;;;;;OAMG;IACG,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAuDtE;;;;;;;OAOG;IACG,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IA6DvF;;;;;OAKG;YACW,iBAAiB;IAa/B;;;;;OAKG;YACW,iBAAiB;CAK/B"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { createSolanaRpcCaller } from "./watcher.js";
|
|
2
|
+
/** Transaction fee estimate (in lamports). */
|
|
3
|
+
const TX_FEE = 5000n;
|
|
4
|
+
/**
|
|
5
|
+
* Solana sweep strategy.
|
|
6
|
+
*
|
|
7
|
+
* Scans deposit addresses for SOL balances and SPL token balances,
|
|
8
|
+
* then creates transfer transactions to sweep funds to the treasury.
|
|
9
|
+
*/
|
|
10
|
+
export class SolanaSweeper {
|
|
11
|
+
rpc;
|
|
12
|
+
token;
|
|
13
|
+
chain;
|
|
14
|
+
contractAddress;
|
|
15
|
+
decimals;
|
|
16
|
+
constructor(opts) {
|
|
17
|
+
this.rpc = createSolanaRpcCaller(opts.rpcUrl, opts.rpcHeaders);
|
|
18
|
+
this.token = opts.token;
|
|
19
|
+
this.chain = opts.chain;
|
|
20
|
+
this.contractAddress = opts.contractAddress;
|
|
21
|
+
this.decimals = opts.decimals;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Scan deposit addresses for balances.
|
|
25
|
+
*
|
|
26
|
+
* For each key:
|
|
27
|
+
* - Check native SOL balance via getBalance
|
|
28
|
+
* - Check SPL token balances via getTokenAccountsByOwner
|
|
29
|
+
*/
|
|
30
|
+
async scan(keys, _treasury) {
|
|
31
|
+
const results = [];
|
|
32
|
+
for (const key of keys) {
|
|
33
|
+
const balance = (await this.rpc("getBalance", [key.address]));
|
|
34
|
+
const nativeBalance = BigInt(balance.value);
|
|
35
|
+
const tokenBalances = [];
|
|
36
|
+
if (this.contractAddress) {
|
|
37
|
+
const tokenAccounts = (await this.rpc("getTokenAccountsByOwner", [
|
|
38
|
+
key.address,
|
|
39
|
+
{ mint: this.contractAddress },
|
|
40
|
+
{ encoding: "jsonParsed" },
|
|
41
|
+
]));
|
|
42
|
+
for (const ta of tokenAccounts.value) {
|
|
43
|
+
const info = ta.account.data.parsed.info;
|
|
44
|
+
const bal = BigInt(info.tokenAmount.amount);
|
|
45
|
+
if (bal > 0n) {
|
|
46
|
+
tokenBalances.push({
|
|
47
|
+
token: info.mint,
|
|
48
|
+
balance: bal,
|
|
49
|
+
decimals: info.tokenAmount.decimals,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (nativeBalance > 0n || tokenBalances.length > 0) {
|
|
55
|
+
results.push({
|
|
56
|
+
index: key.index,
|
|
57
|
+
address: key.address,
|
|
58
|
+
nativeBalance,
|
|
59
|
+
tokenBalances,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return results;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Sweep funds from deposit addresses to treasury.
|
|
67
|
+
*
|
|
68
|
+
* For native SOL: transfers balance minus fee.
|
|
69
|
+
* For SPL tokens: transfers full token balance using token transfer instruction.
|
|
70
|
+
*
|
|
71
|
+
* In dry-run mode, returns what would be swept without broadcasting.
|
|
72
|
+
*/
|
|
73
|
+
async sweep(keys, treasury, dryRun) {
|
|
74
|
+
const deposits = await this.scan(keys, treasury);
|
|
75
|
+
const results = [];
|
|
76
|
+
for (const deposit of deposits) {
|
|
77
|
+
const key = keys.find((k) => k.index === deposit.index);
|
|
78
|
+
if (!key)
|
|
79
|
+
continue;
|
|
80
|
+
// Sweep SPL tokens first
|
|
81
|
+
for (const tb of deposit.tokenBalances) {
|
|
82
|
+
if (dryRun) {
|
|
83
|
+
results.push({
|
|
84
|
+
index: deposit.index,
|
|
85
|
+
address: deposit.address,
|
|
86
|
+
token: tb.token,
|
|
87
|
+
amount: tb.balance.toString(),
|
|
88
|
+
txHash: "dry-run",
|
|
89
|
+
});
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
// In production, this would build and sign an SPL token transfer transaction
|
|
93
|
+
// using @solana/web3.js. For now, placeholder for the transaction submission.
|
|
94
|
+
const txHash = await this.submitSplTransfer(key, treasury, tb.token, tb.balance);
|
|
95
|
+
results.push({
|
|
96
|
+
index: deposit.index,
|
|
97
|
+
address: deposit.address,
|
|
98
|
+
token: tb.token,
|
|
99
|
+
amount: tb.balance.toString(),
|
|
100
|
+
txHash,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
// Sweep native SOL (leave enough for rent + fee if token accounts exist)
|
|
104
|
+
const sweepableNative = deposit.nativeBalance - TX_FEE;
|
|
105
|
+
if (sweepableNative > 0n) {
|
|
106
|
+
if (dryRun) {
|
|
107
|
+
results.push({
|
|
108
|
+
index: deposit.index,
|
|
109
|
+
address: deposit.address,
|
|
110
|
+
token: "SOL",
|
|
111
|
+
amount: sweepableNative.toString(),
|
|
112
|
+
txHash: "dry-run",
|
|
113
|
+
});
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
const txHash = await this.submitSolTransfer(key, treasury, sweepableNative);
|
|
117
|
+
results.push({
|
|
118
|
+
index: deposit.index,
|
|
119
|
+
address: deposit.address,
|
|
120
|
+
token: "SOL",
|
|
121
|
+
amount: sweepableNative.toString(),
|
|
122
|
+
txHash,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return results;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Submit a native SOL transfer.
|
|
130
|
+
*
|
|
131
|
+
* Builds a SystemProgram.transfer instruction, signs with the deposit keypair,
|
|
132
|
+
* and submits via sendTransaction.
|
|
133
|
+
*/
|
|
134
|
+
async submitSolTransfer(key, treasury, lamports) {
|
|
135
|
+
// Get recent blockhash
|
|
136
|
+
const blockhashResult = (await this.rpc("getLatestBlockhash", [{ commitment: "finalized" }]));
|
|
137
|
+
// In production, build + sign the transaction using @solana/web3.js or manual serialization.
|
|
138
|
+
// For Phase 1, we use a simplified approach:
|
|
139
|
+
throw new Error(`SOL transfer not yet implemented — would send ${lamports} lamports from ${key.address} to ${treasury} with blockhash ${blockhashResult.value.blockhash}`);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Submit an SPL token transfer.
|
|
143
|
+
*
|
|
144
|
+
* Builds a TokenProgram.transfer instruction for the given mint,
|
|
145
|
+
* signs with the deposit keypair, and submits via sendTransaction.
|
|
146
|
+
*/
|
|
147
|
+
async submitSplTransfer(key, treasury, mint, amount) {
|
|
148
|
+
throw new Error(`SPL transfer not yet implemented — would send ${amount} of ${mint} from ${key.address} to ${treasury}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=sweeper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sweeper.js","sourceRoot":"","sources":["../../src/solana/sweeper.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/** JSON-RPC call function signature. */
|
|
2
|
+
export type SolanaRpcCall = (method: string, params: unknown[]) => Promise<unknown>;
|
|
3
|
+
/** Solana signature info from getSignaturesForAddress. */
|
|
4
|
+
export interface SignatureInfo {
|
|
5
|
+
signature: string;
|
|
6
|
+
slot: number;
|
|
7
|
+
err: unknown | null;
|
|
8
|
+
memo: string | null;
|
|
9
|
+
blockTime: number | null;
|
|
10
|
+
confirmationStatus: "processed" | "confirmed" | "finalized" | null;
|
|
11
|
+
}
|
|
12
|
+
/** Solana transaction metadata. */
|
|
13
|
+
export interface TransactionMeta {
|
|
14
|
+
err: unknown | null;
|
|
15
|
+
fee: number;
|
|
16
|
+
preBalances: number[];
|
|
17
|
+
postBalances: number[];
|
|
18
|
+
preTokenBalances?: TokenBalance[];
|
|
19
|
+
postTokenBalances?: TokenBalance[];
|
|
20
|
+
}
|
|
21
|
+
/** SPL token balance entry in transaction metadata. */
|
|
22
|
+
export interface TokenBalance {
|
|
23
|
+
accountIndex: number;
|
|
24
|
+
mint: string;
|
|
25
|
+
uiTokenAmount: {
|
|
26
|
+
amount: string;
|
|
27
|
+
decimals: number;
|
|
28
|
+
uiAmountString: string;
|
|
29
|
+
};
|
|
30
|
+
owner?: string;
|
|
31
|
+
}
|
|
32
|
+
/** Parsed Solana transaction from getTransaction. */
|
|
33
|
+
export interface SolanaTransaction {
|
|
34
|
+
slot: number;
|
|
35
|
+
blockTime: number | null;
|
|
36
|
+
meta: TransactionMeta | null;
|
|
37
|
+
transaction: {
|
|
38
|
+
message: {
|
|
39
|
+
accountKeys: string[];
|
|
40
|
+
instructions: Array<{
|
|
41
|
+
programIdIndex: number;
|
|
42
|
+
accounts: number[];
|
|
43
|
+
data: string;
|
|
44
|
+
}>;
|
|
45
|
+
};
|
|
46
|
+
signatures: string[];
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/solana/types.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpF,0DAA0D;AAC1D,MAAM,WAAW,aAAa;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,kBAAkB,EAAE,WAAW,GAAG,WAAW,GAAG,WAAW,GAAG,IAAI,CAAC;CACnE;AAED,mCAAmC;AACnC,MAAM,WAAW,eAAe;IAC/B,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,gBAAgB,CAAC,EAAE,YAAY,EAAE,CAAC;IAClC,iBAAiB,CAAC,EAAE,YAAY,EAAE,CAAC;CACnC;AAED,uDAAuD;AACvD,MAAM,WAAW,YAAY;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE;QACd,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,cAAc,EAAE,MAAM,CAAC;KACvB,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qDAAqD;AACrD,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,IAAI,EAAE,eAAe,GAAG,IAAI,CAAC;IAC7B,WAAW,EAAE;QACZ,OAAO,EAAE;YACR,WAAW,EAAE,MAAM,EAAE,CAAC;YACtB,YAAY,EAAE,KAAK,CAAC;gBACnB,cAAc,EAAE,MAAM,CAAC;gBACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;gBACnB,IAAI,EAAE,MAAM,CAAC;aACb,CAAC,CAAC;SACH,CAAC;QACF,UAAU,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/solana/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { IChainWatcher, PaymentEvent, WatcherOpts } from "@wopr-network/platform-core/crypto-plugin";
|
|
2
|
+
import type { SolanaRpcCall } from "./types.js";
|
|
3
|
+
/** Create a Solana JSON-RPC caller. */
|
|
4
|
+
export declare function createSolanaRpcCaller(rpcUrl: string, extraHeaders?: Record<string, string>): SolanaRpcCall;
|
|
5
|
+
/**
|
|
6
|
+
* Solana chain watcher.
|
|
7
|
+
*
|
|
8
|
+
* Monitors watched addresses for incoming SOL transfers and SPL token transfers.
|
|
9
|
+
* Uses getSignaturesForAddress + getTransaction RPCs. Cursor is a slot number.
|
|
10
|
+
*
|
|
11
|
+
* For native SOL: detects balance increases to watched addresses.
|
|
12
|
+
* For SPL tokens: detects token transfer instructions to watched addresses.
|
|
13
|
+
*/
|
|
14
|
+
export declare class SolanaWatcher implements IChainWatcher {
|
|
15
|
+
private _cursor;
|
|
16
|
+
private _stopped;
|
|
17
|
+
private readonly chain;
|
|
18
|
+
private readonly token;
|
|
19
|
+
private readonly rpc;
|
|
20
|
+
private readonly confirmations;
|
|
21
|
+
private readonly decimals;
|
|
22
|
+
private readonly cursorStore;
|
|
23
|
+
private readonly watcherId;
|
|
24
|
+
private readonly contractAddress?;
|
|
25
|
+
private _watchedAddresses;
|
|
26
|
+
constructor(opts: WatcherOpts);
|
|
27
|
+
init(): Promise<void>;
|
|
28
|
+
setWatchedAddresses(addresses: string[]): void;
|
|
29
|
+
getCursor(): number;
|
|
30
|
+
stop(): void;
|
|
31
|
+
/**
|
|
32
|
+
* Poll for SOL or SPL token transfers to watched addresses.
|
|
33
|
+
*
|
|
34
|
+
* For each watched address:
|
|
35
|
+
* 1. Call getSignaturesForAddress to find recent transactions
|
|
36
|
+
* 2. Call getTransaction for each to extract transfer details
|
|
37
|
+
* 3. Detect native SOL transfers (balance diff) or SPL token transfers
|
|
38
|
+
*
|
|
39
|
+
* Cursor is the highest slot seen, advanced only for finalized transactions.
|
|
40
|
+
*/
|
|
41
|
+
poll(): Promise<PaymentEvent[]>;
|
|
42
|
+
/** Fetch recent signatures for an address, filtering by slot > cursor. */
|
|
43
|
+
private getRecentSignatures;
|
|
44
|
+
/**
|
|
45
|
+
* Extract native SOL transfer events from a transaction.
|
|
46
|
+
*
|
|
47
|
+
* Detects balance increases to the watched address by comparing
|
|
48
|
+
* preBalances and postBalances in the transaction metadata.
|
|
49
|
+
*/
|
|
50
|
+
private extractNativeTransferEvents;
|
|
51
|
+
/**
|
|
52
|
+
* Extract SPL token transfer events from a transaction.
|
|
53
|
+
*
|
|
54
|
+
* Compares preTokenBalances and postTokenBalances for the watched address
|
|
55
|
+
* filtered by the configured token mint (contractAddress).
|
|
56
|
+
*/
|
|
57
|
+
private extractSplTransferEvents;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=watcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["../../src/solana/watcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,aAAa,EAEb,YAAY,EACZ,WAAW,EACX,MAAM,2CAA2C,CAAC;AACnD,OAAO,KAAK,EAAiB,aAAa,EAAqB,MAAM,YAAY,CAAC;AAQlF,uCAAuC;AACvC,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,aAAa,CAiB1G;AAaD;;;;;;;;GAQG;AACH,qBAAa,aAAc,YAAW,aAAa;IAClD,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAgB;IACpC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAsB;IAClD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAS;IAC1C,OAAO,CAAC,iBAAiB,CAAc;gBAE3B,IAAI,EAAE,WAAW;IAavB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAK3B,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI;IAI9C,SAAS,IAAI,MAAM;IAInB,IAAI,IAAI,IAAI;IAIZ;;;;;;;;;OASG;IACG,IAAI,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAgDrC,0EAA0E;YAC5D,mBAAmB;IAOjC;;;;;OAKG;IACH,OAAO,CAAC,2BAA2B;IAkDnC;;;;;OAKG;IACH,OAAO,CAAC,wBAAwB;CAwDhC"}
|