@nervina-labs/acp-sdk
v0.1.1
Published
A toolkit that helps developers interact with the Anyone-Can-Pay (ACP) lock script on Nervos CKB
Readme
ACP-SDK
ACP SDK is a toolkit that helps developers interact with the Anyone-Can-Pay (ACP) lock script on Nervos CKB. This SDK simplifies creating ACP cells and managing token transfers to and from ACP addresses.
⚠️ Note: This project is under active development. APIs and functions may change in future releases.
Table of Contents
Overview
The ACP (Anyone-Can-Pay) lock extends the standard secp256k1-blake2b-sighash-all lock with enhanced functionality. It can be unlocked through:
- Regular signature validation
- Accepting payments of any amount
This powerful feature allows users to send any amount of CKBytes or UDTs to a cell using the ACP lock without creating a new cell each time.
ACP Lock Script Structure
Lock Script:
code_hash: anyone-can-pay lock
args: <20 byte blake160 secp256k1 public key hash>Getting Started with Examples
1. Generate Your CKB Address and Obtain Tokens
Generate a secp256k1 private key:
openssl rand -hex 32Setup environment variables:
cp .env.example .envThen add your generated private key to the
.envfile by updating theEXAMPLE_CKB_SECP256K1_PRIVATE_KEYvalue.Generate addresses:
pnpm generateAddressThis will generate both your default secp256k1 address and ACP address.
Obtain test tokens:
- Visit the testnet explorer: https://testnet.explorer.nervos.org/address/{ckb-secp256k1-address}
- Request CKB and USDI tokens from the faucet

Once completed, you'll have CKB and USDI tokens in your default secp256k1 address.
2. Create ACP Cells
You can change the ACP public key(acpPublicKey in examples/createAcpCells.ts) to create ACP cells for other accounts.
Use your private key and default secp256k1 address to create one or more ACP cells.
Set the desired number of cells by modifying the count parameter in examples/createAcpCells.ts and run the following command in your terminal:
pnpm createAcpCellsThe example Testnet transaction is here.
Inputs:
Normal Cell:
Capacity: N CKBytes
Lock:
code_hash: secp256k1_blake2b lock
args: <public key hash A>
Outputs:
Anyone-can-pay Cell:
Capacity: 144.01 CKBytes
Type: USDI type script
Lock:
code_hash: anyone-can-pay lock
args: <public key hash A>
Data:
Amount: 0 USDI
Change Cell:
Capacity: (N - 144.01 - fee) CKBytes
Lock:
code_hash: secp256k1_blake2b lock
args: <public key hash A>
Witnesses:
<valid signature for public key hash A>2-5. Optional: Deposit CKB to Your ACP Address
Important: Make sure at least one ACP cell exists before transferring to a new ACP address.
The function hasAcpCells of CkbUtils is to check if there's at least an ACP cell.
This step transfers CKB from your secp256k1 address to your ACP address (automatically generated with EXAMPLE_CKB_SECP256K1_PRIVATE_KEY in the example).
To deposit:
- Open
examples/depositCKBToAcp.ts - Set your desired amount in the
ckbAmountparameter - Run the following command:
pnpm depositCKBToAcpThe example Testnet transaction is here.
Inputs:
Normal Cell:
Capacity: N CKBytes
Lock:
code_hash: secp256k1_blake2b lock
args: <public key hash A>
Anyone-can-pay Cell:
Capacity: 144.01 CKBytes
Type: USDI type script
Lock:
code_hash: anyone-can-pay lock
args: <public key hash A>
Data:
Amount: M USDI
Outputs:
Anyone-can-pay Cell:
Capacity: (144.01 + K) CKBytes
Type: USDI type script
Lock:
code_hash: anyone-can-pay lock
args: <public key hash A>
Data:
Amount: M USDI
Change Cell:
Capacity: (N - K - fee) CKBytes
Lock:
code_hash: secp256k1_blake2b lock
args: <public key hash A>
Witnesses:
<valid signature for public key hash A>3. Deposit USDIs to Your ACP Address
Important: Make sure at least one ACP cell exists before transferring to a new ACP address.
The function hasAcpCells of CkbUtils is to check if there's at least an ACP cell.
This step transfers USDIs from your secp256k1 address to your ACP address (automatically generated with EXAMPLE_CKB_SECP256K1_PRIVATE_KEY in the example).
To deposit:
- Open
examples/depositUSDIToAcp.ts - Set your desired amount in the
usdiAmountparameter - Run the following command:
pnpm depositUSDIToAcpThe example Testnet transaction is here.
Inputs:
Normal Cell:
Capacity: N1 CKBytes
Lock:
code_hash: secp256k1_blake2b lock
args: <public key hash A>
Normal USDI Cell:
Capacity: N2 CKBytes
Type: USDI type script
Lock:
code_hash: secp256k1_blake2b lock
args: <public key hash A>
Data:
Amount: M USDI
Anyone-can-pay Cell:
Capacity: 144.01 CKBytes
Type: USDI type script
Lock:
code_hash: anyone-can-pay lock
args: <public key hash A>
Data:
Amount: 0 USDI
Outputs:
Anyone-can-pay Cell:
Capacity: 144.01 CKBytes
Type: USDI type script
Lock:
code_hash: anyone-can-pay lock
args: <public key hash A>
Data:
Amount: K USDI
Change Cell:
Capacity: (N1 + N2 - 144.01 - fee) CKBytes
Type: USDI type script
Lock:
code_hash: secp256k1_blake2b lock
args: <public key hash A>
Data:
Amount: (M - K) USDI
Witnesses:
<valid signature for public key hash A>4. Transfer USDIs Between ACP Addresses
Transfer some USDIs to another ACP address (another ACP address has been set in the example) from your ACP address.
Set a number you want to the usdiAmount and the toAcpAddress of the examples/transferFromAcpToAcp.ts and run the following command in your terminal:
pnpm transferBetweenAcpThe example Testnet transaction is here.
Inputs:
Anyone-can-pay Cell:
Capacity: 144.01 CKBytes
Type: USDI type script
Lock:
code_hash: anyone-can-pay lock
args: <public key hash A>
Data:
Amount: M USDI
Anyone-can-pay Cell:
Capacity: 144.01 CKBytes
Type: USDI type script
Lock:
code_hash: anyone-can-pay lock
args: <public key hash B>
Data:
Amount: S USDI
Outputs:
Anyone-can-pay Cell:
Capacity: 144.01 CKBytes
Type: USDI type script
Lock:
code_hash: anyone-can-pay lock
args: <public key hash B>
Data:
Amount: (S + K) USDI
Anyone-can-pay Change Cell:
Capacity: (144.01 - fee) CKBytes
Type: USDI type script
Lock:
code_hash: anyone-can-pay lock
args: <public key hash A>
Data:
Amount: (M - K) USDI
Witnesses:
<valid signature for public key hash A>5. Withdraw All USDIs to a Non-ACP Address
Transfer all your USDIs to a non-ACP address (A JoyID address has been set in the example) from your ACP address and your ACP cells will be destroyed.
Set a CKB address you want to the toNonAcpAddress of the examples/withdrawAllFromAcp.ts and run the following command in your terminal:
pnpm withdrawAllFromAcpThe example Testnet transaction is here.
Inputs:
Anyone-can-pay Cell:
Capacity: 144.01 CKBytes
Type: USDI type script
Lock:
code_hash: anyone-can-pay lock
args: <public key hash A>
Data:
Amount: M USDI
Outputs:
Non-ACP Cell:
Capacity: (144.01 - fee) CKBytes
Type: USDI type script
Lock: JoyID lock
Data:
Amount: M USDI
Witnesses:
<valid signature for public key hash A>