@donezone/core 0.1.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 ADDED
@@ -0,0 +1,34 @@
1
+ # @donezone/core
2
+
3
+ TypeScript helpers for working with the Done JS contract runtime from Node/Bun tooling.
4
+
5
+ ## Features
6
+
7
+ - `WasmdClient` – thin wrapper around the `wasmd` binary with typed upload/instantiate helpers
8
+ - `deployJsContract` – convenience function that uploads `cw_js.wasm` and instantiates it with a JS
9
+ script (as used by the Done runtime)
10
+ - Command utilities for running child processes with predictable error handling
11
+
12
+ ## Example
13
+
14
+ ```ts
15
+ import { deployJsContract } from "@donezone/core";
16
+
17
+ const result = await deployJsContract({
18
+ scriptPath: "./packages/demo/contract/tokenSale.js",
19
+ from: "validator",
20
+ wasmd: {
21
+ chainId: "testing",
22
+ node: "http://127.0.0.1:26657",
23
+ keyringBackend: "test",
24
+ },
25
+ });
26
+
27
+ console.log("Contract address:", result.instantiate.contractAddress);
28
+ ```
29
+
30
+ You can supply `instantiateMsg` or `instantiateMsgPath` to pass custom state, as well as override the
31
+ `cw_js.wasm` path or admin/funds for the instantiate transaction.
32
+
33
+ The module is used by `@donezone/cli` and can be embedded in custom scripts to automate Done contract
34
+ operations.
@@ -0,0 +1,13 @@
1
+ export interface CommandOptions {
2
+ cwd?: string;
3
+ env?: NodeJS.ProcessEnv;
4
+ allowFail?: boolean;
5
+ stream?: boolean;
6
+ }
7
+ export interface CommandResult {
8
+ stdout: string;
9
+ stderr: string;
10
+ exitCode: number;
11
+ }
12
+ export declare function runCommand(cmd: string[], options?: CommandOptions): Promise<CommandResult>;
13
+ //# sourceMappingURL=command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../src/command.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,aAAa,CAAC,CA2C9F"}
@@ -0,0 +1,42 @@
1
+ import { spawn } from "node:child_process";
2
+ export function runCommand(cmd, options = {}) {
3
+ const { cwd, env, allowFail, stream } = options;
4
+ return new Promise((resolve, reject) => {
5
+ const child = spawn(cmd[0], cmd.slice(1), {
6
+ cwd,
7
+ env: { ...process.env, ...env },
8
+ stdio: stream ? "inherit" : "pipe",
9
+ });
10
+ if (stream) {
11
+ child.on("close", (exitCode) => {
12
+ const result = { stdout: "", stderr: "", exitCode: exitCode ?? 0 };
13
+ if (!allowFail && result.exitCode !== 0) {
14
+ reject(new Error(`command failed (${cmd.join(" ")}) with exit code ${result.exitCode}`));
15
+ }
16
+ else {
17
+ resolve(result);
18
+ }
19
+ });
20
+ child.on("error", reject);
21
+ return;
22
+ }
23
+ const stdoutChunks = [];
24
+ const stderrChunks = [];
25
+ child.stdout?.on("data", (chunk) => stdoutChunks.push(Buffer.from(chunk)));
26
+ child.stderr?.on("data", (chunk) => stderrChunks.push(Buffer.from(chunk)));
27
+ child.on("close", (exitCode) => {
28
+ const result = {
29
+ stdout: Buffer.concat(stdoutChunks).toString("utf8"),
30
+ stderr: Buffer.concat(stderrChunks).toString("utf8"),
31
+ exitCode: exitCode ?? 0,
32
+ };
33
+ if (!allowFail && result.exitCode !== 0) {
34
+ reject(new Error(result.stderr || result.stdout || `command failed (${cmd.join(" ")})`));
35
+ }
36
+ else {
37
+ resolve(result);
38
+ }
39
+ });
40
+ child.on("error", reject);
41
+ });
42
+ }
@@ -0,0 +1,20 @@
1
+ import { type WasmdConfig } from "./wasmd.js";
2
+ import type { InstantiateResult, UploadResult } from "./wasmd.js";
3
+ export interface DeployJsContractOptions {
4
+ scriptPath: string;
5
+ wasmPath?: string;
6
+ instantiateMsgPath?: string;
7
+ instantiateMsg?: Record<string, unknown>;
8
+ label?: string;
9
+ from: string;
10
+ admin?: string;
11
+ funds?: string;
12
+ wasmd?: WasmdConfig;
13
+ }
14
+ export interface DeployJsContractResult {
15
+ upload: UploadResult;
16
+ instantiate: InstantiateResult;
17
+ scriptPath: string;
18
+ }
19
+ export declare function deployJsContract(options: DeployJsContractOptions): Promise<DeployJsContractResult>;
20
+ //# sourceMappingURL=deploy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../src/deploy.ts"],"names":[],"mappings":"AAEA,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAElE,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,YAAY,CAAC;IACrB,WAAW,EAAE,iBAAiB,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CA0BxG"}
package/dist/deploy.js ADDED
@@ -0,0 +1,16 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { WasmdClient } from "./wasmd.js";
4
+ export async function deployJsContract(options) {
5
+ const { scriptPath, wasmPath = resolve("artifacts", "cw_js.wasm"), instantiateMsgPath, instantiateMsg, label = `done-js-${Date.now()}`, from, admin, funds, wasmd, } = options;
6
+ const script = readFileSync(resolve(scriptPath), "utf8");
7
+ const message = instantiateMsg ?? (instantiateMsgPath ? JSON.parse(readFileSync(instantiateMsgPath, "utf8")) : {});
8
+ const instantiatePayload = {
9
+ script,
10
+ msg: message,
11
+ };
12
+ const client = new WasmdClient(wasmd);
13
+ const upload = await client.upload(resolve(wasmPath), from);
14
+ const instantiate = await client.instantiate(upload.codeId, instantiatePayload, from, label, { admin, funds });
15
+ return { upload, instantiate, scriptPath: resolve(scriptPath) };
16
+ }
@@ -0,0 +1,4 @@
1
+ export * from "./command.js";
2
+ export * from "./wasmd.js";
3
+ export * from "./deploy.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from "./command.js";
2
+ export * from "./wasmd.js";
3
+ export * from "./deploy.js";
@@ -0,0 +1,34 @@
1
+ import { type CommandOptions } from "./command.js";
2
+ export interface WasmdConfig {
3
+ binary?: string;
4
+ home?: string;
5
+ node?: string;
6
+ chainId?: string;
7
+ from?: string;
8
+ gas?: string;
9
+ gasPrices?: string;
10
+ gasAdjustment?: string;
11
+ broadcastMode?: "block" | "sync" | "async";
12
+ keyringBackend?: "os" | "file" | "test";
13
+ }
14
+ export interface UploadResult {
15
+ codeId: string;
16
+ transactionHash: string;
17
+ }
18
+ export interface InstantiateResult {
19
+ contractAddress: string;
20
+ transactionHash: string;
21
+ }
22
+ export declare class WasmdClient {
23
+ private readonly config;
24
+ constructor(config?: WasmdConfig);
25
+ private args;
26
+ run(base: string[], options?: CommandOptions): Promise<import("./command.js").CommandResult>;
27
+ upload(wasmPath: string, from: string): Promise<UploadResult>;
28
+ instantiate(codeId: string, msg: unknown, from: string, label: string, options?: {
29
+ admin?: string;
30
+ funds?: string;
31
+ }): Promise<InstantiateResult>;
32
+ protected waitForTx(hash: string, attempts?: number, delayMs?: number): Promise<any>;
33
+ }
34
+ //# sourceMappingURL=wasmd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wasmd.d.ts","sourceRoot":"","sources":["../src/wasmd.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAE/D,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;IAC3C,cAAc,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;CACzC;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,iBAAiB;IAChC,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,GAAE,WAAgB;IAErD,OAAO,CAAC,IAAI;IAoBN,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,cAAmB;IAIhD,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IA6B7D,WAAW,CACf,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO,GAC/C,OAAO,CAAC,iBAAiB,CAAC;cA2Cb,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,SAAK,EAAE,OAAO,SAAO,GAAG,OAAO,CAAC,GAAG,CAAC;CAgBrF"}
package/dist/wasmd.js ADDED
@@ -0,0 +1,163 @@
1
+ import { runCommand } from "./command.js";
2
+ export class WasmdClient {
3
+ config;
4
+ constructor(config = {}) {
5
+ this.config = config;
6
+ }
7
+ args(base) {
8
+ const binary = this.config.binary ?? "wasmd";
9
+ const args = [binary, ...base];
10
+ const command = base[0];
11
+ if (this.config.home)
12
+ args.push("--home", this.config.home);
13
+ if (this.config.node)
14
+ args.push("--node", this.config.node);
15
+ if (command === "tx") {
16
+ if (this.config.chainId)
17
+ args.push("--chain-id", this.config.chainId);
18
+ if (this.config.gas)
19
+ args.push("--gas", this.config.gas);
20
+ if (this.config.gasPrices)
21
+ args.push("--gas-prices", this.config.gasPrices);
22
+ if (this.config.gasAdjustment)
23
+ args.push("--gas-adjustment", this.config.gasAdjustment);
24
+ if (this.config.broadcastMode)
25
+ args.push("--broadcast-mode", this.config.broadcastMode);
26
+ if (this.config.keyringBackend)
27
+ args.push("--keyring-backend", this.config.keyringBackend);
28
+ }
29
+ return args;
30
+ }
31
+ async run(base, options = {}) {
32
+ return runCommand(this.args(base), options);
33
+ }
34
+ async upload(wasmPath, from) {
35
+ const result = await this.run([
36
+ "tx",
37
+ "wasm",
38
+ "store",
39
+ wasmPath,
40
+ "--from",
41
+ from,
42
+ "--yes",
43
+ "--output",
44
+ "json",
45
+ ], { allowFail: false });
46
+ const parsed = JSON.parse(result.stdout);
47
+ if (parsed.code && Number(parsed.code) !== 0) {
48
+ throw new Error(parsed.raw_log ?? "store contract failed");
49
+ }
50
+ const tx = await this.waitForTx(parsed.txhash);
51
+ const codeIdAttr = findAttribute([tx, parsed], "code_id", "store_code") ??
52
+ findAttribute([tx, parsed], "code_id");
53
+ if (!codeIdAttr?.value) {
54
+ throw new Error("failed to extract code_id from store_code event");
55
+ }
56
+ return { codeId: codeIdAttr.value, transactionHash: parsed.txhash };
57
+ }
58
+ async instantiate(codeId, msg, from, label, options = {}) {
59
+ const instantiateArgs = [
60
+ "tx",
61
+ "wasm",
62
+ "instantiate",
63
+ codeId,
64
+ JSON.stringify(msg),
65
+ "--from",
66
+ from,
67
+ "--label",
68
+ label,
69
+ "--yes",
70
+ "--output",
71
+ "json",
72
+ ];
73
+ if (options.admin) {
74
+ instantiateArgs.push("--admin", options.admin);
75
+ }
76
+ else {
77
+ instantiateArgs.push("--no-admin");
78
+ }
79
+ if (options.funds) {
80
+ instantiateArgs.push("--amount", options.funds);
81
+ }
82
+ const result = await this.run(instantiateArgs);
83
+ const parsed = JSON.parse(result.stdout);
84
+ if (parsed.code && Number(parsed.code) !== 0) {
85
+ throw new Error(parsed.raw_log ?? "instantiate failed");
86
+ }
87
+ const tx = await this.waitForTx(parsed.txhash);
88
+ const contractAttr = findAttribute([tx, parsed], "_contract_address", "instantiate") ??
89
+ findAttribute([tx, parsed], "contract_address", "instantiate") ??
90
+ findAttribute([tx, parsed], "address", "instantiate") ??
91
+ findAttribute([tx, parsed], "_contract_address") ??
92
+ findAttribute([tx, parsed], "contract_address") ??
93
+ findAttribute([tx, parsed], "address");
94
+ if (!contractAttr?.value) {
95
+ throw new Error("failed to extract contract address from instantiate logs");
96
+ }
97
+ return { contractAddress: contractAttr.value, transactionHash: parsed.txhash };
98
+ }
99
+ async waitForTx(hash, attempts = 30, delayMs = 1000) {
100
+ for (let i = 0; i < attempts; i++) {
101
+ const res = await this.run(["query", "tx", hash, "--output", "json"], {
102
+ allowFail: true,
103
+ });
104
+ if (res.exitCode === 0 && res.stdout.trim()) {
105
+ try {
106
+ return JSON.parse(res.stdout);
107
+ }
108
+ catch {
109
+ // ignore parse error and retry
110
+ }
111
+ }
112
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
113
+ }
114
+ throw new Error(`tx (${hash}) not found after ${attempts} attempts`);
115
+ }
116
+ }
117
+ function findAttribute(source, key, type) {
118
+ if (!source)
119
+ return undefined;
120
+ if (Array.isArray(source)) {
121
+ for (const item of source) {
122
+ const match = findAttribute(item, key, type);
123
+ if (match)
124
+ return match;
125
+ }
126
+ return undefined;
127
+ }
128
+ const eventMatch = selectFromEvents(source.events, key, type);
129
+ if (eventMatch)
130
+ return eventMatch;
131
+ const logMatch = selectFromLogs(source.logs, key, type);
132
+ if (logMatch)
133
+ return logMatch;
134
+ if (source.tx_response) {
135
+ return findAttribute(source.tx_response, key, type);
136
+ }
137
+ return undefined;
138
+ }
139
+ function selectFromLogs(logs, key, type) {
140
+ if (!Array.isArray(logs))
141
+ return undefined;
142
+ for (const log of logs) {
143
+ const match = selectFromEvents(log?.events, key, type);
144
+ if (match)
145
+ return match;
146
+ }
147
+ return undefined;
148
+ }
149
+ function selectFromEvents(events, key, type) {
150
+ if (!Array.isArray(events))
151
+ return undefined;
152
+ for (const event of events) {
153
+ if (!event)
154
+ continue;
155
+ if (type && event.type !== type)
156
+ continue;
157
+ for (const attr of event.attributes ?? []) {
158
+ if (attr?.key === key)
159
+ return attr;
160
+ }
161
+ }
162
+ return undefined;
163
+ }
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@donezone/core",
3
+ "version": "0.1.0",
4
+ "private": false,
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/index.js",
10
+ "types": "./dist/index.d.ts"
11
+ }
12
+ },
13
+ "types": "dist/index.d.ts",
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsc -p tsconfig.json",
19
+ "clean": "rimraf dist",
20
+ "test": "bun test"
21
+ },
22
+ "dependencies": {
23
+ "@donezone/client": "^0.1.0"
24
+ },
25
+ "devDependencies": {
26
+ "rimraf": "^5.0.10",
27
+ "typescript": "^5.8.3"
28
+ },
29
+ "publishConfig": {
30
+ "access": "public"
31
+ }
32
+ }