Skip to content

Commit 52e5db7

Browse files
authored
Merge pull request #17 from nervina-labs/develop
Release v0.1.0
2 parents ae67ad8 + 51aecf2 commit 52e5db7

33 files changed

+1103
-149
lines changed

.github/workflows/build.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ name: Build
22

33
on: [pull_request, push]
44

5-
65
jobs:
76
build:
87
runs-on: ubuntu-latest
@@ -16,5 +15,7 @@ jobs:
1615
run: yarn
1716
- name: Lint
1817
run: yarn lint
18+
- name: Prettier
19+
run: yarn check
1920
- name: Build
20-
run: yarn build
21+
run: yarn build

.husky/pre-commit

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#!/bin/sh
22
. "$(dirname "$0")/_/husky.sh"
33

4-
yarn lint
4+
yarn lint
5+
yarn check

README.md

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,22 @@
1-
# cota-sdk-js
1+
# cota-sdk-js
2+
3+
[![License](https://img.shields.io/badge/license-MIT-green)](https://github.com/nervina-labs/cota-sdk-js/blob/develop/LICENSE)
4+
[![CI](https://github.com/nervina-labs/cota-sdk-js/actions/workflows/build.yml/badge.svg?branch=develop)](https://github.com/nervina-labs/cota-sdk-js/actions)
5+
[![NPM](https://img.shields.io/npm/v/@nervina-labs/cota-sdk/latest.svg)](https://www.npmjs.com/package/@nervina-labs/cota-sdk)
6+
7+
JavaScript SDK for [CoTA](https://talk.nervos.org/t/rfc-cota-a-compact-token-aggregator-standard-for-extremely-low-cost-nfts-and-fts/6338).
8+
9+
## Feature
10+
11+
- Provide methods for [cota-aggregator](https://github.com/nervina-labs/cota-aggregator) and [cota-registry-aggregator](https://github.com/nervina-labs/cota-registry-aggregator) RPC APIs
12+
- Provide methods to generate CoTA operating transactions
13+
14+
## Examples
15+
16+
- [aggregator example](https://github.com/nervina-labs/cota-sdk-js/blob/develop/example/aggregator.ts): Fetch CoTA NFT data and [SMT](https://github.com/nervosnetwork/sparse-merkle-tree) data from Aggregator server
17+
- [registry example](https://github.com/nervina-labs/cota-sdk-js/blob/develop/example/define.ts): Generate defining CoTA cells transaction
18+
- [mint example](https://github.com/nervina-labs/cota-sdk-js/blob/develop/example/mint.ts): Generate minting CoTA NFT transaction
19+
- [claim example](https://github.com/nervina-labs/cota-sdk-js/blob/develop/example/claim.ts): Generate claiming CoTA NFT transaction
20+
- [withdraw example](https://github.com/nervina-labs/cota-sdk-js/blob/develop/example/withdraw.ts): Generate withdrawing CoTA NFT transaction
21+
- [transfer example](https://github.com/nervina-labs/cota-sdk-js/blob/develop/example/transfer.ts): Generate transferring CoTA NFT transaction
22+
- [update example](https://github.com/nervina-labs/cota-sdk-js/blob/develop/example/update.ts): Generate updating CoTA NFT information transaction

example/aggregator.js

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
1-
const { Aggregator } = require("../lib/aggregator")
1+
const { Aggregator } = require('../lib/aggregator')
22

33
const run = async () => {
4-
const aggregator = new Aggregator({registryUrl: "http://localhost:3050", cotaUrl: "http://localhost:3030"})
4+
const aggregator = new Aggregator({ registryUrl: 'http://localhost:3050', cotaUrl: 'http://localhost:3030' })
55
const holds = await aggregator.getHoldCotaNft({
6-
lockScript: "0x490000001000000030000000310000009bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce80114000000dc70f33de86fdf381b4fc5bf092bb23d02774801",
6+
lockScript:
7+
'0x490000001000000030000000310000009bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce80114000000dc70f33de86fdf381b4fc5bf092bb23d02774801',
78
page: 0,
8-
pageSize: 10
9+
pageSize: 10,
910
})
1011
console.log(JSON.stringify(holds))
1112

12-
const lock_hash = await aggregator.getCotaNftSender({
13-
lockScript: "0x490000001000000030000000310000009bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce80114000000dc70f33de86fdf381b4fc5bf092bb23d02774801",
14-
cotaId: "0xb22585a8053af3fed0fd39127f5b1487ce08b756",
15-
tokenIndex: "0x00000000"
13+
const senderLockHash = await aggregator.getCotaNftSender({
14+
lockScript:
15+
'0x490000001000000030000000310000009bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce80114000000dc70f33de86fdf381b4fc5bf092bb23d02774801',
16+
cotaId: '0xb22585a8053af3fed0fd39127f5b1487ce08b756',
17+
tokenIndex: '0x00000000',
1618
})
17-
console.log(JSON.stringify(lock_hash))
19+
console.log(JSON.stringify(senderLockHash))
1820
}
1921

20-
run()
22+
run()

example/aggregator.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
1-
import { Aggregator } from "../src/aggregator"
1+
import { Aggregator } from '../src/aggregator'
22

33
const run = async () => {
4-
const aggregator = new Aggregator({registryUrl: "http://localhost:3050", cotaUrl: "http://localhost:3030"})
4+
const aggregator = new Aggregator({ registryUrl: 'http://localhost:3050', cotaUrl: 'http://localhost:3030' })
55
const holds = await aggregator.getHoldCotaNft({
6-
lockScript: "0x490000001000000030000000310000009bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce80114000000dc70f33de86fdf381b4fc5bf092bb23d02774801",
6+
lockScript:
7+
'0x490000001000000030000000310000009bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce80114000000dc70f33de86fdf381b4fc5bf092bb23d02774801',
78
page: 0,
8-
pageSize: 10
9+
pageSize: 10,
910
})
1011
console.log(JSON.stringify(holds))
12+
13+
const senderLockHash = await aggregator.getCotaNftSender({
14+
lockScript:
15+
'0x490000001000000030000000310000009bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce80114000000dc70f33de86fdf381b4fc5bf092bb23d02774801',
16+
cotaId: '0xb22585a8053af3fed0fd39127f5b1487ce08b756',
17+
tokenIndex: '0x00000000',
18+
})
19+
console.log(JSON.stringify(senderLockHash))
1120
}
1221

13-
run()
22+
run()

example/claim.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { addressToScript } from '@nervosnetwork/ckb-sdk-utils'
2+
import { Collector } from '../src/collector'
3+
import { Aggregator } from '../src/aggregator'
4+
import { generateClaimCotaTx } from '../src/service/cota'
5+
import { Claim, Service } from '../src'
6+
import CKB from '@nervosnetwork/ckb-sdk-core'
7+
8+
const TEST_ADDRESS = 'ckt1qyq0scej4vn0uka238m63azcel7cmcme7f2sxj5ska'
9+
const RECEIVER_PRIVATE_KEY = '0xcf56c11ce3fbec627e5118acd215838d1f9c5048039792d42143f933cde76311'
10+
const RECEIVER_ADDRESS = 'ckt1qyqdcu8n8h5xlhecrd8ut0cf9wer6qnhfqqsnz3lw9'
11+
12+
const secp256k1CellDep = async (ckb: CKB): Promise<CKBComponents.CellDep> => {
13+
const secp256k1Dep = (await ckb.loadDeps()).secp256k1Dep
14+
return { outPoint: secp256k1Dep.outPoint, depType: 'depGroup' }
15+
}
16+
17+
const run = async () => {
18+
const service: Service = {
19+
collector: new Collector({ ckbNodeUrl: 'http://localhost:8114', ckbIndexerUrl: 'http://localhost:8116' }),
20+
aggregator: new Aggregator({ registryUrl: 'http://localhost:3050', cotaUrl: 'http://localhost:3030' }),
21+
}
22+
const ckb = service.collector.getCkb()
23+
const claimLock = addressToScript(RECEIVER_ADDRESS)
24+
const withdrawLock = addressToScript(TEST_ADDRESS)
25+
26+
const claims: Claim[] = [
27+
{
28+
cotaId: '0x1deb31f603652bf59ff5027b522e1d81c288b72f',
29+
tokenIndex: '0x00000000',
30+
},
31+
]
32+
let rawTx = await generateClaimCotaTx(service, claimLock, withdrawLock, claims)
33+
34+
const secp256k1Dep = await secp256k1CellDep(ckb)
35+
rawTx.cellDeps.push(secp256k1Dep)
36+
37+
const signedTx = ckb.signTransaction(RECEIVER_PRIVATE_KEY)(rawTx)
38+
console.log(JSON.stringify(signedTx))
39+
let txHash = await ckb.rpc.sendTransaction(signedTx, 'passthrough')
40+
console.info(`Claim cota nft tx has been sent with tx hash ${txHash}`)
41+
}
42+
43+
run()

example/define-flashsigner.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { addressToScript, serializeWitnessArgs } from '@nervosnetwork/ckb-sdk-utils'
2+
import { Collector } from '../src/collector'
3+
import { Aggregator } from '../src/aggregator'
4+
import { generateDefineCotaTx } from '../src/service/cota'
5+
import { Service } from '../src'
6+
import { toSnakeCase } from '../src/utils'
7+
8+
const TEST_ADDRESS = 'ckt1qpth5hjexr3wehtzqpm97dzzucgemjv7sl05wnez7y72hqvuszeyyqvz2vhrf3xz0jr8dcmxlv059kmpx4tt5vcluapd4'
9+
10+
const run = async () => {
11+
const service: Service = {
12+
collector: new Collector({ ckbNodeUrl: 'http://localhost:8114', ckbIndexerUrl: 'http://localhost:8116' }),
13+
aggregator: new Aggregator({ registryUrl: 'http://localhost:3050', cotaUrl: 'http://localhost:3030' }),
14+
}
15+
const ckb = service.collector.getCkb()
16+
const defineLock = addressToScript(TEST_ADDRESS)
17+
let {rawTx, cotaId} = await generateDefineCotaTx(service, defineLock, 100, "0x00")
18+
console.log(`cotaId: ${cotaId}`)
19+
const flashsingerDep: CKBComponents.CellDep = {
20+
outPoint: {
21+
txHash: "0xb66776ff3244033fcd15312ae8b17d384c11bebbb923fce3bd896d89f4744d48",
22+
index: "0x0",
23+
},
24+
depType: "depGroup"
25+
}
26+
rawTx.cellDeps.push(flashsingerDep)
27+
rawTx.witnesses = rawTx.witnesses.map(witness => witness !== '0x' ? serializeWitnessArgs(witness) : '0x')
28+
29+
let signedTx = rawTx
30+
rawTx = toSnakeCase(rawTx)
31+
console.log(JSON.stringify(rawTx))
32+
33+
// TODO: Add witnesses signed by flashsigner
34+
signedTx.witnesses = ["flashsigner-signed-witness"]
35+
36+
console.log(JSON.stringify(signedTx))
37+
let txHash = await ckb.rpc.sendTransaction(signedTx, 'passthrough')
38+
console.info(`Define cota nft tx has been sent with tx hash ${txHash}`)
39+
}
40+
41+
run()

example/define.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { addressToScript } from '@nervosnetwork/ckb-sdk-utils'
2+
import { Collector } from '../src/collector'
3+
import { Aggregator } from '../src/aggregator'
4+
import { generateDefineCotaTx } from '../src/service/cota'
5+
import { Service } from '../src'
6+
import CKB from '@nervosnetwork/ckb-sdk-core'
7+
8+
const TEST_PRIVATE_KEY = '0xc5bd09c9b954559c70a77d68bde95369e2ce910556ddc20f739080cde3b62ef2'
9+
const TEST_ADDRESS = 'ckt1qyq0scej4vn0uka238m63azcel7cmcme7f2sxj5ska'
10+
11+
const secp256k1CellDep = async (ckb: CKB): Promise<CKBComponents.CellDep> => {
12+
const secp256k1Dep = (await ckb.loadDeps()).secp256k1Dep
13+
return { outPoint: secp256k1Dep.outPoint, depType: 'depGroup' }
14+
}
15+
16+
const run = async () => {
17+
const service: Service = {
18+
collector: new Collector({ ckbNodeUrl: 'http://localhost:8114', ckbIndexerUrl: 'http://localhost:8116' }),
19+
aggregator: new Aggregator({ registryUrl: 'http://localhost:3050', cotaUrl: 'http://localhost:3030' }),
20+
}
21+
const ckb = service.collector.getCkb()
22+
const defineLock = addressToScript(TEST_ADDRESS)
23+
let {rawTx, cotaId} = await generateDefineCotaTx(service, defineLock, 100, "0x00")
24+
console.log(`cotaId: ${cotaId}`)
25+
const secp256k1Dep = await secp256k1CellDep(ckb)
26+
rawTx.cellDeps.push(secp256k1Dep)
27+
28+
const signedTx = ckb.signTransaction(TEST_PRIVATE_KEY)(rawTx)
29+
console.log(JSON.stringify(signedTx))
30+
let txHash = await ckb.rpc.sendTransaction(signedTx, 'passthrough')
31+
console.info(`Define cota nft tx has been sent with tx hash ${txHash}`)
32+
}
33+
34+
run()

example/mint.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { addressToScript, serializeScript } from '@nervosnetwork/ckb-sdk-utils'
2+
import { Collector } from '../src/collector'
3+
import { Aggregator } from '../src/aggregator'
4+
import { generateMintCotaTx } from '../src/service/cota'
5+
import { MintCotaInfo, Service } from '../src'
6+
import CKB from '@nervosnetwork/ckb-sdk-core'
7+
8+
const TEST_PRIVATE_KEY = '0xc5bd09c9b954559c70a77d68bde95369e2ce910556ddc20f739080cde3b62ef2'
9+
const TEST_ADDRESS = 'ckt1qyq0scej4vn0uka238m63azcel7cmcme7f2sxj5ska'
10+
const RECEIVER_ADDRESS = 'ckt1qyqdcu8n8h5xlhecrd8ut0cf9wer6qnhfqqsnz3lw9'
11+
12+
const secp256k1CellDep = async (ckb: CKB): Promise<CKBComponents.CellDep> => {
13+
const secp256k1Dep = (await ckb.loadDeps()).secp256k1Dep
14+
return { outPoint: secp256k1Dep.outPoint, depType: 'depGroup' }
15+
}
16+
17+
const run = async () => {
18+
const service: Service = {
19+
collector: new Collector({ ckbNodeUrl: 'http://localhost:8114', ckbIndexerUrl: 'http://localhost:8116' }),
20+
aggregator: new Aggregator({ registryUrl: 'http://localhost:3050', cotaUrl: 'http://localhost:3030' }),
21+
}
22+
const ckb = service.collector.getCkb()
23+
const mintLock = addressToScript(TEST_ADDRESS)
24+
25+
const mintCotaInfo: MintCotaInfo = {
26+
cotaId: "0x1deb31f603652bf59ff5027b522e1d81c288b72f",
27+
withdrawals: [
28+
{
29+
tokenIndex: '0x00000000',
30+
state: '0x00',
31+
characteristic: '0xa505050505050505050505050505050505050505',
32+
toLockScript: serializeScript(addressToScript(RECEIVER_ADDRESS)),
33+
},
34+
{
35+
tokenIndex: '0x00000001',
36+
state: '0x00',
37+
characteristic: '0xa505050505050505050505050505050505050505',
38+
toLockScript: serializeScript(addressToScript(RECEIVER_ADDRESS)),
39+
},
40+
]
41+
}
42+
let rawTx = await generateMintCotaTx(service, mintLock, mintCotaInfo)
43+
44+
const secp256k1Dep = await secp256k1CellDep(ckb)
45+
rawTx.cellDeps.push(secp256k1Dep)
46+
47+
const signedTx = ckb.signTransaction(TEST_PRIVATE_KEY)(rawTx)
48+
console.log(JSON.stringify(signedTx))
49+
let txHash = await ckb.rpc.sendTransaction(signedTx, 'passthrough')
50+
console.info(`Mint cota nft tx has been sent with tx hash ${txHash}`)
51+
}
52+
53+
run()

example/registry.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
const {
2+
addressToScript,
3+
rawTransactionToHash,
4+
scriptToHash,
5+
serializeWitnessArgs,
6+
} = require('@nervosnetwork/ckb-sdk-utils')
7+
const { Collector } = require('../lib/collector')
8+
const { Aggregator } = require('../lib/aggregator')
9+
const { TestnetDeployment } = require('../lib/constants')
10+
const { generateRegisterCotaTx } = require('../lib/service/registry')
11+
const signWitnesses = require('@nervosnetwork/ckb-sdk-core/lib/signWitnesses')
12+
13+
const TEST_PRIVATE_KEY = '0xc5bd09c9b954559c70a77d68bde95369e2ce910556ddc20f739080cde3b62ef2'
14+
const TEST_ADDRESS = 'ckt1qyq0scej4vn0uka238m63azcel7cmcme7f2sxj5ska'
15+
16+
const secp256k1CellDep = async ckb => {
17+
const secp256k1Dep = (await ckb.loadDeps()).secp256k1Dep
18+
return { outPoint: secp256k1Dep.outPoint, depType: 'depGroup' }
19+
}
20+
21+
const run = async () => {
22+
const service = {
23+
collector: new Collector({ ckbNodeUrl: 'http://localhost:8114', ckbIndexerUrl: 'http://localhost:8116' }),
24+
aggregator: new Aggregator({ registryUrl: 'http://localhost:3050', cotaUrl: 'http://localhost:3030' }),
25+
}
26+
const ckb = service.collector.getCkb()
27+
const provideCKBLock = addressToScript(TEST_ADDRESS)
28+
const unregisteredCotaLock = addressToScript(TEST_ADDRESS)
29+
let rawTx = await generateRegisterCotaTx(service, [unregisteredCotaLock], provideCKBLock)
30+
const secp256k1Dep = await secp256k1CellDep(ckb)
31+
rawTx.cellDeps.push(secp256k1Dep)
32+
33+
const registryLock = TestnetDeployment.AlwaysSuccessLockScript
34+
35+
let keyMap = new Map()
36+
keyMap.set(scriptToHash(registryLock), '')
37+
keyMap.set(scriptToHash(provideCKBLock), TEST_PRIVATE_KEY)
38+
39+
const cells = rawTx.inputs.map((input, index) => ({
40+
outPoint: input.previousOutput,
41+
lock: index === 0 ? registryLock : provideCKBLock,
42+
}))
43+
44+
const transactionHash = rawTransactionToHash(rawTx)
45+
46+
const signedWitnesses = signWitnesses(keyMap)({
47+
transactionHash,
48+
witnesses: rawTx.witnesses,
49+
inputCells: cells,
50+
skipMissingKeys: true,
51+
})
52+
const signedTx = {
53+
...rawTx,
54+
witnesses: signedWitnesses.map(witness => (typeof witness === 'string' ? witness : serializeWitnessArgs(witness))),
55+
}
56+
console.log(JSON.stringify(signedTx))
57+
let txHash = await ckb.rpc.sendTransaction(signedTx, 'passthrough')
58+
console.log(`Register cota cell tx has been sent with tx hash ${txHash}`)
59+
}
60+
61+
run()

0 commit comments

Comments
 (0)