Before you can perform instant open or instant close actions, your sub‑account must delegate access to the solver (Party B) for these functions. Once delegated, you must obtain an access token through a two-step SIWE (Sign-In With Ethereum) login flow. This process ensures that you are authorized to execute instant actions and that your request includes a validated expiration date.
Flow Overview
Delegate Access:
First, delegate access from your sub‑account to the solver’s address so that they can call functions (such as open, request to close, or cancel close) on your behalf.
Fetch a Nonce:
Query the hedger’s endpoint using your sub‑account address. The nonce ensures the uniqueness of your SIWE message and prevents replay attacks.
Build and Sign the SIWE Message:
Construct a SIWE message that includes your wallet address, the nonce, a statement (the sub-account), and timestamps (issued and expiration). This message must be signed by your wallet to confirm your intent.
Send Login Request:
Submit your signed SIWE message to the hedger’s endpoint. Upon successful verification, you will receive an access token. This token is then used for subsequent instant open or close operations.
Delegating Access
To enable instant actions on the frontend, users must delegate specific functions to solvers so they can perform actions on the user's behalf without requiring signatures for each request.
Front-ends should ensure that the following functions are delegated to the solver addresses through the delegateAccesses() method on the contract, passing these function signatures.:
sendQuote: 0x7f2755b2
sendQuoteWithAffiliate: 0x40f1310c
requestToClosePosition: 0x501e891f
requestToCancelQuote: 0xa8ffc7ab
requestToCancelCloseRequest: 0xa63b9363
allocate: 0x90ca796b
After Delegating Access you can proceed with the login process.
Example Script
Below is a Node.js script (using ethers and axios) that demonstrates the nonce fetch and instant login flow:
Delegation of Access:
Ensure that your sub‑account has already delegated access to the solver for instant actions before starting the login flow.
// Load environment variables from a .env file
require("dotenv").config();
// Import required libraries: ethers for Ethereum utilities, and axios for HTTP requests
const { ethers } = require("ethers");
const axios = require("axios");
// Retrieve the private key from environment variables
const PRIVATE_KEY = process.env.PRIVATE_KEY;
// Convert the active account address from the env into a checksummed Ethereum address.
// Using ethers.getAddress ensures the address format is correct. This is the sub-account.
const activeAccount = ethers.getAddress(process.env.activeAccount);
const wallet = new ethers.Wallet(PRIVATE_KEY);
// Define the base URL of the authentication (solver) server. In this example we'll use Rasa on Base
const SOLVER_BASE_URL = "https://base-hedger82.rasa.capital";
const DOMAIN = "localhost";
const ORIGIN = "http://localhost:3000";
const CHAIN_ID = 8453;
const LOGIN_URI = `${SOLVER_BASE_URL}/login`;
const ISSUED_AT = new Date().toISOString();
const EXPIRATION_DATE = new Date(Date.now() + (24 * 60 * 60 * 10)).toISOString(); //Long-dated expiration
//Fetching Nonce from Solver
async function getNonce(address) {
const url = `${SOLVER_BASE_URL}/nonce/${address}`;
const { data } = await axios.get(url);
return data.nonce;
}
// -----------------------------
// MAIN EXECUTION BLOCK
// -----------------------------
(async function main() {
try {
console.log(`\n[1/4] Wallet Address: ${wallet.address}`);
console.log(`[1.5/4] Active Account (Checksum): ${activeAccount}`);
// Fetch the nonce for the active account from the server
const nonce = await getNonce(activeAccount);
console.log(`[2/4] Got nonce: ${nonce}`);
// Build the SIWE (Sign-In With Ethereum) message using the provided parameters.
// Note that the message is signed using the wallet address, while the active account is used in the statement.
const siweMessage = buildSiweMessage({
domain: DOMAIN,
address: wallet.address,
statement: `msg: ${activeAccount}`,
uri: LOGIN_URI,
version: "1",
chainId: CHAIN_ID,
nonce,
issuedAt: ISSUED_AT,
expirationTime: EXPIRATION_DATE,
});
console.log("\n[3/4] SIWE message to sign:\n", siweMessage);
// Sign the SIWE message using the wallet's private key
const signature = await wallet.signMessage(siweMessage);
console.log("\nSignature:", signature);
// Construct the request body to send to the login endpoint, including the signature and nonce
const body = {
account_address: activeAccount,
expiration_time: EXPIRATION_DATE,
issued_at: ISSUED_AT,
signature,
nonce
};
// Define HTTP headers including content type and origin (used for CORS validation on the server)
const headers = {
"Content-Type": "application/json",
Origin: ORIGIN,
Referer: ORIGIN,
};
console.log("\n[4/4] Sending login request...");
// Send the login request (POST) to the server with the constructed body and headers
const response = await axios.post(
`${SOLVER_BASE_URL}/login`,
body,
{ headers }
);
console.log("Login response:", response.data);
} catch (err) {
console.error("Error in SIWE login flow:", err.response?.data || err.message);
}
})();
// -----------------------------
// UTILITY FUNCTION: buildSiweMessage
// -----------------------------
// Constructs a SIWE (Sign-In With Ethereum) message following the EIP-4361 standard.
// For more details, see: https://eips.ethereum.org/EIPS/eip-4361
function buildSiweMessage({
domain,
address,
statement,
uri,
version,
chainId,
nonce,
issuedAt,
expirationTime
}) {
return `${domain} wants you to sign in with your Ethereum account:
${address}
${statement}
URI: ${uri}
Version: ${version}
Chain ID: ${chainId}
Nonce: ${nonce}
Issued At: ${issuedAt}
Expiration Time: ${expirationTime}`;
}
/*
Example SIWE message output:
---------------------------------------------
localhost wants you to sign in with your Ethereum account:
0x3B5aC601c7bB74999AB3135fa43cbDBc6aB74570
msg: 0xb1936f6158eC7906C37e82A8230bf545aF29102F
URI: https://base-hedger82.rasa.capital/login
Version: 1
Chain ID: 8453
Nonce: zp0JU2TX6N0
Issued At: 2025-03-31T17:02:46.736Z
Expiration Time: 2025-03-31T17:17:10.736Z
*/
Upon successful login, the response includes an access token. This token must be attached in the headers of any instant open or close requests that you subsequently send.