mirror of https://github.com/certusone/oyster.git
refactoring
This commit is contained in:
parent
97bc5f76e3
commit
cee89c00d3
|
@ -34,7 +34,7 @@ export const borrowObligationLiquidity = async (
|
||||||
obligation: ParsedAccount<Obligation>,
|
obligation: ParsedAccount<Obligation>,
|
||||||
) => {
|
) => {
|
||||||
notify({
|
notify({
|
||||||
message: 'Borrowing funds...',
|
message: 'Borrowing liquidity...',
|
||||||
description: 'Please review transactions to approve.',
|
description: 'Please review transactions to approve.',
|
||||||
type: 'warn',
|
type: 'warn',
|
||||||
});
|
});
|
||||||
|
@ -146,7 +146,7 @@ export const borrowObligationLiquidity = async (
|
||||||
);
|
);
|
||||||
|
|
||||||
notify({
|
notify({
|
||||||
message: 'Funds borrowed.',
|
message: 'Liquidity borrowed.',
|
||||||
type: 'success',
|
type: 'success',
|
||||||
description: `Transaction - ${txid}`,
|
description: `Transaction - ${txid}`,
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
import {
|
||||||
|
contexts,
|
||||||
|
LENDING_PROGRAM_ID,
|
||||||
|
models,
|
||||||
|
notify,
|
||||||
|
TokenAccount,
|
||||||
|
} from '@oyster/common';
|
||||||
|
import {
|
||||||
|
Account,
|
||||||
|
Connection,
|
||||||
|
PublicKey,
|
||||||
|
TransactionInstruction,
|
||||||
|
} from '@solana/web3.js';
|
||||||
|
import {
|
||||||
|
depositObligationCollateralInstruction,
|
||||||
|
refreshReserveInstruction,
|
||||||
|
Reserve,
|
||||||
|
} from '../models';
|
||||||
|
|
||||||
|
const { approve } = models;
|
||||||
|
const { sendTransaction } = contexts.Connection;
|
||||||
|
|
||||||
|
// @FIXME
|
||||||
|
export const depositObligationCollateral = async (
|
||||||
|
connection: Connection,
|
||||||
|
wallet: any,
|
||||||
|
collateralAmount: number,
|
||||||
|
source: TokenAccount,
|
||||||
|
reserve: Reserve,
|
||||||
|
reserveAddress: PublicKey,
|
||||||
|
obligationAddress: PublicKey
|
||||||
|
) => {
|
||||||
|
notify({
|
||||||
|
message: 'Depositing collateral...',
|
||||||
|
description: 'Please review transactions to approve.',
|
||||||
|
type: 'warn',
|
||||||
|
});
|
||||||
|
|
||||||
|
// user from account
|
||||||
|
const signers: Account[] = [];
|
||||||
|
const instructions: TransactionInstruction[] = [];
|
||||||
|
const cleanupInstructions: TransactionInstruction[] = [];
|
||||||
|
|
||||||
|
const [lendingMarketAuthority] = await PublicKey.findProgramAddress(
|
||||||
|
[reserve.lendingMarket.toBuffer()],
|
||||||
|
LENDING_PROGRAM_ID,
|
||||||
|
);
|
||||||
|
|
||||||
|
const sourceCollateral = source.pubkey;
|
||||||
|
|
||||||
|
// create approval for transfer transactions
|
||||||
|
const transferAuthority = approve(
|
||||||
|
instructions,
|
||||||
|
cleanupInstructions,
|
||||||
|
sourceCollateral,
|
||||||
|
wallet.publicKey,
|
||||||
|
collateralAmount,
|
||||||
|
);
|
||||||
|
|
||||||
|
signers.push(transferAuthority);
|
||||||
|
|
||||||
|
instructions.push(
|
||||||
|
refreshReserveInstruction(
|
||||||
|
reserveAddress,
|
||||||
|
reserve.liquidity.oracleOption
|
||||||
|
? reserve.liquidity.oraclePubkey
|
||||||
|
: undefined,
|
||||||
|
),
|
||||||
|
depositObligationCollateralInstruction(
|
||||||
|
collateralAmount,
|
||||||
|
sourceCollateral,
|
||||||
|
reserve.collateral.mintPubkey,
|
||||||
|
reserveAddress,
|
||||||
|
obligationAddress,
|
||||||
|
reserve.lendingMarket,
|
||||||
|
lendingMarketAuthority,
|
||||||
|
// @FIXME: wallet must sign
|
||||||
|
wallet.publicKey,
|
||||||
|
transferAuthority.publicKey,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
let { txid } = await sendTransaction(
|
||||||
|
connection,
|
||||||
|
wallet,
|
||||||
|
instructions.concat(cleanupInstructions),
|
||||||
|
signers,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
notify({
|
||||||
|
message: 'Collateral deposited.',
|
||||||
|
type: 'success',
|
||||||
|
description: `Transaction - ${txid}`,
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
// TODO:
|
||||||
|
}
|
||||||
|
};
|
|
@ -15,20 +15,14 @@ import {
|
||||||
} from '@solana/web3.js';
|
} from '@solana/web3.js';
|
||||||
import {
|
import {
|
||||||
depositReserveLiquidityInstruction,
|
depositReserveLiquidityInstruction,
|
||||||
initReserveInstruction,
|
|
||||||
refreshReserveInstruction,
|
refreshReserveInstruction,
|
||||||
Reserve,
|
Reserve,
|
||||||
} from '../models';
|
} from '../models';
|
||||||
|
|
||||||
const { sendTransaction } = contexts.Connection;
|
const { sendTransaction } = contexts.Connection;
|
||||||
const {
|
const { ensureSplAccount, findOrCreateAccountByMint } = actions;
|
||||||
createUninitializedAccount,
|
|
||||||
ensureSplAccount,
|
|
||||||
findOrCreateAccountByMint,
|
|
||||||
} = actions;
|
|
||||||
const { approve } = models;
|
const { approve } = models;
|
||||||
|
|
||||||
// @FIXME: split up into deposit, and init which requires lending market owner
|
|
||||||
export const depositReserveLiquidity = async (
|
export const depositReserveLiquidity = async (
|
||||||
connection: Connection,
|
connection: Connection,
|
||||||
wallet: any,
|
wallet: any,
|
||||||
|
@ -38,13 +32,11 @@ export const depositReserveLiquidity = async (
|
||||||
reserveAddress: PublicKey,
|
reserveAddress: PublicKey,
|
||||||
) => {
|
) => {
|
||||||
notify({
|
notify({
|
||||||
message: 'Depositing funds...',
|
message: 'Depositing liquidity...',
|
||||||
description: 'Please review transactions to approve.',
|
description: 'Please review transactions to approve.',
|
||||||
type: 'warn',
|
type: 'warn',
|
||||||
});
|
});
|
||||||
|
|
||||||
const isInitalized = true; // TODO: finish reserve init
|
|
||||||
|
|
||||||
// user from account
|
// user from account
|
||||||
const signers: Account[] = [];
|
const signers: Account[] = [];
|
||||||
const instructions: TransactionInstruction[] = [];
|
const instructions: TransactionInstruction[] = [];
|
||||||
|
@ -79,70 +71,35 @@ export const depositReserveLiquidity = async (
|
||||||
|
|
||||||
signers.push(transferAuthority);
|
signers.push(transferAuthority);
|
||||||
|
|
||||||
let destinationCollateralAccount: PublicKey = isInitalized
|
let destinationCollateralAccount: PublicKey = await findOrCreateAccountByMint(
|
||||||
? await findOrCreateAccountByMint(
|
wallet.publicKey,
|
||||||
wallet.publicKey,
|
wallet.publicKey,
|
||||||
wallet.publicKey,
|
instructions,
|
||||||
instructions,
|
cleanupInstructions,
|
||||||
cleanupInstructions,
|
accountRentExempt,
|
||||||
accountRentExempt,
|
reserve.collateral.mintPubkey,
|
||||||
reserve.collateral.mintPubkey,
|
signers,
|
||||||
signers,
|
);
|
||||||
)
|
|
||||||
: createUninitializedAccount(
|
|
||||||
instructions,
|
|
||||||
wallet.publicKey,
|
|
||||||
accountRentExempt,
|
|
||||||
signers,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isInitalized) {
|
instructions.push(
|
||||||
instructions.push(
|
refreshReserveInstruction(
|
||||||
refreshReserveInstruction(
|
reserveAddress,
|
||||||
reserveAddress,
|
reserve.liquidity.oracleOption
|
||||||
reserve.liquidity.oracleOption
|
? reserve.liquidity.oraclePubkey
|
||||||
? reserve.liquidity.oraclePubkey
|
: undefined,
|
||||||
: undefined,
|
),
|
||||||
),
|
depositReserveLiquidityInstruction(
|
||||||
depositReserveLiquidityInstruction(
|
liquidityAmount,
|
||||||
liquidityAmount,
|
sourceLiquidityAccount,
|
||||||
sourceLiquidityAccount,
|
destinationCollateralAccount,
|
||||||
destinationCollateralAccount,
|
reserveAddress,
|
||||||
reserveAddress,
|
reserve.liquidity.supplyPubkey,
|
||||||
reserve.liquidity.supplyPubkey,
|
reserve.collateral.mintPubkey,
|
||||||
reserve.collateral.mintPubkey,
|
reserve.lendingMarket,
|
||||||
reserve.lendingMarket,
|
lendingMarketAuthority,
|
||||||
lendingMarketAuthority,
|
transferAuthority.publicKey,
|
||||||
transferAuthority.publicKey,
|
),
|
||||||
),
|
);
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// TODO: finish reserve init
|
|
||||||
// @FIXME: reserve config
|
|
||||||
const MAX_UTILIZATION_RATE = 80;
|
|
||||||
instructions.push(
|
|
||||||
initReserveInstruction(
|
|
||||||
liquidityAmount,
|
|
||||||
MAX_UTILIZATION_RATE,
|
|
||||||
sourceLiquidityAccount,
|
|
||||||
destinationCollateralAccount,
|
|
||||||
reserveAddress,
|
|
||||||
reserve.liquidity.mintPubkey,
|
|
||||||
reserve.liquidity.supplyPubkey,
|
|
||||||
reserve.liquidity.feeReceiver,
|
|
||||||
reserve.collateral.mintPubkey,
|
|
||||||
reserve.collateral.supplyPubkey,
|
|
||||||
reserve.lendingMarket,
|
|
||||||
lendingMarketAuthority,
|
|
||||||
// @FIXME: lending market owner
|
|
||||||
lendingMarketOwner,
|
|
||||||
transferAuthority.publicKey,
|
|
||||||
reserve.liquidity.oracleOption
|
|
||||||
? reserve.liquidity.oraclePubkey
|
|
||||||
: undefined,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let { txid } = await sendTransaction(
|
let { txid } = await sendTransaction(
|
||||||
|
@ -154,7 +111,7 @@ export const depositReserveLiquidity = async (
|
||||||
);
|
);
|
||||||
|
|
||||||
notify({
|
notify({
|
||||||
message: 'Funds deposited.',
|
message: 'Liquidity deposited.',
|
||||||
type: 'success',
|
type: 'success',
|
||||||
description: `Transaction - ${txid}`,
|
description: `Transaction - ${txid}`,
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
import { contexts, notify } from '@oyster/common';
|
||||||
|
import {
|
||||||
|
Account,
|
||||||
|
Connection,
|
||||||
|
PublicKey,
|
||||||
|
TransactionInstruction,
|
||||||
|
} from '@solana/web3.js';
|
||||||
|
import { initObligationInstruction, Obligation } from '../models';
|
||||||
|
|
||||||
|
const { sendTransaction } = contexts.Connection;
|
||||||
|
|
||||||
|
export const initObligation = async (
|
||||||
|
connection: Connection,
|
||||||
|
wallet: any,
|
||||||
|
obligation: Obligation,
|
||||||
|
obligationAddress: PublicKey
|
||||||
|
) => {
|
||||||
|
notify({
|
||||||
|
message: 'Initializing obligation...',
|
||||||
|
description: 'Please review transactions to approve.',
|
||||||
|
type: 'warn',
|
||||||
|
});
|
||||||
|
|
||||||
|
// user from account
|
||||||
|
const signers: Account[] = [];
|
||||||
|
const instructions: TransactionInstruction[] = [];
|
||||||
|
const cleanupInstructions: TransactionInstruction[] = [];
|
||||||
|
|
||||||
|
// @FIXME: obligation owner must sign
|
||||||
|
signers.push(wallet.info.account);
|
||||||
|
|
||||||
|
instructions.push(
|
||||||
|
initObligationInstruction(
|
||||||
|
obligationAddress,
|
||||||
|
obligation.lendingMarket,
|
||||||
|
// @FIXME: need to sign with wallet
|
||||||
|
wallet.publicKey
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
let { txid } = await sendTransaction(
|
||||||
|
connection,
|
||||||
|
wallet,
|
||||||
|
instructions.concat(cleanupInstructions),
|
||||||
|
signers,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
notify({
|
||||||
|
message: 'Obligation initialized.',
|
||||||
|
type: 'success',
|
||||||
|
description: `Transaction - ${txid}`,
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
// TODO:
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,122 @@
|
||||||
|
import {
|
||||||
|
actions,
|
||||||
|
contexts,
|
||||||
|
LENDING_PROGRAM_ID,
|
||||||
|
models,
|
||||||
|
notify,
|
||||||
|
TokenAccount,
|
||||||
|
} from '@oyster/common';
|
||||||
|
import { AccountLayout } from '@solana/spl-token';
|
||||||
|
import {
|
||||||
|
Account,
|
||||||
|
Connection,
|
||||||
|
PublicKey,
|
||||||
|
TransactionInstruction,
|
||||||
|
} from '@solana/web3.js';
|
||||||
|
import { initReserveInstruction, Reserve } from '../models';
|
||||||
|
|
||||||
|
const { sendTransaction } = contexts.Connection;
|
||||||
|
const {
|
||||||
|
createUninitializedAccount,
|
||||||
|
ensureSplAccount,
|
||||||
|
} = actions;
|
||||||
|
const { approve } = models;
|
||||||
|
|
||||||
|
export const initReserve = async (
|
||||||
|
connection: Connection,
|
||||||
|
// @FIXME: wallet must be lending market owner
|
||||||
|
wallet: any,
|
||||||
|
liquidityAmount: number,
|
||||||
|
source: TokenAccount,
|
||||||
|
reserve: Reserve,
|
||||||
|
reserveAddress: PublicKey,
|
||||||
|
) => {
|
||||||
|
notify({
|
||||||
|
message: 'Initializing reserve...',
|
||||||
|
description: 'Please review transactions to approve.',
|
||||||
|
type: 'warn',
|
||||||
|
});
|
||||||
|
|
||||||
|
// user from account
|
||||||
|
const signers: Account[] = [];
|
||||||
|
const instructions: TransactionInstruction[] = [];
|
||||||
|
const cleanupInstructions: TransactionInstruction[] = [];
|
||||||
|
|
||||||
|
const accountRentExempt = await connection.getMinimumBalanceForRentExemption(
|
||||||
|
AccountLayout.span,
|
||||||
|
);
|
||||||
|
|
||||||
|
const [lendingMarketAuthority] = await PublicKey.findProgramAddress(
|
||||||
|
[reserve.lendingMarket.toBuffer()], // which account should be authority
|
||||||
|
LENDING_PROGRAM_ID,
|
||||||
|
);
|
||||||
|
|
||||||
|
const sourceLiquidityAccount = ensureSplAccount(
|
||||||
|
instructions,
|
||||||
|
cleanupInstructions,
|
||||||
|
source,
|
||||||
|
wallet.publicKey,
|
||||||
|
liquidityAmount + accountRentExempt,
|
||||||
|
signers,
|
||||||
|
);
|
||||||
|
|
||||||
|
// create approval for transfer transactions
|
||||||
|
const transferAuthority = approve(
|
||||||
|
instructions,
|
||||||
|
cleanupInstructions,
|
||||||
|
sourceLiquidityAccount,
|
||||||
|
wallet.publicKey,
|
||||||
|
liquidityAmount,
|
||||||
|
);
|
||||||
|
|
||||||
|
signers.push(transferAuthority);
|
||||||
|
|
||||||
|
let destinationCollateralAccount: PublicKey = createUninitializedAccount(
|
||||||
|
instructions,
|
||||||
|
wallet.publicKey,
|
||||||
|
accountRentExempt,
|
||||||
|
signers,
|
||||||
|
);
|
||||||
|
|
||||||
|
instructions.push(
|
||||||
|
initReserveInstruction(
|
||||||
|
liquidityAmount,
|
||||||
|
reserve.config,
|
||||||
|
sourceLiquidityAccount,
|
||||||
|
destinationCollateralAccount,
|
||||||
|
reserveAddress,
|
||||||
|
reserve.liquidity.mintPubkey,
|
||||||
|
reserve.liquidity.supplyPubkey,
|
||||||
|
reserve.liquidity.feeReceiver,
|
||||||
|
reserve.collateral.mintPubkey,
|
||||||
|
reserve.collateral.supplyPubkey,
|
||||||
|
reserve.lendingMarket,
|
||||||
|
lendingMarketAuthority,
|
||||||
|
// @FIXME: need to sign with wallet as lending market owner
|
||||||
|
wallet.publicKey,
|
||||||
|
transferAuthority.publicKey,
|
||||||
|
reserve.liquidity.oracleOption
|
||||||
|
? reserve.liquidity.oraclePubkey
|
||||||
|
: undefined,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
let { txid } = await sendTransaction(
|
||||||
|
connection,
|
||||||
|
wallet,
|
||||||
|
instructions.concat(cleanupInstructions),
|
||||||
|
signers,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
notify({
|
||||||
|
message: 'Reserve initialized.',
|
||||||
|
type: 'success',
|
||||||
|
description: `Transaction - ${txid}`,
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
// TODO:
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
};
|
|
@ -39,7 +39,7 @@ export const liquidateObligation = async (
|
||||||
obligation: ParsedAccount<Obligation>,
|
obligation: ParsedAccount<Obligation>,
|
||||||
) => {
|
) => {
|
||||||
notify({
|
notify({
|
||||||
message: 'Repaying funds...',
|
message: 'Liquidating obligation...',
|
||||||
description: 'Please review transactions to approve.',
|
description: 'Please review transactions to approve.',
|
||||||
type: 'warn',
|
type: 'warn',
|
||||||
});
|
});
|
||||||
|
@ -146,7 +146,7 @@ export const liquidateObligation = async (
|
||||||
);
|
);
|
||||||
|
|
||||||
notify({
|
notify({
|
||||||
message: 'Funds liquidated.',
|
message: 'Obligation liquidated.',
|
||||||
type: 'success',
|
type: 'success',
|
||||||
description: `Transaction - ${txid}`,
|
description: `Transaction - ${txid}`,
|
||||||
});
|
});
|
||||||
|
|
|
@ -32,7 +32,7 @@ export const redeemReserveCollateral = async (
|
||||||
reserveAddress: PublicKey,
|
reserveAddress: PublicKey,
|
||||||
) => {
|
) => {
|
||||||
notify({
|
notify({
|
||||||
message: 'Withdrawing funds...',
|
message: 'Redeeming collateral...',
|
||||||
description: 'Please review transactions to approve.',
|
description: 'Please review transactions to approve.',
|
||||||
type: 'warn',
|
type: 'warn',
|
||||||
});
|
});
|
||||||
|
@ -105,7 +105,7 @@ export const redeemReserveCollateral = async (
|
||||||
);
|
);
|
||||||
|
|
||||||
notify({
|
notify({
|
||||||
message: 'Funds deposited.',
|
message: 'Collateral redeemed.',
|
||||||
type: 'success',
|
type: 'success',
|
||||||
description: `Transaction - ${txid}`,
|
description: `Transaction - ${txid}`,
|
||||||
});
|
});
|
||||||
|
|
|
@ -35,7 +35,7 @@ export const repayObligationLiquidity = async (
|
||||||
obligation: ParsedAccount<Obligation>,
|
obligation: ParsedAccount<Obligation>,
|
||||||
) => {
|
) => {
|
||||||
notify({
|
notify({
|
||||||
message: 'Repaying funds...',
|
message: 'Repaying liquidity...',
|
||||||
description: 'Please review transactions to approve.',
|
description: 'Please review transactions to approve.',
|
||||||
type: 'warn',
|
type: 'warn',
|
||||||
});
|
});
|
||||||
|
@ -117,7 +117,7 @@ export const repayObligationLiquidity = async (
|
||||||
);
|
);
|
||||||
|
|
||||||
notify({
|
notify({
|
||||||
message: 'Funds repaid.',
|
message: 'Liquidity repaid.',
|
||||||
type: 'success',
|
type: 'success',
|
||||||
description: `Transaction - ${txid}`,
|
description: `Transaction - ${txid}`,
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
import {
|
||||||
|
contexts,
|
||||||
|
findOrCreateAccountByMint,
|
||||||
|
LENDING_PROGRAM_ID,
|
||||||
|
models,
|
||||||
|
notify,
|
||||||
|
TokenAccount,
|
||||||
|
} from '@oyster/common';
|
||||||
|
import { AccountLayout } from '@solana/spl-token';
|
||||||
|
import {
|
||||||
|
Account,
|
||||||
|
Connection,
|
||||||
|
PublicKey,
|
||||||
|
TransactionInstruction,
|
||||||
|
} from '@solana/web3.js';
|
||||||
|
import {
|
||||||
|
withdrawObligationCollateralInstruction,
|
||||||
|
refreshReserveInstruction,
|
||||||
|
Reserve,
|
||||||
|
} from '../models';
|
||||||
|
|
||||||
|
const { approve } = models;
|
||||||
|
const { sendTransaction } = contexts.Connection;
|
||||||
|
|
||||||
|
// @FIXME
|
||||||
|
export const withdrawObligationCollateral = async (
|
||||||
|
connection: Connection,
|
||||||
|
wallet: any,
|
||||||
|
collateralAmount: number,
|
||||||
|
source: TokenAccount,
|
||||||
|
reserve: Reserve,
|
||||||
|
reserveAddress: PublicKey,
|
||||||
|
obligationAddress: PublicKey,
|
||||||
|
) => {
|
||||||
|
notify({
|
||||||
|
message: 'Withdrawing collateral...',
|
||||||
|
description: 'Please review transactions to approve.',
|
||||||
|
type: 'warn',
|
||||||
|
});
|
||||||
|
|
||||||
|
// user from account
|
||||||
|
const signers: Account[] = [];
|
||||||
|
const instructions: TransactionInstruction[] = [];
|
||||||
|
const cleanupInstructions: TransactionInstruction[] = [];
|
||||||
|
|
||||||
|
const accountRentExempt = await connection.getMinimumBalanceForRentExemption(
|
||||||
|
AccountLayout.span,
|
||||||
|
);
|
||||||
|
|
||||||
|
const [lendingMarketAuthority] = await PublicKey.findProgramAddress(
|
||||||
|
[reserve.lendingMarket.toBuffer()],
|
||||||
|
LENDING_PROGRAM_ID,
|
||||||
|
);
|
||||||
|
|
||||||
|
// @FIXME: wallet must sign as obligation owner
|
||||||
|
signers.push(wallet.info.account);
|
||||||
|
|
||||||
|
// get destination account
|
||||||
|
const destinationCollateral = await findOrCreateAccountByMint(
|
||||||
|
wallet.publicKey,
|
||||||
|
wallet.publicKey,
|
||||||
|
instructions,
|
||||||
|
cleanupInstructions,
|
||||||
|
accountRentExempt,
|
||||||
|
reserve.collateral.mintPubkey,
|
||||||
|
signers,
|
||||||
|
);
|
||||||
|
|
||||||
|
instructions.push(
|
||||||
|
refreshReserveInstruction(
|
||||||
|
reserveAddress,
|
||||||
|
reserve.liquidity.oracleOption
|
||||||
|
? reserve.liquidity.oraclePubkey
|
||||||
|
: undefined,
|
||||||
|
),
|
||||||
|
withdrawObligationCollateralInstruction(
|
||||||
|
collateralAmount,
|
||||||
|
reserve.collateral.supplyPubkey,
|
||||||
|
destinationCollateral,
|
||||||
|
reserveAddress,
|
||||||
|
obligationAddress,
|
||||||
|
reserve.lendingMarket,
|
||||||
|
lendingMarketAuthority,
|
||||||
|
// @FIXME: wallet must sign
|
||||||
|
wallet.publicKey
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
let { txid } = await sendTransaction(
|
||||||
|
connection,
|
||||||
|
wallet,
|
||||||
|
instructions.concat(cleanupInstructions),
|
||||||
|
signers,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
notify({
|
||||||
|
message: 'Collateral withdrawn.',
|
||||||
|
type: 'success',
|
||||||
|
description: `Transaction - ${txid}`,
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
// TODO:
|
||||||
|
}
|
||||||
|
};
|
|
@ -145,9 +145,7 @@ export const BorrowInput = (props: {
|
||||||
parseFloat(value),
|
parseFloat(value),
|
||||||
borrowReserve,
|
borrowReserve,
|
||||||
// TODO: select existing obligations by collateral reserve
|
// TODO: select existing obligations by collateral reserve
|
||||||
userObligationsByReserve.length > 0
|
userObligationsByReserve[0].obligation.account
|
||||||
? userObligationsByReserve[0].obligation.account
|
|
||||||
: undefined,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
setValue('');
|
setValue('');
|
||||||
|
|
|
@ -45,13 +45,11 @@ export const useLending = () => {
|
||||||
const processAccount = useCallback(
|
const processAccount = useCallback(
|
||||||
(item: { pubkey: PublicKey; account: AccountInfo<Buffer> }) => {
|
(item: { pubkey: PublicKey; account: AccountInfo<Buffer> }) => {
|
||||||
if (isReserve(item.account)) {
|
if (isReserve(item.account)) {
|
||||||
const reserve = cache.add(
|
return cache.add(
|
||||||
item.pubkey.toBase58(),
|
item.pubkey.toBase58(),
|
||||||
item.account,
|
item.account,
|
||||||
ReserveParser,
|
ReserveParser,
|
||||||
);
|
);
|
||||||
|
|
||||||
return reserve;
|
|
||||||
} else if (isLendingMarket(item.account)) {
|
} else if (isLendingMarket(item.account)) {
|
||||||
return cache.add(
|
return cache.add(
|
||||||
item.pubkey.toBase58(),
|
item.pubkey.toBase58(),
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {
|
||||||
import BN from 'bn.js';
|
import BN from 'bn.js';
|
||||||
import * as BufferLayout from 'buffer-layout';
|
import * as BufferLayout from 'buffer-layout';
|
||||||
import * as Layout from '../../utils/layout';
|
import * as Layout from '../../utils/layout';
|
||||||
|
import { ReserveConfig } from '../state';
|
||||||
import { LendingInstruction } from './instruction';
|
import { LendingInstruction } from './instruction';
|
||||||
|
|
||||||
/// Initializes a new lending market reserve.
|
/// Initializes a new lending market reserve.
|
||||||
|
@ -42,8 +43,7 @@ import { LendingInstruction } from './instruction';
|
||||||
// },
|
// },
|
||||||
export const initReserveInstruction = (
|
export const initReserveInstruction = (
|
||||||
liquidityAmount: number | BN,
|
liquidityAmount: number | BN,
|
||||||
// @FIXME: reserve config
|
config: ReserveConfig,
|
||||||
maxUtilizationRate: number,
|
|
||||||
sourceLiquidity: PublicKey,
|
sourceLiquidity: PublicKey,
|
||||||
destinationCollateral: PublicKey,
|
destinationCollateral: PublicKey,
|
||||||
reserve: PublicKey,
|
reserve: PublicKey,
|
||||||
|
@ -61,8 +61,15 @@ export const initReserveInstruction = (
|
||||||
const dataLayout = BufferLayout.struct([
|
const dataLayout = BufferLayout.struct([
|
||||||
BufferLayout.u8('instruction'),
|
BufferLayout.u8('instruction'),
|
||||||
Layout.uint64('liquidityAmount'),
|
Layout.uint64('liquidityAmount'),
|
||||||
// @FIXME: reserve config
|
BufferLayout.u8('optimalUtilizationRate'),
|
||||||
BufferLayout.u8('maxUtilizationRate'),
|
BufferLayout.u8('loanToValueRatio'),
|
||||||
|
BufferLayout.u8('liquidationBonus'),
|
||||||
|
BufferLayout.u8('liquidationThreshold'),
|
||||||
|
BufferLayout.u8('minBorrowRate'),
|
||||||
|
BufferLayout.u8('optimalBorrowRate'),
|
||||||
|
BufferLayout.u8('maxBorrowRate'),
|
||||||
|
Layout.uint64('borrowFeeWad'),
|
||||||
|
BufferLayout.u8('hostFeePercentage'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const data = Buffer.alloc(dataLayout.span);
|
const data = Buffer.alloc(dataLayout.span);
|
||||||
|
@ -70,7 +77,15 @@ export const initReserveInstruction = (
|
||||||
{
|
{
|
||||||
instruction: LendingInstruction.InitReserve,
|
instruction: LendingInstruction.InitReserve,
|
||||||
liquidityAmount: new BN(liquidityAmount),
|
liquidityAmount: new BN(liquidityAmount),
|
||||||
maxUtilizationRate,
|
optimalUtilizationRate: config.optimalUtilizationRate,
|
||||||
|
loanToValueRatio: config.loanToValueRatio,
|
||||||
|
liquidationBonus: config.liquidationBonus,
|
||||||
|
liquidationThreshold: config.liquidationThreshold,
|
||||||
|
minBorrowRate: config.minBorrowRate,
|
||||||
|
optimalBorrowRate: config.optimalBorrowRate,
|
||||||
|
maxBorrowRate: config.maxBorrowRate,
|
||||||
|
borrowFeeWad: config.fees.borrowFeeWad,
|
||||||
|
hostFeePercentage: config.fees.hostFeePercentage,
|
||||||
},
|
},
|
||||||
data,
|
data,
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,4 +1,11 @@
|
||||||
import BN from 'bn.js';
|
import BN from 'bn.js';
|
||||||
|
import * as BufferLayout from 'buffer-layout';
|
||||||
|
import * as Layout from '../../utils/layout';
|
||||||
|
|
||||||
|
export const LastUpdateLayout: typeof BufferLayout.Structure = BufferLayout.struct(
|
||||||
|
[Layout.uint64('slot'), BufferLayout.u8('stale')],
|
||||||
|
'lastUpdate'
|
||||||
|
);
|
||||||
|
|
||||||
export interface LastUpdate {
|
export interface LastUpdate {
|
||||||
slot: BN;
|
slot: BN;
|
||||||
|
|
|
@ -2,6 +2,13 @@ import { AccountInfo, PublicKey } from '@solana/web3.js';
|
||||||
import * as BufferLayout from 'buffer-layout';
|
import * as BufferLayout from 'buffer-layout';
|
||||||
import * as Layout from '../../utils/layout';
|
import * as Layout from '../../utils/layout';
|
||||||
|
|
||||||
|
export interface LendingMarket {
|
||||||
|
version: number;
|
||||||
|
isInitialized: boolean;
|
||||||
|
quoteTokenMint: PublicKey;
|
||||||
|
tokenProgramId: PublicKey;
|
||||||
|
}
|
||||||
|
|
||||||
export const LendingMarketLayout: typeof BufferLayout.Structure = BufferLayout.struct(
|
export const LendingMarketLayout: typeof BufferLayout.Structure = BufferLayout.struct(
|
||||||
[
|
[
|
||||||
BufferLayout.u8('version'),
|
BufferLayout.u8('version'),
|
||||||
|
@ -14,13 +21,6 @@ export const LendingMarketLayout: typeof BufferLayout.Structure = BufferLayout.s
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
export interface LendingMarket {
|
|
||||||
version: number;
|
|
||||||
isInitialized: boolean;
|
|
||||||
quoteTokenMint: PublicKey;
|
|
||||||
tokenProgramId: PublicKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const isLendingMarket = (info: AccountInfo<Buffer>) => {
|
export const isLendingMarket = (info: AccountInfo<Buffer>) => {
|
||||||
return info.data.length === LendingMarketLayout.span;
|
return info.data.length === LendingMarketLayout.span;
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,16 +2,41 @@ import { AccountInfo, PublicKey } from '@solana/web3.js';
|
||||||
import BN from 'bn.js';
|
import BN from 'bn.js';
|
||||||
import * as BufferLayout from 'buffer-layout';
|
import * as BufferLayout from 'buffer-layout';
|
||||||
import * as Layout from '../../utils/layout';
|
import * as Layout from '../../utils/layout';
|
||||||
import { LastUpdate } from './lastUpdate';
|
import { LastUpdate, LastUpdateLayout } from './lastUpdate';
|
||||||
|
|
||||||
|
export interface Obligation {
|
||||||
|
version: number;
|
||||||
|
lastUpdate: LastUpdate;
|
||||||
|
lendingMarket: PublicKey;
|
||||||
|
owner: PublicKey;
|
||||||
|
// @FIXME: check usages
|
||||||
|
deposits: ObligationCollateral[];
|
||||||
|
// @FIXME: check usages
|
||||||
|
borrows: ObligationLiquidity[];
|
||||||
|
depositedValue: BN; // decimals
|
||||||
|
borrowedValue: BN; // decimals
|
||||||
|
allowedBorrowValue: BN; // decimals
|
||||||
|
unhealthyBorrowValue: BN; // decimals
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ObligationCollateral {
|
||||||
|
depositReserve: PublicKey;
|
||||||
|
depositedAmount: BN;
|
||||||
|
marketValue: BN; // decimals
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ObligationLiquidity {
|
||||||
|
borrowReserve: PublicKey;
|
||||||
|
cumulativeBorrowRateWads: BN; // decimals
|
||||||
|
borrowedAmountWads: BN; // decimals
|
||||||
|
marketValue: BN; // decimals
|
||||||
|
}
|
||||||
|
|
||||||
export const ObligationLayout: typeof BufferLayout.Structure = BufferLayout.struct(
|
export const ObligationLayout: typeof BufferLayout.Structure = BufferLayout.struct(
|
||||||
[
|
[
|
||||||
BufferLayout.u8('version'),
|
BufferLayout.u8('version'),
|
||||||
|
|
||||||
BufferLayout.struct(
|
LastUpdateLayout,
|
||||||
[Layout.uint64('slot'), BufferLayout.u8('stale')],
|
|
||||||
'lastUpdate',
|
|
||||||
),
|
|
||||||
|
|
||||||
Layout.publicKey('lendingMarket'),
|
Layout.publicKey('lendingMarket'),
|
||||||
Layout.publicKey('owner'),
|
Layout.publicKey('owner'),
|
||||||
|
@ -61,34 +86,6 @@ export interface ProtoObligation {
|
||||||
dataFlat: Buffer;
|
dataFlat: Buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Obligation {
|
|
||||||
version: number;
|
|
||||||
lastUpdate: LastUpdate;
|
|
||||||
lendingMarket: PublicKey;
|
|
||||||
owner: PublicKey;
|
|
||||||
// @FIXME: check usages
|
|
||||||
deposits: ObligationCollateral[];
|
|
||||||
// @FIXME: check usages
|
|
||||||
borrows: ObligationLiquidity[];
|
|
||||||
depositedValue: BN; // decimals
|
|
||||||
borrowedValue: BN; // decimals
|
|
||||||
allowedBorrowValue: BN; // decimals
|
|
||||||
unhealthyBorrowValue: BN; // decimals
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ObligationCollateral {
|
|
||||||
depositReserve: PublicKey;
|
|
||||||
depositedAmount: BN;
|
|
||||||
marketValue: BN; // decimals
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ObligationLiquidity {
|
|
||||||
borrowReserve: PublicKey;
|
|
||||||
cumulativeBorrowRateWads: BN; // decimals
|
|
||||||
borrowedAmountWads: BN; // decimals
|
|
||||||
marketValue: BN; // decimals
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ObligationParser = (
|
export const ObligationParser = (
|
||||||
pubkey: PublicKey,
|
pubkey: PublicKey,
|
||||||
info: AccountInfo<Buffer>,
|
info: AccountInfo<Buffer>,
|
||||||
|
|
|
@ -3,70 +3,7 @@ import { AccountInfo, PublicKey } from '@solana/web3.js';
|
||||||
import BN from 'bn.js';
|
import BN from 'bn.js';
|
||||||
import * as BufferLayout from 'buffer-layout';
|
import * as BufferLayout from 'buffer-layout';
|
||||||
import * as Layout from '../../utils/layout';
|
import * as Layout from '../../utils/layout';
|
||||||
import { LastUpdate } from './lastUpdate';
|
import { LastUpdate, LastUpdateLayout } from './lastUpdate';
|
||||||
|
|
||||||
export const ReserveLayout: typeof BufferLayout.Structure = BufferLayout.struct(
|
|
||||||
[
|
|
||||||
BufferLayout.u8('version'),
|
|
||||||
|
|
||||||
BufferLayout.struct(
|
|
||||||
[Layout.uint64('slot'), BufferLayout.u8('stale')],
|
|
||||||
'lastUpdate',
|
|
||||||
),
|
|
||||||
|
|
||||||
Layout.publicKey('lendingMarket'),
|
|
||||||
|
|
||||||
BufferLayout.struct(
|
|
||||||
[
|
|
||||||
Layout.publicKey('mintPubkey'),
|
|
||||||
BufferLayout.u8('mintDecimals'),
|
|
||||||
Layout.publicKey('supplyPubkey'),
|
|
||||||
Layout.publicKey('feeReceiver'),
|
|
||||||
// @FIXME: oracle option
|
|
||||||
// TODO: replace u32 option with generic equivalent
|
|
||||||
BufferLayout.u32('oracleOption'),
|
|
||||||
Layout.publicKey('oracle'),
|
|
||||||
Layout.uint64('availableAmount'),
|
|
||||||
Layout.uint128('borrowedAmountWads'),
|
|
||||||
Layout.uint128('cumulativeBorrowRateWads'),
|
|
||||||
Layout.uint64('marketPrice'),
|
|
||||||
],
|
|
||||||
'liquidity',
|
|
||||||
),
|
|
||||||
|
|
||||||
BufferLayout.struct(
|
|
||||||
[
|
|
||||||
Layout.publicKey('mintPubkey'),
|
|
||||||
Layout.uint64('mintTotalSupply'),
|
|
||||||
Layout.publicKey('supplyPubkey'),
|
|
||||||
],
|
|
||||||
'collateral',
|
|
||||||
),
|
|
||||||
|
|
||||||
BufferLayout.struct(
|
|
||||||
[
|
|
||||||
BufferLayout.u8('optimalUtilizationRate'),
|
|
||||||
BufferLayout.u8('loanToValueRatio'),
|
|
||||||
BufferLayout.u8('liquidationBonus'),
|
|
||||||
BufferLayout.u8('liquidationThreshold'),
|
|
||||||
BufferLayout.u8('minBorrowRate'),
|
|
||||||
BufferLayout.u8('optimalBorrowRate'),
|
|
||||||
BufferLayout.u8('maxBorrowRate'),
|
|
||||||
BufferLayout.struct(
|
|
||||||
[Layout.uint64('borrowFeeWad'), BufferLayout.u8('hostFeePercentage')],
|
|
||||||
'fees',
|
|
||||||
),
|
|
||||||
],
|
|
||||||
'config',
|
|
||||||
),
|
|
||||||
|
|
||||||
BufferLayout.blob(256, 'padding'),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
export const isReserve = (info: AccountInfo<Buffer>) => {
|
|
||||||
return info.data.length === ReserveLayout.span;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface Reserve {
|
export interface Reserve {
|
||||||
version: number;
|
version: number;
|
||||||
|
@ -111,6 +48,66 @@ export interface ReserveConfig {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const ReserveLayout: typeof BufferLayout.Structure = BufferLayout.struct(
|
||||||
|
[
|
||||||
|
BufferLayout.u8('version'),
|
||||||
|
|
||||||
|
LastUpdateLayout,
|
||||||
|
|
||||||
|
Layout.publicKey('lendingMarket'),
|
||||||
|
|
||||||
|
BufferLayout.struct(
|
||||||
|
[
|
||||||
|
Layout.publicKey('mintPubkey'),
|
||||||
|
BufferLayout.u8('mintDecimals'),
|
||||||
|
Layout.publicKey('supplyPubkey'),
|
||||||
|
Layout.publicKey('feeReceiver'),
|
||||||
|
// @FIXME: oracle option
|
||||||
|
// TODO: replace u32 option with generic equivalent
|
||||||
|
BufferLayout.u32('oracleOption'),
|
||||||
|
Layout.publicKey('oracle'),
|
||||||
|
Layout.uint64('availableAmount'),
|
||||||
|
Layout.uint128('borrowedAmountWads'),
|
||||||
|
Layout.uint128('cumulativeBorrowRateWads'),
|
||||||
|
Layout.uint64('marketPrice'),
|
||||||
|
],
|
||||||
|
'liquidity',
|
||||||
|
),
|
||||||
|
|
||||||
|
BufferLayout.struct(
|
||||||
|
[
|
||||||
|
Layout.publicKey('mintPubkey'),
|
||||||
|
Layout.uint64('mintTotalSupply'),
|
||||||
|
Layout.publicKey('supplyPubkey'),
|
||||||
|
],
|
||||||
|
'collateral'
|
||||||
|
),
|
||||||
|
|
||||||
|
BufferLayout.struct(
|
||||||
|
[
|
||||||
|
BufferLayout.u8('optimalUtilizationRate'),
|
||||||
|
BufferLayout.u8('loanToValueRatio'),
|
||||||
|
BufferLayout.u8('liquidationBonus'),
|
||||||
|
BufferLayout.u8('liquidationThreshold'),
|
||||||
|
BufferLayout.u8('minBorrowRate'),
|
||||||
|
BufferLayout.u8('optimalBorrowRate'),
|
||||||
|
BufferLayout.u8('maxBorrowRate'),
|
||||||
|
BufferLayout.struct(
|
||||||
|
[Layout.uint64('borrowFeeWad'), BufferLayout.u8('hostFeePercentage')],
|
||||||
|
'fees',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
'config'
|
||||||
|
),
|
||||||
|
|
||||||
|
BufferLayout.blob(256, 'padding'),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
export const isReserve = (info: AccountInfo<Buffer>) => {
|
||||||
|
return info.data.length === ReserveLayout.span;
|
||||||
|
};
|
||||||
|
|
||||||
export const ReserveParser = (pubkey: PublicKey, info: AccountInfo<Buffer>) => {
|
export const ReserveParser = (pubkey: PublicKey, info: AccountInfo<Buffer>) => {
|
||||||
const buffer = Buffer.from(info.data);
|
const buffer = Buffer.from(info.data);
|
||||||
const reserve = ReserveLayout.decode(buffer) as Reserve;
|
const reserve = ReserveLayout.decode(buffer) as Reserve;
|
||||||
|
|
Loading…
Reference in New Issue