From f3608c37d4e166a2cff6277708ea870402878de1 Mon Sep 17 00:00:00 2001 From: bartosz-lipinski <264380+bartosz-lipinski@users.noreply.github.com> Date: Wed, 6 Jan 2021 11:06:32 -0600 Subject: [PATCH] feat: add support for owner/host fees --- .env | 5 +++++ src/actions/borrow.tsx | 41 +++++++++++++++++++++++++---------- src/contexts/accounts.tsx | 4 +++- src/models/lending/borrow.ts | 13 ++++++++++- src/models/lending/reserve.ts | 1 - src/utils/ids.ts | 11 ++++------ 6 files changed, 53 insertions(+), 22 deletions(-) create mode 100644 .env diff --git a/.env b/.env new file mode 100644 index 0000000..4898535 --- /dev/null +++ b/.env @@ -0,0 +1,5 @@ +# HOST Public Key used for additional swap fees +LEND_HOST_FEE_ADDRESS='' + +# Rewired variables to comply with CRA restrictions +REACT_APP_LEND_HOST_FEE_ADDRESS=$LEND_HOST_FEE_ADDRESS diff --git a/src/actions/borrow.tsx b/src/actions/borrow.tsx index 0e21fd2..10b5d4d 100644 --- a/src/actions/borrow.tsx +++ b/src/actions/borrow.tsx @@ -8,7 +8,7 @@ import { sendTransaction } from "../contexts/connection"; import { notify } from "../utils/notifications"; import { LendingReserve } from "./../models/lending/reserve"; import { AccountLayout, MintInfo, MintLayout } from "@solana/spl-token"; -import { LENDING_PROGRAM_ID } from "../utils/ids"; +import { LENDING_PROGRAM_ID, LEND_HOST_FEE_ADDRESS } from "../utils/ids"; import { createTempMemoryAccount, createUninitializedAccount, @@ -60,20 +60,20 @@ export const borrow = async ( const obligation = existingObligation ? existingObligation.pubkey : createUninitializedObligation( - instructions, - wallet.publicKey, - await connection.getMinimumBalanceForRentExemption(LendingObligationLayout.span), - signers - ); + instructions, + wallet.publicKey, + await connection.getMinimumBalanceForRentExemption(LendingObligationLayout.span), + signers + ); const obligationMint = existingObligation ? existingObligation.info.tokenMint : createUninitializedMint( - instructions, - wallet.publicKey, - await connection.getMinimumBalanceForRentExemption(MintLayout.span), - signers - ); + instructions, + wallet.publicKey, + await connection.getMinimumBalanceForRentExemption(MintLayout.span), + signers + ); const obligationTokenOutput = obligationAccount ? obligationAccount @@ -172,6 +172,19 @@ export const borrow = async ( const memory = createTempMemoryAccount(instructions, wallet.publicKey, signers); + // Creates host fee account if it doesn't exsist + let hostFeeReceiver = LEND_HOST_FEE_ADDRESS + ? findOrCreateAccountByMint( + wallet.publicKey, + LEND_HOST_FEE_ADDRESS, + instructions, + cleanupInstructions, + accountRentExempt, + depositReserve.info.collateralMint, + signers + ) + : undefined; + // deposit instructions.push( borrowInstruction( @@ -181,6 +194,8 @@ export const borrow = async ( toAccount, depositReserve.pubkey, depositReserve.info.collateralSupply, + depositReserve.info.collateralFeesReceiver, + borrowReserve.pubkey, borrowReserve.info.liquiditySupply, @@ -196,7 +211,9 @@ export const borrow = async ( dexMarketAddress, dexOrderBookSide, - memory + memory, + + hostFeeReceiver, ) ); try { diff --git a/src/contexts/accounts.tsx b/src/contexts/accounts.tsx index c2a42b7..ca32895 100644 --- a/src/contexts/accounts.tsx +++ b/src/contexts/accounts.tsx @@ -7,7 +7,7 @@ import { PoolInfo, TokenAccount } from './../models'; import { chunks } from './../utils/utils'; import { EventEmitter } from './../utils/eventEmitter'; import { useUserAccounts } from '../hooks/useUserAccounts'; -import { WRAPPED_SOL_MINT, programIds } from '../utils/ids'; +import { WRAPPED_SOL_MINT, programIds, LEND_HOST_FEE_ADDRESS } from '../utils/ids'; const AccountsContext = React.createContext(null); @@ -382,6 +382,8 @@ export function AccountsProvider({ children = null as any }) { if (!connection || !publicKey) { setTokenAccounts([]); } else { + precacheUserTokenAccounts(connection, LEND_HOST_FEE_ADDRESS); + precacheUserTokenAccounts(connection, publicKey).then(() => { setTokenAccounts(selectUserAccounts()); }); diff --git a/src/models/lending/borrow.ts b/src/models/lending/borrow.ts index 94874de..9523e98 100644 --- a/src/models/lending/borrow.ts +++ b/src/models/lending/borrow.ts @@ -41,6 +41,8 @@ export const borrowInstruction = ( to: PublicKey, // Liquidity output SPL Token account, depositReserve: PublicKey, depositReserveCollateralSupply: PublicKey, + ownerFeeReceiver: PublicKey, + borrowReserve: PublicKey, borrowReserveLiquiditySupply: PublicKey, @@ -56,7 +58,9 @@ export const borrowInstruction = ( dexMarket: PublicKey, dexOrderBookSide: PublicKey, - memory: PublicKey + memory: PublicKey, + + hostFeeReceiver?: PublicKey, ): TransactionInstruction => { const dataLayout = BufferLayout.struct([ BufferLayout.u8('instruction'), @@ -83,6 +87,8 @@ export const borrowInstruction = ( isSigner: false, isWritable: true, }, + { pubkey: ownerFeeReceiver, isSigner: false, isWritable: false }, + { pubkey: borrowReserve, isSigner: false, isWritable: true }, { pubkey: borrowReserveLiquiditySupply, @@ -105,6 +111,11 @@ export const borrowInstruction = ( { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false }, { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, ]; + + if(hostFeeReceiver) { + keys.push({ pubkey: hostFeeReceiver, isSigner: false, isWritable: false }) + } + return new TransactionInstruction({ keys, programId: LENDING_PROGRAM_ID, diff --git a/src/models/lending/reserve.ts b/src/models/lending/reserve.ts index 9b637a6..6ff03fa 100644 --- a/src/models/lending/reserve.ts +++ b/src/models/lending/reserve.ts @@ -7,7 +7,6 @@ import { } from '@solana/web3.js'; import BN from 'bn.js'; import * as BufferLayout from 'buffer-layout'; -import { HALF_WAD } from '../../constants'; import { TOKEN_PROGRAM_ID, LENDING_PROGRAM_ID } from '../../utils/ids'; import { wadToLamports } from '../../utils/utils'; import * as Layout from './../../utils/layout'; diff --git a/src/utils/ids.ts b/src/utils/ids.ts index 8cb3dcf..7eb62b3 100644 --- a/src/utils/ids.ts +++ b/src/utils/ids.ts @@ -10,17 +10,14 @@ let SWAP_PROGRAM_ID: PublicKey; let SWAP_PROGRAM_LEGACY_IDS: PublicKey[]; let SWAP_PROGRAM_LAYOUT: any; -export const SWAP_PROGRAM_OWNER_FEE_ADDRESS = new PublicKey('HfoTxFR1Tm6kGmWgYWD6J7YHVy1UwqSULUGVLXkJqaKN'); +export const LEND_HOST_FEE_ADDRESS = process.env.REACT_APP_LEND_HOST_FEE_ADDRESS + ? new PublicKey(`${process.env.REACT_APP_LEND_HOST_FEE_ADDRESS}`) + : undefined; -export const SWAP_HOST_FEE_ADDRESS = process.env.REACT_APP_SWAP_HOST_FEE_ADDRESS - ? new PublicKey(`${process.env.REACT_APP_SWAP_HOST_FEE_ADDRESS}`) - : SWAP_PROGRAM_OWNER_FEE_ADDRESS; + console.debug(`Lend host fee address: ${LEND_HOST_FEE_ADDRESS?.toBase58()}`); export const ENABLE_FEES_INPUT = false; -console.debug(`Host address: ${SWAP_HOST_FEE_ADDRESS?.toBase58()}`); -console.debug(`Owner address: ${SWAP_PROGRAM_OWNER_FEE_ADDRESS?.toBase58()}`); - // legacy pools are used to show users contributions in those pools to allow for withdrawals of funds export const PROGRAM_IDS = [ {