Skip to content

Incorrect signature payload in "update_leverage.py" #41

@svajpayee15

Description

@svajpayee15

The Issue: While integrating the update_leverage endpoint, I encountered 400 Invalid Message & 400 Verification error errors when using the flat signature structure shown in the current documentation.

Investigation: I inspected network traffic on the Pacifica Testnet to capture a successful leverage update request. By reverse-engineering the signature verification from that live transaction, I discovered that the API actually requires the business logic fields to be nested inside a data object.

The corrected payload with dummy data:

{ data: { leverage: 12, symbol: 'BTC' }, expiry_window: 30000, timestamp: 1768977047329, type: 'update_leverage' }

Verification: I have attached a script (debug-sig.js) that verifies this structure against real Testnet data. It confirms that the nested structure passes verification while the documented flat structure fails.

debug-sig.js

const nacl = require("tweetnacl");
const bs58 = require("bs58");

// CONTAINS REAL DATA

const WORKING_PAYLOAD = {
    account: "2eijGcDCAoxgwaT3dSkAzTFz9R91ueNngQpBnv4o5JgP",
    agent_wallet: "5HmxB7QgSLnPnNHyzk3y5gT7xos5KaCMtCm7cjW3z6yb", 
    expiry_window: 300000,
    leverage: 50,
    symbol: "BTC",
    timestamp: 1768975643601
};

const SIGNATURE_STRING = "3xwpZcVkGtRfg7D4BaycxurcUzfKiaEKX1RbBuJgybDUkH82fenC3BzHKQKvvTtTVQf9CbRj6KQDY76g4Bs6VinY";

function sortRecursive(item) {
    if (typeof item !== 'object' || item === null) return item;
    if (Array.isArray(item)) return item.map(sortRecursive);
    return Object.keys(item).sort().reduce((acc, key) => {
        acc[key] = sortRecursive(item[key]);
        return acc;
    }, {});
}

function tryVerify(name, candidateObject) {
    try {
        const sorted = sortRecursive(candidateObject);
        const msgString = JSON.stringify(sorted);
        const msgBytes = new TextEncoder().encode(msgString);
        const sigBytes = bs58.decode(SIGNATURE_STRING);
        const pubKeyBytes = bs58.decode(WORKING_PAYLOAD.agent_wallet);

        const isValid = nacl.sign.detached.verify(msgBytes, sigBytes, pubKeyBytes);

        console.log(`[${isValid ? "matched" : "fail"}] Strategy: ${name}`);
        if (isValid) {
            console.log(" coorect structure:");
            console.log(JSON.stringify(sorted, null, 2));
        }
    } catch (e) {
        console.log(`[ERR] ${name}: ${e.message}`);
    }
}

// --- NEW STRATEGIES ---

// Strategy D: Nested "data" object (Standard Pacifica format)
// Header = timestamp, expiry, type
// Data = symbol, leverage
const strategyD = {
    timestamp: WORKING_PAYLOAD.timestamp,
    expiry_window: WORKING_PAYLOAD.expiry_window,
    type: "update_leverage",
    data: {
        symbol: WORKING_PAYLOAD.symbol,
        leverage: WORKING_PAYLOAD.leverage
    }
};

// Strategy E: Nested "data" WITH account inside 'data'
const strategyE = {
    timestamp: WORKING_PAYLOAD.timestamp,
    expiry_window: WORKING_PAYLOAD.expiry_window,
    type: "update_leverage",
    data: {
        symbol: WORKING_PAYLOAD.symbol,
        leverage: WORKING_PAYLOAD.leverage,
        account: WORKING_PAYLOAD.account 
    }
};

// Strategy F: Nested "data" WITH account inside 'Header' (Top level)
const strategyF = {
    account: WORKING_PAYLOAD.account,
    timestamp: WORKING_PAYLOAD.timestamp,
    expiry_window: WORKING_PAYLOAD.expiry_window,
    type: "update_leverage",
    data: {
        symbol: WORKING_PAYLOAD.symbol,
        leverage: WORKING_PAYLOAD.leverage
    }
};

// Strategy G: Flat but WITHOUT Agent Wallet (Just Account + Data + Type)
const strategyG = {
    account: WORKING_PAYLOAD.account,
    expiry_window: WORKING_PAYLOAD.expiry_window,
    leverage: WORKING_PAYLOAD.leverage,
    symbol: WORKING_PAYLOAD.symbol,
    timestamp: WORKING_PAYLOAD.timestamp,
    type: "update_leverage"
};

console.log("TESTING NESTED STRUCTURES...\n");
tryVerify("Nested Data (Minimal)", strategyD);
tryVerify("Nested Data + Account Inside", strategyE);
tryVerify("Nested Data + Account Top", strategyF);
tryVerify("Flat + Account (No Agent)", strategyG);



Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions