Skip to content

Commit

Permalink
Merge pull request #17 from nervina-labs/develop
Browse files Browse the repository at this point in the history
Release v0.1.0
  • Loading branch information
duanyytop authored Feb 18, 2022
2 parents ae67ad8 + 51aecf2 commit 52e5db7
Show file tree
Hide file tree
Showing 33 changed files with 1,103 additions and 149 deletions.
5 changes: 3 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ name: Build

on: [pull_request, push]


jobs:
build:
runs-on: ubuntu-latest
Expand All @@ -16,5 +15,7 @@ jobs:
run: yarn
- name: Lint
run: yarn lint
- name: Prettier
run: yarn check
- name: Build
run: yarn build
run: yarn build
3 changes: 2 additions & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

yarn lint
yarn lint
yarn check
23 changes: 22 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,22 @@
# cota-sdk-js
# cota-sdk-js

[![License](https://img.shields.io/badge/license-MIT-green)](https://github.com/nervina-labs/cota-sdk-js/blob/develop/LICENSE)
[![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)
[![NPM](https://img.shields.io/npm/v/@nervina-labs/cota-sdk/latest.svg)](https://www.npmjs.com/package/@nervina-labs/cota-sdk)

JavaScript SDK for [CoTA](https://talk.nervos.org/t/rfc-cota-a-compact-token-aggregator-standard-for-extremely-low-cost-nfts-and-fts/6338).

## Feature

- 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
- Provide methods to generate CoTA operating transactions

## Examples

- [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
- [registry example](https://github.com/nervina-labs/cota-sdk-js/blob/develop/example/define.ts): Generate defining CoTA cells transaction
- [mint example](https://github.com/nervina-labs/cota-sdk-js/blob/develop/example/mint.ts): Generate minting CoTA NFT transaction
- [claim example](https://github.com/nervina-labs/cota-sdk-js/blob/develop/example/claim.ts): Generate claiming CoTA NFT transaction
- [withdraw example](https://github.com/nervina-labs/cota-sdk-js/blob/develop/example/withdraw.ts): Generate withdrawing CoTA NFT transaction
- [transfer example](https://github.com/nervina-labs/cota-sdk-js/blob/develop/example/transfer.ts): Generate transferring CoTA NFT transaction
- [update example](https://github.com/nervina-labs/cota-sdk-js/blob/develop/example/update.ts): Generate updating CoTA NFT information transaction
22 changes: 12 additions & 10 deletions example/aggregator.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
const { Aggregator } = require("../lib/aggregator")
const { Aggregator } = require('../lib/aggregator')

const run = async () => {
const aggregator = new Aggregator({registryUrl: "http://localhost:3050", cotaUrl: "http://localhost:3030"})
const aggregator = new Aggregator({ registryUrl: 'http://localhost:3050', cotaUrl: 'http://localhost:3030' })
const holds = await aggregator.getHoldCotaNft({
lockScript: "0x490000001000000030000000310000009bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce80114000000dc70f33de86fdf381b4fc5bf092bb23d02774801",
lockScript:
'0x490000001000000030000000310000009bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce80114000000dc70f33de86fdf381b4fc5bf092bb23d02774801',
page: 0,
pageSize: 10
pageSize: 10,
})
console.log(JSON.stringify(holds))

const lock_hash = await aggregator.getCotaNftSender({
lockScript: "0x490000001000000030000000310000009bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce80114000000dc70f33de86fdf381b4fc5bf092bb23d02774801",
cotaId: "0xb22585a8053af3fed0fd39127f5b1487ce08b756",
tokenIndex: "0x00000000"
const senderLockHash = await aggregator.getCotaNftSender({
lockScript:
'0x490000001000000030000000310000009bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce80114000000dc70f33de86fdf381b4fc5bf092bb23d02774801',
cotaId: '0xb22585a8053af3fed0fd39127f5b1487ce08b756',
tokenIndex: '0x00000000',
})
console.log(JSON.stringify(lock_hash))
console.log(JSON.stringify(senderLockHash))
}

run()
run()
19 changes: 14 additions & 5 deletions example/aggregator.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
import { Aggregator } from "../src/aggregator"
import { Aggregator } from '../src/aggregator'

const run = async () => {
const aggregator = new Aggregator({registryUrl: "http://localhost:3050", cotaUrl: "http://localhost:3030"})
const aggregator = new Aggregator({ registryUrl: 'http://localhost:3050', cotaUrl: 'http://localhost:3030' })
const holds = await aggregator.getHoldCotaNft({
lockScript: "0x490000001000000030000000310000009bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce80114000000dc70f33de86fdf381b4fc5bf092bb23d02774801",
lockScript:
'0x490000001000000030000000310000009bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce80114000000dc70f33de86fdf381b4fc5bf092bb23d02774801',
page: 0,
pageSize: 10
pageSize: 10,
})
console.log(JSON.stringify(holds))

const senderLockHash = await aggregator.getCotaNftSender({
lockScript:
'0x490000001000000030000000310000009bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce80114000000dc70f33de86fdf381b4fc5bf092bb23d02774801',
cotaId: '0xb22585a8053af3fed0fd39127f5b1487ce08b756',
tokenIndex: '0x00000000',
})
console.log(JSON.stringify(senderLockHash))
}

run()
run()
43 changes: 43 additions & 0 deletions example/claim.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { addressToScript } from '@nervosnetwork/ckb-sdk-utils'
import { Collector } from '../src/collector'
import { Aggregator } from '../src/aggregator'
import { generateClaimCotaTx } from '../src/service/cota'
import { Claim, Service } from '../src'
import CKB from '@nervosnetwork/ckb-sdk-core'

const TEST_ADDRESS = 'ckt1qyq0scej4vn0uka238m63azcel7cmcme7f2sxj5ska'
const RECEIVER_PRIVATE_KEY = '0xcf56c11ce3fbec627e5118acd215838d1f9c5048039792d42143f933cde76311'
const RECEIVER_ADDRESS = 'ckt1qyqdcu8n8h5xlhecrd8ut0cf9wer6qnhfqqsnz3lw9'

const secp256k1CellDep = async (ckb: CKB): Promise<CKBComponents.CellDep> => {
const secp256k1Dep = (await ckb.loadDeps()).secp256k1Dep
return { outPoint: secp256k1Dep.outPoint, depType: 'depGroup' }
}

const run = async () => {
const service: Service = {
collector: new Collector({ ckbNodeUrl: 'http://localhost:8114', ckbIndexerUrl: 'http://localhost:8116' }),
aggregator: new Aggregator({ registryUrl: 'http://localhost:3050', cotaUrl: 'http://localhost:3030' }),
}
const ckb = service.collector.getCkb()
const claimLock = addressToScript(RECEIVER_ADDRESS)
const withdrawLock = addressToScript(TEST_ADDRESS)

const claims: Claim[] = [
{
cotaId: '0x1deb31f603652bf59ff5027b522e1d81c288b72f',
tokenIndex: '0x00000000',
},
]
let rawTx = await generateClaimCotaTx(service, claimLock, withdrawLock, claims)

const secp256k1Dep = await secp256k1CellDep(ckb)
rawTx.cellDeps.push(secp256k1Dep)

const signedTx = ckb.signTransaction(RECEIVER_PRIVATE_KEY)(rawTx)
console.log(JSON.stringify(signedTx))
let txHash = await ckb.rpc.sendTransaction(signedTx, 'passthrough')
console.info(`Claim cota nft tx has been sent with tx hash ${txHash}`)
}

run()
41 changes: 41 additions & 0 deletions example/define-flashsigner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { addressToScript, serializeWitnessArgs } from '@nervosnetwork/ckb-sdk-utils'
import { Collector } from '../src/collector'
import { Aggregator } from '../src/aggregator'
import { generateDefineCotaTx } from '../src/service/cota'
import { Service } from '../src'
import { toSnakeCase } from '../src/utils'

const TEST_ADDRESS = 'ckt1qpth5hjexr3wehtzqpm97dzzucgemjv7sl05wnez7y72hqvuszeyyqvz2vhrf3xz0jr8dcmxlv059kmpx4tt5vcluapd4'

const run = async () => {
const service: Service = {
collector: new Collector({ ckbNodeUrl: 'http://localhost:8114', ckbIndexerUrl: 'http://localhost:8116' }),
aggregator: new Aggregator({ registryUrl: 'http://localhost:3050', cotaUrl: 'http://localhost:3030' }),
}
const ckb = service.collector.getCkb()
const defineLock = addressToScript(TEST_ADDRESS)
let {rawTx, cotaId} = await generateDefineCotaTx(service, defineLock, 100, "0x00")
console.log(`cotaId: ${cotaId}`)
const flashsingerDep: CKBComponents.CellDep = {
outPoint: {
txHash: "0xb66776ff3244033fcd15312ae8b17d384c11bebbb923fce3bd896d89f4744d48",
index: "0x0",
},
depType: "depGroup"
}
rawTx.cellDeps.push(flashsingerDep)
rawTx.witnesses = rawTx.witnesses.map(witness => witness !== '0x' ? serializeWitnessArgs(witness) : '0x')

let signedTx = rawTx
rawTx = toSnakeCase(rawTx)
console.log(JSON.stringify(rawTx))

// TODO: Add witnesses signed by flashsigner
signedTx.witnesses = ["flashsigner-signed-witness"]

console.log(JSON.stringify(signedTx))
let txHash = await ckb.rpc.sendTransaction(signedTx, 'passthrough')
console.info(`Define cota nft tx has been sent with tx hash ${txHash}`)
}

run()
34 changes: 34 additions & 0 deletions example/define.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { addressToScript } from '@nervosnetwork/ckb-sdk-utils'
import { Collector } from '../src/collector'
import { Aggregator } from '../src/aggregator'
import { generateDefineCotaTx } from '../src/service/cota'
import { Service } from '../src'
import CKB from '@nervosnetwork/ckb-sdk-core'

const TEST_PRIVATE_KEY = '0xc5bd09c9b954559c70a77d68bde95369e2ce910556ddc20f739080cde3b62ef2'
const TEST_ADDRESS = 'ckt1qyq0scej4vn0uka238m63azcel7cmcme7f2sxj5ska'

const secp256k1CellDep = async (ckb: CKB): Promise<CKBComponents.CellDep> => {
const secp256k1Dep = (await ckb.loadDeps()).secp256k1Dep
return { outPoint: secp256k1Dep.outPoint, depType: 'depGroup' }
}

const run = async () => {
const service: Service = {
collector: new Collector({ ckbNodeUrl: 'http://localhost:8114', ckbIndexerUrl: 'http://localhost:8116' }),
aggregator: new Aggregator({ registryUrl: 'http://localhost:3050', cotaUrl: 'http://localhost:3030' }),
}
const ckb = service.collector.getCkb()
const defineLock = addressToScript(TEST_ADDRESS)
let {rawTx, cotaId} = await generateDefineCotaTx(service, defineLock, 100, "0x00")
console.log(`cotaId: ${cotaId}`)
const secp256k1Dep = await secp256k1CellDep(ckb)
rawTx.cellDeps.push(secp256k1Dep)

const signedTx = ckb.signTransaction(TEST_PRIVATE_KEY)(rawTx)
console.log(JSON.stringify(signedTx))
let txHash = await ckb.rpc.sendTransaction(signedTx, 'passthrough')
console.info(`Define cota nft tx has been sent with tx hash ${txHash}`)
}

run()
53 changes: 53 additions & 0 deletions example/mint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { addressToScript, serializeScript } from '@nervosnetwork/ckb-sdk-utils'
import { Collector } from '../src/collector'
import { Aggregator } from '../src/aggregator'
import { generateMintCotaTx } from '../src/service/cota'
import { MintCotaInfo, Service } from '../src'
import CKB from '@nervosnetwork/ckb-sdk-core'

const TEST_PRIVATE_KEY = '0xc5bd09c9b954559c70a77d68bde95369e2ce910556ddc20f739080cde3b62ef2'
const TEST_ADDRESS = 'ckt1qyq0scej4vn0uka238m63azcel7cmcme7f2sxj5ska'
const RECEIVER_ADDRESS = 'ckt1qyqdcu8n8h5xlhecrd8ut0cf9wer6qnhfqqsnz3lw9'

const secp256k1CellDep = async (ckb: CKB): Promise<CKBComponents.CellDep> => {
const secp256k1Dep = (await ckb.loadDeps()).secp256k1Dep
return { outPoint: secp256k1Dep.outPoint, depType: 'depGroup' }
}

const run = async () => {
const service: Service = {
collector: new Collector({ ckbNodeUrl: 'http://localhost:8114', ckbIndexerUrl: 'http://localhost:8116' }),
aggregator: new Aggregator({ registryUrl: 'http://localhost:3050', cotaUrl: 'http://localhost:3030' }),
}
const ckb = service.collector.getCkb()
const mintLock = addressToScript(TEST_ADDRESS)

const mintCotaInfo: MintCotaInfo = {
cotaId: "0x1deb31f603652bf59ff5027b522e1d81c288b72f",
withdrawals: [
{
tokenIndex: '0x00000000',
state: '0x00',
characteristic: '0xa505050505050505050505050505050505050505',
toLockScript: serializeScript(addressToScript(RECEIVER_ADDRESS)),
},
{
tokenIndex: '0x00000001',
state: '0x00',
characteristic: '0xa505050505050505050505050505050505050505',
toLockScript: serializeScript(addressToScript(RECEIVER_ADDRESS)),
},
]
}
let rawTx = await generateMintCotaTx(service, mintLock, mintCotaInfo)

const secp256k1Dep = await secp256k1CellDep(ckb)
rawTx.cellDeps.push(secp256k1Dep)

const signedTx = ckb.signTransaction(TEST_PRIVATE_KEY)(rawTx)
console.log(JSON.stringify(signedTx))
let txHash = await ckb.rpc.sendTransaction(signedTx, 'passthrough')
console.info(`Mint cota nft tx has been sent with tx hash ${txHash}`)
}

run()
61 changes: 61 additions & 0 deletions example/registry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
const {
addressToScript,
rawTransactionToHash,
scriptToHash,
serializeWitnessArgs,
} = require('@nervosnetwork/ckb-sdk-utils')
const { Collector } = require('../lib/collector')
const { Aggregator } = require('../lib/aggregator')
const { TestnetDeployment } = require('../lib/constants')
const { generateRegisterCotaTx } = require('../lib/service/registry')
const signWitnesses = require('@nervosnetwork/ckb-sdk-core/lib/signWitnesses')

const TEST_PRIVATE_KEY = '0xc5bd09c9b954559c70a77d68bde95369e2ce910556ddc20f739080cde3b62ef2'
const TEST_ADDRESS = 'ckt1qyq0scej4vn0uka238m63azcel7cmcme7f2sxj5ska'

const secp256k1CellDep = async ckb => {
const secp256k1Dep = (await ckb.loadDeps()).secp256k1Dep
return { outPoint: secp256k1Dep.outPoint, depType: 'depGroup' }
}

const run = async () => {
const service = {
collector: new Collector({ ckbNodeUrl: 'http://localhost:8114', ckbIndexerUrl: 'http://localhost:8116' }),
aggregator: new Aggregator({ registryUrl: 'http://localhost:3050', cotaUrl: 'http://localhost:3030' }),
}
const ckb = service.collector.getCkb()
const provideCKBLock = addressToScript(TEST_ADDRESS)
const unregisteredCotaLock = addressToScript(TEST_ADDRESS)
let rawTx = await generateRegisterCotaTx(service, [unregisteredCotaLock], provideCKBLock)
const secp256k1Dep = await secp256k1CellDep(ckb)
rawTx.cellDeps.push(secp256k1Dep)

const registryLock = TestnetDeployment.AlwaysSuccessLockScript

let keyMap = new Map()
keyMap.set(scriptToHash(registryLock), '')
keyMap.set(scriptToHash(provideCKBLock), TEST_PRIVATE_KEY)

const cells = rawTx.inputs.map((input, index) => ({
outPoint: input.previousOutput,
lock: index === 0 ? registryLock : provideCKBLock,
}))

const transactionHash = rawTransactionToHash(rawTx)

const signedWitnesses = signWitnesses(keyMap)({
transactionHash,
witnesses: rawTx.witnesses,
inputCells: cells,
skipMissingKeys: true,
})
const signedTx = {
...rawTx,
witnesses: signedWitnesses.map(witness => (typeof witness === 'string' ? witness : serializeWitnessArgs(witness))),
}
console.log(JSON.stringify(signedTx))
let txHash = await ckb.rpc.sendTransaction(signedTx, 'passthrough')
console.log(`Register cota cell tx has been sent with tx hash ${txHash}`)
}

run()
Loading

0 comments on commit 52e5db7

Please sign in to comment.