rootchain-sdk 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/LICENSE +21 -0
- package/README.md +114 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/provider.d.ts +127 -0
- package/dist/provider.js +131 -0
- package/dist/signer.d.ts +19 -0
- package/dist/signer.js +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/wallet.d.ts +17 -0
- package/dist/wallet.js +69 -0
- package/package.json +50 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 RootChain
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# rootchain-sdk
|
|
2
|
+
|
|
3
|
+
<div align="center">
|
|
4
|
+
<h3>The Official TypeScript SDK for RootChain</h3>
|
|
5
|
+
<p>Communicate with RootChain nodes, deploy WASM smart contracts, and construct deterministic offline transactions seamlessly from any JavaScript environment.</p>
|
|
6
|
+
|
|
7
|
+
[](https://npmjs.org/package/rootchain-sdk)
|
|
8
|
+
[]()
|
|
9
|
+
[]()
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
The `rootchain-sdk` provides a clean, heavily-typed API wrapper over the `rootchain-rpc` JSON-RPC 2.0 endpoints. It empowers developers to build rich, reactive Web3 interfaces on top of the RootChain ecosystem with absolute minimal overhead.
|
|
15
|
+
|
|
16
|
+
## 📦 Installation
|
|
17
|
+
|
|
18
|
+
This package is optimized for modern toolchains (Node >= 18, Bun, Vite).
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install rootchain-sdk
|
|
22
|
+
# or
|
|
23
|
+
bun add rootchain-sdk
|
|
24
|
+
# or
|
|
25
|
+
yarn add rootchain-sdk
|
|
26
|
+
# or
|
|
27
|
+
pnpm add rootchain-sdk
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## âš¡ Core Features
|
|
31
|
+
|
|
32
|
+
* **100% Type-Safe**: Comprehensive types for transactions, blocks, receipts, and RRC network structs.
|
|
33
|
+
* **Offline Transaction Building**: Deterministically serialize and sign payloads completely offline, mitigating key-leakage attacks.
|
|
34
|
+
* **JSON-RPC Provider Wrapper**: Native `JsonRpcProvider` for network data, account querying, and telemetry extraction.
|
|
35
|
+
* **Key Derivation**: Securely derive Ed25519 paths via standard BIP-39 mnemonic recovery phrases.
|
|
36
|
+
* **WASM Deployment Ready**: Methods and structures natively adapted for deploying and querying sandboxed webassembly bytecodes.
|
|
37
|
+
|
|
38
|
+
## 🚀 Quick Start Guide
|
|
39
|
+
|
|
40
|
+
### 1. Initialize the Provider
|
|
41
|
+
|
|
42
|
+
Connect directly to your local node or remote `rootchain-rpc` endpoint:
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import { JsonRpcProvider } from 'rootchain-sdk';
|
|
46
|
+
|
|
47
|
+
// Initialize the generic provider
|
|
48
|
+
const provider = new JsonRpcProvider('http://localhost:8545');
|
|
49
|
+
|
|
50
|
+
// Fetch network status
|
|
51
|
+
const { height, chain_id } = await provider.getChainInfo();
|
|
52
|
+
console.log(`Connected to ${chain_id} at block ${height}`);
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 2. Wallet & Account Derivation
|
|
56
|
+
|
|
57
|
+
Derive your private keys deterministically and check your native balance securely:
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
import { Wallet } from 'rootchain-sdk';
|
|
61
|
+
|
|
62
|
+
// Instantiate a wallet connected to the provider
|
|
63
|
+
const privateKeyHex = "0x4f3c..."; // Ensure 32-bytes representation
|
|
64
|
+
const wallet = new Wallet(privateKeyHex, provider);
|
|
65
|
+
|
|
66
|
+
// Resolve public key representation
|
|
67
|
+
const address = await wallet.getAddress();
|
|
68
|
+
|
|
69
|
+
// Retrieve canonical balance and account nonce
|
|
70
|
+
const { balance, nonce } = await provider.getBalance(address);
|
|
71
|
+
console.log(`Remaining Balance: ${balance} micro-ROOT`);
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 3. Issue a Raw Transaction
|
|
75
|
+
|
|
76
|
+
Seamlessly instruct the provider to broadcast signed `Transfer` transitions directly to the PoA network:
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
const txReceipt = await wallet.sendTransaction({
|
|
80
|
+
tx_type: "Transfer",
|
|
81
|
+
to: "0x8888...", // 32-byte recipient Hash
|
|
82
|
+
amount: 1000000000000n, // BigInt for safe u128 handling
|
|
83
|
+
fee: 1000n, // Network execution fee
|
|
84
|
+
payload: new Uint8Array() // Zero-length buffer for standardized transfers
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
console.log(`Transaction successfully queued with hash: ${txReceipt.hash}`);
|
|
88
|
+
|
|
89
|
+
// Optionally, await network determinism
|
|
90
|
+
await provider.waitForTransaction(txReceipt.hash);
|
|
91
|
+
console.log('Transaction explicitly finalized within an immutable block!');
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## 📚 Advanced Documentation
|
|
95
|
+
|
|
96
|
+
### Submitting Equivocation Proofs
|
|
97
|
+
The SDK provides a built-in helper for submitting proofs of validator misbehavior:
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
const proof = {
|
|
101
|
+
validator: "0xaddr...",
|
|
102
|
+
height: 500,
|
|
103
|
+
round: 1,
|
|
104
|
+
hash_a: "0x...",
|
|
105
|
+
signature_a: "0x...",
|
|
106
|
+
hash_b: "0x...",
|
|
107
|
+
signature_b: "0x..."
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const { hash } = await provider.submitEquivocationProof(proof);
|
|
111
|
+
console.log(`Equivocation proof submitted: ${hash}`);
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
For deeper operational hooks into `rootchain-std` execution contracts (`ContractCall` and `ContractDeploy`), refer to the advanced ecosystem tutorials outlined in the `/docs` directory.
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
export interface ChainInfo {
|
|
2
|
+
height: number;
|
|
3
|
+
best_hash: string;
|
|
4
|
+
validators: string[];
|
|
5
|
+
slashed: string[];
|
|
6
|
+
chain_id: number;
|
|
7
|
+
}
|
|
8
|
+
export interface BalanceInfo {
|
|
9
|
+
balance: string;
|
|
10
|
+
nonce: number;
|
|
11
|
+
}
|
|
12
|
+
export interface Transaction {
|
|
13
|
+
tx_type: string;
|
|
14
|
+
from: number[] | string;
|
|
15
|
+
to: number[] | string;
|
|
16
|
+
amount: string;
|
|
17
|
+
fee: string;
|
|
18
|
+
nonce: number;
|
|
19
|
+
payload: number[] | string;
|
|
20
|
+
signature: number[] | string;
|
|
21
|
+
}
|
|
22
|
+
export interface ContractEvent {
|
|
23
|
+
contract_address: string;
|
|
24
|
+
topics: string[];
|
|
25
|
+
data: string;
|
|
26
|
+
}
|
|
27
|
+
export interface TransactionReceipt {
|
|
28
|
+
transaction: Transaction;
|
|
29
|
+
block_height: number;
|
|
30
|
+
block_hash: string;
|
|
31
|
+
events: ContractEvent[];
|
|
32
|
+
gas_used: string;
|
|
33
|
+
success: boolean;
|
|
34
|
+
error?: string;
|
|
35
|
+
transaction_hash?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface EquivocationProof {
|
|
38
|
+
validator: string;
|
|
39
|
+
height: number;
|
|
40
|
+
round: number;
|
|
41
|
+
hash_a: string;
|
|
42
|
+
signature_a: string;
|
|
43
|
+
hash_b: string;
|
|
44
|
+
signature_b: string;
|
|
45
|
+
}
|
|
46
|
+
export interface Block {
|
|
47
|
+
header: {
|
|
48
|
+
height: number;
|
|
49
|
+
prev_hash: number[] | string;
|
|
50
|
+
merkle_root: number[] | string;
|
|
51
|
+
state_root: number[] | string;
|
|
52
|
+
proposer: number[] | string;
|
|
53
|
+
timestamp: number;
|
|
54
|
+
signature: number[] | string;
|
|
55
|
+
};
|
|
56
|
+
transactions: Transaction[];
|
|
57
|
+
}
|
|
58
|
+
export interface GovernanceProposal {
|
|
59
|
+
id: string;
|
|
60
|
+
type: string;
|
|
61
|
+
params: any;
|
|
62
|
+
status: 'Active' | 'Passed' | 'Failed';
|
|
63
|
+
signatures: number;
|
|
64
|
+
threshold: number;
|
|
65
|
+
description: string;
|
|
66
|
+
created_at: number;
|
|
67
|
+
}
|
|
68
|
+
export interface PeerInfo {
|
|
69
|
+
peer_id: string;
|
|
70
|
+
address: string;
|
|
71
|
+
rtt_ms: number;
|
|
72
|
+
height: number;
|
|
73
|
+
}
|
|
74
|
+
export interface ContractCode {
|
|
75
|
+
address: string;
|
|
76
|
+
bytecode: string;
|
|
77
|
+
bytecode_hex: string;
|
|
78
|
+
}
|
|
79
|
+
export interface StorageValue {
|
|
80
|
+
key: string;
|
|
81
|
+
value: string | null;
|
|
82
|
+
}
|
|
83
|
+
export declare class JsonRpcProvider {
|
|
84
|
+
readonly url: string;
|
|
85
|
+
constructor(url?: string);
|
|
86
|
+
send<T>(method: string, params?: any[]): Promise<T>;
|
|
87
|
+
getBalance(address: string): Promise<{
|
|
88
|
+
balance: string;
|
|
89
|
+
nonce: number;
|
|
90
|
+
}>;
|
|
91
|
+
sendRawTransaction(tx: any): Promise<{
|
|
92
|
+
hash: string;
|
|
93
|
+
contractAddress?: string;
|
|
94
|
+
}>;
|
|
95
|
+
getChainInfo(): Promise<ChainInfo>;
|
|
96
|
+
getFinalizedBlock(): Promise<Block | null>;
|
|
97
|
+
submitProposal(proposalHex: string, fromAddress: string, fee?: number): Promise<{
|
|
98
|
+
status: string;
|
|
99
|
+
tx_hash: string;
|
|
100
|
+
}>;
|
|
101
|
+
getGovernanceProposals(): Promise<GovernanceProposal[]>;
|
|
102
|
+
getPeerInfo(): Promise<PeerInfo[]>;
|
|
103
|
+
getCode(address: string): Promise<ContractCode>;
|
|
104
|
+
getStorageAt(address: string, key: string): Promise<StorageValue>;
|
|
105
|
+
getBlock(id: string | number): Promise<Block | null>;
|
|
106
|
+
getBlocks(endHeight?: number, limit?: number): Promise<Block[]>;
|
|
107
|
+
getTransaction(hash: string): Promise<TransactionReceipt | null>;
|
|
108
|
+
getTransactionsByAddress(address: string, limit?: number, offset?: number): Promise<TransactionReceipt[]>;
|
|
109
|
+
getLogs(filter: {
|
|
110
|
+
address?: string;
|
|
111
|
+
fromBlock?: number;
|
|
112
|
+
toBlock?: number;
|
|
113
|
+
}): Promise<any[]>;
|
|
114
|
+
submitEquivocationProof(proof: EquivocationProof): Promise<{
|
|
115
|
+
hash: string;
|
|
116
|
+
}>;
|
|
117
|
+
getMetadata(address: string): Promise<{
|
|
118
|
+
metadata: string;
|
|
119
|
+
} | null>;
|
|
120
|
+
waitForTransaction(hash: string, timeoutMs?: number): Promise<TransactionReceipt>;
|
|
121
|
+
}
|
|
122
|
+
export declare class EventDecoder {
|
|
123
|
+
/**
|
|
124
|
+
* Decodes a raw contract event using the contract's metadata schema.
|
|
125
|
+
*/
|
|
126
|
+
static decode(event: ContractEvent, metadataJson: string | any): any;
|
|
127
|
+
}
|
package/dist/provider.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
export class JsonRpcProvider {
|
|
2
|
+
url;
|
|
3
|
+
constructor(url) {
|
|
4
|
+
// @ts-ignore
|
|
5
|
+
const envUrl = typeof process !== 'undefined' ? process.env.VITE_RPC_URL || process.env.RPC_URL : undefined;
|
|
6
|
+
// @ts-ignore
|
|
7
|
+
const metaUrl = typeof import.meta !== 'undefined' && import.meta.env ? import.meta.env.VITE_RPC_URL : undefined;
|
|
8
|
+
this.url = url || metaUrl || envUrl || 'http://127.0.0.1:8545';
|
|
9
|
+
}
|
|
10
|
+
async send(method, params = []) {
|
|
11
|
+
const response = await fetch(this.url, {
|
|
12
|
+
method: "POST",
|
|
13
|
+
headers: { "Content-Type": "application/json" },
|
|
14
|
+
body: JSON.stringify({
|
|
15
|
+
jsonrpc: "2.0",
|
|
16
|
+
method,
|
|
17
|
+
params,
|
|
18
|
+
id: Date.now(),
|
|
19
|
+
}),
|
|
20
|
+
});
|
|
21
|
+
if (!response.ok) {
|
|
22
|
+
throw new Error(`HTTP Error: ${response.status}`);
|
|
23
|
+
}
|
|
24
|
+
const data = await response.json();
|
|
25
|
+
if (data.error) {
|
|
26
|
+
throw new Error(data.error.message);
|
|
27
|
+
}
|
|
28
|
+
return data.result;
|
|
29
|
+
}
|
|
30
|
+
async getBalance(address) {
|
|
31
|
+
return this.send("rootchain_getBalance", [address]);
|
|
32
|
+
}
|
|
33
|
+
async sendRawTransaction(tx) {
|
|
34
|
+
const result = await this.send("rootchain_sendRawTransaction", [tx]);
|
|
35
|
+
return {
|
|
36
|
+
hash: result.hash,
|
|
37
|
+
contractAddress: result.contractAddress || result.contract_address,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
getChainInfo() {
|
|
41
|
+
return this.send('rootchain_getChainInfo');
|
|
42
|
+
}
|
|
43
|
+
getFinalizedBlock() {
|
|
44
|
+
return this.send('rootchain_getFinalizedBlock');
|
|
45
|
+
}
|
|
46
|
+
submitProposal(proposalHex, fromAddress, fee = 100) {
|
|
47
|
+
return this.send('rootchain_submitProposal', [proposalHex, fromAddress, fee]);
|
|
48
|
+
}
|
|
49
|
+
getGovernanceProposals() {
|
|
50
|
+
return this.send('rootchain_listProposals');
|
|
51
|
+
}
|
|
52
|
+
getPeerInfo() {
|
|
53
|
+
return this.send('rootchain_getNetworkTopology');
|
|
54
|
+
}
|
|
55
|
+
getCode(address) {
|
|
56
|
+
return this.send('rootchain_getCode', [address]);
|
|
57
|
+
}
|
|
58
|
+
getStorageAt(address, key) {
|
|
59
|
+
return this.send('rootchain_getStorageAt', [address, key]);
|
|
60
|
+
}
|
|
61
|
+
getBlock(id) {
|
|
62
|
+
return this.send('rootchain_getBlock', [id]);
|
|
63
|
+
}
|
|
64
|
+
async getBlocks(endHeight, limit = 20) {
|
|
65
|
+
// If no endHeight passed, first get the current chain height
|
|
66
|
+
if (endHeight === undefined) {
|
|
67
|
+
const info = await this.getChainInfo().catch(() => null);
|
|
68
|
+
endHeight = info?.height ?? 0;
|
|
69
|
+
}
|
|
70
|
+
return this.send('rootchain_getBlocks', [endHeight, limit]);
|
|
71
|
+
}
|
|
72
|
+
getTransaction(hash) {
|
|
73
|
+
return this.send('rootchain_getTransaction', [hash]);
|
|
74
|
+
}
|
|
75
|
+
getTransactionsByAddress(address, limit = 10, offset = 0) {
|
|
76
|
+
return this.send('rootchain_getTransactionsByAddress', [address, limit, offset]);
|
|
77
|
+
}
|
|
78
|
+
async getLogs(filter) {
|
|
79
|
+
return this.send("rootchain_getLogs", [filter]);
|
|
80
|
+
}
|
|
81
|
+
async submitEquivocationProof(proof) {
|
|
82
|
+
return this.send("rootchain_submitEquivocationProof", [proof]);
|
|
83
|
+
}
|
|
84
|
+
async getMetadata(address) {
|
|
85
|
+
return this.send('rootchain_getMetadata', [address]);
|
|
86
|
+
}
|
|
87
|
+
async waitForTransaction(hash, timeoutMs = 60000) {
|
|
88
|
+
const start = Date.now();
|
|
89
|
+
while (Date.now() - start < timeoutMs) {
|
|
90
|
+
const receipt = await this.getTransaction(hash);
|
|
91
|
+
if (receipt)
|
|
92
|
+
return receipt;
|
|
93
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
94
|
+
}
|
|
95
|
+
throw new Error(`Timeout waiting for transaction ${hash}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
export class EventDecoder {
|
|
99
|
+
/**
|
|
100
|
+
* Decodes a raw contract event using the contract's metadata schema.
|
|
101
|
+
*/
|
|
102
|
+
static decode(event, metadataJson) {
|
|
103
|
+
try {
|
|
104
|
+
const metadata = typeof metadataJson === 'string' ? JSON.parse(metadataJson) : metadataJson;
|
|
105
|
+
if (!metadata || !metadata.events)
|
|
106
|
+
return event;
|
|
107
|
+
// Simple matching: find event with same number of topics
|
|
108
|
+
for (const [name, schema] of Object.entries(metadata.events)) {
|
|
109
|
+
const s = schema;
|
|
110
|
+
if (event.topics.length === s.topics.length) {
|
|
111
|
+
const params = {};
|
|
112
|
+
s.topics.forEach((topicName, i) => {
|
|
113
|
+
params[topicName] = event.topics[i];
|
|
114
|
+
});
|
|
115
|
+
if (s.data) {
|
|
116
|
+
params[s.data] = event.data;
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
name,
|
|
120
|
+
address: event.contract_address,
|
|
121
|
+
parameters: params
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch (e) {
|
|
127
|
+
console.error("Failed to decode event:", e);
|
|
128
|
+
}
|
|
129
|
+
return event;
|
|
130
|
+
}
|
|
131
|
+
}
|
package/dist/signer.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { JsonRpcProvider } from "./provider.js";
|
|
2
|
+
export interface TransactionRequest {
|
|
3
|
+
tx_type: string;
|
|
4
|
+
from?: string;
|
|
5
|
+
to?: string;
|
|
6
|
+
amount?: bigint | string | number;
|
|
7
|
+
fee?: bigint | string | number;
|
|
8
|
+
nonce?: number;
|
|
9
|
+
payload?: Uint8Array;
|
|
10
|
+
}
|
|
11
|
+
export interface Signer {
|
|
12
|
+
getAddress(): Promise<string>;
|
|
13
|
+
signTransaction(tx: TransactionRequest): Promise<string>;
|
|
14
|
+
sendTransaction(tx: TransactionRequest): Promise<{
|
|
15
|
+
hash: string;
|
|
16
|
+
contractAddress?: string;
|
|
17
|
+
}>;
|
|
18
|
+
connect(provider: JsonRpcProvider): Signer;
|
|
19
|
+
}
|
package/dist/signer.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"root":["../src/index.ts","../src/provider.ts","../src/signer.ts","../src/wallet.ts"],"version":"5.9.3"}
|
package/dist/wallet.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { JsonRpcProvider } from "./provider.js";
|
|
2
|
+
import type { Signer, TransactionRequest } from "./signer.js";
|
|
3
|
+
export declare class Wallet implements Signer {
|
|
4
|
+
private address?;
|
|
5
|
+
readonly privateKeyHex: string;
|
|
6
|
+
readonly provider?: JsonRpcProvider;
|
|
7
|
+
constructor(privateKeyHex: string, provider?: JsonRpcProvider);
|
|
8
|
+
connect(provider: JsonRpcProvider): Wallet;
|
|
9
|
+
getAddress(): Promise<string>;
|
|
10
|
+
getContractAddress(nonce: number): Promise<string>;
|
|
11
|
+
signTransaction(tx: TransactionRequest): Promise<string>;
|
|
12
|
+
sendTransaction(tx: TransactionRequest): Promise<{
|
|
13
|
+
hash: string;
|
|
14
|
+
contractAddress?: string;
|
|
15
|
+
}>;
|
|
16
|
+
private hexToBytes;
|
|
17
|
+
}
|
package/dist/wallet.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { get_address_from_key, sign_transaction, get_contract_address } from "rootchain-wasm";
|
|
2
|
+
export class Wallet {
|
|
3
|
+
address;
|
|
4
|
+
privateKeyHex;
|
|
5
|
+
provider;
|
|
6
|
+
constructor(privateKeyHex, provider) {
|
|
7
|
+
this.privateKeyHex = privateKeyHex;
|
|
8
|
+
this.provider = provider;
|
|
9
|
+
}
|
|
10
|
+
connect(provider) {
|
|
11
|
+
return new Wallet(this.privateKeyHex, provider);
|
|
12
|
+
}
|
|
13
|
+
async getAddress() {
|
|
14
|
+
if (this.address)
|
|
15
|
+
return this.address;
|
|
16
|
+
const cleanKey = this.privateKeyHex.replace("0x", "");
|
|
17
|
+
const result = get_address_from_key(cleanKey);
|
|
18
|
+
this.address = typeof result === "string" ? result : result.toString();
|
|
19
|
+
return this.address;
|
|
20
|
+
}
|
|
21
|
+
async getContractAddress(nonce) {
|
|
22
|
+
const address = await this.getAddress();
|
|
23
|
+
return get_contract_address(address, BigInt(nonce));
|
|
24
|
+
}
|
|
25
|
+
async signTransaction(tx) {
|
|
26
|
+
// Fill missing fields
|
|
27
|
+
const fullTx = {
|
|
28
|
+
tx_type: tx.tx_type,
|
|
29
|
+
from: Array(32).fill(0), // WASM overwrites this anyway based on private key
|
|
30
|
+
to: tx.to ? this.hexToBytes(tx.to) : Array(32).fill(0),
|
|
31
|
+
amount: tx.amount?.toString() ?? "0",
|
|
32
|
+
fee: tx.fee?.toString() ?? "1000",
|
|
33
|
+
nonce: tx.nonce ?? 1,
|
|
34
|
+
payload: tx.payload ? Array.from(tx.payload) : [],
|
|
35
|
+
signature: Array(64).fill(0)
|
|
36
|
+
};
|
|
37
|
+
const cleanKey = this.privateKeyHex.replace("0x", "");
|
|
38
|
+
return sign_transaction(JSON.stringify(fullTx), cleanKey);
|
|
39
|
+
}
|
|
40
|
+
async sendTransaction(tx) {
|
|
41
|
+
if (!this.provider) {
|
|
42
|
+
throw new Error("Wallet is not connected to a Provider");
|
|
43
|
+
}
|
|
44
|
+
const address = await this.getAddress();
|
|
45
|
+
// Auto-fetch nonce if not provided
|
|
46
|
+
if (tx.nonce === undefined) {
|
|
47
|
+
const { nonce } = await this.provider.getBalance(address);
|
|
48
|
+
tx.nonce = nonce + 1; // Expected nonce is current recorded nonce + 1
|
|
49
|
+
}
|
|
50
|
+
let predictedAddress;
|
|
51
|
+
if (tx.tx_type === "ContractDeploy") {
|
|
52
|
+
predictedAddress = await this.getContractAddress(tx.nonce);
|
|
53
|
+
}
|
|
54
|
+
const signedTxJson = await this.signTransaction(tx);
|
|
55
|
+
const result = await this.provider.sendRawTransaction(JSON.parse(signedTxJson));
|
|
56
|
+
return {
|
|
57
|
+
hash: result.hash,
|
|
58
|
+
contractAddress: result.contractAddress || predictedAddress
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
hexToBytes(hex) {
|
|
62
|
+
const cleanHex = hex.replace("0x", "");
|
|
63
|
+
const bytes = new Uint8Array(cleanHex.length / 2);
|
|
64
|
+
for (let i = 0; i < cleanHex.length; i += 2) {
|
|
65
|
+
bytes[i / 2] = parseInt(cleanHex.substring(i, i + 2), 16);
|
|
66
|
+
}
|
|
67
|
+
return Array.from(bytes);
|
|
68
|
+
}
|
|
69
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "rootchain-sdk",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "The Official TypeScript SDK for RootChain - High-precision RPC client.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"README.md",
|
|
11
|
+
"LICENSE"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc -b",
|
|
15
|
+
"prepublishOnly": "npm run build"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/BronzonTech-Cloud/rootchain.git"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"rootchain",
|
|
23
|
+
"blockchain",
|
|
24
|
+
"sdk",
|
|
25
|
+
"u128",
|
|
26
|
+
"wasm",
|
|
27
|
+
"wallet"
|
|
28
|
+
],
|
|
29
|
+
"author": "Charles Bronzon",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"bugs": {
|
|
32
|
+
"url": "https://github.com/BronzonTech-Cloud/rootchain/issues"
|
|
33
|
+
},
|
|
34
|
+
"homepage": "https://github.com/BronzonTech-Cloud/rootchain#readme",
|
|
35
|
+
"exports": {
|
|
36
|
+
".": {
|
|
37
|
+
"types": "./dist/index.d.ts",
|
|
38
|
+
"default": "./dist/index.js"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"rootchain-wasm": "^1.0.1"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"typescript": "^5.0.0"
|
|
46
|
+
},
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public"
|
|
49
|
+
}
|
|
50
|
+
}
|