Skip to content

Implementing a Custom Chain Signature Contract

This guide explains how to implement a custom Chain Signature Contract to provide as argument when instantiating a Chain instance.

Overview

The ChainSignatureContract is an abstract class that defines the interface for interacting with the Sig Network infrastructure.

  • Key Derivation: Derive the child key from the root key using Sig Network key derivation function
  • Sign: Sigs the given payload using Sig Network MPC
  • Current Fee: Gets the current signature deposit that handles network congestion
  • Root Public Key: Gets the root public key of the Smart Contract on Sig Network MPC

You have the flexibility to implement your own contract for other blockchain networks.

Using the EVM Implementation

import { contracts, chainAdapters } from 'signet.js'
 
const contract = new contracts.evm.ChainSignatureContract({
  publicClient: undefined as any,
  walletClient: undefined as any,
  contractAddress: '0x...'
})

Implementing a Custom Chain Signature Contract

To create your own implementation to use on the Chain Adapter Instance, your contract must implement the BaseChainSignatureContract interface.

In case you need you want all Sig Network Smart Contract capabilities, you can implement the ChainSignatureContract interface.

import type BN from 'bn.js'
 
import type { RSVSignature, UncompressedPubKeySEC1 } from '@types'
 
export interface SignArgs {
  /** The payload to sign as an array of 32 bytes */
  payload: number[]
  /** The derivation path for key generation */
  path: string
  /** Version of the key to use */
  key_version: number
}
 
/**
 * Base contract interface required for compatibility with ChainAdapter instances like EVM and Bitcoin.
 *
 * See {@link EVM} and {@link Bitcoin} for example implementations.
 */
export abstract class BaseChainSignatureContract {
  /**
   * Gets the current signature deposit required by the contract.
   * This deposit amount helps manage network congestion.
   *
   * @returns Promise resolving to the required deposit amount as a BigNumber
   */
  abstract getCurrentSignatureDeposit(): Promise<BN>
 
  /**
   * Derives a child public key using a\ derivation path and predecessor.
   *
   * @param args - Arguments for key derivation
   * @param args.path - The string path to use derive the key
   * @param args.predecessor - The id/address of the account requesting signature
   * @param args.keyVersion - Optional key version controlling the derivation prefix (defaults to 0)
   * @returns Promise resolving to the derived SEC1 uncompressed public key
   */
  abstract getDerivedPublicKey(
    args: {
      path: string
      predecessor: string
      keyVersion: number
    } & Record<string, unknown>
  ): Promise<UncompressedPubKeySEC1>
}
 
/**
 * Full contract interface that extends BaseChainSignatureContract to provide all Sig Network Smart Contract capabilities.
 */
export abstract class ChainSignatureContract extends BaseChainSignatureContract {
  /**
   * Signs a payload using Sig Network MPC.
   *
   * @param args - Arguments for the signing operation
   * @param args.payload - The data to sign as an array of 32 bytes
   * @param args.path - The string path to use derive the key
   * @param args.key_version - Version of the key to use
   * @returns Promise resolving to the RSV signature
   */
  abstract sign(args: SignArgs & Record<string, unknown>): Promise<RSVSignature>
 
  /**
   * Gets the public key associated with this contract instance.
   *
   * @returns Promise resolving to the SEC1 uncompressed public key
   */
  abstract getPublicKey(): Promise<UncompressedPubKeySEC1>
}

Example: EVM Implementation

Refer to the EVM contract in the source tree at src/contracts/evm/ChainSignaturesContract.ts.