diff --git a/src/actions/borrow.tsx b/src/actions/borrow.tsx index ca1e9c1..0e21fd2 100644 --- a/src/actions/borrow.tsx +++ b/src/actions/borrow.tsx @@ -147,14 +147,14 @@ export const borrow = async ( ); // create approval for transfer transactions - approve( + const transferAuthority = approve( instructions, cleanupInstructions, fromAccount, - authority, wallet.publicKey, fromLamports ); + signers.push(transferAuthority); const dexMarketAddress = borrowReserve.info.dexMarketOption ? borrowReserve.info.dexMarket @@ -189,7 +189,9 @@ export const borrow = async ( obligationTokenOutput, wallet.publicKey, + depositReserve.info.lendingMarket, authority, + transferAuthority.publicKey, dexMarketAddress, dexOrderBookSide, diff --git a/src/actions/deposit.tsx b/src/actions/deposit.tsx index ad9d3c3..454f3a2 100644 --- a/src/actions/deposit.tsx +++ b/src/actions/deposit.tsx @@ -58,15 +58,16 @@ export const deposit = async ( ); // create approval for transfer transactions - approve( + const transferAuthority = approve( instructions, cleanupInstructions, fromAccount, - authority, wallet.publicKey, amountLamports ); + signers.push(transferAuthority); + let toAccount: PublicKey; if (isInitalized) { // get destination account @@ -90,7 +91,9 @@ export const deposit = async ( amountLamports, fromAccount, toAccount, + reserve.lendingMarket, authority, + transferAuthority.publicKey, reserveAddress, reserve.liquiditySupply, reserve.collateralMint @@ -112,6 +115,7 @@ export const deposit = async ( reserve.collateralSupply, reserve.lendingMarket, authority, + transferAuthority.publicKey, reserve.dexMarket ) ); diff --git a/src/actions/liquidate.tsx b/src/actions/liquidate.tsx index 43dfd32..d71ccd1 100644 --- a/src/actions/liquidate.tsx +++ b/src/actions/liquidate.tsx @@ -55,14 +55,14 @@ export const liquidate = async ( ); // create approval for transfer transactions - approve( + const transferAuthority = approve( instructions, cleanupInstructions, fromAccount, - authority, wallet.publicKey, amountLamports ); + signers.push(transferAuthority); // get destination account const toAccount = await findOrCreateAccountByMint( @@ -104,7 +104,9 @@ export const liquidate = async ( withdrawReserve.pubkey, withdrawReserve.info.collateralSupply, obligation.pubkey, + repayReserve.info.lendingMarket, authority, + transferAuthority.publicKey, dexMarketAddress, dexOrderBookSide, memory diff --git a/src/actions/repay.tsx b/src/actions/repay.tsx index a48a886..af46916 100644 --- a/src/actions/repay.tsx +++ b/src/actions/repay.tsx @@ -51,14 +51,14 @@ export const repay = async ( const fromAccount = from.pubkey; // create approval for transfer transactions - approve( + const transferAuthority = approve( instructions, cleanupInstructions, fromAccount, - authority, wallet.publicKey, amountLamports ); + signers.push(transferAuthority); // get destination account const toAccount = await findOrCreateAccountByMint( @@ -76,9 +76,11 @@ export const repay = async ( instructions, cleanupInstructions, obligationToken.pubkey, - authority, wallet.publicKey, - obligationToken.info.amount.toNumber() + obligationToken.info.amount.toNumber(), + + // reuse transfer authority + transferAuthority.publicKey, ); // TODO: add obligation @@ -95,7 +97,9 @@ export const repay = async ( obligation.pubkey, obligation.info.tokenMint, obligationToken.pubkey, - authority + repayReserve.info.lendingMarket, + authority, + transferAuthority.publicKey, ) ); diff --git a/src/actions/withdraw.tsx b/src/actions/withdraw.tsx index 9ba11a2..2e3455c 100644 --- a/src/actions/withdraw.tsx +++ b/src/actions/withdraw.tsx @@ -38,15 +38,16 @@ export const withdraw = async ( const fromAccount = from.pubkey; // create approval for transfer transactions - approve( + const transferAuthority = approve( instructions, cleanupInstructions, fromAccount, - authority, wallet.publicKey, amountLamports ); + signers.push(transferAuthority); + // get destination account const toAccount = await findOrCreateAccountByMint( wallet.publicKey, @@ -66,7 +67,9 @@ export const withdraw = async ( reserveAddress, reserve.collateralMint, reserve.liquiditySupply, - authority + reserve.lendingMarket, + authority, + transferAuthority.publicKey, ) ); diff --git a/src/models/account.ts b/src/models/account.ts index cc29d98..13f648a 100644 --- a/src/models/account.ts +++ b/src/models/account.ts @@ -1,4 +1,4 @@ -import { AccountInfo, PublicKey, TransactionInstruction } from "@solana/web3.js"; +import { Account, AccountInfo, PublicKey, TransactionInstruction } from "@solana/web3.js"; import { AccountInfo as TokenAccountInfo, Token } from "@solana/spl-token"; import { TOKEN_PROGRAM_ID } from "../utils/ids"; @@ -13,16 +13,20 @@ export function approve( instructions: TransactionInstruction[], cleanupInstructions: TransactionInstruction[], account: PublicKey, - delegate: PublicKey, owner: PublicKey, amount: number, -): void { + + // if delegate is not passed ephemeral transfer authority is used + delegate?: PublicKey, +): Account { const tokenProgram = TOKEN_PROGRAM_ID; + const transferAuthority = new Account(); + instructions.push( Token.createApproveInstruction( tokenProgram, account, - delegate, + delegate ?? transferAuthority.publicKey, owner, [], amount @@ -36,4 +40,6 @@ export function approve( owner, []), ); + + return transferAuthority; } \ No newline at end of file diff --git a/src/models/lending/borrow.ts b/src/models/lending/borrow.ts index 0cf2eb7..87c7ec7 100644 --- a/src/models/lending/borrow.ts +++ b/src/models/lending/borrow.ts @@ -15,23 +15,26 @@ export enum BorrowAmountType { /// Borrow tokens from a reserve by depositing collateral tokens. The number of borrowed tokens /// is calculated by market price. The debt obligation is tokenized. /// -/// 0. `[writable]` Collateral input SPL Token account, $authority can transfer $collateral_amount -/// 1. `[writable]` Liquidity output SPL Token account +/// 0. `[writable]` Source collateral token account, minted by deposit reserve collateral mint, +/// $authority can transfer $collateral_amount +/// 1. `[writable]` Destination liquidity token account, minted by borrow reserve liquidity mint /// 2. `[writable]` Deposit reserve account. /// 3. `[writable]` Deposit reserve collateral supply SPL Token account /// 4. `[writable]` Borrow reserve account. /// 5. `[writable]` Borrow reserve liquidity supply SPL Token account -/// 6. `[writable]` Obligation - uninitialized -/// 7. `[writable]` Obligation token mint - uninitialized -/// 8. `[writable]` Obligation token output - uninitialized +/// 6. `[writable]` Obligation +/// 7. `[writable]` Obligation token mint +/// 8. `[writable]` Obligation token output /// 9. `[]` Obligation token owner -/// 10 `[]` Derived lending market authority ($authority). -/// 11 `[]` Dex market -/// 12 `[]` Dex order book side // could be bid/ask -/// 13 `[]` Temporary memory -/// 14 `[]` Clock sysvar -/// 15 `[]` Rent sysvar -/// 16 '[]` Token program id +/// 10 `[]` Lending market account. +/// 11 `[]` Derived lending market authority. +/// 12 `[]` User transfer authority ($authority). +/// 13 `[]` Dex market +/// 14 `[]` Dex market order book side +/// 15 `[]` Temporary memory +/// 16 `[]` Clock sysvar +/// 17 `[]` Rent sysvar +/// 18 '[]` Token program id export const borrowInstruction = ( amount: number | BN, amountType: BorrowAmountType, @@ -47,7 +50,9 @@ export const borrowInstruction = ( obligationTokenOutput: PublicKey, obligationTokenOwner: PublicKey, + lendingMarket: PublicKey, lendingMarketAuthority: PublicKey, + transferAuthority: PublicKey, dexMarket: PublicKey, dexOrderBookSide: PublicKey, @@ -89,7 +94,11 @@ export const borrowInstruction = ( { pubkey: obligationMint, isSigner: false, isWritable: true }, { pubkey: obligationTokenOutput, isSigner: false, isWritable: true }, { pubkey: obligationTokenOwner, isSigner: false, isWritable: false }, + + { pubkey: lendingMarket, isSigner: false, isWritable: false }, { pubkey: lendingMarketAuthority, isSigner: false, isWritable: false }, + { pubkey: transferAuthority, isSigner: false, isWritable: false }, + { pubkey: dexMarket, isSigner: false, isWritable: false }, { pubkey: dexOrderBookSide, isSigner: false, isWritable: false }, { pubkey: memory, isSigner: false, isWritable: false }, diff --git a/src/models/lending/deposit.ts b/src/models/lending/deposit.ts index b878b80..b820db9 100644 --- a/src/models/lending/deposit.ts +++ b/src/models/lending/deposit.ts @@ -11,19 +11,23 @@ import { LendingReserve } from './reserve'; /// Deposit liquidity into a reserve. The output is a collateral token representing ownership /// of the reserve liquidity pool. /// -/// 0. `[writable]` Liquidity input SPL Token account. $authority can transfer $liquidity_amount -/// 1. `[writable]` Collateral output SPL Token account, +/// 0. `[writable]` Source liquidity token account. $authority can transfer $liquidity_amount +/// 1. `[writable]` Destination collateral token account. /// 2. `[writable]` Reserve account. /// 3. `[writable]` Reserve liquidity supply SPL Token account. /// 4. `[writable]` Reserve collateral SPL Token mint. -/// 5. `[]` Derived lending market authority ($authority). -/// 6. `[]` Clock sysvar -/// 7. '[]` Token program id +/// 5. `[]` Lending market account. +/// 6. `[]` Derived lending market authority. +/// 7. `[]` User transfer authority ($authority). +/// 8. `[]` Clock sysvar +/// 9. '[]` Token program id export const depositInstruction = ( liquidityAmount: number | BN, from: PublicKey, // Liquidity input SPL Token account. $authority can transfer $liquidity_amount to: PublicKey, // Collateral output SPL Token account, + lendingMarket: PublicKey, reserveAuthority: PublicKey, + transferAuthority: PublicKey, reserveAccount: PublicKey, reserveSupply: PublicKey, collateralMint: PublicKey @@ -45,7 +49,9 @@ export const depositInstruction = ( { pubkey: reserveAccount, isSigner: false, isWritable: true }, { pubkey: reserveSupply, isSigner: false, isWritable: true }, { pubkey: collateralMint, isSigner: false, isWritable: true }, + { pubkey: lendingMarket, isSigner: false, isWritable: false }, { pubkey: reserveAuthority, isSigner: false, isWritable: false }, + { pubkey: transferAuthority, isSigner: false, isWritable: false }, { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false }, { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, ]; diff --git a/src/models/lending/liquidate.ts b/src/models/lending/liquidate.ts index c3c2717..a5f21cc 100644 --- a/src/models/lending/liquidate.ts +++ b/src/models/lending/liquidate.ts @@ -7,19 +7,22 @@ import { TOKEN_PROGRAM_ID, LENDING_PROGRAM_ID } from '../../utils/ids'; /// Purchase collateral tokens at a discount rate if the chosen obligation is unhealthy. /// -/// 0. `[writable]` Liquidity input SPL Token account, $authority can transfer $liquidity_amount -/// 1. `[writable]` Collateral output SPL Token account +/// 0. `[writable]` Source liquidity token account, minted by repay reserve liquidity mint +/// $authority can transfer $collateral_amount +/// 1. `[writable]` Destination collateral token account, minted by withdraw reserve collateral mint /// 2. `[writable]` Repay reserve account. /// 3. `[writable]` Repay reserve liquidity supply SPL Token account /// 4. `[writable]` Withdraw reserve account. /// 5. `[writable]` Withdraw reserve collateral supply SPL Token account /// 6. `[writable]` Obligation - initialized -/// 7. `[]` Derived lending market authority ($authority). -/// 8. `[]` Dex market -/// 9. `[]` Dex market orders -/// 10 `[]` Temporary memory -/// 11 `[]` Clock sysvar -/// 12 `[]` Token program id +/// 7. `[]` Lending market account. +/// 8. `[]` Derived lending market authority. +/// 9. `[]` User transfer authority ($authority). +/// 10 `[]` Dex market +/// 11 `[]` Dex market order book side +/// 12 `[]` Temporary memory +/// 13 `[]` Clock sysvar +/// 14 `[]` Token program id export const liquidateInstruction = ( liquidityAmount: number | BN, from: PublicKey, // Liquidity input SPL Token account. $authority can transfer $liquidity_amount @@ -29,7 +32,9 @@ export const liquidateInstruction = ( withdrawReserve: PublicKey, withdrawReserveCollateralSupply: PublicKey, obligation: PublicKey, + lendingMarket: PublicKey, authority: PublicKey, + transferAuthority: PublicKey, dexMarket: PublicKey, dexOrderBookSide: PublicKey, memory: PublicKey @@ -61,7 +66,9 @@ export const liquidateInstruction = ( { pubkey: obligation, isSigner: false, isWritable: true }, + { pubkey: lendingMarket, isSigner: false, isWritable: false }, { pubkey: authority, isSigner: false, isWritable: false }, + { pubkey: transferAuthority, isSigner: false, isWritable: false }, { pubkey: dexMarket, isSigner: false, isWritable: false }, { pubkey: dexOrderBookSide, isSigner: false, isWritable: false }, diff --git a/src/models/lending/repay.ts b/src/models/lending/repay.ts index f6e0acc..d1c6d92 100644 --- a/src/models/lending/repay.ts +++ b/src/models/lending/repay.ts @@ -8,18 +8,21 @@ import { TOKEN_PROGRAM_ID, LENDING_PROGRAM_ID } from '../../utils/ids'; /// Repay loaned tokens to a reserve and receive collateral tokens. The obligation balance /// will be recalculated for interest. /// -/// 0. `[writable]` Liquidity input SPL Token account, $authority can transfer $liquidity_amount -/// 1. `[writable]` Collateral output SPL Token account +/// 0. `[writable]` Source liquidity token account, minted by repay reserve liquidity mint +/// $authority can transfer $collateral_amount +/// 1. `[writable]` Destination collateral token account, minted by withdraw reserve collateral mint /// 2. `[writable]` Repay reserve account. /// 3. `[writable]` Repay reserve liquidity supply SPL Token account /// 4. `[]` Withdraw reserve account. /// 5. `[writable]` Withdraw reserve collateral supply SPL Token account /// 6. `[writable]` Obligation - initialized -/// 7. `[writable]` Obligation token mint, $authority can transfer calculated amount -/// 8. `[writable]` Obligation token input -/// 9. `[]` Derived lending market authority ($authority). -/// 10 `[]` Clock sysvar -/// 11 `[]` Token program id +/// 7. `[writable]` Obligation token mint +/// 8. `[writable]` Obligation token input, $authority can transfer calculated amount +/// 9. `[]` Lending market account. +/// 10 `[]` Derived lending market authority. +/// 11 `[]` User transfer authority ($authority). +/// 12 `[]` Clock sysvar +/// 13 `[]` Token program id export const repayInstruction = ( liquidityAmount: number | BN, from: PublicKey, // Liquidity input SPL Token account. $authority can transfer $liquidity_amount @@ -31,7 +34,9 @@ export const repayInstruction = ( obligation: PublicKey, obligationMint: PublicKey, obligationInput: PublicKey, - authority: PublicKey + lendingMarket: PublicKey, + authority: PublicKey, + transferAuthority: PublicKey, ): TransactionInstruction => { const dataLayout = BufferLayout.struct([BufferLayout.u8('instruction'), Layout.uint64('liquidityAmount')]); @@ -62,7 +67,10 @@ export const repayInstruction = ( { pubkey: obligationMint, isSigner: false, isWritable: true }, { pubkey: obligationInput, isSigner: false, isWritable: true }, + { pubkey: lendingMarket, isSigner: false, isWritable: false }, { pubkey: authority, isSigner: false, isWritable: false }, + { pubkey: transferAuthority, isSigner: false, isWritable: false }, + { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false }, { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, ]; diff --git a/src/models/lending/reserve.ts b/src/models/lending/reserve.ts index 9e1c83f..8f8542d 100644 --- a/src/models/lending/reserve.ts +++ b/src/models/lending/reserve.ts @@ -114,6 +114,7 @@ export const initReserveInstruction = ( collateralSupply: PublicKey, lendingMarket: PublicKey, lendingMarketAuthority: PublicKey, + transferAuthority: PublicKey, dexMarket: PublicKey // TODO: optional ): TransactionInstruction => { @@ -145,6 +146,7 @@ export const initReserveInstruction = ( // NOTE: Why lending market needs to be a signer? { pubkey: lendingMarket, isSigner: true, isWritable: true }, { pubkey: lendingMarketAuthority, isSigner: false, isWritable: false }, + { pubkey: transferAuthority, isSigner: false, isWritable: false }, { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false }, { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false }, { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, diff --git a/src/models/lending/withdraw.ts b/src/models/lending/withdraw.ts index 9b9db09..c0c2bf7 100644 --- a/src/models/lending/withdraw.ts +++ b/src/models/lending/withdraw.ts @@ -12,7 +12,9 @@ export const withdrawInstruction = ( reserveAccount: PublicKey, collateralMint: PublicKey, reserveSupply: PublicKey, - authority: PublicKey + lendingMarket: PublicKey, + authority: PublicKey, + transferAuthority: PublicKey, ): TransactionInstruction => { const dataLayout = BufferLayout.struct([BufferLayout.u8('instruction'), Layout.uint64('collateralAmount')]); @@ -31,7 +33,9 @@ export const withdrawInstruction = ( { pubkey: reserveAccount, isSigner: false, isWritable: true }, { pubkey: collateralMint, isSigner: false, isWritable: true }, { pubkey: reserveSupply, isSigner: false, isWritable: true }, + { pubkey: lendingMarket, isSigner: false, isWritable: false }, { pubkey: authority, isSigner: false, isWritable: false }, + { pubkey: transferAuthority, isSigner: false, isWritable: false }, { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false }, { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, ];