Documentation Index
Fetch the complete documentation index at: https://v2-docs.exponent.finance/llms.txt
Use this file to discover all available pages before exploring further.
The Loopscale instructions module enables vault managers and allocators to interact with Loopscale through LoopscaleClient. Unlike the other integrations that start from createVaultSyncTransaction directly, Loopscale flows start from raw Loopscale API responses and then turn those responses into executable vault transactions.
Loopscale exposes two distinct Strategy Vault surfaces:
- Lender-side strategy flows — create, fund, update, withdraw from, and close a Loopscale strategy
- Borrower-side loan flows — create a loan, deposit collateral, borrow principal, repay, withdraw collateral, and close the loan
How co-signing works
Loopscale transaction flow is slightly different from the other Strategy Vault integrations:
- Loopscale constructs the transaction flow through its API.
- The SDK turns that raw response into manager-facing vault transactions and signs them locally.
- If a transaction is flagged with
requiresLoopscaleCoSign, send that transaction to client.coSign(...).
- Submit the returned co-signed transaction on-chain.
Only the wrapped Loopscale transaction belongs to Loopscale’s signing domain. Setup transactions and other local top-level transactions should be sent directly.
If you need more detail on Loopscale-specific mechanics, markets, or transaction endpoints, visit the Loopscale Docs.
Loopscale client
Create a client once and reuse it across your strategy or loan flow:
import { LoopscaleClient } from "@exponent-labs/exponent-sdk";
const client = new LoopscaleClient({
connection,
userWallet: vault.state.squadsVault,
});
Choose an execution path
Loopscale transaction methods return raw Loopscale responses. After each call, choose one of two execution paths.
Prepare appendable transactions
Use prepareVaultTransactions(...) when you want lower-level transaction pieces that you can compose yourself.
import { SQUADS_PROGRAM_ID } from "@exponent-labs/exponent-sdk";
const preparedTransactions = await client.prepareVaultTransactions({
response,
context: {
connection,
signer: wallet.publicKey,
vaultPda: vault.state.squadsVault,
vaultAddress: vault.selfAddress,
squadsProgram: SQUADS_PROGRAM_ID,
},
});
Each prepared entry contains:
setupInstructions — send these first when present
instructions — the main instruction list for the step
signers — any extra local signers required for the step
addressLookupTableAddresses — lookup tables needed to compile the transaction
requiresLoopscaleCoSign — whether the main transaction still needs client.coSign(...)
Build ready-to-send transactions
Use buildVaultTransactions(...) when you want locally signed VersionedTransactions that are ready to send.
import {
LoopscaleClient,
SQUADS_PROGRAM_ID,
type LoopscaleTransactionResponse,
} from "@exponent-labs/exponent-sdk";
async function executeLoopscaleResponse(response: LoopscaleTransactionResponse) {
const builtTransactions = await client.buildVaultTransactions({
response,
context: {
connection,
signer: wallet.publicKey,
signers: [wallet],
vaultPda: vault.state.squadsVault,
vaultAddress: vault.selfAddress,
squadsProgram: SQUADS_PROGRAM_ID,
},
});
for (const builtTransaction of builtTransactions) {
const transaction = builtTransaction.requiresLoopscaleCoSign
? await client.coSign(builtTransaction.transaction)
: builtTransaction.transaction;
await connection.sendTransaction(transaction, { skipPreflight: false });
}
}
requiresLoopscaleCoSign is the exact boundary for Loopscale MPC signing. Only call coSign(...) for transactions flagged true.
buildVaultTransactions(...) requires context.signers[0] to match context.signer.
If you are already using VaultTransactionBuilder, pass the raw response to addLoopscaleResponse(...) and let result.send() handle any required Loopscale co-signing.
Create strategy
createStrategy(...) returns a raw Loopscale batch response. The response itself is enough to execute the create flow. If you want to keep the created strategy address for later calls, you can extract it from the response.
const response = await client.createStrategy({
principalMint: new PublicKey("..."),
lender: vault.state.squadsVault,
amount: 0,
});
await executeLoopscaleResponse(response);
const strategyAddress = await client.extractCreatedStrategyAddress(response);
Parameters
| Parameter | Type | Description |
|---|
principalMint | PublicKey | string | Mint of the strategy principal asset |
lender | PublicKey | string | Vault-owned lender address |
amount | bigint | number | Initial funding amount |
collateralTerms | Array<...> | Optional collateral and APY configuration |
marketInformation | PublicKey | string | Optional external market information account |
externalYieldSourceArgs | TxnExternalYieldSourceArgs | Optional external yield source configuration |
A matching policy must exist before executing. See Policy Builders. See also Loopscale: Create Strategy for API details.
Deposit strategy
const response = await client.depositStrategy({
strategy: strategyAddress,
amount: 500_000_000,
});
await executeLoopscaleResponse(response);
Parameters
| Parameter | Type | Description |
|---|
strategy | PublicKey | string | Loopscale strategy account |
amount | bigint | number | Amount of principal to deposit |
A matching policy must exist before executing. See Policy Builders. See also Loopscale: Deposit Strategy for API details.
Update strategy
const response = await client.updateStrategy({
strategy: strategyAddress,
updateParams: {
originationsEnabled: true,
liquidityBuffer: 500,
},
});
await executeLoopscaleResponse(response);
updateStrategy(...) also accepts collateralTerms when you need to change collateral matrices or duration / APY settings.
Parameters
| Parameter | Type | Description |
|---|
strategy | PublicKey | string | Loopscale strategy account |
collateralTerms | StrategyCollateralUpdates | Optional collateral matrix updates |
updateParams | EditStrategySettingsArgs | Optional strategy settings updates |
A matching policy must exist before executing. See Policy Builders. See also Loopscale: Update Strategy for API details.
Withdraw strategy
const response = await client.withdrawStrategy({
strategy: strategyAddress,
amount: 0,
withdrawAll: true,
});
await executeLoopscaleResponse(response);
Parameters
| Parameter | Type | Description |
|---|
strategy | PublicKey | string | Loopscale strategy account |
amount | bigint | number | Amount of principal to withdraw |
withdrawAll | boolean | Whether to withdraw the full position |
A matching policy must exist before executing. See Policy Builders. See also Loopscale: Withdraw Strategy for API details.
Close strategy
const response = await client.closeStrategy({
strategy: strategyAddress,
});
await executeLoopscaleResponse(response);
Parameters
| Parameter | Type | Description |
|---|
strategy | PublicKey | string | Loopscale strategy account |
A matching policy must exist before executing. See Policy Builders. See also Loopscale: Close Strategy for API details.
Create loan
createLoan(...) returns a raw Loopscale response plus a loanAddress string you can use immediately in follow-up calls.
const response = await client.createLoan({
borrower: vault.state.squadsVault,
depositCollateral: [{
collateralAmount: 500_000_000,
collateralAssetData: {
Spl: { mint: new PublicKey("...").toBase58() },
},
}],
principalRequested: [{
ledgerIndex: 0,
principalAmount: 100_000_000,
principalMint: new PublicKey("..."),
strategy: strategyAddress,
durationIndex: 0,
expectedLoanValues: {
expectedApy: 0,
expectedLqt: [0, 0, 0, 0, 0],
},
}],
});
const loanAddress = new PublicKey(response.loanAddress);
await executeLoopscaleResponse(response);
Parameters
| Parameter | Type | Description |
|---|
borrower | PublicKey | string | Vault-owned borrower address |
depositCollateral | Array<...> | Collateral legs to deposit into the loan |
principalRequested | Array<...> | Requested principal legs tied to strategies and durations |
assetIndexGuidance | number[] | Optional asset index hints |
loanNonce | string | Optional loan nonce override |
isLoop | boolean | Optional loop-mode flag |
A matching policy must exist before executing. See Policy Builders. See also Loopscale: Create Loan for API details.
Deposit collateral
const response = await client.depositCollateral({
loan: loanAddress,
depositMint: new PublicKey("..."),
amount: 500_000_000,
assetType: 0,
assetIdentifier: new PublicKey("..."),
expectedLoanValues: {
expectedApy: 0,
expectedLqt: [0, 0, 0, 0, 0],
},
});
await executeLoopscaleResponse(response);
Parameters
| Parameter | Type | Description |
|---|
loan | PublicKey | string | Loopscale loan account |
depositMint | PublicKey | string | Mint being deposited as collateral |
amount | bigint | number | Collateral amount |
assetType | number | Loopscale asset type discriminator |
assetIdentifier | PublicKey | string | Asset identifier for the collateral leg |
assetIndexGuidance | number[] | Optional asset index hints |
expectedLoanValues | { expectedApy?: number; expectedLqt?: number[] } | Optional loan-state hints |
A matching policy must exist before executing. See Policy Builders. See also Loopscale: Deposit Collateral for API details.
Borrow principal
Before you request a borrow, inspect the available Loopscale lending options for the principal, collateral, and duration you want to use. In the SDK, the usual discovery calls are:
getQuotes(...) when you want a list of current lend orders for a principal / collateral / duration combination
getMaxQuote(...) when you already know the collateral input and want the top matching quote for that borrow
After you choose the strategy you want to borrow from, pass that strategy address into borrowPrincipal(...).
const response = await client.borrowPrincipal({
loan: loanAddress,
strategy: strategyAddress,
borrowParams: {
amount: 100_000_000,
durationIndex: 0,
expectedLoanValues: {
expectedApy: 0,
expectedLqt: [0, 0, 0, 0, 0],
},
},
});
await executeLoopscaleResponse(response);
Parameters
| Parameter | Type | Description |
|---|
loan | PublicKey | string | Loopscale loan account |
strategy | PublicKey | string | Strategy providing the borrowed principal |
borrowParams | { amount, durationIndex, expectedLoanValues? } | Requested borrow amount and duration |
refinanceParams | { ledgerIndex, durationIndex } | Optional refinance target |
isLoop | boolean | Optional loop-mode flag |
A matching policy must exist before executing. See Policy Builders. See also Loopscale: Borrow Principal for API details.
Repay loan
repayLoanSimple(...) builds the raw repay_simple Loopscale response.
const response = await client.repayLoanSimple({
loan: loanAddress,
repayParams: {
amount: 0,
ledgerIndex: 0,
repayAll: true,
},
strategy: strategyAddress,
});
await executeLoopscaleResponse(response);
Parameters
| Parameter | Type | Description |
|---|
loan | PublicKey | string | Loopscale loan account |
repayParams | { amount, ledgerIndex, repayAll } | Repayment details for the loan |
strategy | PublicKey | string | Strategy used for the repayment flow |
A matching policy must exist before executing. See Policy Builders. See also Loopscale: Repay Loan for API details.
Withdraw collateral
const response = await client.withdrawCollateral({
loan: loanAddress,
collateralMint: new PublicKey("..."),
amount: 500_000_000,
collateralIndex: 0,
expectedLoanValues: {
expectedApy: 0,
expectedLqt: [0, 0, 0, 0, 0],
},
});
await executeLoopscaleResponse(response);
Parameters
| Parameter | Type | Description |
|---|
loan | PublicKey | string | Loopscale loan account |
collateralMint | PublicKey | string | Mint to withdraw |
amount | bigint | number | Collateral amount to withdraw |
collateralIndex | number | Collateral slot to withdraw from |
expectedLoanValues | { expectedApy?: number; expectedLqt?: number[] } | Loan-state hints required by the request |
assetIndexGuidance | number[] | Optional asset index hints |
A matching policy must exist before executing. See Policy Builders. See also Loopscale: Withdraw Collateral for API details.
Close loan
const response = await client.closeLoan({
loan: loanAddress,
});
await executeLoopscaleResponse(response);
Parameters
| Parameter | Type | Description |
|---|
loan | PublicKey | string | Loopscale loan account |
A matching policy must exist before executing. See Policy Builders. See also Loopscale: Close Loan for API details.
Practical notes
createStrategy(...) can be executed directly from its raw response. Use extractCreatedStrategyAddress(...) only when you want to reference the created strategy later.
createLoan(...) returns a raw response plus loanAddress, so you can construct the loan public key immediately.
- Only call
coSign(...) for transactions flagged with requiresLoopscaleCoSign === true.
- Split lender-side strategy actions and borrower-side loan actions into separate Loopscale policies when you configure the vault.