Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export type {
Unsubscribe,
} from "./events/types.js";

export { getInvoice, listInvoicesBySubmitter, listInvoicesByLP, getSubmitterInvoices, getPayerScore } from "./methods/queries.js";
export { getInvoice, listInvoicesBySubmitter, listInvoicesByLP, getSubmitterInvoices } from "./methods/queries.js";
export { getLpInvoices } from "./methods/lpInvoices.js";
export { getNftMetadata, getNftOwner } from "./methods/nft.js";
Expand Down Expand Up @@ -142,4 +143,4 @@ export {
submitBatchTransaction,
} from "./methods/batch.js";
export type { BatchContractCall, BatchTransactionOptions, BatchTransactionResult } from "./methods/batch.js";
export { setAdmin, upgrade, setDistributionContract } from "./methods/admin.js";
export { setAdmin, upgrade, setDistributionContract, addToken, removeToken, updateFeeRate, updateMaxDiscount, setPriceOracle, setMaxOracleAge } from "./methods/admin.js";
328 changes: 328 additions & 0 deletions sdk/src/methods/admin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,331 @@ export async function setDistributionContract(

return { txHash: sendResult.hash };
}

/**
* Add an approved token to the ILN invoice_liquidity contract.
* Admin only — subject to the default rate limit.
*/
export async function addToken(
server: SorobanRpc.Server,
contractAddress: string,
token: string,
decimals: number,
sourceAccount: Account,
signTransaction: (tx: Transaction) => Promise<Transaction> | Transaction,
networkPassphrase: string
): Promise<{ txHash: string }> {
validateContractId(token);

const contract = new Contract(contractAddress);
const op = contract.call(
"add_token",
nativeToScVal(token, { type: "address" }),
nativeToScVal(decimals, { type: "u32" })
);

const tx = new TransactionBuilder(sourceAccount, {
fee: BASE_FEE,
networkPassphrase,
})
.addOperation(op)
.setTimeout(30)
.build();

const sim = await retry(() => server.simulateTransaction(tx));
if (SorobanRpc.Api.isSimulationError(sim)) {
throw ILNError.fromError(sim.error);
}

const assembledTx = SorobanRpc.assembleTransaction(tx, sim).build();
const signedTx = await signTransaction(assembledTx);
const sendResult = await retry(() => server.sendTransaction(signedTx));
if (sendResult.errorResult) {
throw new Error(`Transaction failed: ${sendResult.errorResult}`);
}

let status = await retry(() => server.getTransaction(sendResult.hash));
let retries = 0;
while (status.status === SorobanRpc.Api.GetTransactionStatus.NOT_FOUND && retries < 15) {
await new Promise(r => setTimeout(r, 2000));
status = await retry(() => server.getTransaction(sendResult.hash));
retries++;
}

if (status.status === SorobanRpc.Api.GetTransactionStatus.FAILED) {
throw new Error("Transaction failed during execution");
}

return { txHash: sendResult.hash };
}

/**
* Update the protocol fee rate (in basis points) on the ILN invoice_liquidity
* contract. Admin only — subject to the economic-parameter cooldown.
*/
export async function updateFeeRate(
server: SorobanRpc.Server,
contractAddress: string,
rate: number,
sourceAccount: Account,
signTransaction: (tx: Transaction) => Promise<Transaction> | Transaction,
networkPassphrase: string
): Promise<{ txHash: string }> {
const contract = new Contract(contractAddress);
const op = contract.call(
"update_fee_rate",
nativeToScVal(rate, { type: "u32" })
);

const tx = new TransactionBuilder(sourceAccount, {
fee: BASE_FEE,
networkPassphrase,
})
.addOperation(op)
.setTimeout(30)
.build();

const sim = await retry(() => server.simulateTransaction(tx));
if (SorobanRpc.Api.isSimulationError(sim)) {
throw ILNError.fromError(sim.error);
}

const assembledTx = SorobanRpc.assembleTransaction(tx, sim).build();
const signedTx = await signTransaction(assembledTx);
const sendResult = await retry(() => server.sendTransaction(signedTx));
if (sendResult.errorResult) {
throw new Error(`Transaction failed: ${sendResult.errorResult}`);
}

let status = await retry(() => server.getTransaction(sendResult.hash));
let retries = 0;
while (status.status === SorobanRpc.Api.GetTransactionStatus.NOT_FOUND && retries < 15) {
await new Promise(r => setTimeout(r, 2000));
status = await retry(() => server.getTransaction(sendResult.hash));
retries++;
}

if (status.status === SorobanRpc.Api.GetTransactionStatus.FAILED) {
throw new Error("Transaction failed during execution");
}

return { txHash: sendResult.hash };
}

/**
* Update the maximum invoice discount rate (in basis points) on the ILN
* invoice_liquidity contract. Admin only — subject to the economic-parameter
* cooldown.
*/
export async function updateMaxDiscount(
server: SorobanRpc.Server,
contractAddress: string,
rate: number,
sourceAccount: Account,
signTransaction: (tx: Transaction) => Promise<Transaction> | Transaction,
networkPassphrase: string
): Promise<{ txHash: string }> {
const contract = new Contract(contractAddress);
const op = contract.call(
"update_max_discount",
nativeToScVal(rate, { type: "u32" })
);

const tx = new TransactionBuilder(sourceAccount, {
fee: BASE_FEE,
networkPassphrase,
})
.addOperation(op)
.setTimeout(30)
.build();

const sim = await retry(() => server.simulateTransaction(tx));
if (SorobanRpc.Api.isSimulationError(sim)) {
throw ILNError.fromError(sim.error);
}

const assembledTx = SorobanRpc.assembleTransaction(tx, sim).build();
const signedTx = await signTransaction(assembledTx);
const sendResult = await retry(() => server.sendTransaction(signedTx));
if (sendResult.errorResult) {
throw new Error(`Transaction failed: ${sendResult.errorResult}`);
}

let status = await retry(() => server.getTransaction(sendResult.hash));
let retries = 0;
while (status.status === SorobanRpc.Api.GetTransactionStatus.NOT_FOUND && retries < 15) {
await new Promise(r => setTimeout(r, 2000));
status = await retry(() => server.getTransaction(sendResult.hash));
retries++;
}

if (status.status === SorobanRpc.Api.GetTransactionStatus.FAILED) {
throw new Error("Transaction failed during execution");
}

return { txHash: sendResult.hash };
}

/**
* Set the price oracle contract address on the ILN invoice_liquidity
* contract. Admin only — subject to the default rate limit.
*/
export async function setPriceOracle(
server: SorobanRpc.Server,
contractAddress: string,
oracle: string,
sourceAccount: Account,
signTransaction: (tx: Transaction) => Promise<Transaction> | Transaction,
networkPassphrase: string
): Promise<{ txHash: string }> {
validateContractId(oracle);

const contract = new Contract(contractAddress);
const op = contract.call(
"set_price_oracle",
nativeToScVal(oracle, { type: "address" })
);

const tx = new TransactionBuilder(sourceAccount, {
fee: BASE_FEE,
networkPassphrase,
})
.addOperation(op)
.setTimeout(30)
.build();

const sim = await retry(() => server.simulateTransaction(tx));
if (SorobanRpc.Api.isSimulationError(sim)) {
throw ILNError.fromError(sim.error);
}

const assembledTx = SorobanRpc.assembleTransaction(tx, sim).build();
const signedTx = await signTransaction(assembledTx);
const sendResult = await retry(() => server.sendTransaction(signedTx));
if (sendResult.errorResult) {
throw new Error(`Transaction failed: ${sendResult.errorResult}`);
}

let status = await retry(() => server.getTransaction(sendResult.hash));
let retries = 0;
while (status.status === SorobanRpc.Api.GetTransactionStatus.NOT_FOUND && retries < 15) {
await new Promise(r => setTimeout(r, 2000));
status = await retry(() => server.getTransaction(sendResult.hash));
retries++;
}

if (status.status === SorobanRpc.Api.GetTransactionStatus.FAILED) {
throw new Error("Transaction failed during execution");
}

return { txHash: sendResult.hash };
}

/**
* Update the maximum oracle data age (in ledgers) on the ILN
* invoice_liquidity contract. Admin only — subject to the default rate
* limit. Setting this to 0 disables the freshness check entirely.
*/
export async function setMaxOracleAge(
server: SorobanRpc.Server,
contractAddress: string,
maxAgeLedgers: bigint,
sourceAccount: Account,
signTransaction: (tx: Transaction) => Promise<Transaction> | Transaction,
networkPassphrase: string
): Promise<{ txHash: string }> {
const contract = new Contract(contractAddress);
const op = contract.call(
"set_max_oracle_age",
nativeToScVal(maxAgeLedgers, { type: "u64" })
);

const tx = new TransactionBuilder(sourceAccount, {
fee: BASE_FEE,
networkPassphrase,
})
.addOperation(op)
.setTimeout(30)
.build();

const sim = await retry(() => server.simulateTransaction(tx));
if (SorobanRpc.Api.isSimulationError(sim)) {
throw ILNError.fromError(sim.error);
}

const assembledTx = SorobanRpc.assembleTransaction(tx, sim).build();
const signedTx = await signTransaction(assembledTx);
const sendResult = await retry(() => server.sendTransaction(signedTx));
if (sendResult.errorResult) {
throw new Error(`Transaction failed: ${sendResult.errorResult}`);
}

let status = await retry(() => server.getTransaction(sendResult.hash));
let retries = 0;
while (status.status === SorobanRpc.Api.GetTransactionStatus.NOT_FOUND && retries < 15) {
await new Promise(r => setTimeout(r, 2000));
status = await retry(() => server.getTransaction(sendResult.hash));
retries++;
}

if (status.status === SorobanRpc.Api.GetTransactionStatus.FAILED) {
throw new Error("Transaction failed during execution");
}

return { txHash: sendResult.hash };
}

/**
* Remove an approved token from the ILN invoice_liquidity contract.
* Admin only — subject to the default rate limit.
*/
export async function removeToken(
server: SorobanRpc.Server,
contractAddress: string,
token: string,
sourceAccount: Account,
signTransaction: (tx: Transaction) => Promise<Transaction> | Transaction,
networkPassphrase: string
): Promise<{ txHash: string }> {
validateContractId(token);

const contract = new Contract(contractAddress);
const op = contract.call(
"remove_token",
nativeToScVal(token, { type: "address" })
);

const tx = new TransactionBuilder(sourceAccount, {
fee: BASE_FEE,
networkPassphrase,
})
.addOperation(op)
.setTimeout(30)
.build();

const sim = await retry(() => server.simulateTransaction(tx));
if (SorobanRpc.Api.isSimulationError(sim)) {
throw ILNError.fromError(sim.error);
}

const assembledTx = SorobanRpc.assembleTransaction(tx, sim).build();
const signedTx = await signTransaction(assembledTx);
const sendResult = await retry(() => server.sendTransaction(signedTx));
if (sendResult.errorResult) {
throw new Error(`Transaction failed: ${sendResult.errorResult}`);
}

let status = await retry(() => server.getTransaction(sendResult.hash));
let retries = 0;
while (status.status === SorobanRpc.Api.GetTransactionStatus.NOT_FOUND && retries < 15) {
await new Promise(r => setTimeout(r, 2000));
status = await retry(() => server.getTransaction(sendResult.hash));
retries++;
}

if (status.status === SorobanRpc.Api.GetTransactionStatus.FAILED) {
throw new Error("Transaction failed during execution");
}

return { txHash: sendResult.hash };
}
Loading
Loading