Constellation Network
IntroductionFundamentalsFor DevelopersNode Validators
  • Index
  • Guide
    • Introduction
    • Provider Activation
    • Sending RPC Requests
    • Signing Data
    • Supported Connectors
    • Using External Libraries
  • API Reference
    • Overview
    • Wallet provider API
      • Overview
      • errorTypes
      • version
      • getProvider()
  • Chain Provider API
    • Overview
    • activated
    • chain
    • version
    • on()
    • removeListener()
    • async activate()
    • async onAsync()
    • async removeListenerAsync()
    • async request()
  • Constellation RPC API
    • Overview
    • dag_accounts
    • dag_chainId
    • dag_getBalance
    • dag_getMetagraphBalance
    • dag_getMetagraphPendingTransaction
    • dag_getMetagraphTransaction
    • dag_getPendingTransaction
    • dag_getPublicKey
    • dag_getTransaction
    • dag_requestAccounts
    • dag_sendMetagraphTransaction
    • dag_sendMetagraphDataTransaction
    • dag_signMetagraphDataTransaction
    • dag_sendTransaction
    • dag_signData
    • dag_signMessage
    • wallet_watchAsset
    • dag_delegatedStake
    • dag_withdrawDelegatedStake
    • dag_allowSpend
    • dag_tokenLock
  • Ethereum RPC API
    • Overview
    • eth_accounts
    • eth_blockNumber
    • eth_call
    • eth_chainId
    • eth_estimateGas
    • eth_gasPrice
    • eth_getBalance
    • eth_getBlockByHash
    • eth_getBlockByNumber
    • eth_getBlockTransactionCountByHash
    • eth_getBlockTransactionCountByNumber
    • eth_getCode
    • eth_getFilterChanges
    • eth_getFilterLogs
    • eth_getLogs
    • eth_getStorageAt
    • eth_getTransactionByBlockHashAndIndex
    • eth_getTransactionByBlockNumberAndIndex
    • eth_getTransactionByHash
    • eth_getTransactionCount
    • eth_getTransactionReceipt
    • eth_getUncleByBlockHashAndIndex
    • eth_getUncleByBlockNumberAndIndex
    • eth_getUncleCountByBlockHash
    • eth_getUncleCountByBlockNumber
    • eth_newBlockFilter
    • eth_newFilter
    • eth_protocolVersion
    • eth_requestAccounts
    • eth_sendTransaction
    • eth_signTypedData
    • eth_signTypedData_v4
    • eth_uninstallFilter
    • net_version
    • personal_sign
    • web3_sha3
  • Resources
    • Stargazer Github
    • Stargazer Connector Github
    • Stargazer Demos Github
    • Stargazer Chrome
    • Stargazer Android
    • Stargazer IOS
    • EIP-1193
Powered by GitBook

Main

  • Website
  • Get DAG
  • Explore Projects
  • Partners

Socials

  • Telegram
  • Discord
  • X (Twitter)

Tools

  • Wallet
  • DAG Explorer
  • Coingecko

© 2025 CONSTELLATION NETWORK

On this page
  • Constellation Message Signing​
  • Ethereum Message Signing​
  • Constellation Signature Verification​
  • Ethereum Signature Verification​

Was this helpful?

Export as PDF
  1. Guide

Signing Data

PreviousSending RPC RequestsNextSupported Connectors

Last updated 1 month ago

Was this helpful?

Signing arbitrary data enables you to verify the user's possession of an account. This guide will walk you through the signing process and verification.

Obtain a chain provider

As covered in , obtain a chain provider for the networks you want to interact with. In the following examples, we will use both Ethereum and Constellation providers.

const dagProvider = window.stargazer.getProvider("constellation");
const ethProvider = window.stargazer.getProvider("ethereum");

Constellation Message Signing

Build a signature request

Constellation signatures for messages are done through a . The signature request object is sent for the user to accept. Uppon approval, a signature of the whole object is returned.

// Build the signature request
const signatureRequest: SignatureRequest = {
  content: "Sign this message to confirm your address",
  metadata: {
    user: "3feb69d6-d3f0-4812-9c93-384bee08afe8",
  },
};

Encode the signature request

Requests need to be a Base64 < JSON encoded string to sign. The wallet will then generate the signature from the same characters that compose this encoded request.

// Encode the signature request - Base64 < JSON < Request
const signatureRequestEnconded = window.btoa(JSON.stringify(signatureRequest));

Important

// Send the request and wait for the signature
await dagProvider.request({
  method: "dag_signMessage",
  params: [
    "DAG88C9WDSKH451sisyEP3hAkgCKn5DN72fuwjfX",
    signatureRequestEnconded,
  ],
});
// "3045022100b35798008516373fcc6eef75fe8e322ce8fe0dccc4802b052f3ddc7c6b5dc2900220154cac1e4f3e7d9a64f4ed9d2a518221b273fe782f037a5842725054f1c62280"

The returned signature corresponds to the SHA512 hash of the encoded signature request and the private key of the user. ECDSA.sign(privateKey, sha512(signatureRequestEnconded)).

After you generate a signature from your encoded request, you need to retrieve the public key from the signer's account for future verification. This is due to the fact that Constellation signatures are not recoverable (i.e. do not contain the v parameter like in Ethereum).

// Send the request and wait for the signature
await dagProvider.request({
  method: "dag_getPublicKey",
  params: ["DAG88C9WDSKH451sisyEP3hAkgCKn5DN72fuwjfX"],
});
// "0482c4566a9c4cbb6f23b9a31c96876501c71f5c04b35f416e0b2243113cce8fb386a2db0b3881d1c908d33465748b948649165a6705904120238999eed6eed1f4"
// Send the request and wait for the signature
await dagProvider.request({
  method: "personal_sign",
  params: [
    "0x5369676e2074686973206d65737361676520746f20636f6e6669726d20796f7572206164647265737320616e64207573657249642033666562363964362d643366302d343831322d396339332d333834626565303861666538",
    "0x9b2055d370f73ec7d8a03e965129118dc8f5bf83",
  ],
});
// "0xa3f20717a250c2b0b729b7e5becbff67fdaef7e0699da4de7ca5895b02a170a12d887fd3b17bfdce3481f10bea41f45ba9f709d39ce8325427b57afcfc994cee1b"

// Can also be a valid UTF-8 string
await dagProvider.request({
  method: "personal_sign",
  params: [
    "Sign this message to confirm your address and userId 3feb69d6-d3f0-4812-9c93-384bee08afe8",
    "0x9b2055d370f73ec7d8a03e965129118dc8f5bf83",
  ],
});
// "0xa3f20717a250c2b0b729b7e5becbff67fdaef7e0699da4de7ca5895b02a170a12d887fd3b17bfdce3481f10bea41f45ba9f709d39ce8325427b57afcfc994cee1b"

The returned signature corresponds to the keccak256 hash of the prefix + message string and the private key of the user. ECDSA.sign(privateKey, keccak256("\x19Ethereum Signed Message:\n" + len(message) + message)).

await provider.request({
  method: "eth_signTypedData",
  params: [
    "0x567d0382442c5178105fC03bd52b8Db6Afb4fE40",
    {
      types: {
        DeviceControl: [
          {
            name: "principal",
            type: "AuthorizedEntity",
          },
          {
            name: "emergency",
            type: "AuthorizedEntity",
          },
        ],
        AuthorizedEntity: [
          {
            name: "address",
            type: "address",
          },
          {
            name: "validUntil",
            type: "uint256",
          },
        ],
        EIP712Domain: [
          {
            name: "name",
            type: "string",
          },
          {
            name: "version",
            type: "string",
          },
          {
            name: "chainId",
            type: "uint256",
          },
          {
            name: "verifyingContract",
            type: "address",
          },
        ],
      },
      domain: {
        name: "Stargazer Demo",
        version: "1.0.0",
        chainId: "3",
        verifyingContract: "0xeb14c9bb6c2dec2ecb9b278c9fa1ec763b04d545",
      },
      primaryType: "DeviceControl",
      message: {
        principal: {
          address: "0xeb14c9bb6c2dec2ecb9b278c9fa1ec763b04d545",
          validUntil: "1657823568",
        },
        emergency: {
          address: "0xcac3da343670abb46bc6e8e6d375b66217519093",
          validUntil: "1752517998",
        },
      },
    },
  ],
});
// "0xa3f20717a250c2b0b729b7e5becbff67fdaef7e0699da4de7ca5895b02a170a12d887fd3b17bfdce3481f10bea41f45ba9f709d39ce8325427b57afcfc994cee1b"

The returned signature corresponds to the keccak256 hash of the domainSeparator + hashStruct(message) and the private key of the user. ECDSA.sign(privateKey, keccak256("\x19\x01" + domainSeparator + hashStruct(message)).

import { dag4 } from "@stardust-collective/dag4";

const publicKey = "account-public-key";
const signatureRequestEnconded = "the-base64-encoded-signature-request";
const signatureHex = "some-hex-encoded-signature";

const valid: boolean = dag4.keyStore.verify(
  publicKey,
  signatureRequestEnconded,
  signatureHex
);

const publicKeyAddress = dag4.keyStore.getDagAddressFromPublicKey(publicKey);

eth_personalSign

import * as ethers from "ethers";

const accountWhichSigned = "0x9b2055d370f73ec7d8a03e965129118dc8f5bf83";
const messageSigned = "some-message-the-user-signed";
const signatureHex = "some-hex-encoded-signature";

const messageHash = ethers.utils.hashMessage(messageSigned);
const recoveredAddress = ethers.utils.recoverAddress(messageHash, signatureHex);

if (recoveredAddress !== accountWhichSigned) {
  throw new Error("Signature is not valid");
}

eth_signTypedData

import * as ethers from "ethers";

const accountWhichSigned = "0x9b2055d370f73ec7d8a03e965129118dc8f5bf83";
const messageSigned = {
  // The EIP-712 domain signed
  domain: {
    name: "Stargazer Demo",
    version: "1.0.0",
    chainId: 3,
    verifyingContract: "0xabcdefABCDEF1234567890abcdefABCDEF123456",
  },
  // The EIP-712 types signed
  types: {
    DeviceControl: [
      { name: "principal", type: "AuthorizedEntity" },
      { name: "emergency", type: "AuthorizedEntity" },
    ],
    AuthorizedEntity: [
      { name: "address", type: "address" },
      { name: "validUntil", type: "uint256" },
    ],
  },
  // The EIP-712 message signed
  value: {
    principal: {
      address: "0xEb14c9bb6C2DEc2eCb9B278C9fa1EC763B04d545",
      validUntil: 1657823568,
    },
    emergency: {
      address: "0xcAc3DA343670aBB46BC6E8e6d375B66217519093",
      validUntil: 1752517998,
    },
  },
};
const signatureHex = "some-hex-encoded-signature";

const messageHash = ethers.utils._TypedDataEncoder.hash(
  messageSigned.domain,
  messageSigned.types,
  messageSigned.value
);
const recoveredAddress = ethers.utils.recoverAddress(messageHash, signatureHex);

if (recoveredAddress !== accountWhichSigned) {
  throw new Error("Signature is not valid");
}

Send the signature request

Once built and encoded, you can send the encoded signature request using the RPC method.

When the signature request is sent, the wallet will verify compliance with the schema of the . If it does not comply, the wallet will throw an error.

Read more about

Get the account public key

Ethereum Message Signing

The Stargazer Ethereum RPC API implements both () and () as arbitrary message signing methods.

personal_sign method

The RPC API provided reveals the RPC method for message signing. In this case, the message signed is an arbitrary hex string prefixed by the "\x19Ethereum Signed Message:\n" string and the length of the message in bytes from .

Read more about

eth_signTypedData method

The RPC API provided reveals the RPC method for typed message signing. In this case, the message signed is the hash of the typed data according to prefixed by the "\x19\x01" string according to .

Read more about

Constellation Signature Verification

For signature verification, we will be using the package. The following snippet illustrates how you can verify an encoded request signature.

Ethereum Signature Verification

For signature verification, we will be using the package. The following snippets illustrate how you can verify different message signatures.

Provider Activation
​
​
signature request object
​
​
dag_signMessage
signature request object
Constellation signature verification
​
​
EIP-191
personal_sign
EIP-712
eth_signTypedData
​
personal_sign
EIP-191
​
eth_signTypedData
EIP-712
EIP-191
Ethereum signature verification
​
@stardust-collective/dag4
​
ethers
Ethereum signature verification