Create an External Party (Wallet)

Overview

This document describes the steps required to create a new party (wallet/address) on a validator. Parties represent acting entites in the network and all transaction happens between one or more parties. To understand more about parties see Parties section here.

A detailed tutorial of the steps below can be seen in the External Signing Tutorial here using python example scripts.

This document focuses on the steps required to create an external party using the Wallet SDK.

How do I quickly allocate a party?

Using the wallet SDK you can quickly allocate a party using the following code snippet:

import {
    WalletSDKImpl,
    TopologyController,
    localNetAuthDefault,
    localNetLedgerDefault,
    localNetTopologyDefault,
} from '@canton-network/wallet-sdk'
import { LOCALNET_SCAN_API_URL } from '../config.js'

// it is important to configure the SDK correctly else you might run into connectivity or authentication issues
const sdk = new WalletSDKImpl().configure({
    logger: console,
    authFactory: localNetAuthDefault, // or use your specific configuration
    ledgerFactory: localNetLedgerDefault, // or use your specific configuration
    topologyFactory: localNetTopologyDefault, // or use your specific configuration
})
await sdk.connectTopology(LOCALNET_SCAN_API_URL)

const { publicKey, privateKey } = TopologyController.createNewKeyPair()
//partyHint is optional but recommended to make it easier to identify the party
const partyHint = 'my-wallet-1'

const allocatedParty = await sdk.topology?.prepareSignAndSubmitExternalParty(
    privateKey,
    partyHint
)

Create the key Pair

The process for creating a key using standard encryption practices is similar that in other blockchains. The full details of supported cryptographic algorithms can be found Here. By default an Ed25519 encryption is used. There exists many libraries that can be used to generate such a key pair, you can do it simply with the WalletSDK using:

import { TopologyController } from '@canton-network/wallet-sdk'
// static method call
const { publicKey, privateKey } = TopologyController.createNewKeyPair()

Choosing a party hint

A party ID is defined as ${partyHint}::${fingerprint}. The partyHint is a user friendly name for the party and can be anything that is unique for the fingerprint, e.g. “alice”, “bob” or “my-wallet-1”.

If you want to be to derive your party IDs from the public key, you can use a static party hint for all parties with different fingerprints, or also derive party hint from the public key, too.

Generate the fingerprint

To generate the fingerprint the wallet SDK has a built in function:

import { TopologyController } from '@canton-network/wallet-sdk'
const publicKey = 'your-public-key-here'
// static method call
const fingerPrint = TopologyController.createFingerprintFromPublicKey(publicKey)

Generating the topology transactions

When onboarding using external signing, multiple topology transactions are required to be generated and signed. This is because both the keyHolder (the party) and the node (the validator) need to agree on the hosting relationship. The three transactions that needs to be generated are:

  • PartyToParticipant: This transaction indicates that the party agrees to be hosted by the participant (validator).

  • ParticipantToParty: This transaction indicates that the participant (validator) agrees to host the party.

  • KeyToParty: This transaction indicates that the key (public key) is associated with the party.

Once all the transactions are built they can be combined into a single hash and submitted as part of a single signature. The wallet SDK has helper functions to generate these transactions:

import {
    WalletSDKImpl,
    TopologyController,
    localNetAuthDefault,
    localNetLedgerDefault,
    localNetTopologyDefault,
} from '@canton-network/wallet-sdk'
import { LOCALNET_SCAN_API_URL } from '../config.js'

// it is important to configure the SDK correctly else you might run into connectivity or authentication issues
const sdk = new WalletSDKImpl().configure({
    logger: console,
    authFactory: localNetAuthDefault, // or use your specific configuration
    ledgerFactory: localNetLedgerDefault, // or use your specific configuration
    topologyFactory: localNetTopologyDefault, // or use your specific configuration
})

await sdk.connectTopology(LOCALNET_SCAN_API_URL)

const { publicKey, privateKey } = TopologyController.createNewKeyPair()
//partyHint is optional but recommended to make it easier to identify the party
const partyHint = 'my-wallet-1'

const preparedParty = await sdk.topology?.prepareExternalPartyTopology(
    privateKey,
    partyHint
)

Sign multi-hash

Since the topology transactions need to be submitted together the combined hash needs to be signed. The wallet SDK has a helper function to sign the combined hash:

import { signTransactionHash } from '@canton-network/wallet-sdk'

const preparedParty = { combinedHash: 'combined-hash-here' }
const privateKey = 'your-private-key-here'

const signature = signTransactionHash(preparedParty.combinedHash, privateKey)

Submit the topology transactions

Once the signature is generated, the topology transactions can be submitted to the validator. The wallet SDK has a helper function to submit the transactions:

import {
    WalletSDKImpl,
    localNetAuthDefault,
    localNetLedgerDefault,
    localNetTopologyDefault,
} from '@canton-network/wallet-sdk'
import { LOCALNET_SCAN_API_URL } from '../config.js'

// it is important to configure the SDK correctly else you might run into connectivity or authentication issues
const sdk = new WalletSDKImpl().configure({
    logger: console,
    authFactory: localNetAuthDefault, // or use your specific configuration
    ledgerFactory: localNetLedgerDefault, // or use your specific configuration
    topologyFactory: localNetTopologyDefault, // or use your specific configuration
})
await sdk.connectTopology(LOCALNET_SCAN_API_URL)

const preparedParty = {
    partyTransactions: [], // array of topology transactions
    combinedHash: 'the-combined-hash',
    txHashes: [], // the individual transaction hashes
    namespace: 'your-namespace-here',
    partyId: 'your-party-id-here',
}
const signature = 'your-signed-hash-here'

sdk.topology?.submitExternalPartyTopology(signature, preparedParty)