Skip to main content

Wallet Bridge Example

This page contains a complete example demonstrating all Wallet Bridge functionality. You can use this as a reference or test file when building wallet-enabled applications in Net Storage.

Overview

This example provides a comprehensive test suite for Wallet Bridge features, including:

  • Connection testing
  • Basic wallet information retrieval
  • Message signing
  • Transaction submission
  • Function call encoding
  • Error handling

Complete Example Code

<!DOCTYPE html>
<html>
<head>
<title>Wallet Bridge Test</title>
<style>
body {
font-family: Arial, sans-serif;
padding: 20px;
background: #f5f5f5;
color: black;
}
.test-section {
margin: 20px 0;
padding: 15px;
border: 1px solid #ccc;
background: white;
border-radius: 8px;
color: black;
}
.test-button {
margin: 5px;
padding: 10px 15px;
background: #007bff;
color: white;
border: none;
cursor: pointer;
border-radius: 4px;
}
.test-button:hover {
background: #0056b3;
}
.result {
margin: 10px 0;
padding: 10px;
background: #f8f9fa;
border-left: 4px solid #007bff;
border-radius: 4px;
color: black;
}
.error {
border-left-color: #dc3545;
background: #f8d7da;
}
.success {
border-left-color: #28a745;
background: #d4edda;
}
.loading {
border-left-color: #ffc107;
background: #fff3cd;
}
input {
padding: 8px;
margin: 5px;
border: 1px solid #ccc;
border-radius: 4px;
color: black;
}
</style>
</head>
<body>
<h1>🔗 Wallet Bridge Test Suite</h1>
<p>
This page tests the wallet bridge functionality. Make sure you're viewing
this content on a Net Storage page with wallet bridge enabled.
</p>

<!-- Connection Status -->
<div class="test-section">
<h2>🔌 Connection Status</h2>
<button class="test-button" onclick="testConnection()">
Test Connection
</button>
<div id="connection-result" class="result">
Click "Test Connection" to check if wallet bridge is available
</div>
</div>

<!-- Basic Wallet Info -->
<div class="test-section">
<h2>👤 Basic Wallet Info</h2>
<button class="test-button" onclick="testGetAccount()">
Get Account
</button>
<button class="test-button" onclick="testGetChainId()">
Get Chain ID
</button>
<button class="test-button" onclick="testGetBalance()">
Get Balance
</button>
<div id="wallet-info-result" class="result">
Click buttons above to test wallet info retrieval
</div>
</div>

<!-- Message Signing -->
<div class="test-section">
<h2>✍️ Message Signing</h2>
<input
type="text"
id="message-input"
placeholder="Enter message to sign"
value="Hello, Net Protocol!"
style="width: 300px"
/>
<br /><br />
<button class="test-button" onclick="testSignMessage()">
Sign Message
</button>
<button class="test-button" onclick="testSignTypedData()">
Sign Typed Data
</button>
<div id="signing-result" class="result">
Click buttons above to test message signing
</div>
</div>

<!-- Transaction Submission -->
<div class="test-section">
<h2>💸 Transaction Submission</h2>
<input
type="text"
id="tx-to"
placeholder="To address"
value="0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6"
style="width: 300px"
/>
<input
type="text"
id="tx-value"
placeholder="Value in ETH"
value="0.001"
style="width: 100px"
/>
<br /><br />
<button class="test-button" onclick="testSendTransaction()">
Send Transaction
</button>
<div id="transaction-result" class="result">
Click button above to test transaction submission
</div>
</div>

<!-- Pure Alpha Upvote -->
<div class="test-section">
<h2>🚀 Pure Alpha Upvote</h2>
<button class="test-button" onclick="testPureAlphaUpvote()">
Upvote Pure Alpha (1 upvote = 0.000025 ETH)
</button>
<div id="upvote-result" class="result">
Click button above to test pure alpha upvote transaction
</div>
</div>

<!-- Function Call Encoding -->
<div class="test-section">
<h2>🔧 Function Call Encoding</h2>
<button class="test-button" onclick="testEncodeFunctionCall()">
Test encodeFunctionCall
</button>
<button class="test-button" onclick="testEncodeAndSubmitFlow()">
Test Encode + Submit Flow
</button>
<div id="encode-result" class="result">
Click buttons above to test function call encoding
</div>
</div>

<!-- Error Testing -->
<div class="test-section">
<h2>⚠️ Error Testing</h2>
<button class="test-button" onclick="testInvalidMessage()">
Test Invalid Message
</button>
<button class="test-button" onclick="testInvalidTransaction()">
Test Invalid Transaction
</button>
<button class="test-button" onclick="testUserRejection()">
Test User Rejection
</button>
<div id="error-result" class="result">
Click buttons above to test error handling
</div>
</div>

<script>
// Test utility functions
function logResult(elementId, message, type = "info") {
const element = document.getElementById(elementId);
element.innerHTML = `<strong>${new Date().toLocaleTimeString()}</strong>: ${message}`;
element.className = `result ${type}`;
}

function logError(elementId, error) {
logResult(elementId, `Error: ${error.message}`, "error");
}

function logSuccess(elementId, message) {
logResult(elementId, message, "success");
}

function logLoading(elementId, message) {
logResult(elementId, message, "loading");
}

// Test functions
async function testConnection() {
try {
logLoading("connection-result", "Testing wallet connection...");
if (typeof window.wallet === "undefined") {
throw new Error(
"Wallet bridge not available - make sure you are viewing this content on a Net Storage page with wallet bridge enabled"
);
}
const account = await window.wallet.getAccount();
logSuccess("connection-result", `✅ Connected! Account: ${account}`);
} catch (error) {
logError("connection-result", error);
}
}

async function testGetAccount() {
try {
logLoading("wallet-info-result", "Getting account...");
const account = await window.wallet.getAccount();
logSuccess("wallet-info-result", `Account: ${account}`);
} catch (error) {
logError("wallet-info-result", error);
}
}

async function testGetChainId() {
try {
logLoading("wallet-info-result", "Getting chain ID...");
const chainId = await window.wallet.getChainId();
logSuccess("wallet-info-result", `Chain ID: ${chainId}`);
} catch (error) {
logError("wallet-info-result", error);
}
}

async function testGetBalance() {
try {
logLoading("wallet-info-result", "Getting balance...");
const balance = await window.wallet.getBalance();
logSuccess("wallet-info-result", `Balance: ${balance} ETH`);
} catch (error) {
logError("wallet-info-result", error);
}
}

async function testSignMessage() {
try {
const message = document.getElementById("message-input").value;
if (!message.trim()) {
throw new Error("Please enter a message");
}
logLoading("signing-result", "Signing message...");
const signature = await window.wallet.signMessage(message);
logSuccess("signing-result", `Signature: ${signature}`);
} catch (error) {
logError("signing-result", error);
}
}

async function testSignTypedData() {
try {
// Get the current chain ID from the wallet
const chainId = await window.wallet.getChainId();

const parsedChainId = parseInt(chainId);

const typedData = {
domain: {
name: "Net Protocol",
version: "1",
chainId: parsedChainId,
verifyingContract: "0x0000000000000000000000000000000000000000",
},
types: {
Message: [
{ name: "content", type: "string" },
{ name: "timestamp", type: "uint256" },
],
},
primaryType: "Message",
message: {
content: "Hello, Net Protocol!",
timestamp: Math.floor(Date.now() / 1000),
},
};

logLoading(
"signing-result",
`Signing typed data for chain ${chainId}...`
);
const signature = await window.wallet.signTypedData(typedData);
logSuccess("signing-result", `Typed Data Signature: ${signature}`);
} catch (error) {
console.error("[testSignTypedData] Error caught:", error);
logError("signing-result", error);
}
}

async function testSendTransaction() {
try {
const to = document.getElementById("tx-to").value;
const value = document.getElementById("tx-value").value;

if (!to || !value) {
throw new Error("Please enter to address and value");
}

const params = {
to: to,
value: (parseFloat(value) * 1e18).toString(), // Convert ETH to wei
};

logLoading("transaction-result", "Sending transaction...");
const hash = await window.wallet.sendTransaction(params);
logSuccess("transaction-result", `Transaction Hash: ${hash}`);
} catch (error) {
logError("transaction-result", error);
}
}

async function testPureAlphaUpvote() {
try {
logLoading(
"upvote-result",
"Sending pure alpha upvote transaction..."
);

// Manually encoded function call for upvote(strategy, scoreKey, scoreDelta, scoreStoredContext, scoreUnstoredContext)
// Function signature: upvote(address,bytes32,uint256,bytes,bytes)
const functionSelector = "0xe50517cc"; // keccak256("upvote(address,bytes32,uint256,bytes,bytes)").slice(0, 10)

const upvoteAppAddress = "0x00000001f0b8173316a016a5067ad74e8cea47bf";
const strategyAddress = "0x00000001b1bcdeddeafd5296aaf4f3f3e21ae876";
const scoreKey =
"0x0000000000000000000000000000000000000000000000000000000000000001";
const scoreDelta =
"0x0000000000000000000000000000000000000000000000000000000000000001"; // 1 upvote
const scoreStoredContext =
"0x00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
const scoreUnstoredContext =
"0x0000000000000000000000000000000000000000000000000000000000000000";

const encodedData =
"0xe50517cc000000000000000000000000000000063f84e07a3e7a7ee578b42704ee6d22c90000000000000000000000003d01fe5a38ddbd307fdd635b4cb0e29681226d6f000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000003d01fe5a38ddbd307fdd635b4cb0e29681226d6f00000000000000000000000042000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";

const params = {
to: upvoteAppAddress,
data: encodedData,
value: "25000000000000", // 0.000025 ETH in wei (decimal string)
};

const hash = await window.wallet.sendTransaction(params);
logSuccess(
"upvote-result",
`✅ Upvote successful! Transaction Hash: ${hash}`
);
} catch (error) {
logError("upvote-result", error);
}
}

async function testInvalidMessage() {
try {
logLoading("error-result", "Testing invalid message...");
await window.wallet.signMessage("");
logError(
"error-result",
new Error("Should have failed with empty message")
);
} catch (error) {
logSuccess(
"error-result",
`✅ Correctly caught error: ${error.message}`
);
}
}

async function testInvalidTransaction() {
try {
logLoading("error-result", "Testing invalid transaction...");
await window.wallet.sendTransaction({
to: "invalid-address",
value: "1000",
});
logError(
"error-result",
new Error("Should have failed with invalid address")
);
} catch (error) {
logSuccess(
"error-result",
`✅ Correctly caught error: ${error.message}`
);
}
}

async function testUserRejection() {
try {
logLoading("error-result", "Testing user rejection...");
logResult(
"error-result",
"Click Cancel in the confirmation dialog to test user rejection",
"info"
);
await window.wallet.signMessage("This should be rejected");
logError(
"error-result",
new Error("Should have been rejected by user")
);
} catch (error) {
logSuccess(
"error-result",
`✅ Correctly caught user rejection: ${error.message}`
);
}
}

async function testEncodeFunctionCall() {
try {
logLoading("encode-result", "Testing function call encoding...");

// Simple ABI for testing
const testABI = [
{
type: "function",
name: "transfer",
inputs: [
{ name: "to", type: "address" },
{ name: "amount", type: "uint256" },
],
outputs: [{ name: "", type: "bool" }],
},
];

const result = await window.wallet.encodeFunctionCall(
testABI,
"transfer",
[
"0x1234567890123456789012345678901234567890",
"1000000000000000000",
]
);

logSuccess(
"encode-result",
`✅ Encoding successful! Calldata: ${result.calldata}`
);
logSuccess("encode-result", `Warning: ${result.warning}`);
} catch (error) {
logError("encode-result", error);
}
}

async function testEncodeAndSubmitFlow() {
try {
logLoading(
"encode-result",
"Testing complete encode + submit flow with upvote..."
);

// Upvote function ABI from upvote-first-app
const upvoteABI = [
{
type: "function",
name: "upvote",
inputs: [
{ name: "strategy", type: "address" },
{ name: "upvoteKey", type: "bytes32" },
{ name: "numUpvotes", type: "uint256" },
{ name: "upvoteStoredContext", type: "bytes" },
{ name: "upvoteUnstoredContext", type: "bytes" },
],
outputs: [],
stateMutability: "payable",
},
];

// Step 1: Encode upvote function call
logLoading(
"encode-result",
"Step 1: Encoding upvote function call..."
);
const encodingResult = await window.wallet.encodeFunctionCall(
upvoteABI,
"upvote",
[
"0x00000001b1bcdeddeafd5296aaf4f3f3e21ae876", // Pure Alpha Strategy
"0x0000000000000000000000000000000000000000000000000000000000000000", // ALPHA token upvote key
1, // 1 upvote
"0x", // Empty stored context
"0x", // Empty unstored context
]
);

logSuccess(
"encode-result",
`✅ Step 1 Complete! Encoded calldata: ${encodingResult.calldata}`
);

// Step 2: Submit transaction with encoded calldata
logLoading(
"encode-result",
"Step 2: Submitting upvote transaction with encoded calldata..."
);

const transactionParams = {
to: "0x00000001f0b8173316a016a5067ad74e8cea47bf", // UpvoteApp contract address
data: encodingResult.calldata, // Use the encoded data
value: "25000000000000", // 0.000025 ETH in wei (upvote price)
};

const hash = await window.wallet.sendTransaction(transactionParams);

logSuccess(
"encode-result",
`✅ Complete upvote flow successful! Transaction Hash: ${hash}`
);
} catch (error) {
logError("encode-result", error);
}
}

// Auto-test connection on load
window.addEventListener("load", () => {
setTimeout(() => {
logResult(
"connection-result",
'Page loaded. Click "Test Connection" to check wallet bridge availability.',
"info"
);
}, 1000);
});
</script>
</body>
</html>

Test Sections Explained

Connection Status

Tests whether the wallet bridge is available and a wallet is connected. This is the first thing to check when using Wallet Bridge.

Basic Wallet Info

Demonstrates reading wallet information:

  • Get Account: Retrieves the connected wallet address
  • Get Chain ID: Gets the current chain ID
  • Get Balance: Fetches the wallet balance in wei

Message Signing

Shows how to sign messages and typed data:

  • Sign Message: Signs a plain text message
  • Sign Typed Data: Signs EIP-712 structured data

Transaction Submission

Demonstrates sending transactions:

  • Allows you to specify recipient address and value
  • Sends a simple ETH transfer transaction

Pure Alpha Upvote

A complete example of encoding and sending a complex transaction (upvoting ALPHA token). This shows manual calldata encoding.

Function Call Encoding

Tests the encodeFunctionCall utility:

  • Test encodeFunctionCall: Encodes a simple transfer function call
  • Test Encode + Submit Flow: Complete flow of encoding an upvote function call and submitting it as a transaction

Error Testing

Demonstrates error handling:

  • Test Invalid Message: Shows how empty messages are rejected
  • Test Invalid Transaction: Shows how invalid addresses are rejected
  • Test User Rejection: Shows how user cancellation is handled

How to Use This Example

  1. Store the HTML: Store this HTML content in Net Storage with a key like wallet-test
  2. Connect Wallet: Connect your wallet on the Net website
  3. Navigate to Storage: Go to the storage page where you stored this content
  4. Test Functions: Click the buttons to test each Wallet Bridge function

Notes

  • This is a testing/example file - modify it as needed for your use case
  • All wallet operations require user confirmation via dialogs
  • Make sure you're on the correct chain for the operations you're testing
  • The example includes both manual encoding and encodeFunctionCall approaches
  • Error handling is demonstrated for common failure scenarios