@voidifydao/sdk 1.0.0 → 2.0.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/README.md +105 -0
- package/dist/cli/config/init.js +1 -7
- package/dist/cli/config/loader.js +0 -1
- package/dist/cli/config/types.d.ts +0 -1
- package/dist/cli/deposit.js +45 -29
- package/dist/cli/helpers.js +0 -3
- package/dist/cli/progress.d.ts +5 -0
- package/dist/cli/progress.js +37 -0
- package/dist/cli/relayer.js +16 -7
- package/dist/cli/withdraw.js +20 -6
- package/dist/context.d.ts +1 -4
- package/dist/context.js +14 -12
- package/dist/idl/voidify/idl.d.ts +1 -1
- package/dist/idl/voidify/idl.json +1 -1
- package/dist/index.d.ts +2 -3
- package/dist/index.js +0 -2
- package/dist/relayer/server/server.js +29 -13
- package/dist/relayer/server/switchboard.js +15 -6
- package/dist/relayer/types.d.ts +1 -0
- package/dist/substream/chain/index.d.ts +10 -3
- package/dist/substream/chain/index.js +14 -7
- package/dist/substream/chain/registry.d.ts +2 -2
- package/dist/substream/chain/utils.d.ts +2 -1
- package/dist/substream/chain/utils.js +35 -11
- package/dist/substream/client.d.ts +6 -1
- package/dist/substream/database/indexeddb.js +3 -0
- package/dist/substream/database/sqlite.d.ts +1 -0
- package/dist/substream/database/sqlite.js +6 -0
- package/dist/substream/modules/deposit.d.ts +2 -1
- package/dist/substream/modules/deposit.js +24 -20
- package/dist/substream/modules/relayer.d.ts +2 -1
- package/dist/substream/modules/relayer.js +39 -33
- package/dist/substream/runtime.d.ts +19 -4
- package/dist/substream/runtime.js +216 -16
- package/dist/substream/server/server.d.ts +2 -0
- package/dist/substream/server/server.js +42 -8
- package/dist/substream/types.d.ts +21 -0
- package/dist/types/index.d.ts +0 -1
- package/dist/types/index.js +1 -1
- package/dist/voidify/deposit.d.ts +2 -0
- package/dist/voidify/deposit.js +1 -1
- package/dist/voidify/program.d.ts +0 -4
- package/dist/voidify/program.js +0 -10
- package/dist/voidify/relayer/list.d.ts +2 -0
- package/dist/voidify/relayer/list.js +1 -1
- package/dist/voidify/withdraw.d.ts +7 -2
- package/dist/voidify/withdraw.js +68 -10
- package/package.json +5 -4
- package/dist/idl/voidify-staking/idl.d.ts +0 -93
- package/dist/idl/voidify-staking/idl.js +0 -1
- package/dist/idl/voidify-staking/idl.json +0 -87
- package/dist/staking/commands.d.ts +0 -3
- package/dist/staking/commands.js +0 -13
- package/dist/staking/index.d.ts +0 -2
- package/dist/staking/index.js +0 -2
- package/dist/staking/program.d.ts +0 -18
- package/dist/staking/program.js +0 -40
- package/dist/types/errors.d.ts +0 -1
- package/dist/types/errors.js +0 -16
package/README.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Voidify SDK
|
|
2
|
+
|
|
3
|
+
[English](README.md) | [中文](docs/README.zh-CN.md) | [Русский](docs/README.ru.md) | [日本語](docs/README.ja.md)
|
|
4
|
+
|
|
5
|
+
`@voidifydao/sdk` is the Voidify SDK and CLI for deposits, private notes, relayer withdrawals, relayer services, and indexed protocol activity on Solana.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
As a library:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm install @voidifydao/sdk
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
As a command-line tool:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
npm install -g @voidifydao/sdk
|
|
19
|
+
voidify --help
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## CLI Setup
|
|
23
|
+
|
|
24
|
+
Generate a JSON configuration file, then fill in that same file:
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
voidify config init --type default --path ./voidify.json
|
|
28
|
+
voidify -c ./voidify.json config set programId YOUR_VOIDIFY_PROGRAM_ID
|
|
29
|
+
voidify -c ./voidify.json config set keypair.path /absolute/path/to/solana-keypair.json
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
For withdrawal proof generation, download the proof artifacts from the
|
|
33
|
+
[Voidify ceremony record v1.0.0 release](https://github.com/VoidifyCommunity/voidify-ceremony-record/releases/tag/v1.0.0).
|
|
34
|
+
Extract `withdraw.wasm` and `withdraw.zkey`, then place them at the
|
|
35
|
+
`proof.wasmPath` and `proof.zkeyPath` paths in the generated config.
|
|
36
|
+
|
|
37
|
+
All following commands use the generated `./voidify.json` file through `-c`.
|
|
38
|
+
|
|
39
|
+
## CLI Commands
|
|
40
|
+
|
|
41
|
+
Generate a private note:
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
voidify -c ./voidify.json note gen 1
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Deposit `1 SOL`. If `--commitment` is omitted, a new note is generated and printed:
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
voidify -c ./voidify.json deposit 1
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
List deposits in a pool:
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
voidify -c ./voidify.json deposit list 1
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Withdraw through an automatically selected healthy relayer:
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
voidify -c ./voidify.json withdraw "YOUR_PRIVATE_NOTE" --recipient RECIPIENT_SOLANA_ADDRESS
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Choose a relayer by name:
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
voidify -c ./voidify.json withdraw "YOUR_PRIVATE_NOTE" --recipient RECIPIENT_SOLANA_ADDRESS --relayer RELAYER_NAME
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
> Keep your private note secure. Anyone with the note can withdraw the deposit, and a lost note cannot be recovered.
|
|
72
|
+
|
|
73
|
+
## Run a Relayer
|
|
74
|
+
|
|
75
|
+
Generate a relayer JSON configuration, fill in that file, then use it for relayer commands:
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
voidify config init --type relayer --path ./relayer.json
|
|
79
|
+
voidify -c ./relayer.json relayer start
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## SDK Usage
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import { Context, Note, voidify } from "@voidifydao/sdk";
|
|
86
|
+
import { Keypair, PublicKey } from "@solana/web3.js";
|
|
87
|
+
|
|
88
|
+
const wallet = Keypair.generate();
|
|
89
|
+
const ctx = new Context({
|
|
90
|
+
rpcUrl: "https://api.mainnet-beta.solana.com",
|
|
91
|
+
programId: new PublicKey("YOUR_VOIDIFY_PROGRAM_ID"),
|
|
92
|
+
wallet,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const note = await Note.generate("1");
|
|
96
|
+
const signature = await voidify.deposit(
|
|
97
|
+
ctx,
|
|
98
|
+
note.commitment,
|
|
99
|
+
1_000_000_000n,
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
console.log(note.serialize(), signature);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The package also exports withdrawal helpers, relayer types, `VoidifyProgram`, substream clients and stores, and amount/note utilities.
|
package/dist/cli/config/init.js
CHANGED
|
@@ -13,7 +13,6 @@ export function buildTemplate(type) {
|
|
|
13
13
|
return {
|
|
14
14
|
rpcUrl: defaults.rpcUrl,
|
|
15
15
|
programId: REQUIRED("voidify program ID"),
|
|
16
|
-
stakingProgramId: null,
|
|
17
16
|
keypair: fileKeypairPlaceholder("user keypair"),
|
|
18
17
|
substream: { ...defaults.substream },
|
|
19
18
|
proof: { ...defaults.proof },
|
|
@@ -22,7 +21,6 @@ export function buildTemplate(type) {
|
|
|
22
21
|
return {
|
|
23
22
|
rpcUrl: defaults.rpcUrl,
|
|
24
23
|
programId: REQUIRED("voidify program ID"),
|
|
25
|
-
stakingProgramId: null,
|
|
26
24
|
keypair: fileKeypairPlaceholder("relayer keypair"),
|
|
27
25
|
relayerServer: { ...defaults.relayerServer },
|
|
28
26
|
};
|
|
@@ -37,7 +35,6 @@ export function buildTemplate(type) {
|
|
|
37
35
|
return {
|
|
38
36
|
rpcUrl: defaults.rpcUrl,
|
|
39
37
|
programId: REQUIRED("voidify program ID"),
|
|
40
|
-
stakingProgramId: null,
|
|
41
38
|
keypair: fileKeypairPlaceholder("keypair for this config"),
|
|
42
39
|
substream: { ...defaults.substream },
|
|
43
40
|
proof: { ...defaults.proof },
|
|
@@ -53,7 +50,6 @@ export function postInitHint(type) {
|
|
|
53
50
|
"Next steps:",
|
|
54
51
|
" - programId <- voidify main program",
|
|
55
52
|
" - keypair.path <- your keypair JSON file path",
|
|
56
|
-
" - stakingProgramId <- optional staking program ID",
|
|
57
53
|
" (substream / proof already use defaults; no changes needed)",
|
|
58
54
|
"",
|
|
59
55
|
"Applicable commands: deposit / withdraw / note.",
|
|
@@ -63,8 +59,7 @@ export function postInitHint(type) {
|
|
|
63
59
|
"Next steps:",
|
|
64
60
|
" - programId <- voidify main program",
|
|
65
61
|
" - keypair.path <- keypair for the relayer service itself",
|
|
66
|
-
" - relayerServer.feedId
|
|
67
|
-
" - stakingProgramId <- optional staking program ID",
|
|
62
|
+
" - relayerServer.feedId ← Switchboard on-demand feed ID",
|
|
68
63
|
"",
|
|
69
64
|
"Applicable commands: relayer start / relayer list.",
|
|
70
65
|
].join("\n");
|
|
@@ -80,7 +75,6 @@ export function postInitHint(type) {
|
|
|
80
75
|
return [
|
|
81
76
|
"Next steps: full template; fill in values as needed.",
|
|
82
77
|
" required: programId, keypair.path, relayerServer.feedId",
|
|
83
|
-
" optional: stakingProgramId",
|
|
84
78
|
"",
|
|
85
79
|
"Reminder: one config should use one keypair. Create separate config files and switch with -c when roles differ.",
|
|
86
80
|
].join("\n");
|
package/dist/cli/deposit.js
CHANGED
|
@@ -3,27 +3,66 @@ import { deposit, listDeposits } from "../voidify/deposit.js";
|
|
|
3
3
|
import { parseUnits } from "../utils/amount.js";
|
|
4
4
|
import { Note } from "../utils/note.js";
|
|
5
5
|
import { createServiceContext, SOL_DECIMALS, } from "../cli/helpers.js";
|
|
6
|
+
import { createCliProgressBar } from "../cli/progress.js";
|
|
6
7
|
export function registerDepositCommands(program) {
|
|
7
8
|
const depositCommand = new Command("deposit")
|
|
8
9
|
.enablePositionalOptions()
|
|
10
|
+
.argument("<amount>", "Deposit amount in UI units, such as 1 for 1 SOL")
|
|
9
11
|
.description("Deposit commands");
|
|
12
|
+
depositCommand.option("-c, --commitment <string>", "Commitment generated by the note gen command; if omitted, a new one is generated and printed");
|
|
10
13
|
depositCommand
|
|
11
|
-
.command("
|
|
12
|
-
.
|
|
13
|
-
.
|
|
14
|
-
.
|
|
14
|
+
.command("list <amount>")
|
|
15
|
+
.description("List records for a denomination pool, using UI units such as 1 for 1 SOL")
|
|
16
|
+
.option("--offset <number>", "Pagination offset")
|
|
17
|
+
.option("--limit <number>", "Page size")
|
|
18
|
+
.option("-o, --output <file>", "Write output to a file")
|
|
19
|
+
.action(async (amount, options) => {
|
|
20
|
+
try {
|
|
21
|
+
const ctx = await createServiceContext(program.opts());
|
|
22
|
+
const progress = createCliProgressBar("Sync deposits");
|
|
23
|
+
const deposits = await (async () => {
|
|
24
|
+
try {
|
|
25
|
+
return await listDeposits(ctx, parseUnits(amount, SOL_DECIMALS), {
|
|
26
|
+
offset: options.offset !== undefined
|
|
27
|
+
? parseInt(options.offset)
|
|
28
|
+
: undefined,
|
|
29
|
+
limit: options.limit !== undefined
|
|
30
|
+
? parseInt(options.limit)
|
|
31
|
+
: undefined,
|
|
32
|
+
output: options.output,
|
|
33
|
+
sync: { reporter: progress },
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
progress.finish();
|
|
38
|
+
}
|
|
39
|
+
})();
|
|
40
|
+
if (!options.output) {
|
|
41
|
+
console.log("Deposit records:", deposits);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
console.error("List deposits failed:", error);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
depositCommand.action(async (amount, options) => {
|
|
50
|
+
if (!amount) {
|
|
51
|
+
depositCommand.help({ error: true });
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
15
54
|
try {
|
|
16
55
|
const ctx = await createServiceContext(program.opts());
|
|
17
56
|
let commitment = options.commitment;
|
|
18
57
|
if (!commitment) {
|
|
19
|
-
const note = await Note.generate(
|
|
58
|
+
const note = await Note.generate(amount);
|
|
20
59
|
commitment = note.commitment;
|
|
21
60
|
console.log("Note generated:", {
|
|
22
61
|
note: note.serialize(),
|
|
23
62
|
commitment: note.commitment,
|
|
24
63
|
});
|
|
25
64
|
}
|
|
26
|
-
const txSignature = await deposit(ctx, commitment, parseUnits(
|
|
65
|
+
const txSignature = await deposit(ctx, commitment, parseUnits(amount, SOL_DECIMALS));
|
|
27
66
|
console.log("Transaction successful:", { txSignature });
|
|
28
67
|
}
|
|
29
68
|
catch (error) {
|
|
@@ -31,28 +70,5 @@ export function registerDepositCommands(program) {
|
|
|
31
70
|
process.exit(1);
|
|
32
71
|
}
|
|
33
72
|
});
|
|
34
|
-
depositCommand
|
|
35
|
-
.command("list <amount>")
|
|
36
|
-
.description("List records for a denomination pool, using UI units such as 1 for 1 SOL")
|
|
37
|
-
.option("--offset <number>", "Pagination offset")
|
|
38
|
-
.option("--limit <number>", "Page size")
|
|
39
|
-
.option("-o, --output <file>", "Write output to a file")
|
|
40
|
-
.action(async (amount, options) => {
|
|
41
|
-
try {
|
|
42
|
-
const ctx = await createServiceContext(program.opts());
|
|
43
|
-
const deposits = await listDeposits(ctx, parseUnits(amount, SOL_DECIMALS), {
|
|
44
|
-
offset: options.offset !== undefined
|
|
45
|
-
? parseInt(options.offset)
|
|
46
|
-
: undefined,
|
|
47
|
-
limit: options.limit !== undefined ? parseInt(options.limit) : undefined,
|
|
48
|
-
output: options.output,
|
|
49
|
-
});
|
|
50
|
-
console.log("Deposit records:", deposits);
|
|
51
|
-
}
|
|
52
|
-
catch (error) {
|
|
53
|
-
console.error("List deposits failed:", error);
|
|
54
|
-
process.exit(1);
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
73
|
program.addCommand(depositCommand);
|
|
58
74
|
}
|
package/dist/cli/helpers.js
CHANGED
|
@@ -39,9 +39,6 @@ export async function contextFromConfig(cfg, cliKeypairPath) {
|
|
|
39
39
|
return new Context({
|
|
40
40
|
rpcUrl: cfg.rpcUrl,
|
|
41
41
|
programId: cfg.programId ? new PublicKey(cfg.programId) : undefined,
|
|
42
|
-
stakingProgramId: cfg.stakingProgramId
|
|
43
|
-
? new PublicKey(cfg.stakingProgramId)
|
|
44
|
-
: undefined,
|
|
45
42
|
wallet: keypair,
|
|
46
43
|
substream,
|
|
47
44
|
wasmPath: cfg.proof ? expandHome(cfg.proof.wasmPath) : undefined,
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export function createCliProgressBar(label) {
|
|
2
|
+
if (!process.stderr.isTTY) {
|
|
3
|
+
return {
|
|
4
|
+
update() { },
|
|
5
|
+
finish() { },
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
let started = false;
|
|
9
|
+
let lastLength = 0;
|
|
10
|
+
function render(status) {
|
|
11
|
+
const progress = status.progress;
|
|
12
|
+
if (!progress)
|
|
13
|
+
return;
|
|
14
|
+
const width = 28;
|
|
15
|
+
const ratio = progress.total > 0 ? progress.current / progress.total : 1;
|
|
16
|
+
const complete = Math.min(width, Math.floor(ratio * width));
|
|
17
|
+
const bar = `${"#".repeat(complete)}${"-".repeat(width - complete)}`;
|
|
18
|
+
const percent = Math.floor(ratio * 100)
|
|
19
|
+
.toString()
|
|
20
|
+
.padStart(3, " ");
|
|
21
|
+
const text = `${label} [${bar}] ${percent}% ${progress.current}/${progress.total}`;
|
|
22
|
+
const padding = " ".repeat(Math.max(0, lastLength - text.length));
|
|
23
|
+
process.stderr.write(`\r${text}${padding}`);
|
|
24
|
+
started = true;
|
|
25
|
+
lastLength = text.length;
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
update: render,
|
|
29
|
+
finish() {
|
|
30
|
+
if (!started)
|
|
31
|
+
return;
|
|
32
|
+
process.stderr.write("\n");
|
|
33
|
+
started = false;
|
|
34
|
+
lastLength = 0;
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
package/dist/cli/relayer.js
CHANGED
|
@@ -2,21 +2,30 @@ import { Command } from "commander";
|
|
|
2
2
|
import { startRelayer } from "../relayer/server/index.js";
|
|
3
3
|
import { listRelayers } from "../voidify/relayer/list.js";
|
|
4
4
|
import { createServiceContext, contextFromConfig, loadCliConfig, } from "../cli/helpers.js";
|
|
5
|
+
import { createCliProgressBar } from "../cli/progress.js";
|
|
5
6
|
export function registerRelayerCommands(program) {
|
|
6
7
|
const relayerCommand = new Command("relayer")
|
|
7
8
|
.enablePositionalOptions()
|
|
8
9
|
.description("Relayer commands");
|
|
9
10
|
relayerCommand
|
|
10
|
-
.command("list")
|
|
11
|
-
.description("List relayer information
|
|
12
|
-
.option("--pubkey <pubkey>", "Specific relayer public key")
|
|
11
|
+
.command("list [pubkey]")
|
|
12
|
+
.description("List relayer information for a specific relayer")
|
|
13
13
|
.option("-o, --output <file>", "Write output to a file")
|
|
14
|
-
.action(async (options) => {
|
|
14
|
+
.action(async (pubkey, options) => {
|
|
15
15
|
try {
|
|
16
16
|
const ctx = await createServiceContext(program.opts());
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
const progress = createCliProgressBar("Sync relayers");
|
|
18
|
+
const relayers = await (async () => {
|
|
19
|
+
try {
|
|
20
|
+
return await listRelayers(ctx, pubkey, {
|
|
21
|
+
output: options.output,
|
|
22
|
+
sync: { reporter: progress },
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
finally {
|
|
26
|
+
progress.finish();
|
|
27
|
+
}
|
|
28
|
+
})();
|
|
20
29
|
console.log("Relayer records:", relayers);
|
|
21
30
|
}
|
|
22
31
|
catch (error) {
|
package/dist/cli/withdraw.js
CHANGED
|
@@ -1,17 +1,31 @@
|
|
|
1
1
|
import { withdraw } from "../voidify/withdraw.js";
|
|
2
2
|
import { createServiceContext } from "../cli/helpers.js";
|
|
3
|
+
import { createCliProgressBar } from "../cli/progress.js";
|
|
3
4
|
export function registerWithdrawCommands(program) {
|
|
4
5
|
program
|
|
5
6
|
.command("withdraw")
|
|
6
7
|
.description("Withdraw through a relayer")
|
|
7
|
-
.
|
|
8
|
-
.
|
|
9
|
-
.
|
|
10
|
-
.option("--
|
|
11
|
-
.action(async (options) => {
|
|
8
|
+
.argument("<note>", "Note generated when depositing")
|
|
9
|
+
.option("--recipient <pubkey>", "Recipient address")
|
|
10
|
+
.option("--relayer <name>", "Relayer name")
|
|
11
|
+
.option("--send-rpc", "Send this client's RPC URL to the relayer for this withdraw request")
|
|
12
|
+
.action(async (note, options) => {
|
|
12
13
|
try {
|
|
13
14
|
const ctx = await createServiceContext(program.opts());
|
|
14
|
-
const
|
|
15
|
+
const depositProgress = createCliProgressBar("Sync deposits");
|
|
16
|
+
const relayerProgress = createCliProgressBar("Sync relayers");
|
|
17
|
+
const result = await (async () => {
|
|
18
|
+
try {
|
|
19
|
+
return await withdraw(ctx, note, options.recipient, options.relayer, {
|
|
20
|
+
depositSync: { reporter: depositProgress },
|
|
21
|
+
relayerSync: { reporter: relayerProgress },
|
|
22
|
+
}, options.sendRpc ?? false);
|
|
23
|
+
}
|
|
24
|
+
finally {
|
|
25
|
+
depositProgress.finish();
|
|
26
|
+
relayerProgress.finish();
|
|
27
|
+
}
|
|
28
|
+
})();
|
|
15
29
|
console.log("Withdraw successful:", { txSignature: result });
|
|
16
30
|
process.exit(0);
|
|
17
31
|
}
|
package/dist/context.d.ts
CHANGED
|
@@ -17,7 +17,6 @@ export type SubstreamConfig = {
|
|
|
17
17
|
export interface ContextOptions {
|
|
18
18
|
rpcUrl?: string;
|
|
19
19
|
programId?: PublicKey;
|
|
20
|
-
stakingProgramId?: PublicKey;
|
|
21
20
|
wallet?: anchor.Wallet | Keypair | null;
|
|
22
21
|
substream?: SubstreamConfig;
|
|
23
22
|
wasmPath?: string;
|
|
@@ -27,17 +26,15 @@ export declare class Context {
|
|
|
27
26
|
private readonly _rpcUrl;
|
|
28
27
|
private readonly _connection;
|
|
29
28
|
private readonly _programId;
|
|
30
|
-
private readonly _stakingProgramId;
|
|
31
29
|
private readonly _substream;
|
|
32
30
|
private readonly _wasmPath;
|
|
33
31
|
private readonly _zkeyPath;
|
|
34
32
|
readonly wallet: anchor.Wallet | null;
|
|
35
33
|
constructor(opts?: ContextOptions);
|
|
34
|
+
withRpcUrl(rpcUrl: string): Context;
|
|
36
35
|
get rpcUrl(): string;
|
|
37
36
|
get connection(): Connection;
|
|
38
37
|
get programId(): PublicKey;
|
|
39
|
-
get stakingProgramId(): PublicKey;
|
|
40
|
-
hasStakingProgramId(): boolean;
|
|
41
38
|
get substream(): SubstreamConfig;
|
|
42
39
|
get wasmPath(): string;
|
|
43
40
|
get zkeyPath(): string;
|
package/dist/context.js
CHANGED
|
@@ -4,7 +4,6 @@ export class Context {
|
|
|
4
4
|
_rpcUrl;
|
|
5
5
|
_connection;
|
|
6
6
|
_programId;
|
|
7
|
-
_stakingProgramId;
|
|
8
7
|
_substream;
|
|
9
8
|
_wasmPath;
|
|
10
9
|
_zkeyPath;
|
|
@@ -12,10 +11,12 @@ export class Context {
|
|
|
12
11
|
constructor(opts = {}) {
|
|
13
12
|
this._rpcUrl = opts.rpcUrl ?? null;
|
|
14
13
|
this._connection = opts.rpcUrl
|
|
15
|
-
? new Connection(opts.rpcUrl,
|
|
14
|
+
? new Connection(opts.rpcUrl, {
|
|
15
|
+
commitment: "confirmed",
|
|
16
|
+
disableRetryOnRateLimit: true,
|
|
17
|
+
})
|
|
16
18
|
: null;
|
|
17
19
|
this._programId = opts.programId ?? null;
|
|
18
|
-
this._stakingProgramId = opts.stakingProgramId ?? null;
|
|
19
20
|
this._substream = opts.substream ?? null;
|
|
20
21
|
this._wasmPath = opts.wasmPath ?? null;
|
|
21
22
|
this._zkeyPath = opts.zkeyPath ?? null;
|
|
@@ -23,6 +24,16 @@ export class Context {
|
|
|
23
24
|
this.wallet =
|
|
24
25
|
w === null ? null : w instanceof Keypair ? new anchor.Wallet(w) : w;
|
|
25
26
|
}
|
|
27
|
+
withRpcUrl(rpcUrl) {
|
|
28
|
+
return new Context({
|
|
29
|
+
rpcUrl,
|
|
30
|
+
programId: this._programId ?? undefined,
|
|
31
|
+
wallet: this.wallet,
|
|
32
|
+
substream: this._substream ?? undefined,
|
|
33
|
+
wasmPath: this._wasmPath ?? undefined,
|
|
34
|
+
zkeyPath: this._zkeyPath ?? undefined,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
26
37
|
get rpcUrl() {
|
|
27
38
|
if (!this._rpcUrl) {
|
|
28
39
|
throw new Error("rpcUrl is required for this operation");
|
|
@@ -41,15 +52,6 @@ export class Context {
|
|
|
41
52
|
}
|
|
42
53
|
return this._programId;
|
|
43
54
|
}
|
|
44
|
-
get stakingProgramId() {
|
|
45
|
-
if (!this._stakingProgramId) {
|
|
46
|
-
throw new Error("stakingProgramId is required for this operation");
|
|
47
|
-
}
|
|
48
|
-
return this._stakingProgramId;
|
|
49
|
-
}
|
|
50
|
-
hasStakingProgramId() {
|
|
51
|
-
return this._stakingProgramId !== null;
|
|
52
|
-
}
|
|
53
55
|
get substream() {
|
|
54
56
|
if (!this._substream) {
|
|
55
57
|
throw new Error("substream config is required for this operation");
|
package/dist/index.d.ts
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
export { Context } from "./context.js";
|
|
2
2
|
export type { SubstreamConfig, SubstreamMode } from "./context.js";
|
|
3
3
|
export * as voidify from "./voidify/index.js";
|
|
4
|
-
export * as staking from "./staking/index.js";
|
|
5
4
|
export { VoidifyProgram } from "./voidify/program.js";
|
|
6
|
-
export { VoidifyStakingProgram } from "./staking/program.js";
|
|
7
5
|
export type { WithdrawArtifact } from "./voidify/withdraw.js";
|
|
8
6
|
export { SubstreamCliClient } from "./substream/client.js";
|
|
9
7
|
export type { SubstreamCliConfig, EventsApiResponse, CursorWire, } from "./substream/client.js";
|
|
10
8
|
export { makeIndexedDBStores } from "./substream/database/indexeddb.js";
|
|
11
9
|
export type { DepositModuleApi, RelayerModuleApi, } from "./substream/modules/index.js";
|
|
12
|
-
export type {
|
|
10
|
+
export type { ChainSyncOptions } from "./substream/chain/index.js";
|
|
11
|
+
export type { DepositRecord, RelayerRecord, EventCursor, SyncProgress, SyncPhase, SyncStatus, SyncStatusReporter, ApplyOutcome, ChainEventRecord, ChainEventWire, EventScope, EventStore, EventProjection, ProjectionStateRecord, ProjectionStateValue, ProjectionStore, SubstreamRepos, SubstreamStores, } from "./substream/types.js";
|
|
13
12
|
export { Note, TOKEN_DECIMALS } from "./utils/note.js";
|
|
14
13
|
export { parseUnits, formatUnits, toBN } from "./utils/amount.js";
|
|
15
14
|
export type { Voidify } from "./idl/voidify/idl.js";
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
export { Context } from "./context.js";
|
|
2
2
|
export * as voidify from "./voidify/index.js";
|
|
3
|
-
export * as staking from "./staking/index.js";
|
|
4
3
|
export { VoidifyProgram } from "./voidify/program.js";
|
|
5
|
-
export { VoidifyStakingProgram } from "./staking/program.js";
|
|
6
4
|
export { SubstreamCliClient } from "./substream/client.js";
|
|
7
5
|
export { makeIndexedDBStores } from "./substream/database/indexeddb.js";
|
|
8
6
|
export { Note, TOKEN_DECIMALS } from "./utils/note.js";
|
|
@@ -2,7 +2,6 @@ import express from "express";
|
|
|
2
2
|
import cors from "cors";
|
|
3
3
|
import { updateQuote } from "./switchboard.js";
|
|
4
4
|
import { withdrawIx } from "../../voidify/withdraw.js";
|
|
5
|
-
import { notifyRewardAmountIx } from "../../staking/commands.js";
|
|
6
5
|
import { signAndSend } from "../../utils/tx.js";
|
|
7
6
|
import { relayerLogger as logger } from "../../utils/logger.js";
|
|
8
7
|
export class RelayerHttpServer {
|
|
@@ -58,14 +57,13 @@ export class RelayerHttpServer {
|
|
|
58
57
|
});
|
|
59
58
|
return;
|
|
60
59
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const signature = await signAndSend(this.ctx, ixs);
|
|
60
|
+
const requestCtx = body.rpcUrl
|
|
61
|
+
? this.ctx.withRpcUrl(body.rpcUrl)
|
|
62
|
+
: this.ctx;
|
|
63
|
+
await updateQuote(requestCtx, this.feedId);
|
|
64
|
+
const switchboardQuote = await this.getSwitchboardQuote(requestCtx);
|
|
65
|
+
const ixs = await withdrawIx(requestCtx, new Uint8Array(body.proof), new Uint8Array(body.root), new Uint8Array(body.nullifierHash), body.recipient, requestCtx.publicKey.toBase58(), BigInt(body.fee), BigInt(body.treasury), switchboardQuote, BigInt(body.amount));
|
|
66
|
+
const signature = await signAndSend(requestCtx, ixs);
|
|
69
67
|
logger.info({ signature }, "withdraw submitted");
|
|
70
68
|
res.json({
|
|
71
69
|
success: true,
|
|
@@ -73,10 +71,11 @@ export class RelayerHttpServer {
|
|
|
73
71
|
});
|
|
74
72
|
}
|
|
75
73
|
catch (error) {
|
|
76
|
-
|
|
74
|
+
let error_msg = error instanceof Error ? error.message : String(error);
|
|
75
|
+
logger.error({ error_msg }, "Failed to withdraw");
|
|
77
76
|
res.status(500).json({
|
|
78
77
|
success: false,
|
|
79
|
-
error:
|
|
78
|
+
error: error_msg,
|
|
80
79
|
});
|
|
81
80
|
}
|
|
82
81
|
}
|
|
@@ -97,6 +96,23 @@ export class RelayerHttpServer {
|
|
|
97
96
|
if (!body.recipient || typeof body.recipient !== "string") {
|
|
98
97
|
return "Invalid recipient: must be a string";
|
|
99
98
|
}
|
|
99
|
+
if (body.rpcUrl !== undefined) {
|
|
100
|
+
if (typeof body.rpcUrl !== "string") {
|
|
101
|
+
return "Invalid rpcUrl: must be a string";
|
|
102
|
+
}
|
|
103
|
+
if (body.rpcUrl.length > 2048) {
|
|
104
|
+
return "Invalid rpcUrl: too long";
|
|
105
|
+
}
|
|
106
|
+
try {
|
|
107
|
+
const parsed = new URL(body.rpcUrl);
|
|
108
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
109
|
+
return "Invalid rpcUrl: must use http or https";
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return "Invalid rpcUrl: not a valid URL";
|
|
114
|
+
}
|
|
115
|
+
}
|
|
100
116
|
for (const field of ["fee", "treasury", "amount"]) {
|
|
101
117
|
const value = body[field];
|
|
102
118
|
if (value === undefined || value === null) {
|
|
@@ -113,9 +129,9 @@ export class RelayerHttpServer {
|
|
|
113
129
|
}
|
|
114
130
|
return null;
|
|
115
131
|
}
|
|
116
|
-
async getSwitchboardQuote() {
|
|
132
|
+
async getSwitchboardQuote(ctx) {
|
|
117
133
|
const sb = await import("@switchboard-xyz/on-demand");
|
|
118
|
-
const queue = await sb.Queue.loadDefault(await sb.AnchorUtils.loadProgramFromConnection(
|
|
134
|
+
const queue = await sb.Queue.loadDefault(await sb.AnchorUtils.loadProgramFromConnection(ctx.connection));
|
|
119
135
|
const [quotePDA] = sb.OracleQuote.getCanonicalPubkey(queue.pubkey, [
|
|
120
136
|
this.feedId,
|
|
121
137
|
]);
|