Git Product home page Git Product logo

ckb-sdk-rust's Introduction

CKB SDK Rust

The Rust SDK for Nervos CKB provides several essential features for developers:

  • RPC access to CKB nodes
  • Data structure definitions for various concepts within CKB
  • Support for assembling CKB transactions
  • Signature unlocking support for commonly used lock scripts.

These features allow for seamless interaction with CKB and facilitate the development of decentralized applications on the CKB network.

Install

# Cargo.toml
[dependencies]
ckb-sdk = "3.0.1"

Build

Build:

cargo build

Run unit tests:

make test

Please refer to the Makefile for more compilation commands.

Quick start

Setup

ckb-sdk-rust provides a convenient client that enables you to easily interact with CKB nodes.

use ckb_sdk::rpc::CkbRpcClient;

let mut ckb_client = CkbRpcClient::new("https://testnet.ckb.dev");
let block = ckb_client.get_block_by_number(0.into()).unwrap();
println!("block: {}", serde_json::to_string_pretty(&block).unwrap());

For more details about CKB RPC APIs, please refer to the CKB RPC doc.

Build transaction by manual

The following code example demonstrates how to construct a transfer transaction on CKB. You can use it to transfer a specified amount of CKB from one address to another.

NOTE: The address and key are for demo purposes only and should not be used in a production environment.

use ckb_sdk::{
    constants::SIGHASH_TYPE_HASH,
    rpc::CkbRpcClient,
    traits::{
        DefaultCellCollector, DefaultCellDepResolver, DefaultHeaderDepResolver,
        DefaultTransactionDependencyProvider, SecpCkbRawKeySigner,
    },
    tx_builder::{transfer::CapacityTransferBuilder, CapacityBalancer, TxBuilder},
    unlock::{ScriptUnlocker, SecpSighashUnlocker},
    Address, HumanCapacity, ScriptId,
};
use ckb_types::{
    bytes::Bytes,
    core::BlockView,
    h256,
    packed::{CellOutput, Script, WitnessArgs},
    prelude::*,
};
use std::{collections::HashMap, str::FromStr};

// Prepare the necessary data for a CKB transaction:
//   * set the RPC endpoint for the testnet
//   * define the sender's address and secret key
//   * define the recipient's address
//   * specify the capacity to transfer
let ckb_rpc = "https://testnet.ckb.dev:8114";
let sender = Address::from_str("ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqf7v2xsyj0p8szesqrwqapvvygpc8hzg9sku954v").unwrap();
let sender_key = secp256k1::SecretKey::from_slice(
    h256!("0xef4dfe655b3df20838bdd16e20afc70dfc1b9c3e87c54c276820315a570e6555").as_bytes(),
)
.unwrap();
let receiver = Address::from_str("ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqvglkprurm00l7hrs3rfqmmzyy3ll7djdsujdm6z").unwrap();
let capacity = HumanCapacity::from_str("100.0").unwrap();

 // Build ScriptUnlocker
let signer = SecpCkbRawKeySigner::new_with_secret_keys(vec![sender_key]);
let sighash_unlocker = SecpSighashUnlocker::from(Box::new(signer) as Box<_>);
let sighash_script_id = ScriptId::new_type(SIGHASH_TYPE_HASH.clone());
let mut unlockers = HashMap::default();
unlockers.insert(
    sighash_script_id,
    Box::new(sighash_unlocker) as Box<dyn ScriptUnlocker>,
);

// Build CapacityBalancer
let placeholder_witness = WitnessArgs::new_builder()
    .lock(Some(Bytes::from(vec![0u8; 65])).pack())
    .build();
let balancer = CapacityBalancer::new_simple(sender.payload().into(), placeholder_witness, 1000);

// Build:
//   * CellDepResolver
//   * HeaderDepResolver
//   * CellCollector
//   * TransactionDependencyProvider
let mut ckb_client = CkbRpcClient::new(ckb_rpc);
let cell_dep_resolver = {
    let genesis_block = ckb_client.get_block_by_number(0.into()).unwrap().unwrap();
    DefaultCellDepResolver::from_genesis(&BlockView::from(genesis_block)).unwrap()
};
let header_dep_resolver = DefaultHeaderDepResolver::new(ckb_rpc);
let mut cell_collector = DefaultCellCollector::new(ckb_rpc);
let tx_dep_provider = DefaultTransactionDependencyProvider::new(ckb_rpc, 10);

// Build the transaction
let output = CellOutput::new_builder()
    .lock(Script::from(&receiver))
    .capacity(capacity.0.pack())
    .build();
let builder = CapacityTransferBuilder::new(vec![(output, Bytes::default())]);
let (_tx, _) = builder
    .build_unlocked(
        &mut cell_collector,
        &cell_dep_resolver,
        &header_dep_resolver,
        &tx_dep_provider,
        &balancer,
        &unlockers,
    )
    .unwrap();

Generate a new address

In CKB, a private key can be used to generate a public key, which is then hashed using the Blake2b hashing algorithm to produce a CKB address. The public key is derived from the private key using the secp256k1 elliptic curve cryptography algorithm. This process results in a unique CKB address that can be used to receive or send CKB tokens. It is important to keep the private key secure, as anyone with access to it can potentially access the associated CKB funds.

use ckb_sdk::types::{Address, AddressPayload, NetworkType};
use rand::Rng;

let mut rng = rand::thread_rng();
let privkey_bytes: [u8; 32] = rng.gen();
let secp_secret_key = secp256k1::SecretKey::from_slice(&privkey_bytes).unwrap();
let pubkey =
    secp256k1::PublicKey::from_secret_key(&ckb_crypto::secp::SECP256K1, &secp_secret_key);
let payload = AddressPayload::from_pubkey(&pubkey);
let address = Address::new(NetworkType::Mainnet, payload, true);
println!("address: {}", address.to_string());

Parse address

In the world of CKB, a lock script can be represented as an address. It is possible to parse an address from an encoded string and then obtain its network and script.

use ckb_sdk::types::Address;
use ckb_types::packed::Script;
use std::str::FromStr;

let addr_str = "ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqgvf0k9sc40s3azmpfvhyuudhahpsj72tsr8cx3d";
let addr = Address::from_str(addr_str).unwrap();
let _network = addr.network();
let _script: Script = addr.payload().into();

For more details please about CKB address refer to CKB rfc 0021.

More Examples

You can try compiling them by running the following command in your terminal:

cargo build --examples

For more use cases of building transactions with CKB node, please refer to these examples and unit tests.

License

The SDK is available as open source under the terms of the MIT License.

ChangeLog

See CHANGELOG for more details.

ckb-sdk-rust's People

Contributors

blckngm avatar doitian avatar ethanyuan avatar eval-exec avatar kaoimin avatar liuck8080 avatar quake avatar thewawar avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ckb-sdk-rust's Issues

Improve jsonrpc client implementation

  • Use use jsonrpc_derive::rpc; to declare all rpc methods
  • Handle special verbosity with wrapper rpc methods, for example:
    • get_block : Get block use json format (call get_block with verbosity=2)
    • get_block_bin: Get block by molecule encoded block data (call get_block with verbosity=0)

Support generate open transaction message to sign

Provide apis to read all data of an open transaction for sign, include all input command and according data to read.

The cell mask:

The full current transaction hash
length of input & output cells in current script group
data from input and output cell:

| 0x1   | Capacity         |
| 0x2   | lock.code_hash   |
| 0x4   | lock.hash_type   |
| 0x8   | lock.args        |
| 0x10  | type.code_hash   |
| 0x20  | type.hash_type   |
| 0x40  | type.args        |
| 0x80  | Cell data        |
| 0x100 | Lock script hash |
| 0x200 | Type script hash |
| 0x400 | The whole cell   |

The cell input mask: data from CellInput structure:

| 0x1   | Capacity         |
| 0x2   | lock.code_hash   |
| 0x4   | lock.hash_type   |
| 0x8   | lock.args        |
| 0x10  | type.code_hash   |
| 0x20  | type.hash_type   |
| 0x40  | type.args        |
| 0x80  | Cell data        |
| 0x100 | Lock script hash |
| 0x200 | Type script hash |
| 0x400 | The whole cell   |

Upgrade the usage of the client to make it more convenient for users.

Currently, the Rust SDK hardcodes the client as reqwest::blocking::Client::new().

$struct_name { url, id: 0.into(), client: reqwest::blocking::Client::new(), }

However, sometimes users may need to customize the client, for example:

https://github.com/synapseweb3/forcerelay/blob/07c3463d2200423740366f5f9b0440bdbc17618a/crates/relayer/src/chain/ckb/rpc_client.rs#L72-L81

Transaction fee calculation

Currently transaction fee calculation only consider transaction size, we must also consider transaction cycles cost.

mock rpc test result

SDK Commit: b982f48

List of Unsupported Features:

  • calculate_dao_field
  • calculate_dao_maximum_withdraw
  • dry_run_transaction (deprecated)
  • generate_block currently does not support passing a warehouse
  • generate_block_with_template
  • get_block_filter
  • get_fee_rate_statics(&self, tartet: Option) -> FeeRateStatistics
    • Typo in "tartet"
    • FeeRateStatistics should be an Option
  • get_fee_rate_statistics, same as get_fee_rate_statics
  • get_transaction does not support the "only_committed" parameter

Enforce Semver

The bump from version 1.0.0 to 1.0.1 created breaking changes by removing GenesisInfo. Such a change should be reflected in a version increment of greater significance than patch version update.

[ckb-light-client] Incompatible RPC

  • fetch_transaction: it should be TransactionWithStatus, not TransactionWithHeader.
  • get_transaction: it should be TransactionWithStatus, not TransactionWithHeader.
  • set_script: not support SetScriptCommand
  • local_node_info: not support now

Improve rust doc

Currently data structure like CellQueryOptions do not have rust doc, it will confuse new users.

We need add more rust doc to the code, so that even a fresh CKB user can get the basic idea of how to using this library.

Support sign open transaction for future usage

Process the open transaction sign input list, generate the message to sign, and sign the message according to different algorithms.

The following id flags will be support:

  • 0x0 blake160 hash of a secp256k1 public key
  • 0x1 ethereum
  • 0x06 ckb multisig
  • 0xFC owner lock

The correct parameter name should be target instead of tartet

The rust sdk needs to cover the automated test regression of the example case on ci

Does the example of rust sdk run on ci? This needs to be added. The purpose is to prevent some crates from being upgraded, causing the case to become passively outdated and unable to build normally.

expect add workflows steps

  • cargo build --examples
  • cargo run --examples examples_name

sUDT fully support

I found when I start to build sUDT type script through ckb-sdk, I find no utilities to use, but the sUDT code hash is officially posted on the doc-site, so I recommend to add utility function to generate sUDT script both on mainnet and testnet.

Make it easier to build deployment transactions

I find it really useful to have the following functions when building custom deployment tools. It may worth adding similar functions to ckb-sdk:

Maybe we should also add a function that adds the next output as a type id cell with some specified lock and data, given a transaction that has at least one input.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.