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.
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
localhostor127.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;
}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');
};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
});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 accountIf the user declines to connect the wallet, the response will be an empty array:
[] // Empty array when the user rejects the connectionTo 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'] - The
accountmethod returns an array of wallet addresses as strings. - If no wallet is connected, the response will be an empty array (
[]).
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 connectedThe 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
}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);
}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 andnetworkData.chainIdis set to the correct chain ID. - Handle errors gracefully to catch any issues during the transaction process.
To use the createSerializedRawTxObject method, you need to install the supra-l1-sdk package:
npm install supra-l1-sdkconst 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);
}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"
}- 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.
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
}
*/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- 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.
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.");
}
}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();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");
});accountChanged: Triggered when the connected accounts change. Theaccountsparameter contains the updated list of wallet addresses.networkChanged: Triggered when the connected network changes. Thedataparameter contains the newchainId.disconnect: Triggered when the wallet is disconnected. You can handle cleanup or UI updates here.
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);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');
};