npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@fivenorth/loop-sdk

v0.10.0

Published

Loop SDK allows dApps connect to a [Loop](https://cantonloop.com) account. The Loop wallet can be on mobile or on a desktop browser. All the interaction will happen inside the dApp. For signing, user will be prompted to sign either on their Loop wallet on

Readme

Loop SDK

Loop SDK allows dApps connect to a Loop account. The Loop wallet can be on mobile or on a desktop browser. All the interaction will happen inside the dApp. For signing, user will be prompted to sign either on their Loop wallet on mobile devices or on browser.

Limitation

Currently, we only support DAML transaction from the Splice build-in DAR files and Utility app DAR files.

There is no plan to upload and support third party DAR at this moment

Quick overview

For a quick overview of how the code look like, you can take a look at this pen https://codepen.io/kureikain/pen/KwVGgLX.

Usage guide

To use the Loop SDK, you first need to install it from NPM:

bun add @fivenorth/loop-sdk

Then you can import it in your dApp:

import { loop } from '@fivenorth/loop-sdk';

Note that, If you don't want to implement a build process, you can include the file directly with unpkg such as

import { loop } from 'https://unpkg.com/@fivenorth/[email protected]/dist';

An example of how we use it in that manner is on our loopsdk demo

1. Initialize the SDK

Before you can connect, you need to initialize the SDK. This is typically done once when your application loads.

loop.init({
    appName: 'My Awesome dApp',
    network: 'local', // or 'devnet', 'mainnet'
    onTransactionUpdate: (payload) => {
        console.log('Transaction update:', payload);
    },
    options: {
        openMode: 'popup', // 'popup' (default) or 'tab'
        requestSigningMode: 'popup', // 'popup' (default) or 'tab'
        redirectUrl: 'https://myapp.com/after-connect', // optional redirect after approval
    },
    onAccept: (provider) => {
        console.log('Connected!', provider);
        // You can now use the provider to interact with the wallet
    },
    onReject: () => {
        console.log('Connection rejected by user.');
    },
});

The init method takes a configuration object with the following properties:

  • appName: The name of your application, which will be displayed to the user in the Loop wallet.
  • network: The network to connect to. Can be local, devnet, or mainnet.
  • onTransactionUpdate: Called when a transaction update is finalized (includes update_id and optional update_data).
  • options: Optional object containing:
    • openMode: Controls how Loop opens: 'popup' (default) or 'tab'.
    • requestSigningMode: Controls how signing/transaction requests open the wallet UI after you're connected: 'popup' (default) or 'tab'.
    • redirectUrl: Optional redirect URL the wallet will navigate back to after successful approval. If omitted, user stays on Loop dashboard.
  • onAccept: A callback function that is called when the user accepts the connection. It receives a provider object.
  • onReject: A callback function that is called when the user rejects the connection.

2. Connect to the wallet

To initiate the connection, call loop.connect():

loop.connect();

This will open a modal with a QR code for the user to scan with their Loop wallet. If you set requestSigningMode to 'popup' (or 'tab'), each signing/transaction request will also open the wallet dashboard and auto-close the popup once the wallet responds.

3. Using the Provider

Once the connection is established, the onAccept callback will receive a provider object. This object provides methods to interact with the user's wallet and the DAML ledger.

The provider object has the party_id of the connected user.

Get Holdings

To get the user's token holdings:

const holdings = await provider.getHolding();
console.log(holdings);

Each holding includes its instrument_id (with admin and id fields), which you can use when building transfers for CC, CIP-56 tokens, LOOP, or any custom instrument.

Get Active Contracts

You can query for active contracts by templateId or interfaceId.

By Template ID:

const contracts = await provider.getActiveContracts({ 
    templateId: '#splice-amulet:Splice.Amulet:Amulet' 
});
console.log(contracts);

By Interface ID:

const contracts = await provider.getActiveContracts({ 
    interfaceId: '#splice-api-token-holding-v1:Splice.Api.Token.HoldingV1:Holding' 
});
console.log(contracts);

Submit a Transaction

To submit a DAML transaction, you need to construct a command object and pass it to submitTransaction:

const damlCommand = {
    commands: [{
        ExerciseCommand: {
            templateId: "#splice-api-token-transfer-instruction-v1:Splice.Api.Token.TransferInstructionV1:TransferFactory",
            contractId: 'your-contract-id', // The contract ID to exercise the choice on
            choice: 'TransferFactory_Transfer',
            choiceArgument: {
                // ... your choice arguments
            }
        }
    }],
    // ... other command properties
};

try {
    const result = await provider.submitTransaction(damlCommand, {
        // Optional: show a custom message in the wallet prompt
        message: 'Transfer 10 CC to RetailStore',
        estimateTraffic: true, // optional: return estimated traffic in submission response
    });
    console.log('Transaction successful:', result);
} catch (error) {
    console.error('Transaction failed:', error);
}

onTransactionUpdate fires once per transaction with a single payload that includes command_id and submission_id. On success it also includes update_id and update_data (ledger transaction tree); on failure it includes status: "failed" and error.error_message.

submitTransaction is the default async path. It returns the submission result first (including command_id and submission_id), then the ledger update arrives later via onTransactionUpdate with update_id and update_data.

To wait for the transaction result directly (opt-in), use:

await provider.submitAndWaitForTransaction(damlCommand, {
    message: 'Transfer 10 CC to RetailStore',
});

In wait mode, the final result is returned as a single onTransactionUpdate payload (command/submission IDs plus update data or failure status).

Note: submitAndWaitForTransaction errors do not always mean the transaction failed. A 4xx error (e.g., 400) indicates a definite failure. A 5xx/timeout can mean the ledger is slow or backed up; the transaction may still be committed later, so clients should continue to listen for updates rather than assume failure.

Deduplication: both async execute and execute-and-wait use a 1 hour deduplication window. If you retry within that window, resubmit the same command_id and submission_id so the request is idempotent.

Sign a Message

You can request the user to sign an arbitrary message:

const message = 'Hello, Loop!';
try {
    const signature = await provider.signMessage(message);
    console.log('Signature:', signature);
} catch (error) {
    console.error('Signing failed:', error);
}

Transfer (built-in helper)

await loop.wallet.transfer(
  'receiver::fingerprint',
  '5', 
  {
    instrument_admin: 'issuer::fingerprint', // optional: DSO (default)
    instrument_id: 'Amulet',                 // optional: Amulet (default)
  },
  {
    message: 'Send 5 CC to Alice', // optional: show a custom message in the wallet prompt
    memo: 'optional memo for the transfer',   // optional: stored as transfer metadata
    executionMode: 'wait',                   // optional: 'async' (default) or 'wait'
    requestedAt: new Date().toISOString(),   // optional
    executeBefore: new Date(Date.now() + 24*60*60*1000).toISOString(), // optional
    requestTimeout: 5 * 60 * 1000,           // optional (ms), defaults to 5 minutes
    estimateTraffic: true,                   // optional: return estimated traffic in submission response
  },
);

Notes:

  • You must have spendable holdings for the specified instrument (admin + id). If left blank, the SDK defaults to the native token.
  • The helper handles fetching holdings, building the transfer factory payload, and submitting via Wallet Connect.

Common instrument overrides (pass into the instrument argument above):

  • Canton Coin (CC): { instrument_admin: 'cc-issuer::fingerprint', instrument_id: 'CC' }
  • CIP-56: { instrument_admin: 'cip56-issuer::fingerprint', instrument_id: 'CIP-56' }

Swap in the admin/id for the specific instrument you hold in the Loop wallet.

USDC withdraw helper

await loop.wallet.extension.usdcBridge.withdrawalUSDCxToEthereum(
  '0xYourEthAddress',
  '10.5', // amount in USDCx
  {
    reference: 'optional memo',
    message: 'Withdraw 10.5 USDCx to 0xabc', // optional custom prompt text
    requestTimeout: 5 * 60 * 1000, // optional override (ms)
  },
);

Notes:

  • Uses the connect-based withdraw endpoint to prepare the transaction and sends it over Wallet Connect.
  • The helper auto-reconnects the websocket if it was closed before sending the request.

API

Coming soon

Development Guide

This section is only if you want to actively develop the SDK itself. To use the SDK, follow the #Usage Guide section

To install dependencies:

bun install

To run the dev server, that is also auto re-compile the sdk:

bun start

Upon doing so you can visit http://localhost:3030/ to see the local demo app, serve in demo/test.html and SDK is auto compile so you can actively working and trying out the SDK.

Publish the package to NPM

bun run build
bun publish