Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 

Repository files navigation

StarKey Wallet Connect Demo

This project is a demo site for testing StarKey Wallet Connect integration. It provides a simple interface to explore wallet connection functionality within a web application.

Detecting StarKey Wallet Installation

To determine if a user has StarKey installed, a web application should check for the presence of a starkey object. StarKey's browser extension automatically injects this object into the window of any web application that meets the following conditions:

  • The site uses https://
  • The site is running on localhost or 127.0.0.1

Note: StarKey does not inject the provider into iframes or sites using http://.

If the starkey object is present, Supra dApps can interact with StarKey through the API available at window.starkey.

function isStarKeyAvailable(): boolean {
  return typeof window !== 'undefined' && !!window.starkey;
}

Connecting to Supra Chain

If StarKey is not installed, we suggest redirecting your users to our website. The implementation might look something like this:

const provider = window.starkey?.supra;

// OR

const getProvider = () => {
  if ('starkey' in window) {
    const provider = window.starkey?.supra;
    if (provider) {
      return provider;
    }
  }

  window.open('https://starkey.app/', '_blank');
};

Establish a Connection

To establish a connection with the StarKey Wallet, use the connect method. This allows you to connect to the Supra Chain.

const provider = getProvider(); // See "Detecting the Provider"

// Default: Connect with MainNet (Chain ID: 8) in the Supra environment
const accounts = await provider.connect();

// OR

// Optional: Connect with specific options
const accounts = await provider.connect({
  chainId: 6, // Connect with a specific Supra Chain ID (e.g., MainNet: 8, TestNet: 6), Default: 8,
  multiple: true, // Default: true, allows connecting multiple accounts
});

Response

The connect method returns an array of wallet addresses as strings. The currently selected account is always at index 0. For example:

['0x841c9ce39632178257eb2bf1b463ca89a12c360eb4bb167cb17d488f05c13389', '0x161a497aa19321bce07277674a134deca15817ed87bd85b72d53b4c5dfa9ab6d']

You can access the current selected currentaccount like this:

console.log(accounts[0]); // Outputs the current selected account

If the user declines to connect the wallet, the response will be an empty array:

[] // Empty array when the user rejects the connection

Check Current Connected Accounts

To retrieve the currently connected accounts, use the account method:

const provider = getProvider(); // See "Detecting the Provider"
const accounts = await provider.account(); 
// ['0x841...89','0x16...6d'] 

Notes:

  • The account method returns an array of wallet addresses as strings.
  • If no wallet is connected, the response will be an empty array ([]).

Get Current Connected Chain ID

The getChainId method returns the current connected network's chain ID.

const response = await window.starkey.supra.getChainId();

// Example response:
{ chainId: '8' } // Current connected network chain ID
null // When the wallet is not connected

Switch Network

The changeNetwork method allows switching the currently connected network.

try {
  const response = await window.starkey.supra.changeNetwork({ chainId: '8' }); 
  // Supported formats: chain ID as a string or number

  // Example response:
  console.log(response); // { chainId: '8' } - Updated network chain ID
} catch (error) {
  console.error(error); 
  // Error: Unrecognized chain ID or user declined to switch network
}

Send a Transaction

const provider = getProvider(); // See "Detecting the Provider"

const params = {
  from: accounts[0], // sender's address 
  to: "0x161a497aa19321bce07277674a134deca15817ed87bd85b72d53b4c5dfa9ab6d", // receiver's address 
  chainId: networkData.chainId,
  value: "100000000", // Transfer 1 Supra
  options: {
    waitForTransaction: true, // Default: true. If true, waits for transaction completion. If false, returns the transaction hash immediately.
  },
};

try {
  const txHash = await provider.sendTransaction(params);
  console.log(txHash); // Logs the transaction hash.
} catch (error) {
  console.error("Transaction failed:", error);
}

Notes:

  • waitForTransaction:
    • true: Waits for the transaction to complete. If the transaction fails, no hash is returned.
    • false: Returns the transaction hash as soon as it is generated.
  • Ensure that accounts[0] contains the sender's address and networkData.chainId is set to the correct chain ID.
  • Handle errors gracefully to catch any issues during the transaction process.

Create & Send Raw Transaction

Prerequisite: Install the Supra TypeScript SDK

To use the createSerializedRawTxObject method, you need to install the supra-l1-sdk package:

npm install supra-l1-sdk

Example: Creating and Sending a Raw Transaction

const provider = getProvider(); // See "Detecting the Provider"

// Define optional transaction payload arguments
const optionalTransactionPayloadArgs = {
  txExpiryTime: Math.ceil(Date.now() / 1000) + 30, // Set expiration time for the raw transaction to 30 seconds
};

/**
 * Create a serialized raw transaction for `entry_function_payload` type.
 * This method uses `createRawTxObject` internally to create a raw transaction and serializes it using the BCS serializer.
 *
 * Parameters:
 * - senderAddr: Sender account address
 * - senderSequenceNumber: Sender account sequence number
 * - moduleAddr: Target module address
 * - moduleName: Target module name
 * - functionName: Target function name
 * - functionTypeArgs: Target function type arguments
 * - functionArgs: Target function arguments
 * - optionalTransactionPayloadArgs: Optional arguments for the transaction payload
 *
 * Returns:
 * - Serialized raw transaction object
 */

// Create a serialized raw transaction
const supraCoinTransferSerializedRawTransaction = await supraClient.createSerializedRawTxObject(
  accounts[0], // Sender's address
  0, // Sender's sequence number
  "0000000000000000000000000000000000000000000000000000000000000001", // Module address
  "supra_account", // Module name
  "transfer", // Function name
  [], // Function type arguments
  [receiverAddress.toUint8Array(), BCS.bcsSerializeUint64(1000)], // Function arguments
  optionalTransactionPayloadArgs // Optional payload arguments
);

// Convert the serialized transaction to hex format
const convertedToHexData = Buffer.from(supraCoinTransferSerializedRawTransaction).toString("hex");

// Define transaction parameters
const params = {
  data: convertedToHexData,
  from: accounts[0], // Sender's address
  chainId: networkData.chainId, // Target chain ID
  options: {
    waitForTransaction: true, // Default: true. Waits for transaction completion. If false, returns the transaction hash immediately.
  },
};

// Send the raw transaction
try {
  const txHash = await provider.sendTransaction(params);
  console.log("Transaction Hash:", txHash); // Logs the transaction hash
} catch (error) {
  console.error("Transaction failed:", error);
}

Wait for Transaction Completion

The waitForTransactionWithResult method is used to check the status of a transaction by its hash. It waits until the transaction is completed and provides the result, indicating whether it was successful or failed.

const tx = await window.starkey.supra.waitForTransactionWithResult({
  hash: '0xbdc5016f166f49979fb51dbd0407d7bf561b68eb9c0ad5a2849e01441988b4e3',
});

// Example Response:
{
  "hash": "0xbdc5016f166f49979fb51dbd0407d7bf561b68eb9c0ad5a2849e01441988b4e3",
  "status": "Success", // Possible values: "Success" or "Failed"
  "vmStatus": "Executed successfully"
}

Notes:

  • Possible Status Values:
    • "Success": The transaction was executed successfully.
    • "Failed": The transaction failed or expired.
  • Invalid Hash: If the provided hash is invalid, the method will return null.
  • Usage: Use this method to track the status of a transaction after it has been submitted.

Sign a Message

const provider = getProvider(); // See "Detecting the Provider"

// Sign a UTF-8 string message
const originalTextMessage = 'Welcome to StarKey Wallet';
const utf8ToHexString = '0x' + Buffer.from(originalTextMessage, 'utf8').toString('hex');
const response = await provider.signMessage({ message: utf8ToHexString });

// Sign a Hex string message
const hexMessage = '0x57656c636f6d6520746f20537461724b65792057616c6c6574'; // Some hex data
const hexResponse = await provider.signHexMessage({ message: hexMessage });

// Example response
console.log(response);
/*
{
  "address": "0x841c....389", // Signed account address
  "publicKey": "0xf348...42b", // Signed account public key
  "signature": "0x94208328...c3a100b" // Signature in hex format
}
*/

Handle Response and Verify Signature

const { publicKey, signature, address } = response;

// Helper function to remove the "0x" prefix from a hex string
const remove0xPrefix = (hexString: string): string => {
  return hexString.startsWith('0x') ? hexString.slice(2) : hexString;
};

// Prepare the data for verification
const signatureWithoutPrefix = remove0xPrefix(signature);
const publicKeyWithoutPrefix = remove0xPrefix(publicKey);

// Use the original message for verification
const messageToVerify = isHexMessage
  ? Uint8Array.from(Buffer.from(signMessage, 'hex')) // If the message is in hex format
  : new TextEncoder().encode(signMessage); // If the message is a UTF-8 string

// Verify the signature
const verified = nacl.sign.detached.verify(
  messageToVerify, // Convert the message to Uint8Array
  Uint8Array.from(Buffer.from(signatureWithoutPrefix, 'hex')), // Convert the signature to Uint8Array
  Uint8Array.from(Buffer.from(publicKeyWithoutPrefix, 'hex')) // Convert the public key to Uint8Array
);

console.log('Signature:', signature);
console.log('Verified:', verified); // true if the signature is valid

Notes:

  • UTF-8 Message Signing: The message is converted to a hex string before signing.
  • Hex Message Signing: Ensure the input is already in hex format.
  • Verification: Use the original message and the public key to verify the signature.
  • Error Handling: Always handle errors gracefully to ensure the verification process does not break the application.
  • isHexMessage: A boolean flag to determine if the message is in hex format or UTF-8.

Sign and Send a Supra Raw Transaction

import { BCS, HexString, SupraClient } from "supra-l1-sdk";

/**
 * Utility: Convert a human-readable value (e.g. "1.2345") into a Supra-compatible bigint.
 */
export const convertToSupraBigInt = (value: string | number, decimals = 8): bigint => {
  const [integerPart, fractionalPart = ""] = value.toString().split(".");
  const normalized = integerPart + (fractionalPart + "0".repeat(decimals)).slice(0, decimals);
  return BigInt(normalized);
};

/**
 * Example function to create, sign, and send a Supra raw transaction using the StarKey Wallet provider.
 */
export async function signAndSendSupraTransaction({
  rpcUrl,
  walletAddress,
  recipientAddress,
  amount,
  chainId,
}: {
  rpcUrl: string;
  walletAddress: string;
  recipientAddress: string;
  amount: string | number;
  chainId: number;
}) {
  try {
    // Initialize Supra client
    const supraClient = await SupraClient.init(rpcUrl);

    // Get StarKey Supra provider injected by the wallet
    const supraProvider = (window as any)?.starkey?.supra;
    if (!supraProvider) {
      throw new Error("Supra wallet provider not found. Please ensure the wallet is connected.");
    }

    // Prepare recipient and amount
    const receiver = HexString.ensure(recipientAddress);
    const amountInBigInt = convertToSupraBigInt(amount, 8); // e.g. 1.2345 → 123450000

    // Fetch sender account info (for sequence number)
    const accountInfo = await supraClient.getAccountInfo(walletAddress);

    // Create a raw transaction for transferring Supra tokens.
   // You can modify the parameters in `createRawTxObject` as per your specific use case (e.g., contract calls, staking, custom modules, etc.).

    const rawTransaction = await supraClient.createRawTxObject(
      HexString.ensure(walletAddress),
      accountInfo.sequence_number,
      "0000000000000000000000000000000000000000000000000000000000000001", // Supra coin module address
      "supra_account", // Module name
      "transfer", // Function name
      [],
      [receiver.toUint8Array(), BCS.bcsSerializeUint64(amountInBigInt)],
    );

    const rawTxBytes = BCS.bcsToBytes(rawTransaction);

    // Prepare payload for signing
    const txPayload = {
      data: rawTxBytes,
      from: walletAddress,
      to: recipientAddress,
      value: 0,
      chainId,
    };

    // Request wallet to sign the transaction
    const signedAuthenticator = await supraProvider.signTransaction(txPayload);
    if (!signedAuthenticator?.Ed25519) {
      throw new Error("Failed to sign transaction: invalid response from wallet.");
    }

    const { public_key, signature } = signedAuthenticator.Ed25519;

    // Submit the signed transaction to the network
    const { txHash, result } =
      await supraClient.sendTxUsingSerializedRawTransactionAndSignature(
        public_key,
        signature,
        rawTxBytes,
        {
          enableTransactionSimulation: true,
          enableWaitForTransaction: true,
        }
      );

    console.log("✅ Transaction Sent Successfully");
    console.log("Transaction Hash:", txHash);
    console.log("Execution Result:", result);

    return { txHash, result };
  } catch (error: any) {
    console.error(" Error signing or sending transaction:", error);
    throw new Error(error?.message || "Unknown error occurred during Supra transaction.");
  }
}

Disconnect Wallet

The disconnect method is used to disconnect the site from the wallet if it is currently connected.

const provider = getProvider(); // See "Detecting the Provider"

// Disconnect using the provider instance
await provider.disconnect();

// OR

// Disconnect directly using the global StarKey object
await window.starkey.supra.disconnect();

Events Listening

You can listen to various events emitted by the provider to handle changes in accounts, network, or disconnection.

const provider = getProvider(); // See "Detecting the Provider"

// Listen for account changes
provider.on("accountChanged", function (accounts) {
  console.log("Accounts changed:", accounts);
  // Example: ['0x123...', '0x456...']
});

// Listen for network changes
provider.on("networkChanged", function (data) {
  console.log("Network changed:", data);
  // Example: { chainId: 7 }
});

// Listen for wallet disconnection
provider.on("disconnect", function () {
  console.log("Wallet disconnected");
});

Notes:

  • accountChanged: Triggered when the connected accounts change. The accounts parameter contains the updated list of wallet addresses.
  • networkChanged: Triggered when the connected network changes. The data parameter contains the new chainId.
  • disconnect: Triggered when the wallet is disconnected. You can handle cleanup or UI updates here.

Detecting First-Time StarKey Extension Installation

If the StarKey extension is installed for the first time, you can detect it using the message event and prompt the user to reload the page for proper initialization.

function handleExtensionEvents(event: MessageEvent) {
  // Ensure event and event.data exist before accessing 'name'
  if (
    event &&
    event.data &&
    event.data.name === "starkey-extension-installed"
  ) {
    console.log("StarKey extension installed");

    // Remove the listener after detecting the installation
    window.removeEventListener("message", handleExtensionEvents);

    // Optionally, prompt the user to reload the page
    alert("StarKey extension has been installed. Please reload the page to continue.");
  }
}

// Add the event listener to detect the installation
window.addEventListener("message", handleExtensionEvents);

Connecting to Ethereum Chain

const provider = window.starkey?.ethereum;

// OR

const getProvider = () => {
  if ('starkey' in window) {
    const provider = window.starkey.ethereum;
    if (provider) {
      return provider;
    }
  }

  window.open('https://starkey.app/', '_blank');
};

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors