This guide explains how to take out a loan from an inventory pool
Prerequisites
An account that has been whitelisted as a borrower on the target inventory pool
A sufficient amount of collateral deposited
Process Overview
Request a borrow digest from the API
Sign the digest with your private key
Submit the borrow request with your signature
Execute the resulting transaction on-chain
Step 1: Request Borrow Digest
This step authenticates your request, preventing any other address from requesting a borrow on your behalf.
Make a GET request to https://api.nomial.io/borrow/digest with the following query parameters:
{
"chain_id": "1", // The chain ID (e.g., 1 for Ethereum mainnet)
"pool": "0x...", // The inventory pool address
"borrower": "0x...", // Your borrower address
"amount": "1000000", // The amount of ERC20 to borrow (in base units)
"recipient": "0x...", // The address that will receive the borrowed funds (can be borrower address)
"expiry": "1234567890", // Unix timestamp when the request expires (1 hour in the future or less)
"salt": "0x..." // An arbitrary 32-byte hex string to force request uniqueness
}
The API will return a digest that needs to be signed by your borrower address
{
"digest": "0x..." // The digest to sign
}
Step 2: Sign the Digest
Sign the provided hex digest directly with the private key of your borrower address. The resulting signature must use the standard 65-byte Ethereum format (r, s, v).
Be sure to sign the raw digest, without including an ERC-191 (“Ethereum Signed Message”) prefix.
Step 3: Submit Borrow Request
Make a POST request to https://api.nomial.io/borrow. This should include identical parameters and values to your digest request, with the addition of signature (your signature of the request digest).
{
"chain_id": "1", // The chain ID
"pool": "0x...", // The inventory pool address
"borrower": "0x...", // Your borrower address
"amount": "1000000", // The amount to borrow in base units
"recipient": "0x...", // The address that will receive the borrowed funds
"expiry": "1234567890", // Unix timestamp when the request expires
"salt": "0x...", // The same salt used for the request digest
"signature": "0x..." // Your signature of the request digest
}
If your borrow request is valid, the API will return a transaction with validator signatures that can be executed to the inventory pool's owner (access manager):
{
"call": {
"chain": {
"id": "1",
"name": "ethereum"
},
"contract": {
"name": "InventoryPoolDefaultAccessManager01",
"address": "0x..."
},
"function": "borrow(address pool, uint256 amount, address recipient, uint256 expiry, bytes32 salt, bytes[] signatures)",
"selector": "0x...",
"calldata": "0x...",
"params": [
{
"name": "pool",
"value": "0x..."
},
{
"name": "amount",
"value": "1000000"
},
{
"name": "recipient",
"value": "0x..."
},
{
"name": "expiry",
"value": "1234567890"
},
{
"name": "salt",
"value": "0x..."
},
{
"name": "signatures",
"value": ["0x...", "0x..."]
}
]
},
"tx": {
"to": "0x...", // The access manager contract address
"data": "0x...", // The encoded function call data
"value": "0", // The amount of native token to send
"chain_id": "1" // The chain ID
},
"signed_digest": "0x...", // The digest that was signed
"validator_signatures": [ // Array of validator signatures
{
"validator": "validator1",
"signature": "0x..."
}
]
}
Step 4: Execute the Transaction
You can submit your signed transaction to the chain it was intended for. Here's an example using ethers.js:
const provider = new ethers.providers.JsonRpcProvider(rpcUrl);
const tx = {
to: response.tx.to,
data: response.tx.data,
value: response.tx.value
};
// Send the transaction
const result = await wallet.connect(provider).sendTransaction(tx);
await result.wait();
Alternatively, you can construct the transaction yourself using the call object:
// Import the contract ABI
const accessManagerABI = [
"function borrow(address pool, uint256 amount, address recipient, uint256 expiry, bytes32 salt, bytes[] signatures)"
];
// Create contract instance
const accessManager = new ethers.Contract(
response.call.contract.address,
accessManagerABI,
wallet
);
// Execute the borrow function
const result = await accessManager.borrow(
response.call.params[0].value, // pool
response.call.params[1].value, // amount
response.call.params[2].value, // recipient
response.call.params[3].value, // expiry
response.call.params[4].value, // salt
response.call.params[5].value // signatures
);
await result.wait();
Note that you must execute your transaction on the access manager contract that is owner on the inventory pool, and not the inventory pool itself.