Using Signer JS Library (Low-Level TypeScript)
npm install @slide-computer/signer @slide-computer/signer-web @slide-computer/signer-agent @dfinity/agent @dfinity/principal @dfinity/ledger-icrc
# or yarn add ...
# or pnpm add ...import { Signer } from '@slide-computer/signer';
import { PostMessageTransport, type PostMessageTransportOptions } from '@slide-computer/signer-web';
import { SignerAgent } from '@slide-computer/signer-agent';
import { IcrcLedgerCanister, type Account } from '@dfinity/ledger-icrc'; // Using ICRC-1 types for accounts
import { Principal } from '@dfinity/principal';
import { Actor, HttpAgent } from '@dfinity/agent'; // Actor is needed, HttpAgent might be for other non-signed calls
// Ensure you have the IDL for the ICP ledger if not using a higher-level library for it
// For this example, we'll use IcrcLedgerCanister from @dfinity/ledger-icrc which has its own IDL.
let signerInstance: Signer | null = null;
let transportInstance: PostMessageTransport | null = null;
let walletAgent: SignerAgent | null = null; // This will be the agent that uses the wallet
let userPrincipal: Principal | null = null;
let userAccountsFromWallet: Account[] | null = null; // Using ICRC-1 Account type
// OISY's official signing endpoint
const OISY_SIGN_URL = 'https://oisy.com/sign';
const ICP_LEDGER_CANISTER_ID = 'ryjl3-tyaaa-aaaaa-aaaba-cai';
async function connectOisyWithSignerJs() {
console.log('Attempting to connect OISY with signer-js...');
// 1. Configure and create the transport for OISY (uses ICRC-29 postMessage)
const transportOptions: PostMessageTransportOptions = {
targetUrl: OISY_SIGN_URL,
// Configure window features for the popup
windowFeatures: 'width=500,height=700,noopener,noreferrer',
};
transportInstance = new PostMessageTransport(transportOptions);
// 2. Create the Signer instance with the transport
signerInstance = new Signer({ transport: transportInstance });
try {
// 3. Initiate the connection (this opens the OISY window for user approval)
// This step handles the ICRC-25 handshake.
await transportInstance.connect();
console.log('OISY transport connected successfully!');
// 4. Get user accounts (uses ICRC-27)
// This retrieves the principal and associated accounts the user has permitted.
const accountsResult = await signerInstance.accounts();
if (!accountsResult || accountsResult.length === 0) {
throw new Error('No accounts found or permission denied by user.');
}
userAccountsFromWallet = accountsResult.map((acc) => ({
owner: acc.owner,
subaccount: acc.subaccount,
}));
userPrincipal = userAccountsFromWallet.owner; // Typically use the principal from the first account
console.log('OISY Accounts:', userAccountsFromWallet);
console.log('User Principal:', userPrincipal.toText());
// 5. Create a SignerAgent (optional but highly convenient)
// This agent will use our 'signerInstance' to sign any outgoing update calls.
// For query calls, it can use a standard anonymous HttpAgent or be configured.
walletAgent = await SignerAgent.create({
signer: signerInstance,
identity: userPrincipal, // The identity obtained from the wallet
host: 'https://icp-api.io', // Mainnet IC boundary node URL
});
console.log('SignerAgent created successfully.');
// Update your UI to reflect the connected state
updateUIOnConnect(userPrincipal.toText(), userAccountsFromWallet); // Implement this function
} catch (error) {
console.error('OISY Connection failed:', error);
alert(`OISY Connection Error: ${error.message || error}`);
await disconnectOisyWithSignerJs(); // Clean up any partial connection
}
}
async function disconnectOisyWithSignerJs() {
if (transportInstance && transportInstance.connected) {
await transportInstance.disconnect();
}
signerInstance = null;
transportInstance = null;
walletAgent = null;
userPrincipal = null;
userAccountsFromWallet = null;
updateUIOnDisconnect(); // Implement this function
console.log('Disconnected from OISY.');
}
// --- Placeholder UI update functions (you need to implement these) ---
function updateUIOnConnect(principalText: string, account: Account) {
document.getElementById('connect-oisy-signerjs').style.display = 'none';
document.getElementById('disconnect-oisy-signerjs').style.display = 'block';
document.getElementById('user-info').innerText =
`Connected: ${principalText}, Account: ${JSON.stringify(account)}`;
document.getElementById('transfer-icp-signerjs').style.display = 'block';
}
function updateUIOnDisconnect() {
document.getElementById('connect-oisy-signerjs').style.display = 'block';
document.getElementById('disconnect-oisy-signerjs').style.display = 'none';
document.getElementById('user-info').innerText = 'Not Connected';
document.getElementById('transfer-icp-signerjs').style.display = 'none';
}
// --- Add button listeners in your HTML ---
// <button id="connect-oisy-signerjs">Connect OISY (signer-js)</button>
// <button id="disconnect-oisy-signerjs" style="display:none;">Disconnect</button>
// <p id="user-info">Not Connected</p>
// <button id="transfer-icp-signerjs" style="display:none;">Send ICP (signer-js)</button>
document
.getElementById('connect-oisy-signerjs')
?.addEventListener('click', connectOisyWithSignerJs);
document
.getElementById('disconnect-oisy-signerjs')
?.addEventListener('click', disconnectOisyWithSignerJs);Signer JS Summary
Last updated