Migrate From ckb-sdk-core to Lumos
Summary
To avoid splitting the development ecosystem, ckb-sdk-js will be migrated to lumos, please check out the migration list.
If you are using any function that is not on this list, please refer to the lumos documentation.
reference:
Transaction migration example list
Simple transaction migration example
before: ckb-sdk-js simple example
after:
simple transaction with lumos example
import { Script, Address, config, Indexer, RPC, hd, commons } from "@ckb-lumos/lumos"
import { TransactionSkeleton, encodeToAddress, sealTransaction } from "@ckb-lumos/helpers"
// ckt
const CKB_RPC_URL = "https://testnet.ckb.dev/rpc"
const CKB_INDEXER_URL = "https://testnet.ckb.dev/indexer"
const rpc = new RPC(CKB_RPC_URL)
const indexer = new Indexer(CKB_INDEXER_URL, CKB_RPC_URL)
const CONFIG = config.createConfig({
  PREFIX: "ckt",
  SCRIPTS: {
    ...config.predefined.AGGRON4.SCRIPTS,
  },
})
config.initializeConfig(CONFIG)
export const generateSECP256K1Account = (privKey: string) => {
  const pubKey = hd.key.privateToPublic(privKey)
  const args = hd.key.publicKeyToBlake160(pubKey)
  const template = CONFIG.SCRIPTS["SECP256K1_BLAKE160"]!
  const lockScript = {
    codeHash: template.CODE_HASH,
    hashType: template.HASH_TYPE,
    args: args,
  }
  const address = encodeToAddress(lockScript, { config: CONFIG })
  return {
    lockScript,
    address,
    pubKey,
    privKey,
  }
}
const bootstrap = async () => {
  const alice = generateSECP256K1Account("0xd00c06bfd800d27397002dca6fb0993d5ba6399b4238b2f29ee9deb97593d2bc")
  const bob = generateSECP256K1Account("0x63d86723e08f0f813a36ce6aa123bb2289d90680ae1e99d4de8cdb334553f24d")
  let txSkeleton = TransactionSkeleton({ cellProvider: indexer })
  txSkeleton = await commons.secp256k1Blake160.transfer(txSkeleton, alice.address, bob.address, BigInt(1000 * 10 ** 8))
  txSkeleton = await commons.secp256k1Blake160.payFee(txSkeleton, alice.address, BigInt(1 * 10 ** 8), {
    config: CONFIG,
  })
  txSkeleton = commons.common.prepareSigningEntries(txSkeleton)
  const message = txSkeleton.get("signingEntries").get(0)?.message
  const Sig = hd.key.signRecoverable(message!, alice.privKey)
  const tx = sealTransaction(txSkeleton, [Sig])
  const hash = await rpc.sendTransaction(tx, "passthrough")
  console.log("The transaction hash is", hash)
}
bootstrap()
sudt transaction migration example
before: ckb-sdk-js sudt example
after:
sudt transaction with lumos example
import { config, Indexer, RPC, hd, commons } from "@ckb-lumos/lumos"
import { TransactionSkeleton, encodeToAddress, sealTransaction } from "@ckb-lumos/helpers"
const CKB_RPC_URL = "https://testnet.ckb.dev/rpc"
const CKB_INDEXER_URL = "https://testnet.ckb.dev/indexer"
const rpc = new RPC(CKB_RPC_URL)
const indexer = new Indexer(CKB_INDEXER_URL, CKB_RPC_URL)
const CONFIG = config.createConfig({
  PREFIX: "ckt",
  SCRIPTS: {
    ...config.predefined.AGGRON4.SCRIPTS,
    ANYONE_CAN_PAY: {
      CODE_HASH: "0x3419a1c09eb2567f6552ee7a8ecffd64155cffe0f1796e6e61ec088d740c1356",
      HASH_TYPE: "type",
      TX_HASH: "0xec26b0f85ed839ece5f11c4c4e837ec359f5adc4420410f6453b1f6b60fb96a6",
      INDEX: "0x0",
      DEP_TYPE: "code",
    },
  },
})
config.initializeConfig(CONFIG)
export const generateSECP256K1Account = (privKey: string) => {
  const pubKey = hd.key.privateToPublic(privKey)
  const args = hd.key.publicKeyToBlake160(pubKey)
  const template = CONFIG.SCRIPTS["SECP256K1_BLAKE160"]!
  const lockScript = {
    codeHash: template.CODE_HASH,
    hashType: template.HASH_TYPE,
    args: args,
  }
  const address = encodeToAddress(lockScript, { config: CONFIG })
  return {
    lockScript,
    address,
    pubKey,
    privKey,
  }
}
export const issueToken = async (fromAddress: string, privKey: string) => {
  let txSkeleton = TransactionSkeleton({ cellProvider: indexer })
  txSkeleton = await commons.sudt.issueToken(txSkeleton, fromAddress, BigInt(10000))
  txSkeleton = await commons.secp256k1Blake160.payFee(txSkeleton, fromAddress, BigInt(1 * 10 ** 8))
  txSkeleton = commons.common.prepareSigningEntries(txSkeleton)
  const message = txSkeleton.get("signingEntries").get(0)?.message
  const Sig = hd.key.signRecoverable(message!, privKey)
  const tx = sealTransaction(txSkeleton, [Sig])
  const hash = await rpc.sendTransaction(tx, "passthrough")
  return hash
}
export const transferToken = async (fromAddress: string, toAddress: string, privKey: string) => {
  const token = commons.sudt.ownerForSudt(fromAddress)
  let txSkeleton = TransactionSkeleton({ cellProvider: indexer })
  txSkeleton = await commons.sudt.transfer(txSkeleton, [fromAddress], token, toAddress, BigInt(1000))
  txSkeleton = await commons.secp256k1Blake160.payFee(txSkeleton, fromAddress, BigInt(1 * 10 ** 8))
  txSkeleton = commons.common.prepareSigningEntries(txSkeleton)
  const message = txSkeleton.get("signingEntries").get(0)?.message
  const Sig = hd.key.signRecoverable(message!, privKey)
  const tx = sealTransaction(txSkeleton, [Sig])
  const hash = await rpc.sendTransaction(tx, "passthrough")
  return hash
}
const bootstrap = async () => {
  const alice = generateSECP256K1Account("0xd00c06bfd800d27397002dca6fb0993d5ba6399b4238b2f29ee9deb97593d2bc")
  const bob = generateSECP256K1Account("0x63d86723e08f0f813a36ce6aa123bb2289d90680ae1e99d4de8cdb334553f24d")
  const issueTxHash = await issueToken(bob.address, bob.privKey)
  console.log("issueTxHash is", issueTxHash)
  // Wait a minute.
  const transferTxHash = await transferToken(alice.address, bob.address, alice.privKey)
  console.log("transferTxHash is", transferTxHash)
}
bootstrap()
dao transaction migration example
before: ckb-sdk-js dao example
after:
dao transaction with lumos example
import { BI, OutPoint, Cell, config, Indexer, RPC, hd, commons } from "@ckb-lumos/lumos"
import { TransactionSkeleton, encodeToAddress, sealTransaction } from "@ckb-lumos/helpers"
// ckt
const CKB_RPC_URL = "https://testnet.ckb.dev/rpc"
const CKB_INDEXER_URL = "https://testnet.ckb.dev/indexer"
const rpc = new RPC(CKB_RPC_URL)
const indexer = new Indexer(CKB_INDEXER_URL, CKB_RPC_URL)
const CONFIG = config.createConfig({
  PREFIX: "ckt",
  SCRIPTS: {
    ...config.predefined.AGGRON4.SCRIPTS,
  },
})
config.initializeConfig(CONFIG)
export const generateSECP256K1Account = (privKey: string) => {
  const pubKey = hd.key.privateToPublic(privKey)
  const args = hd.key.publicKeyToBlake160(pubKey)
  const template = CONFIG.SCRIPTS["SECP256K1_BLAKE160"]!
  const lockScript = {
    codeHash: template.CODE_HASH,
    hashType: template.HASH_TYPE,
    args: args,
  }
  const address = encodeToAddress(lockScript, { config: CONFIG })
  return {
    lockScript,
    address,
    pubKey,
    privKey,
  }
}
export const getCellByOutPoint = async (outpoint: OutPoint): Promise<Cell> => {
  const tx = await rpc.get_transaction(outpoint.txHash)
  if (!tx) {
    throw new Error(`not found tx: ${outpoint.txHash}`)
  }
  const block = await rpc.getBlock(tx.txStatus.blockHash!)
  return {
    cellOutput: tx.transaction.outputs[0],
    data: tx.transaction.outputsData[0],
    outPoint: outpoint,
    blockHash: tx.txStatus.blockHash,
    blockNumber: block!.header.number,
  }
}
export const deposit = async (fromAddress: string, privKey: string) => {
  let txSkeleton = TransactionSkeleton({ cellProvider: indexer })
  txSkeleton = await commons.dao.deposit(txSkeleton, fromAddress, fromAddress, BigInt(1000 * 10 ** 8))
  txSkeleton = await commons.secp256k1Blake160.payFee(txSkeleton, fromAddress, BigInt(1 * 10 ** 8))
  txSkeleton = commons.common.prepareSigningEntries(txSkeleton)
  const message = txSkeleton.get("signingEntries").get(0)?.message
  const Sig = hd.key.signRecoverable(message!, privKey)
  const tx = sealTransaction(txSkeleton, [Sig])
  const hash = await rpc.sendTransaction(tx, "passthrough")
  return hash
}
export const withdraw = async (depositOutpoint: OutPoint, fromAddress: string, privKey: string) => {
  let txSkeleton = TransactionSkeleton({ cellProvider: indexer })
  const depositCell = await getCellByOutPoint(depositOutpoint)
  txSkeleton = await commons.dao.withdraw(txSkeleton, depositCell, fromAddress)
  txSkeleton = await commons.secp256k1Blake160.payFee(txSkeleton, fromAddress, BigInt(1 * 10 ** 8))
  txSkeleton = commons.common.prepareSigningEntries(txSkeleton)
  const message = txSkeleton.get("signingEntries").get(0)?.message
  const Sig = hd.key.signRecoverable(message!, privKey)
  const tx = sealTransaction(txSkeleton, [Sig])
  const hash = await rpc.sendTransaction(tx, "passthrough")
  return hash
}
export const unlock = async (
  depositOutpoint: OutPoint,
  withdrawOutpoint: OutPoint,
  fromAddress: string,
  privKey: string
) => {
  let txSkeleton = TransactionSkeleton({ cellProvider: indexer })
  const depositCell = await getCellByOutPoint(depositOutpoint)
  const withdrawCell = await getCellByOutPoint(withdrawOutpoint)
  txSkeleton = await commons.dao.unlock(txSkeleton, depositCell, withdrawCell, fromAddress, fromAddress)
  txSkeleton = await commons.secp256k1Blake160.payFee(txSkeleton, fromAddress, BI.from(1 * 10 ** 8))
  txSkeleton = commons.common.prepareSigningEntries(txSkeleton)
  const message = txSkeleton.get("signingEntries").get(0)?.message
  const Sig = hd.key.signRecoverable(message!, privKey)
  const tx = sealTransaction(txSkeleton, [Sig])
  const hash = await rpc.sendTransaction(tx, "passthrough")
  return hash
}
const bootstrap = async () => {
  const alice = generateSECP256K1Account("0xd00c06bfd800d27397002dca6fb0993d5ba6399b4238b2f29ee9deb97593d2bc")
  const depositTx = await deposit(alice.address, alice.privKey)
  const depositOutpoint = { txHash: depositTx, index: "0x0" }
  const withdrawTx = await withdraw(depositOutpoint, alice.address, alice.privKey)
  const withdrawOutpoint = { txHash: withdrawTx, index: "0x0" }
  // wait 180 epoch
  const unlockTx = await unlock(depositOutpoint, withdrawOutpoint, alice.address, alice.privKey)
  console.log("unlockTx is", unlockTx)
}
bootstrap()