Skip to content

Commit

Permalink
feat(core): add the method of generateDaoWithdrawTransaction
Browse files Browse the repository at this point in the history
  • Loading branch information
Keith-CY committed Nov 7, 2019
1 parent f4cd7e7 commit a375abd
Show file tree
Hide file tree
Showing 7 changed files with 399 additions and 18 deletions.
122 changes: 122 additions & 0 deletions packages/ckb-sdk-core/__tests__/fixtures.json
Original file line number Diff line number Diff line change
Expand Up @@ -418,5 +418,127 @@
"witnesses": []
}
}
},
"generateDaoDepositTransaction": {
"params": {
"fromAddress": "ckt1qyqw975zuu9svtyxgjuq44lv7mspte0n2tmqa703cd",
"capacity": "0x174876e800",
"fee": "0x186a0",
"cells": [
{
"blockHash": "0xf15ea2efcee00a41afadabbb71d4ac4b614e602628d6d542bde9084f1c8b7107",
"lock": {
"codeHash": "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8",
"hashType": "type",
"args": "0xe2fa82e70b062c8644b80ad7ecf6e015e5f352f6"
},
"outPoint": {
"txHash": "0x2da368a15fc31bbf0108bfb119b10a50742d9607530c64ca6f6f41d79621772e",
"index": "0x0"
},
"capacity": "0x2f766e9925",
"dataHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"status": "live",
"type": null
}
]
},
"expected": {
"version": "0x0",
"cellDeps": [
{
"outPoint": {
"txHash": "0xcb77d6dd01abde6dde8cd3fffaa9811399309ae47e18162096b7ae45e5e69f14",
"index": "0x0"
},
"depType": "depGroup"
},
{
"outPoint": {
"txHash": "0xb5724acb4f5f82afb717c3ec3fe025d3b6e45ff48f4ffbb6162c950399cbcabe",
"index": "0x2"
},
"depType": "code"
}
],
"headerDeps": [],
"inputs": [
{
"previousOutput": {
"txHash": "0x2da368a15fc31bbf0108bfb119b10a50742d9607530c64ca6f6f41d79621772e",
"index": "0x0"
},
"since": "0x0"
}
],
"outputs": [
{
"capacity": "0x174876e800",
"lock": {
"hashType": "type",
"codeHash": "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8",
"args": "0xe2fa82e70b062c8644b80ad7ecf6e015e5f352f6"
},
"type": {
"codeHash": "0x82d76d1b75fe2fd9a27dfbaa65a039221a380d76c926f378d3f81cf3e7e13f2e",
"args": "0x",
"hashType": "type"
}
},
{
"capacity": "0x182df62a85",
"lock": {
"codeHash": "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8",
"hashType": "type",
"args": "0xe2fa82e70b062c8644b80ad7ecf6e015e5f352f6"
}
}
],
"witnesses": [{ "lock": "", "inputType": "", "outputType": "" }],
"outputsData": ["0x0000000000000000", "0x"]
}
},
"generateDaoWithdrawStartTransaction": {
"params": {
"outPoint": {
"txHash": "0xe5f1f754d0f032edf073187d2b69c6d1b81cf91528f2aaf2d2aa658db4b556fd",
"index": "0x0"
},
"fee": "1000",
"cells": [
{
"blockHash": "0x7790fbe20bea5037c753caa8ee3c5a7937687b32bdcf73ebfa8abafb8108ffd4",
"lock": {
"codeHash": "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8",
"hashType": "type",
"args": "0xe2fa82e70b062c8644b80ad7ecf6e015e5f352f6"
},
"outPoint": {
"txHash": "0xe5f1f754d0f032edf073187d2b69c6d1b81cf91528f2aaf2d2aa658db4b556fd",
"index": "0x1"
},
"capacity": "0x182df62a85",
"dataHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"status": "live",
"type": null
},
{
"blockHash": "0xb8171c6953e55f56b92935b554fe2923358452970a143bdcb539a19ee0b30447",
"lock": {
"codeHash": "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8",
"hashType": "type",
"args": "0xe2fa82e70b062c8644b80ad7ecf6e015e5f352f6"
},
"outPoint": {
"txHash": "0x0e8d950607252dc0beaf879c2fd8ee989f28d8a5309d35061424212be1c07eb6",
"index": "0x0"
},
"capacity": "0x2f765892a5",
"dataHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"status": "live",
"type": null
}
]
}
}
}
42 changes: 42 additions & 0 deletions packages/ckb-sdk-core/__tests__/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,46 @@ describe('ckb-core', () => {
}
})
})

describe('nervos dao', () => {
beforeEach(() => {
core.config.secp256k1Dep = {
hashType: 'type',
codeHash: '0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8',
outPoint: {
txHash: '0xcb77d6dd01abde6dde8cd3fffaa9811399309ae47e18162096b7ae45e5e69f14',
index: '0x0',
},
}
core.config.daoDep = {
hashType: 'type',
codeHash: '0x516be0333273bbe12a723f3be583c524f0b6089326f89c49fc61e24d1f56be21',
typeHash: '0x82d76d1b75fe2fd9a27dfbaa65a039221a380d76c926f378d3f81cf3e7e13f2e',
outPoint: {
txHash: '0xb5724acb4f5f82afb717c3ec3fe025d3b6e45ff48f4ffbb6162c950399cbcabe',
index: '0x2',
},
}
})
it('generate deposit transaction', async () => {
const { params, expected } = fixtures.generateDaoDepositTransaction
const tx = await core.generateDaoDepositTransaction({
fromAddress: params.fromAddress,
capacity: BigInt(params.capacity),
fee: BigInt(params.fee),
cells: params.cells,
})
expect(tx).toEqual(expected)
})

it.skip('generate start withdraw transaction', async () => {
const { params, expected } = fixtures.generateDaoWithdrawStartTransaction
const tx = await core.generateDaoWithdrawStartTransaction({
outPoint: params.outPoint,
fee: BigInt(params.fee),
cells: params.cells,
})
expect(tx).toEqual(expected)
})
})
})
102 changes: 102 additions & 0 deletions packages/ckb-sdk-core/examples/depositAndWithdraw.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/* eslint-disable */
const Core = require('../lib').default
const nodeUrl = process.env.NODE_URL || 'http://localhost:8114' // example node url

const core = new Core(nodeUrl)

const privateKey = process.env.PRIV_KEY || '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' // example private key

const address = core.utils.privateKeyToAddress(privateKey, {
prefix: 'ckb'
})

const depositTxHash = ''
const startWithdrawTxHash = ''

/**
* @description deposit a cell to Nervos DAO
*/
const deposit = async () => {
const currentEpoch = await core.rpc.getCurrentEpoch()
console.log(`current epoch: ${JSON.stringify(currentEpoch, null, 2)}`)

const rawDepositTx = await core.generateDaoDepositTransaction({
fromAddress: address,
capacity: 600000000000n,
fee: 10000000n,
cells: []
})

const signedDepositTx = core.signTransaction(privateKey)(rawDepositTx)

const txHash = await core.rpc.sendTransaction(signedDepositTx)
console.log(`deposit tx hash: ${txHash}`)
return txHash
}

/**
* @description inspect the deposit transaction
*/
const inspectDepositTx = async () => {
const tx = await core.rpc.getTransaction(depositTxHash)
console.log(JSON.stringify(tx, null, 2))
}

/**
* @description start to withdraw a Nervos DAO cell
*/
const startWithdraw = async () => {
const outPoint = {
txHash: depositTxHash,
index: '0x0'
}
const currentBlockNumber = await core.rpc.getTipBlockNumber()
const liveCell = await core.rpc.getLiveCell(outPoint, false)
const lockScript = liveCell.cell.output.lock
const lockHash = core.utils.scriptToHash(lockScript)
await core.loadCells({
lockHash,
start: BigInt(+currentBlockNumber - 50),
end: currentBlockNumber,
save: true
})

const rawStartWithdrawTx = await core.generateDaoWithdrawStartTransaction({
outPoint,
fee: BigInt(100000)
})
const signedStartWithdrawTx = core.signTransaction(privateKey)(rawStartWithdrawTx)
const txHash = await core.rpc.sendTransaction(signedStartWithdrawTx)
console.log(`start withdraw tx hash: ${txHash}`)
return txHash
}

/**
* @description withdraw a Nervos DAO cell
*/
const withdraw = async () => {
const depositOutPoint = {
txHash: depositTxHash,
index: '0x0'
}
const withdrawOutPoint = {
txHash: startWithdrawTxHash,
index: '0x0'
}
const rawWithdrawTx = await core.generateDaoWithdrawTransaction({
depositOutPoint,
withdrawOutPoint,
fee: 1000,
})

const signedWithdrawTx = core.signTransaction(privateKey)(rawWithdrawTx)
const txHash = await core.rpc.sendTransaction(signedWithdrawTx)
console.log(`withdraw tx hash: ${txHash}`)
return txHash
}


// deposit()
// inspectDepositTx()
// startWithdraw()
// withdraw()
31 changes: 19 additions & 12 deletions packages/ckb-sdk-core/src/generateRawTransaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ const generateRawTransaction = ({
safeMode = true,
cells: unspentCells = [],
deps,
cellCapacityThreshold = BigInt(61_00_000_000),
capacityThreshold = BigInt(61_00_000_000),
changeThreshold = BigInt(61_00_000_000),
}: {
fromPublicKeyHash: string
toPublicKeyHash: string
Expand All @@ -19,7 +20,8 @@ const generateRawTransaction = ({
safeMode: boolean
cells?: CachedCell[]
deps: DepCellInfo
cellCapacityThreshold?: bigint | string | number
capacityThreshold?: bigint | string | number
changeThreshold?: bigint | string | number
}): CKBComponents.RawTransactionToSign => {
if (!deps) {
throw new Error('The deps is not loaded')
Expand All @@ -29,19 +31,24 @@ const generateRawTransaction = ({
throw new HexStringShouldStartWith0x(capacity)
}

if (typeof cellCapacityThreshold === 'string' && !cellCapacityThreshold.startsWith('0x')) {
throw new HexStringShouldStartWith0x(cellCapacityThreshold)
if (typeof capacityThreshold === 'string' && !capacityThreshold.startsWith('0x')) {
throw new HexStringShouldStartWith0x(capacityThreshold)
}

if (typeof changeThreshold === 'string' && !changeThreshold.startsWith('0x')) {
throw new HexStringShouldStartWith0x(changeThreshold)
}

const targetCapacity = BigInt(capacity)
const realFee = BigInt(fee)
const threshold = BigInt(cellCapacityThreshold)
const targetFee = BigInt(fee)
const minCapacity = BigInt(capacityThreshold)
const minChange = BigInt(changeThreshold)

if (targetCapacity < threshold) {
throw new Error(`Capacity should not be less than ${threshold} shannon`)
if (targetCapacity < minCapacity) {
throw new Error(`Capacity should not be less than ${minCapacity} shannon`)
}

const costCapacity = targetCapacity + realFee + threshold
const costCapacity = targetCapacity + targetFee + minChange

const lockScript = {
codeHash: deps.codeHash,
Expand Down Expand Up @@ -79,7 +86,7 @@ const generateRawTransaction = ({
*/
for (let i = 0; i < unspentCells.length; i++) {
const unspentCell = unspentCells[i]
if (!safeMode || unspentCell.dataHash === EMPTY_DATA_HASH) {
if (!safeMode || (unspentCell.dataHash === EMPTY_DATA_HASH && !unspentCell.type)) {
inputs.push({
previousOutput: unspentCell.outPoint,
since: '0x0',
Expand All @@ -93,8 +100,8 @@ const generateRawTransaction = ({
if (inputCapacity < costCapacity) {
throw new Error('Input capacity is not enough')
}
if (inputCapacity > targetCapacity + realFee) {
changeOutput.capacity = inputCapacity - targetCapacity - realFee
if (inputCapacity > targetCapacity + targetFee) {
changeOutput.capacity = inputCapacity - targetCapacity - targetFee
}

/**
Expand Down

0 comments on commit a375abd

Please sign in to comment.