@offckb/cli 0.1.0-rc1 → 0.1.0-rc3
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 +31 -9
- package/dist/cli.js +11 -11
- package/package.json +2 -2
- package/template/ckb.ts +11 -0
- package/template/config.json +63 -0
- package/template/index.html +13 -0
- package/template/index.tsx +55 -0
- package/template/lib.ts +153 -0
- package/template/package.json +29 -0
- package/template/tsconfig.json +10 -0
- package/template/yarn.lock +2315 -0
package/README.md
CHANGED
|
@@ -5,24 +5,46 @@ ckb development environment for professionals
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
7
7
|
```sh
|
|
8
|
-
|
|
9
|
-
cd offckb && alias offckb='yarn start'
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
eventually you will do simple
|
|
13
|
-
```sh
|
|
14
|
-
npm install -g offckb // not yet, todo
|
|
8
|
+
npm install -g @offckb/cli
|
|
15
9
|
```
|
|
16
10
|
|
|
17
11
|
## Usage
|
|
18
12
|
|
|
19
13
|
```sh
|
|
20
14
|
offckb node // start the devnet of CKB
|
|
21
|
-
offckb init // init a typescript boilerplate with lumos to get started with to build CKB DAPP,think 'hardhat init'
|
|
22
|
-
offckb list-hashes // list scripts hashes, equals `ckb list-hashes`
|
|
15
|
+
offckb init <project-name> // init a typescript boilerplate with lumos to get started with to build CKB DAPP,think 'hardhat init'
|
|
23
16
|
offckb accounts // list 20 accounts info with prefund CKB tokens
|
|
17
|
+
offckb list-hashes // list scripts hashes, equals `ckb list-hashes`
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Get started
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
offckb init my-awesome-ckb-dapp
|
|
24
|
+
cd my-awesome-ckb-dapp
|
|
25
|
+
yarn && yarn start
|
|
26
|
+
|
|
27
|
+
## results
|
|
28
|
+
yarn run v1.22.19
|
|
29
|
+
$ parcel index.html
|
|
30
|
+
Server running at http://localhost:1234
|
|
31
|
+
✨ Built in 10ms
|
|
24
32
|
```
|
|
25
33
|
|
|
34
|
+
open another terminal and start the devnet:
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
offckb node
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
open another terminal and check the accounts to use:
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
offckb accounts
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Copy some private keys and visit http://localhost:1234 to play basic CKB transfer!
|
|
47
|
+
|
|
26
48
|
### Built-in scripts
|
|
27
49
|
|
|
28
50
|
- [x] xUDT https://github.com/nervosnetwork/rfcs/pull/428
|
package/dist/cli.js
CHANGED
|
@@ -16,11 +16,20 @@ program
|
|
|
16
16
|
.name('offckb')
|
|
17
17
|
.description('CLI to provide full ckb development environment for professionals')
|
|
18
18
|
.version(version);
|
|
19
|
+
program
|
|
20
|
+
.command('init')
|
|
21
|
+
.description('init dapp project with lumos')
|
|
22
|
+
.argument('<string>', 'name of the dapp')
|
|
23
|
+
.action((str) => {
|
|
24
|
+
const name = str !== null && str !== void 0 ? str : 'offckb-dapp';
|
|
25
|
+
return (0, init_1.init)(name);
|
|
26
|
+
});
|
|
27
|
+
program.command('node').description('Use the CKB to start devnet').action(node_1.node);
|
|
28
|
+
program.command('accounts').description('print account list info').action(accounts_1.accounts);
|
|
29
|
+
program.command('list-hashes').description('Use the CKB to list blockchain scripts hashes').action(list_hashes_1.listHashes);
|
|
19
30
|
// Define the CLI commands and options
|
|
20
31
|
program.command('install').description('Install the ckb dependency binary').action(install_1.installDependency);
|
|
21
32
|
program.command('genkey').description('generate 20 accounts').action(genkey_1.genkey);
|
|
22
|
-
program.command('list-hashes').description('Use the CKB to list blockchain scripts hashes').action(list_hashes_1.listHashes);
|
|
23
|
-
program.command('node').description('Use the CKB to start devnet').action(node_1.node);
|
|
24
33
|
program.command('init-chain').description('Use the CKB to init devnet').action(init_chain_1.initChainIfNeeded);
|
|
25
34
|
program.command('build-lumos-config').description('Use the CKB to generate lumos config.json').action(build_lumos_config_1.buildLumosConfig);
|
|
26
35
|
program.command('build-accounts').description('generate accounts with prefunded CKB tokens').action(genkey_1.buildAccounts);
|
|
@@ -28,15 +37,6 @@ program
|
|
|
28
37
|
.command('print-account-issue-info')
|
|
29
38
|
.description('print account issue cells config toml sections')
|
|
30
39
|
.action(genkey_1.printIssueSectionForToml);
|
|
31
|
-
program.command('accounts').description('print account list info').action(accounts_1.accounts);
|
|
32
|
-
program
|
|
33
|
-
.command('init')
|
|
34
|
-
.description('init dapp project with lumos')
|
|
35
|
-
.argument('<string>', 'name of the dapp')
|
|
36
|
-
.action((str) => {
|
|
37
|
-
const name = str !== null && str !== void 0 ? str : 'offckb-dapp';
|
|
38
|
-
return (0, init_1.init)(name);
|
|
39
|
-
});
|
|
40
40
|
// Parse command-line arguments
|
|
41
41
|
program.parse(process.argv);
|
|
42
42
|
// If no command is specified, display help
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@offckb/cli",
|
|
3
|
-
"version": "0.1.0-
|
|
3
|
+
"version": "0.1.0-rc3",
|
|
4
4
|
"description": "ckb development environment for professionals",
|
|
5
5
|
"author": "Retric Su <retric@cryptape.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"dist",
|
|
17
17
|
"account",
|
|
18
18
|
"docker",
|
|
19
|
-
"
|
|
19
|
+
"template"
|
|
20
20
|
],
|
|
21
21
|
"private": false,
|
|
22
22
|
"publishConfig": {
|
package/template/ckb.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Indexer, RPC, config } from '@ckb-lumos/lumos';
|
|
2
|
+
import devConfig from './config.json';
|
|
3
|
+
|
|
4
|
+
export const lumosConfig: config.Config = devConfig as config.Config;
|
|
5
|
+
//export const lumosConfig: config.Config = config.predefined.AGGRON4;
|
|
6
|
+
|
|
7
|
+
export const CKB_RPC_URL = 'http://localhost:8114';
|
|
8
|
+
//export const CKB_RPC_URL = "https://testnet.ckb.dev/rpc";
|
|
9
|
+
|
|
10
|
+
export const rpc = new RPC(CKB_RPC_URL);
|
|
11
|
+
export const indexer = new Indexer(CKB_RPC_URL);
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"PREFIX": "ckt",
|
|
3
|
+
"SCRIPTS": {
|
|
4
|
+
"SECP256K1_BLAKE160": {
|
|
5
|
+
"CODE_HASH": "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8",
|
|
6
|
+
"HASH_TYPE": "type",
|
|
7
|
+
"TX_HASH": "0x37f2b7799b199491f4732c572c086afdace0bf92992faf0b90bae44cdd119f9e",
|
|
8
|
+
"INDEX": "0x0",
|
|
9
|
+
"DEP_TYPE": "depGroup",
|
|
10
|
+
"SHORT_ID": 1
|
|
11
|
+
},
|
|
12
|
+
"SECP256K1_BLAKE160_MULTISIG": {
|
|
13
|
+
"CODE_HASH": "0x5c5069eb0857efc65e1bca0c07df34c31663b3622fd3876c876320fc9634e2a8",
|
|
14
|
+
"HASH_TYPE": "type",
|
|
15
|
+
"TX_HASH": "0x37f2b7799b199491f4732c572c086afdace0bf92992faf0b90bae44cdd119f9e",
|
|
16
|
+
"INDEX": "0x1",
|
|
17
|
+
"DEP_TYPE": "depGroup"
|
|
18
|
+
},
|
|
19
|
+
"DAO": {
|
|
20
|
+
"CODE_HASH": "0x82d76d1b75fe2fd9a27dfbaa65a039221a380d76c926f378d3f81cf3e7e13f2e",
|
|
21
|
+
"HASH_TYPE": "type",
|
|
22
|
+
"TX_HASH": "0x920bb4250dc6216c08ee0713f86b3fcb01bf444027b08b7d92db0ed1c0fb9214",
|
|
23
|
+
"INDEX": "0x2",
|
|
24
|
+
"DEP_TYPE": "code",
|
|
25
|
+
"SHORT_ID": 2
|
|
26
|
+
},
|
|
27
|
+
"SUDT": {
|
|
28
|
+
"CODE_HASH": "0x6283a479a3cf5d4276cd93594de9f1827ab9b55c7b05b3d28e4c2e0a696cfefd",
|
|
29
|
+
"HASH_TYPE": "type",
|
|
30
|
+
"TX_HASH": "0x920bb4250dc6216c08ee0713f86b3fcb01bf444027b08b7d92db0ed1c0fb9214",
|
|
31
|
+
"INDEX": "0x5",
|
|
32
|
+
"DEP_TYPE": "code"
|
|
33
|
+
},
|
|
34
|
+
"XUDT": {
|
|
35
|
+
"CODE_HASH": "0x1a1e4fef34f5982906f745b048fe7b1089647e82346074e0f32c2ece26cf6b1e",
|
|
36
|
+
"HASH_TYPE": "type",
|
|
37
|
+
"TX_HASH": "0x920bb4250dc6216c08ee0713f86b3fcb01bf444027b08b7d92db0ed1c0fb9214",
|
|
38
|
+
"INDEX": "0x6",
|
|
39
|
+
"DEP_TYPE": "code"
|
|
40
|
+
},
|
|
41
|
+
"OMNILOCK": {
|
|
42
|
+
"CODE_HASH": "0x9c6933d977360f115a3e9cd5a2e0e475853681b80d775d93ad0f8969da343e56",
|
|
43
|
+
"HASH_TYPE": "type",
|
|
44
|
+
"TX_HASH": "0x920bb4250dc6216c08ee0713f86b3fcb01bf444027b08b7d92db0ed1c0fb9214",
|
|
45
|
+
"INDEX": "0x7",
|
|
46
|
+
"DEP_TYPE": "code"
|
|
47
|
+
},
|
|
48
|
+
"ANYONE_CAN_PAY": {
|
|
49
|
+
"CODE_HASH": "0xe09352af0066f3162287763ce4ddba9af6bfaeab198dc7ab37f8c71c9e68bb5b",
|
|
50
|
+
"HASH_TYPE": "type",
|
|
51
|
+
"TX_HASH": "0x920bb4250dc6216c08ee0713f86b3fcb01bf444027b08b7d92db0ed1c0fb9214",
|
|
52
|
+
"INDEX": "0x8",
|
|
53
|
+
"DEP_TYPE": "code"
|
|
54
|
+
},
|
|
55
|
+
"ALWAYS_SUCCESS": {
|
|
56
|
+
"CODE_HASH": "0xbb4469004225b39e983929db71fe2253cba1d49a76223e9e1d212cdca1f79f28",
|
|
57
|
+
"HASH_TYPE": "type",
|
|
58
|
+
"TX_HASH": "0x920bb4250dc6216c08ee0713f86b3fcb01bf444027b08b7d92db0ed1c0fb9214",
|
|
59
|
+
"INDEX": "0x9",
|
|
60
|
+
"DEP_TYPE": "code"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>happy coding with offckb</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="root"></div>
|
|
11
|
+
<script src="index.tsx" type="module"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
import ReactDOM from 'react-dom';
|
|
3
|
+
import { Script } from '@ckb-lumos/lumos';
|
|
4
|
+
import { capacityOf, generateAccountFromPrivateKey, transfer } from './lib';
|
|
5
|
+
|
|
6
|
+
const app = document.getElementById('root');
|
|
7
|
+
ReactDOM.render(<App />, app);
|
|
8
|
+
|
|
9
|
+
export function App() {
|
|
10
|
+
const [privKey, setPrivKey] = useState('');
|
|
11
|
+
const [fromAddr, setFromAddr] = useState('');
|
|
12
|
+
const [fromLock, setFromLock] = useState<Script>();
|
|
13
|
+
const [balance, setBalance] = useState('0');
|
|
14
|
+
|
|
15
|
+
const [toAddr, setToAddr] = useState('');
|
|
16
|
+
const [amount, setAmount] = useState('');
|
|
17
|
+
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
const updateFromInfo = async () => {
|
|
20
|
+
const { lockScript, address } = generateAccountFromPrivateKey(privKey);
|
|
21
|
+
const capacity = await capacityOf(address);
|
|
22
|
+
setFromAddr(address);
|
|
23
|
+
setFromLock(lockScript);
|
|
24
|
+
setBalance(capacity.toString());
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
if (privKey) {
|
|
28
|
+
updateFromInfo();
|
|
29
|
+
}
|
|
30
|
+
}, [privKey]);
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<div>
|
|
34
|
+
<label htmlFor="private-key">Private Key: </label>
|
|
35
|
+
<input id="private-key" type="text" onChange={(e) => setPrivKey(e.target.value)} />
|
|
36
|
+
<ul>
|
|
37
|
+
<li>CKB Address: {fromAddr}</li>
|
|
38
|
+
<li>
|
|
39
|
+
Current lock script:
|
|
40
|
+
<pre>{JSON.stringify(fromLock, null, 2)}</pre>
|
|
41
|
+
</li>
|
|
42
|
+
|
|
43
|
+
<li>Total capacity: {balance}</li>
|
|
44
|
+
</ul>
|
|
45
|
+
<label htmlFor="to-address">Transfer to Address: </label>
|
|
46
|
+
<input id="to-address" type="text" onChange={(e) => setToAddr(e.target.value)} />
|
|
47
|
+
<br />
|
|
48
|
+
<label htmlFor="amount">Amount</label>
|
|
49
|
+
|
|
50
|
+
<input id="amount" type="text" onChange={(e) => setAmount(e.target.value)} />
|
|
51
|
+
<br />
|
|
52
|
+
<button onClick={() => transfer({ amount, from: fromAddr, to: toAddr, privKey }).catch(alert)}>Transfer</button>
|
|
53
|
+
</div>
|
|
54
|
+
);
|
|
55
|
+
}
|
package/template/lib.ts
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { bytes } from '@ckb-lumos/codec';
|
|
2
|
+
import { helpers, Address, Script, hd, config, Cell, commons, WitnessArgs, BI } from '@ckb-lumos/lumos';
|
|
3
|
+
import { values, blockchain } from '@ckb-lumos/base';
|
|
4
|
+
import { indexer, lumosConfig, rpc } from './ckb';
|
|
5
|
+
const { ScriptValue } = values;
|
|
6
|
+
|
|
7
|
+
config.initializeConfig(lumosConfig);
|
|
8
|
+
|
|
9
|
+
type Account = {
|
|
10
|
+
lockScript: Script;
|
|
11
|
+
address: Address;
|
|
12
|
+
pubKey: string;
|
|
13
|
+
};
|
|
14
|
+
export const generateAccountFromPrivateKey = (privKey: string): Account => {
|
|
15
|
+
const pubKey = hd.key.privateToPublic(privKey);
|
|
16
|
+
const args = hd.key.publicKeyToBlake160(pubKey);
|
|
17
|
+
const template = lumosConfig.SCRIPTS['SECP256K1_BLAKE160']!;
|
|
18
|
+
const lockScript = {
|
|
19
|
+
codeHash: template.CODE_HASH,
|
|
20
|
+
hashType: template.HASH_TYPE,
|
|
21
|
+
args: args,
|
|
22
|
+
};
|
|
23
|
+
const address = helpers.encodeToAddress(lockScript, { config: lumosConfig });
|
|
24
|
+
return {
|
|
25
|
+
lockScript,
|
|
26
|
+
address,
|
|
27
|
+
pubKey,
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export async function capacityOf(address: string): Promise<BI> {
|
|
32
|
+
const collector = indexer.collector({
|
|
33
|
+
lock: helpers.parseAddress(address, { config: lumosConfig }),
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
let balance = BI.from(0);
|
|
37
|
+
for await (const cell of collector.collect()) {
|
|
38
|
+
balance = balance.add(cell.cellOutput.capacity);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return balance;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface Options {
|
|
45
|
+
from: string;
|
|
46
|
+
to: string;
|
|
47
|
+
amount: string;
|
|
48
|
+
privKey: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export async function transfer(options: Options): Promise<string> {
|
|
52
|
+
let txSkeleton = helpers.TransactionSkeleton({});
|
|
53
|
+
const fromScript = helpers.parseAddress(options.from, {
|
|
54
|
+
config: lumosConfig,
|
|
55
|
+
});
|
|
56
|
+
const toScript = helpers.parseAddress(options.to, { config: lumosConfig });
|
|
57
|
+
|
|
58
|
+
if (BI.from(options.amount).lt(BI.from('6100000000'))) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
`every cell's capacity must be at least 61 CKB, see https://medium.com/nervosnetwork/understanding-the-nervos-dao-and-cell-model-d68f38272c24`,
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// additional 0.001 ckb for tx fee
|
|
65
|
+
// the tx fee could calculated by tx size
|
|
66
|
+
// this is just a simple example
|
|
67
|
+
const neededCapacity = BI.from(options.amount).add(100000);
|
|
68
|
+
let collectedSum = BI.from(0);
|
|
69
|
+
const collected: Cell[] = [];
|
|
70
|
+
const collector = indexer.collector({ lock: fromScript, type: 'empty' });
|
|
71
|
+
for await (const cell of collector.collect()) {
|
|
72
|
+
collectedSum = collectedSum.add(cell.cellOutput.capacity);
|
|
73
|
+
collected.push(cell);
|
|
74
|
+
if (collectedSum >= neededCapacity) break;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (collectedSum.lt(neededCapacity)) {
|
|
78
|
+
throw new Error(`Not enough CKB, ${collectedSum} < ${neededCapacity}`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const transferOutput: Cell = {
|
|
82
|
+
cellOutput: {
|
|
83
|
+
capacity: BI.from(options.amount).toHexString(),
|
|
84
|
+
lock: toScript,
|
|
85
|
+
},
|
|
86
|
+
data: '0x',
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const changeOutput: Cell = {
|
|
90
|
+
cellOutput: {
|
|
91
|
+
capacity: collectedSum.sub(neededCapacity).toHexString(),
|
|
92
|
+
lock: fromScript,
|
|
93
|
+
},
|
|
94
|
+
data: '0x',
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
txSkeleton = txSkeleton.update('inputs', (inputs) => inputs.push(...collected));
|
|
98
|
+
txSkeleton = txSkeleton.update('outputs', (outputs) => outputs.push(transferOutput, changeOutput));
|
|
99
|
+
txSkeleton = txSkeleton.update('cellDeps', (cellDeps) =>
|
|
100
|
+
cellDeps.push({
|
|
101
|
+
outPoint: {
|
|
102
|
+
txHash: lumosConfig.SCRIPTS.SECP256K1_BLAKE160.TX_HASH,
|
|
103
|
+
index: lumosConfig.SCRIPTS.SECP256K1_BLAKE160.INDEX,
|
|
104
|
+
},
|
|
105
|
+
depType: lumosConfig.SCRIPTS.SECP256K1_BLAKE160.DEP_TYPE,
|
|
106
|
+
}),
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
const firstIndex = txSkeleton
|
|
110
|
+
.get('inputs')
|
|
111
|
+
.findIndex((input) =>
|
|
112
|
+
new ScriptValue(input.cellOutput.lock, { validate: false }).equals(
|
|
113
|
+
new ScriptValue(fromScript, { validate: false }),
|
|
114
|
+
),
|
|
115
|
+
);
|
|
116
|
+
if (firstIndex !== -1) {
|
|
117
|
+
while (firstIndex >= txSkeleton.get('witnesses').size) {
|
|
118
|
+
txSkeleton = txSkeleton.update('witnesses', (witnesses) => witnesses.push('0x'));
|
|
119
|
+
}
|
|
120
|
+
let witness: string = txSkeleton.get('witnesses').get(firstIndex)!;
|
|
121
|
+
const newWitnessArgs: WitnessArgs = {
|
|
122
|
+
/* 65-byte zeros in hex */
|
|
123
|
+
lock: '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
|
|
124
|
+
};
|
|
125
|
+
if (witness !== '0x') {
|
|
126
|
+
const witnessArgs = blockchain.WitnessArgs.unpack(bytes.bytify(witness));
|
|
127
|
+
const lock = witnessArgs.lock;
|
|
128
|
+
if (!!lock && !!newWitnessArgs.lock && !bytes.equal(lock, newWitnessArgs.lock)) {
|
|
129
|
+
throw new Error('Lock field in first witness is set aside for signature!');
|
|
130
|
+
}
|
|
131
|
+
const inputType = witnessArgs.inputType;
|
|
132
|
+
if (inputType) {
|
|
133
|
+
newWitnessArgs.inputType = inputType;
|
|
134
|
+
}
|
|
135
|
+
const outputType = witnessArgs.outputType;
|
|
136
|
+
if (outputType) {
|
|
137
|
+
newWitnessArgs.outputType = outputType;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
witness = bytes.hexify(blockchain.WitnessArgs.pack(newWitnessArgs));
|
|
141
|
+
txSkeleton = txSkeleton.update('witnesses', (witnesses) => witnesses.set(firstIndex, witness));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
txSkeleton = commons.common.prepareSigningEntries(txSkeleton);
|
|
145
|
+
const message = txSkeleton.get('signingEntries').get(0)?.message;
|
|
146
|
+
const Sig = hd.key.signRecoverable(message!, options.privKey);
|
|
147
|
+
const tx = helpers.sealTransaction(txSkeleton, [Sig]);
|
|
148
|
+
const hash = await rpc.sendTransaction(tx, 'passthrough');
|
|
149
|
+
console.log('The transaction hash is', hash);
|
|
150
|
+
alert(`The transaction hash is ${hash}`);
|
|
151
|
+
|
|
152
|
+
return hash;
|
|
153
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@offckb/lumos-scaffold",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "parcel index.html",
|
|
8
|
+
"lint": "tsc --noEmit"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [],
|
|
11
|
+
"author": "",
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@ckb-lumos/base": "0.21.1",
|
|
15
|
+
"@ckb-lumos/codec": "0.21.1",
|
|
16
|
+
"@ckb-lumos/lumos": "0.21.1",
|
|
17
|
+
"@types/react": "^18.0.25",
|
|
18
|
+
"@types/react-dom": "^18.0.9",
|
|
19
|
+
"react": "^18.2.0",
|
|
20
|
+
"react-dom": "^18.2.0"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"crypto-browserify": "^3.12.0",
|
|
24
|
+
"parcel": "^2.9.3",
|
|
25
|
+
"path-browserify": "^1.0.0",
|
|
26
|
+
"process": "^0.11.10",
|
|
27
|
+
"stream-browserify": "^3.0.0"
|
|
28
|
+
}
|
|
29
|
+
}
|