Skip to main content
The ECDSA signer uses the Ownable Validator module to authorise transactions with standard Ethereum key pairs. It supports both single-owner and multisig (n/m threshold) configurations on the same account.

Single owner

To create an account owned by a single ECDSA key:
import { RhinestoneSDK } from '@rhinestone/sdk'
import { privateKeyToAccount } from 'viem/accounts'

const signer = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)

const rhinestone = new RhinestoneSDK({
  apiKey: process.env.RHINESTONE_API_KEY as string,
})

const account = await rhinestone.createAccount({
  owners: {
    type: 'ecdsa',
    accounts: [signer],
  },
})

Multisig

The Ownable Validator supports n/m multisig with multiple owners and a configurable signature threshold. This is useful for shared accounts, treasury management, or any scenario where unilateral control is a risk.

Setup

Pass multiple accounts and set a threshold. The threshold defines how many signatures are required to authorise a transaction.
const account = await rhinestone.createAccount({
  owners: {
    type: 'ecdsa',
    accounts: [signerA, signerB, signerC],
    threshold: 2, // 2-of-3
  },
})
By default, threshold is 1, meaning any single owner can sign.

Signing with a subset of owners

For m-of-n setups, specify which signers to use when sending a transaction:
const result = await account.sendTransaction({
  chain,
  calls: [
    // …
  ],
  signers: {
    type: 'owner',
    kind: 'ecdsa',
    accounts: [signerA, signerB],
  },
})
Provide at least as many signers as the threshold requires, or the transaction will fail validation.

Add a signer

import { addOwner } from '@rhinestone/sdk/actions/ecdsa'

await account.sendTransaction({
  chain,
  calls: [addOwner(newSigner.address)],
})

Remove a signer

import { removeOwner } from '@rhinestone/sdk/actions/ecdsa'

await account.sendTransaction({
  chain,
  calls: [removeOwner(signerC.address)],
})

Change threshold

import { changeThreshold } from '@rhinestone/sdk/actions/ecdsa'

await account.sendTransaction({
  chain,
  calls: [changeThreshold(2)],
})

Get current owners

const owners = await account.getOwners(chain)
// → { accounts: ['0xaaa…', '0xbbb…', '0xccc…'], threshold: 2 }

Enable in a separate transaction

If you need to enable the ECDSA module on an existing account rather than at creation time:
import { enable as enableEcdsa } from '@rhinestone/sdk/actions/ecdsa'

await account.sendTransaction({
  chain,
  calls: [enableEcdsa([signer.address])],
  tokenRequests: [],
})