Use our SDKs
We provide various language SDKs to make integrations easier for developers.
Available SDKsโ
Language | Repository | Status |
---|---|---|
Go | ark-network/ark/pkg/client-sdk | Experimental ๐ง |
TypeScript | ArkLabsHQ/wallet-sdk | Experimental ๐ง |
Rust | ArkLabsHQ/ark-rs | Experimental ๐ง |
Install the SDKโ
- Go
- Rust
- Typescript
go get github.com/ark-network/ark/pkg/client-sdk
cargo install ark-rs
npm install @arklabs/wallet-sdk
Initialize the Clientโ
- Go
- Rust
- Typescript
storeSvc, err := store.NewStore(store.Config{
ConfigStoreType: arksdktypes.FileStore,
AppDataStoreType: arksdktypes.SQLStore,
BaseDir: "path/to/datadir",
})
if err != nil {
log.Fatalf("failed to setup client db: %s", err)
}
clientSvc, err := arksdk.LoadArkClient(storeSvc)
if err != nil {
clientSvc, err = arksdk.NewArkClient(storeSvc)
if err != nil {
log.Fatalf("failed to setup ark client: %s", err)
}
}
let blockchain = Arc::new(MyBlockchain::new("https://esplora.example.com"));
let wallet = Arc::new(MyWallet::new());
let server_url = "https://ark-server.example.com".to_string();
// no need to initialize client in typescript
Creating a walletโ
- Go
- Rust
- Typescript
password := "password"
serverUrl := "localhost:7070"
ctx := context.Background()
if err := clientSvc.Init(ctx, arksdk.InitArgs{
WalletType: arksdk.SingleKeyWallet,
ClientType: arksdk.GrpcClient,
ServerUrl: serverUrl,
Password: password,
}); err != nil {
log.Fatalf("failed to initialize ark client: %s", err)
}
if err := clientSvc.Unlock(ctx, password); err != nil {
log.Fatalf("failed to unlock ark client: %s", err)
}
let secp = bitcoin::key::Secp256k1::new();
let secret_key = SecretKey::from_str("your_private_key_here")?;
let keypair = Keypair::from_secret_key(&secp, &secret_key);
let offline_client = OfflineClient::new(
"my-ark-client".to_string(),
keypair,
blockchain,
wallet,
server_url,
);
let client = offline_client.connect().await?;
const identity = new InMemoryKey()
const wallet = await Wallet.create({
network: 'mutinynet',
identity: identity
})
Load an existing walletโ
- Go
- Rust
- Typescript
password := "password"
ctx := context.Background()
if err := clientSvc.Unlock(ctx, password); err != nil {
log.Fatalf("failed to unlock ark client: %s", err)
}
let secp = bitcoin::key::Secp256k1::new();
let secret_key = SecretKey::from_str("your_private_key_here")?;
let keypair = Keypair::from_secret_key(&secp, &secret_key);
let offline_client = OfflineClient::new(
"my-ark-client".to_string(),
keypair,
blockchain,
wallet,
server_url,
);
let client = offline_client.connect().await?;
const identity = InMemoryKey.fromHex('private_key_hex')
const wallet = await Wallet.create({
network: 'mutinynet',
identity: identity,
})
Receiving fundsโ
- Go
- Rust
- Typescript
myOffchainAddr, myBoardingAddr, err := clientSvc.Receive(context.Backgroud())
if err != nil {
log.Fatalf("failed to fetch address: %s", err)
}
fmt.Printf("offchain address: %s\nboarding address: %s\n", myOffchainAddr, myBoardingAddr)
let (ark_address, vtxo) = client.get_offchain_address();
println!("Send VTXOs to this offchain address: {}", ark_address);
let boarding_address = client.get_boarding_address()?;
println!("Send coins to this on-chain address: {}", boarding_address);
const addresses = await wallet.getAddress()
console.log('Bitcoin Address:', addresses.onchain)
console.log('Ark Address:', addresses.offchain)
console.log('Boarding Address:', addresses.boarding)
console.log('BIP21 URI:', addresses.bip21)
Sending fundsโ
- Go
- Rust
- Typescript
ctx := context.Background()
receivers := []arksdk.Receiver{
arksdk.NewBitcoinReceiver(destOffchainAddr, amountInSats),
}
var change []arksdktypes.Vtxo
var err error
wg := &sync.WaitGroup{}
wg.Add(1)
go func() {
change, err = clientSvc.NotifyIncomingFunds(ctx, myOffchainAddr)
wg.Done()
}()
withExpiryCoinSelection := true
withZeroFees := true
txid, err := clientSvc.SendOffChain(ctx, !withExpiryCoinSelection, receivers, withZeroFees)
if err != nil {
log.Fatalf("failed to send offchain: %s", err)
}
wg.Wait()
if err != nil {
log.Fatalf("failed to fetch incoming funds: %s", err)
}
log.Printf("sent funds offchain: %s\nchange vtxos: %+v\n", txid, change)
let ark_address = ArkAddress::decode(address)?;
let amount = Amount::from_sat(amount_sats);
let psbt = client.send_vtxo(ark_address, amount).await?;
let txid = psbt.extract_tx()?.compute_txid();
println!(
"Sent {} sats to {} in transaction {}",
amount_sats, address, txid
);
const txid = await wallet.sendBitcoin({
address: offchainAddress,
amount: amount // in satoshis
})
Detect incoming fundsโ
- Go
- Rust
- Typescript
vtxos, err := clientSvc.NotifyIncomingFunds(ctx, myOffchainAddr)
if err != nil {
log.Fatalf("failed to fetch incoming funds: %s", err)
}
fmt.Printf("vtxos: %+v\n", vtxos)
let (my_offchain_addr, _) = client.get_offchain_address();
let initial_balance = client.offchain_balance().await?;
println!("Initial balance: confirmed = {}, pending = {}", initial_balance.confirmed(), initial_balance.pending());
tokio::time::timeout(Duration::from_secs(30), async {
loop {
let current_balance = client.offchain_balance().await?;
if current_balance.confirmed() != initial_balance.confirmed() ||
current_balance.pending() != initial_balance.pending() {
println!("Balance changed: confirmed = {}, pending = {}",
current_balance.confirmed(), current_balance.pending());
return Ok::<_, ark_client::Error>(());
}
println!("Waiting for balance to change...");
tokio::time::sleep(Duration::from_secs(1)).await;
}
})
.await
.unwrap_or_else(|_| {
println!("Timeout reached while waiting for balance change");
Ok(())
})?;
function watchWalletChanges(wallet: any) {
let intervalId: NodeJS.Timeout | null = null;
// Function to stop watching
const stop = () => {
if (intervalId) clearInterval(intervalId);
};
// Promise that resolves when changes are detected
const promise = new Promise<void>(async (resolve) => {
// Get initial state
const initialVtxos = await wallet.getVtxos();
const initialBoardingUtxos = await wallet.getBoardingUtxos();
console.log(`Initial: ${initialVtxos.length} VTXOs, ${initialBoardingUtxos.length} boarding UTXOs`);
// Check for changes every second
intervalId = setInterval(async () => {
const currentVtxos = await wallet.getVtxos();
const currentBoardingUtxos = await wallet.getBoardingUtxos();
// Compare counts for simplicity in this example
if (currentVtxos.length !== initialVtxos.length ||
currentBoardingUtxos.length !== initialBoardingUtxos.length) {
console.log(`Changed: ${currentVtxos.length} VTXOs, ${currentBoardingUtxos.length} boarding UTXOs`);
stop();
resolve();
}
}, 1000);
});
return { stop, promise };
}
// Example usage:
// const watcher = watchWalletChanges(wallet);
//
// // Stop watching after 10 seconds
// setTimeout(() => watcher.stop(), 10000);
//
// // Wait for changes
// watcher.promise.then(() => console.log("Changes detected"));
Fetch your balanceโ
- Go
- Rust
- Typescript
computeExpiry := true
skipComputeExpiry := !computeExpiry
balance, err := clientSvc.Balance(context.Background(), skipComputeExpiry)
if err != nil {
log.Fatal(err)
}
fmt.Printf("offchain balance: %+v\nonchain balance: %+v\n", balance.OffchainBalance, balance.OnchainBalance)
let balance = client.offchain_balance().await?;
println!(
"Offchain balance: confirmed = {}, pending = {}, total = {}",
balance.confirmed(),
balance.pending(),
balance.total()
);
let spendable_vtxos = client.spendable_vtxos().await?;
println!("Number of spendable vtxos: {}", spendable_vtxos.len());
const balance = await wallet.getBalance()
console.log('Total Onchain:', balance.onchain.total)
console.log('Total Offchain:', balance.offchain.total)
Batch Swapโ
- Go
- Rust
- Typescript
ctx := context.Background()
var vtxos []arksdktypes.Vtxo
var err error
wg := &sync.WaitGroup{}
wg.Add(1)
go func() {
vtxos, err = clientSvc.NotifyIncomingFunds(ctx, myOffchainAddr)
wg.Done()
}()
commitmenTxid, err := clientSvc.Settle(ctx)
if err != nil {
log.Fatalf("failed to settle: %s", err)
}
wg.Wait()
if err != nil {
log.Fatalf("failed to fetch incoming funds: %s", err)
}
fmt.Printf("vtxos settled in commitment tx: %s\nsettled vtxos: %+v\n", commitmenTxid, vtxos)
let mut rng = thread_rng();
client.board(&mut rng).await.unwrap();
const inputs = (await Promise.all([
wallet.getVtxos(),
wallet.getBoardingUtxos()
])).flat()
const ownAddress = (await wallet.getAddress()).offchain
const amount = BigInt(inputs.reduce((acc, input) => acc + input.amount, 0))
const settleTxid = await wallet.settle({
inputs,
outputs: [{
address: ownAddress,
amount
}]
})
Collaborative Exitโ
- Go
- Rust
- Typescript
ctx := context.Background()
var change []arksdktypes.Vtxo
var err error
wg := &sync.WaitGroup{}
wg.Add(1)
go func() {
change, err = clientSvc.NotifyIncomingFunds(ctx, myOffchainAddr)
wg.Done()
}()
withExpiryCoinSelection := true
commitmentTxid, err := clientSvc.CollaborativeExit(ctx, destOnchainAddr, amountInSats, !withExpiryCoinSelection)
if err != nil {
log.Fatalf("failed to send onchain: %s", err)
}
wg.Wait()
if err != nil {
log.Fatalf("failed to fetch incoming funds: %s", err)
}
log.Printf("sent funds onchain in commitment tx: %s\nchange vtxos: %+v\n", commitmentTxid, change)
client.send_on_chain(address, amount).await?;
const inputs = (await Promise.all([
wallet.getVtxos(),
wallet.getBoardingUtxos()
])).flat()
const settleTxid = await wallet.settle({
inputs,
outputs: [{
address: destinationAddress,
amount: BigInt(amount)
}]
})
Unilateral Exitโ
- Go
- Rust
- Typescript
if err := clientSvc.StartUnilateralExit(ctx context.Context); err != nil {
log.Fatalf("failed to unilaterally exit offchain funds: %s", err)
}
fmt.Println("all vtxos have been unrolled, wait until locktime expiration to move the funds to your wallet")
// Once all branches are onchain, the user can move the funds only after a locktime of usually 24h.
// As soon as the locktime expires, the user can move the unrolled funds to his own onchain wallet with:
txid, err := clientSvc.CompleteUnilateralExit(ctx context.Context, myOnchainWalletAddr string) (string, error)
if err != nil {
log.Fatalf("failed to move funds to your wallet: %s", err)
}
fmt.Printf("moved funds to your wallet: %s\n", txid)
client.commit_vtxos_on_chain().await.unwrap();
//Not implemented yet