mirror of https://github.com/certusone/oyster.git
chore: cleanup unused code
This commit is contained in:
parent
4d16a1c182
commit
16d6cd60a8
|
@ -131,12 +131,12 @@ export const AppLayout = React.memo((props: any) => {
|
|||
</Menu>
|
||||
<Menu theme={theme} defaultSelectedKeys={[defaultKey]} selectable={false} mode="inline" className="bottom-links">
|
||||
<Menu.Item key="16" icon={<ForkOutlined />}>
|
||||
<a title="Fork" href={`${config.repository.url}/fork`} target="_blank">
|
||||
<a title="Fork" href={`${config.repository.url}/fork`} target="_blank" rel="noopener noreferrer" >
|
||||
Fork
|
||||
</a>
|
||||
</Menu.Item>,
|
||||
<Menu.Item key="15" icon={<GithubOutlined />}>
|
||||
<a title="Gtihub" href={config.repository.url} target="_blank">
|
||||
<a title="Gtihub" href={config.repository.url} target="_blank" rel="noopener noreferrer" >
|
||||
Github
|
||||
</a>
|
||||
</Menu.Item>
|
||||
|
|
|
@ -7,7 +7,6 @@ import { PoolInfo, TokenAccount } from './../models';
|
|||
import { chunks } from './../utils/utils';
|
||||
import { EventEmitter } from './../utils/eventEmitter';
|
||||
import { useUserAccounts } from '../hooks/useUserAccounts';
|
||||
import { usePools } from '../utils/pools';
|
||||
import { WRAPPED_SOL_MINT, programIds } from '../utils/ids';
|
||||
|
||||
const AccountsContext = React.createContext<any>(null);
|
||||
|
@ -347,7 +346,6 @@ export function AccountsProvider({ children = null as any }) {
|
|||
const [tokenAccounts, setTokenAccounts] = useState<TokenAccount[]>([]);
|
||||
const [userAccounts, setUserAccounts] = useState<TokenAccount[]>([]);
|
||||
const { nativeAccount } = UseNativeAccount();
|
||||
const { pools } = usePools();
|
||||
|
||||
const selectUserAccounts = useCallback(() => {
|
||||
return cache
|
||||
|
@ -419,7 +417,6 @@ export function AccountsProvider({ children = null as any }) {
|
|||
<AccountsContext.Provider
|
||||
value={{
|
||||
userAccounts,
|
||||
pools,
|
||||
nativeAccount,
|
||||
}}
|
||||
>
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
import { Numberu64 } from '@solana/spl-token-swap';
|
||||
import { PublicKey, Account, TransactionInstruction } from '@solana/web3.js';
|
||||
import * as BufferLayout from 'buffer-layout';
|
||||
import { programIds } from '../utils/ids';
|
||||
import { publicKey, uint64 } from '../utils/layout';
|
||||
import { CurveType, PoolConfig } from './pool';
|
||||
|
||||
export { TokenSwap } from '@solana/spl-token-swap';
|
||||
|
||||
|
@ -70,369 +66,3 @@ export const TokenSwapLayout: typeof BufferLayout.Structure = BufferLayout.struc
|
|||
FEE_LAYOUT,
|
||||
CURVE_NODE,
|
||||
]);
|
||||
|
||||
export const createInitSwapInstruction = (
|
||||
tokenSwapAccount: Account,
|
||||
authority: PublicKey,
|
||||
tokenAccountA: PublicKey,
|
||||
tokenAccountB: PublicKey,
|
||||
tokenPool: PublicKey,
|
||||
feeAccount: PublicKey,
|
||||
destinationAccount: PublicKey,
|
||||
tokenProgramId: PublicKey,
|
||||
swapProgramId: PublicKey,
|
||||
nonce: number,
|
||||
config: PoolConfig
|
||||
): TransactionInstruction => {
|
||||
const keys = [
|
||||
{ pubkey: tokenSwapAccount.publicKey, isSigner: false, isWritable: true },
|
||||
{ pubkey: authority, isSigner: false, isWritable: false },
|
||||
{ pubkey: tokenAccountA, isSigner: false, isWritable: false },
|
||||
{ pubkey: tokenAccountB, isSigner: false, isWritable: false },
|
||||
{ pubkey: tokenPool, isSigner: false, isWritable: true },
|
||||
{ pubkey: feeAccount, isSigner: false, isWritable: false },
|
||||
{ pubkey: destinationAccount, isSigner: false, isWritable: true },
|
||||
{ pubkey: tokenProgramId, isSigner: false, isWritable: false },
|
||||
];
|
||||
|
||||
let data = Buffer.alloc(1024);
|
||||
{
|
||||
const isLatestLayout = programIds().swapLayout === TokenSwapLayout;
|
||||
if (isLatestLayout) {
|
||||
const fields = [
|
||||
BufferLayout.u8('instruction'),
|
||||
BufferLayout.u8('nonce'),
|
||||
BufferLayout.nu64('tradeFeeNumerator'),
|
||||
BufferLayout.nu64('tradeFeeDenominator'),
|
||||
BufferLayout.nu64('ownerTradeFeeNumerator'),
|
||||
BufferLayout.nu64('ownerTradeFeeDenominator'),
|
||||
BufferLayout.nu64('ownerWithdrawFeeNumerator'),
|
||||
BufferLayout.nu64('ownerWithdrawFeeDenominator'),
|
||||
BufferLayout.nu64('hostFeeNumerator'),
|
||||
BufferLayout.nu64('hostFeeDenominator'),
|
||||
BufferLayout.u8('curveType'),
|
||||
];
|
||||
|
||||
if (config.curveType === CurveType.ConstantProductWithOffset) {
|
||||
fields.push(BufferLayout.nu64('token_b_offset'));
|
||||
fields.push(BufferLayout.blob(24, 'padding'));
|
||||
} else if (config.curveType === CurveType.ConstantPrice) {
|
||||
fields.push(BufferLayout.nu64('token_b_price'));
|
||||
fields.push(BufferLayout.blob(24, 'padding'));
|
||||
} else {
|
||||
fields.push(BufferLayout.blob(32, 'padding'));
|
||||
}
|
||||
|
||||
const commandDataLayout = BufferLayout.struct(fields);
|
||||
|
||||
const { fees, ...rest } = config;
|
||||
|
||||
const encodeLength = commandDataLayout.encode(
|
||||
{
|
||||
instruction: 0, // InitializeSwap instruction
|
||||
nonce,
|
||||
...fees,
|
||||
...rest,
|
||||
},
|
||||
data
|
||||
);
|
||||
data = data.slice(0, encodeLength);
|
||||
} else {
|
||||
const commandDataLayout = BufferLayout.struct([
|
||||
BufferLayout.u8('instruction'),
|
||||
BufferLayout.u8('nonce'),
|
||||
BufferLayout.u8('curveType'),
|
||||
BufferLayout.nu64('tradeFeeNumerator'),
|
||||
BufferLayout.nu64('tradeFeeDenominator'),
|
||||
BufferLayout.nu64('ownerTradeFeeNumerator'),
|
||||
BufferLayout.nu64('ownerTradeFeeDenominator'),
|
||||
BufferLayout.nu64('ownerWithdrawFeeNumerator'),
|
||||
BufferLayout.nu64('ownerWithdrawFeeDenominator'),
|
||||
BufferLayout.blob(16, 'padding'),
|
||||
]);
|
||||
|
||||
const encodeLength = commandDataLayout.encode(
|
||||
{
|
||||
instruction: 0, // InitializeSwap instruction
|
||||
nonce,
|
||||
curveType: config.curveType,
|
||||
tradeFeeNumerator: config.fees.tradeFeeNumerator,
|
||||
tradeFeeDenominator: config.fees.tradeFeeDenominator,
|
||||
ownerTradeFeeNumerator: config.fees.ownerTradeFeeNumerator,
|
||||
ownerTradeFeeDenominator: config.fees.ownerTradeFeeDenominator,
|
||||
ownerWithdrawFeeNumerator: config.fees.ownerWithdrawFeeNumerator,
|
||||
ownerWithdrawFeeDenominator: config.fees.ownerWithdrawFeeDenominator,
|
||||
},
|
||||
data
|
||||
);
|
||||
data = data.slice(0, encodeLength);
|
||||
}
|
||||
}
|
||||
|
||||
return new TransactionInstruction({
|
||||
keys,
|
||||
programId: swapProgramId,
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
export const depositPoolInstruction = (
|
||||
tokenSwap: PublicKey,
|
||||
authority: PublicKey,
|
||||
sourceA: PublicKey,
|
||||
sourceB: PublicKey,
|
||||
intoA: PublicKey,
|
||||
intoB: PublicKey,
|
||||
poolToken: PublicKey,
|
||||
poolAccount: PublicKey,
|
||||
swapProgramId: PublicKey,
|
||||
tokenProgramId: PublicKey,
|
||||
poolTokenAmount: number | Numberu64,
|
||||
maximumTokenA: number | Numberu64,
|
||||
maximumTokenB: number | Numberu64
|
||||
): TransactionInstruction => {
|
||||
const dataLayout = BufferLayout.struct([
|
||||
BufferLayout.u8('instruction'),
|
||||
uint64('poolTokenAmount'),
|
||||
uint64('maximumTokenA'),
|
||||
uint64('maximumTokenB'),
|
||||
]);
|
||||
|
||||
const data = Buffer.alloc(dataLayout.span);
|
||||
dataLayout.encode(
|
||||
{
|
||||
instruction: 2, // Deposit instruction
|
||||
poolTokenAmount: new Numberu64(poolTokenAmount).toBuffer(),
|
||||
maximumTokenA: new Numberu64(maximumTokenA).toBuffer(),
|
||||
maximumTokenB: new Numberu64(maximumTokenB).toBuffer(),
|
||||
},
|
||||
data
|
||||
);
|
||||
|
||||
const keys = [
|
||||
{ pubkey: tokenSwap, isSigner: false, isWritable: false },
|
||||
{ pubkey: authority, isSigner: false, isWritable: false },
|
||||
{ pubkey: sourceA, isSigner: false, isWritable: true },
|
||||
{ pubkey: sourceB, isSigner: false, isWritable: true },
|
||||
{ pubkey: intoA, isSigner: false, isWritable: true },
|
||||
{ pubkey: intoB, isSigner: false, isWritable: true },
|
||||
{ pubkey: poolToken, isSigner: false, isWritable: true },
|
||||
{ pubkey: poolAccount, isSigner: false, isWritable: true },
|
||||
{ pubkey: tokenProgramId, isSigner: false, isWritable: false },
|
||||
];
|
||||
return new TransactionInstruction({
|
||||
keys,
|
||||
programId: swapProgramId,
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
export const depositExactOneInstruction = (
|
||||
tokenSwap: PublicKey,
|
||||
authority: PublicKey,
|
||||
source: PublicKey,
|
||||
intoA: PublicKey,
|
||||
intoB: PublicKey,
|
||||
poolToken: PublicKey,
|
||||
poolAccount: PublicKey,
|
||||
swapProgramId: PublicKey,
|
||||
tokenProgramId: PublicKey,
|
||||
sourceTokenAmount: number | Numberu64,
|
||||
minimumPoolTokenAmount: number | Numberu64
|
||||
): TransactionInstruction => {
|
||||
const dataLayout = BufferLayout.struct([
|
||||
BufferLayout.u8('instruction'),
|
||||
uint64('sourceTokenAmount'),
|
||||
uint64('minimumPoolTokenAmount'),
|
||||
]);
|
||||
|
||||
const data = Buffer.alloc(dataLayout.span);
|
||||
dataLayout.encode(
|
||||
{
|
||||
instruction: 4, // DepositExactOne instruction
|
||||
sourceTokenAmount: new Numberu64(sourceTokenAmount).toBuffer(),
|
||||
minimumPoolTokenAmount: new Numberu64(minimumPoolTokenAmount).toBuffer(),
|
||||
},
|
||||
data
|
||||
);
|
||||
|
||||
const keys = [
|
||||
{ pubkey: tokenSwap, isSigner: false, isWritable: false },
|
||||
{ pubkey: authority, isSigner: false, isWritable: false },
|
||||
{ pubkey: source, isSigner: false, isWritable: true },
|
||||
{ pubkey: intoA, isSigner: false, isWritable: true },
|
||||
{ pubkey: intoB, isSigner: false, isWritable: true },
|
||||
{ pubkey: poolToken, isSigner: false, isWritable: true },
|
||||
{ pubkey: poolAccount, isSigner: false, isWritable: true },
|
||||
{ pubkey: tokenProgramId, isSigner: false, isWritable: false },
|
||||
];
|
||||
return new TransactionInstruction({
|
||||
keys,
|
||||
programId: swapProgramId,
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
export const withdrawPoolInstruction = (
|
||||
tokenSwap: PublicKey,
|
||||
authority: PublicKey,
|
||||
poolMint: PublicKey,
|
||||
feeAccount: PublicKey | undefined,
|
||||
sourcePoolAccount: PublicKey,
|
||||
fromA: PublicKey,
|
||||
fromB: PublicKey,
|
||||
userAccountA: PublicKey,
|
||||
userAccountB: PublicKey,
|
||||
swapProgramId: PublicKey,
|
||||
tokenProgramId: PublicKey,
|
||||
poolTokenAmount: number | Numberu64,
|
||||
minimumTokenA: number | Numberu64,
|
||||
minimumTokenB: number | Numberu64
|
||||
): TransactionInstruction => {
|
||||
const dataLayout = BufferLayout.struct([
|
||||
BufferLayout.u8('instruction'),
|
||||
uint64('poolTokenAmount'),
|
||||
uint64('minimumTokenA'),
|
||||
uint64('minimumTokenB'),
|
||||
]);
|
||||
|
||||
const data = Buffer.alloc(dataLayout.span);
|
||||
dataLayout.encode(
|
||||
{
|
||||
instruction: 3, // Withdraw instruction
|
||||
poolTokenAmount: new Numberu64(poolTokenAmount).toBuffer(),
|
||||
minimumTokenA: new Numberu64(minimumTokenA).toBuffer(),
|
||||
minimumTokenB: new Numberu64(minimumTokenB).toBuffer(),
|
||||
},
|
||||
data
|
||||
);
|
||||
|
||||
const keys = [
|
||||
{ pubkey: tokenSwap, isSigner: false, isWritable: false },
|
||||
{ pubkey: authority, isSigner: false, isWritable: false },
|
||||
{ pubkey: poolMint, isSigner: false, isWritable: true },
|
||||
{ pubkey: sourcePoolAccount, isSigner: false, isWritable: true },
|
||||
{ pubkey: fromA, isSigner: false, isWritable: true },
|
||||
{ pubkey: fromB, isSigner: false, isWritable: true },
|
||||
{ pubkey: userAccountA, isSigner: false, isWritable: true },
|
||||
{ pubkey: userAccountB, isSigner: false, isWritable: true },
|
||||
];
|
||||
|
||||
if (feeAccount) {
|
||||
keys.push({ pubkey: feeAccount, isSigner: false, isWritable: true });
|
||||
}
|
||||
keys.push({ pubkey: tokenProgramId, isSigner: false, isWritable: false });
|
||||
|
||||
return new TransactionInstruction({
|
||||
keys,
|
||||
programId: swapProgramId,
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
export const withdrawExactOneInstruction = (
|
||||
tokenSwap: PublicKey,
|
||||
authority: PublicKey,
|
||||
poolMint: PublicKey,
|
||||
sourcePoolAccount: PublicKey,
|
||||
fromA: PublicKey,
|
||||
fromB: PublicKey,
|
||||
userAccount: PublicKey,
|
||||
feeAccount: PublicKey | undefined,
|
||||
swapProgramId: PublicKey,
|
||||
tokenProgramId: PublicKey,
|
||||
sourceTokenAmount: number | Numberu64,
|
||||
maximumTokenAmount: number | Numberu64
|
||||
): TransactionInstruction => {
|
||||
const dataLayout = BufferLayout.struct([
|
||||
BufferLayout.u8('instruction'),
|
||||
uint64('sourceTokenAmount'),
|
||||
uint64('maximumTokenAmount'),
|
||||
]);
|
||||
|
||||
const data = Buffer.alloc(dataLayout.span);
|
||||
dataLayout.encode(
|
||||
{
|
||||
instruction: 5, // WithdrawExactOne instruction
|
||||
sourceTokenAmount: new Numberu64(sourceTokenAmount).toBuffer(),
|
||||
maximumTokenAmount: new Numberu64(maximumTokenAmount).toBuffer(),
|
||||
},
|
||||
data
|
||||
);
|
||||
|
||||
const keys = [
|
||||
{ pubkey: tokenSwap, isSigner: false, isWritable: false },
|
||||
{ pubkey: authority, isSigner: false, isWritable: false },
|
||||
{ pubkey: poolMint, isSigner: false, isWritable: true },
|
||||
{ pubkey: sourcePoolAccount, isSigner: false, isWritable: true },
|
||||
{ pubkey: fromA, isSigner: false, isWritable: true },
|
||||
{ pubkey: fromB, isSigner: false, isWritable: true },
|
||||
{ pubkey: userAccount, isSigner: false, isWritable: true },
|
||||
];
|
||||
|
||||
if (feeAccount) {
|
||||
keys.push({ pubkey: feeAccount, isSigner: false, isWritable: true });
|
||||
}
|
||||
keys.push({ pubkey: tokenProgramId, isSigner: false, isWritable: false });
|
||||
|
||||
return new TransactionInstruction({
|
||||
keys,
|
||||
programId: swapProgramId,
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
export const swapInstruction = (
|
||||
tokenSwap: PublicKey,
|
||||
authority: PublicKey,
|
||||
userSource: PublicKey,
|
||||
poolSource: PublicKey,
|
||||
poolDestination: PublicKey,
|
||||
userDestination: PublicKey,
|
||||
poolMint: PublicKey,
|
||||
feeAccount: PublicKey,
|
||||
swapProgramId: PublicKey,
|
||||
tokenProgramId: PublicKey,
|
||||
amountIn: number | Numberu64,
|
||||
minimumAmountOut: number | Numberu64,
|
||||
programOwner?: PublicKey
|
||||
): TransactionInstruction => {
|
||||
const dataLayout = BufferLayout.struct([
|
||||
BufferLayout.u8('instruction'),
|
||||
uint64('amountIn'),
|
||||
uint64('minimumAmountOut'),
|
||||
]);
|
||||
|
||||
const keys = [
|
||||
{ pubkey: tokenSwap, isSigner: false, isWritable: false },
|
||||
{ pubkey: authority, isSigner: false, isWritable: false },
|
||||
{ pubkey: userSource, isSigner: false, isWritable: true },
|
||||
{ pubkey: poolSource, isSigner: false, isWritable: true },
|
||||
{ pubkey: poolDestination, isSigner: false, isWritable: true },
|
||||
{ pubkey: userDestination, isSigner: false, isWritable: true },
|
||||
{ pubkey: poolMint, isSigner: false, isWritable: true },
|
||||
{ pubkey: feeAccount, isSigner: false, isWritable: true },
|
||||
{ pubkey: tokenProgramId, isSigner: false, isWritable: false },
|
||||
];
|
||||
|
||||
// optional depending on the build of token-swap program
|
||||
if (programOwner) {
|
||||
keys.push({ pubkey: programOwner, isSigner: false, isWritable: true });
|
||||
}
|
||||
|
||||
const data = Buffer.alloc(dataLayout.span);
|
||||
dataLayout.encode(
|
||||
{
|
||||
instruction: 1, // Swap instruction
|
||||
amountIn: new Numberu64(amountIn).toBuffer(),
|
||||
minimumAmountOut: new Numberu64(minimumAmountOut).toBuffer(),
|
||||
},
|
||||
data
|
||||
);
|
||||
|
||||
return new TransactionInstruction({
|
||||
keys,
|
||||
programId: swapProgramId,
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,350 +1,19 @@
|
|||
import { Account, Connection, PublicKey, SystemProgram, TransactionInstruction } from '@solana/web3.js';
|
||||
import { Connection, PublicKey } from '@solana/web3.js';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { Token, MintLayout, AccountLayout } from '@solana/spl-token';
|
||||
import { notify } from './notifications';
|
||||
import { programIds, SWAP_HOST_FEE_ADDRESS, SWAP_PROGRAM_OWNER_FEE_ADDRESS, WRAPPED_SOL_MINT } from './ids';
|
||||
import { MintLayout, AccountLayout } from '@solana/spl-token';
|
||||
import { programIds } from './ids';
|
||||
import {
|
||||
LiquidityComponent,
|
||||
PoolInfo,
|
||||
TokenAccount,
|
||||
createInitSwapInstruction,
|
||||
TokenSwapLayout,
|
||||
depositPoolInstruction,
|
||||
TokenSwapLayoutLegacyV0 as TokenSwapLayoutV0,
|
||||
TokenSwapLayoutV1,
|
||||
swapInstruction,
|
||||
PoolConfig,
|
||||
depositExactOneInstruction,
|
||||
withdrawExactOneInstruction,
|
||||
withdrawPoolInstruction,
|
||||
} from './../models';
|
||||
import { sendTransaction, useConnection } from '../contexts/connection';
|
||||
import { cache, getCachedAccount, getMultipleAccounts, TokenAccountParser, useCachedPool } from '../contexts/accounts';
|
||||
import { useUserAccounts } from '../hooks/useUserAccounts';
|
||||
|
||||
const LIQUIDITY_TOKEN_PRECISION = 8;
|
||||
import { useConnection } from '../contexts/connection';
|
||||
import { cache, getMultipleAccounts, TokenAccountParser } from '../contexts/accounts';
|
||||
|
||||
export const LIQUIDITY_PROVIDER_FEE = 0.003;
|
||||
export const SERUM_FEE = 0.0005;
|
||||
|
||||
export const removeLiquidity = async (
|
||||
connection: Connection,
|
||||
wallet: any,
|
||||
liquidityAmount: number,
|
||||
account: TokenAccount,
|
||||
pool?: PoolInfo
|
||||
) => {
|
||||
if (!pool) {
|
||||
throw new Error('Pool is required');
|
||||
}
|
||||
|
||||
notify({
|
||||
message: 'Removing Liquidity...',
|
||||
description: 'Please review transactions to approve.',
|
||||
type: 'warn',
|
||||
});
|
||||
|
||||
// TODO get min amounts based on total supply and liquidity
|
||||
const minAmount0 = 0;
|
||||
const minAmount1 = 0;
|
||||
|
||||
const poolMint = await cache.queryMint(connection, pool.pubkeys.mint);
|
||||
const accountA = await cache.query(connection, pool.pubkeys.holdingAccounts[0]);
|
||||
const accountB = await cache.query(connection, pool.pubkeys.holdingAccounts[1]);
|
||||
if (!poolMint.mintAuthority) {
|
||||
throw new Error('Mint doesnt have authority');
|
||||
}
|
||||
const authority = poolMint.mintAuthority;
|
||||
|
||||
const signers: Account[] = [];
|
||||
const instructions: TransactionInstruction[] = [];
|
||||
const cleanupInstructions: TransactionInstruction[] = [];
|
||||
|
||||
const accountRentExempt = await connection.getMinimumBalanceForRentExemption(AccountLayout.span);
|
||||
|
||||
const toAccounts: PublicKey[] = [
|
||||
await findOrCreateAccountByMint(
|
||||
wallet.publicKey,
|
||||
wallet.publicKey,
|
||||
instructions,
|
||||
cleanupInstructions,
|
||||
accountRentExempt,
|
||||
accountA.info.mint,
|
||||
signers
|
||||
),
|
||||
await findOrCreateAccountByMint(
|
||||
wallet.publicKey,
|
||||
wallet.publicKey,
|
||||
instructions,
|
||||
cleanupInstructions,
|
||||
accountRentExempt,
|
||||
accountB.info.mint,
|
||||
signers
|
||||
),
|
||||
];
|
||||
|
||||
instructions.push(
|
||||
Token.createApproveInstruction(programIds().token, account.pubkey, authority, wallet.publicKey, [], liquidityAmount)
|
||||
);
|
||||
|
||||
// withdraw
|
||||
instructions.push(
|
||||
withdrawPoolInstruction(
|
||||
pool.pubkeys.account,
|
||||
authority,
|
||||
pool.pubkeys.mint,
|
||||
pool.pubkeys.feeAccount,
|
||||
account.pubkey,
|
||||
pool.pubkeys.holdingAccounts[0],
|
||||
pool.pubkeys.holdingAccounts[1],
|
||||
toAccounts[0],
|
||||
toAccounts[1],
|
||||
pool.pubkeys.program,
|
||||
programIds().token,
|
||||
liquidityAmount,
|
||||
minAmount0,
|
||||
minAmount1
|
||||
)
|
||||
);
|
||||
|
||||
const deleteAccount = liquidityAmount === account.info.amount.toNumber();
|
||||
if (deleteAccount) {
|
||||
instructions.push(
|
||||
Token.createCloseAccountInstruction(programIds().token, account.pubkey, authority, wallet.publicKey, [])
|
||||
);
|
||||
}
|
||||
|
||||
let tx = await sendTransaction(connection, wallet, instructions.concat(cleanupInstructions), signers);
|
||||
|
||||
if (deleteAccount) {
|
||||
cache.delete(account.pubkey);
|
||||
}
|
||||
|
||||
notify({
|
||||
message: 'Liquidity Returned. Thank you for your support.',
|
||||
type: 'success',
|
||||
description: `Transaction - ${tx}`,
|
||||
});
|
||||
|
||||
return [
|
||||
accountA.info.mint.equals(WRAPPED_SOL_MINT) ? (wallet.publicKey as PublicKey) : toAccounts[0],
|
||||
accountB.info.mint.equals(WRAPPED_SOL_MINT) ? (wallet.publicKey as PublicKey) : toAccounts[1],
|
||||
];
|
||||
};
|
||||
|
||||
export const removeExactOneLiquidity = async (
|
||||
connection: Connection,
|
||||
wallet: any,
|
||||
account: TokenAccount,
|
||||
liquidityAmount: number,
|
||||
tokenAmount: number,
|
||||
tokenMint: string,
|
||||
pool?: PoolInfo
|
||||
) => {
|
||||
if (!pool) {
|
||||
throw new Error('Pool is required');
|
||||
}
|
||||
|
||||
notify({
|
||||
message: 'Removing Liquidity...',
|
||||
description: 'Please review transactions to approve.',
|
||||
type: 'warn',
|
||||
});
|
||||
// Maximum number of LP tokens
|
||||
// needs to be different math because the new instruction
|
||||
const liquidityMaxAmount = liquidityAmount * (1 + SLIPPAGE);
|
||||
|
||||
const poolMint = await cache.queryMint(connection, pool.pubkeys.mint);
|
||||
const accountA = await cache.query(connection, pool.pubkeys.holdingAccounts[0]);
|
||||
const accountB = await cache.query(connection, pool.pubkeys.holdingAccounts[1]);
|
||||
if (!poolMint.mintAuthority) {
|
||||
throw new Error('Mint doesnt have authority');
|
||||
}
|
||||
|
||||
const tokenMatchAccount = tokenMint === pool.pubkeys.holdingMints[0].toBase58() ? accountA : accountB;
|
||||
const authority = poolMint.mintAuthority;
|
||||
|
||||
const signers: Account[] = [];
|
||||
const instructions: TransactionInstruction[] = [];
|
||||
const cleanupInstructions: TransactionInstruction[] = [];
|
||||
|
||||
const accountRentExempt = await connection.getMinimumBalanceForRentExemption(AccountLayout.span);
|
||||
|
||||
const toAccount: PublicKey = await findOrCreateAccountByMint(
|
||||
wallet.publicKey,
|
||||
wallet.publicKey,
|
||||
instructions,
|
||||
cleanupInstructions,
|
||||
accountRentExempt,
|
||||
tokenMatchAccount.info.mint,
|
||||
signers
|
||||
);
|
||||
|
||||
instructions.push(
|
||||
Token.createApproveInstruction(
|
||||
programIds().token,
|
||||
account.pubkey,
|
||||
authority,
|
||||
wallet.publicKey,
|
||||
[],
|
||||
account.info.amount.toNumber() // liquidityAmount <- need math tuning
|
||||
)
|
||||
);
|
||||
|
||||
// withdraw exact one
|
||||
instructions.push(
|
||||
withdrawExactOneInstruction(
|
||||
pool.pubkeys.account,
|
||||
authority,
|
||||
pool.pubkeys.mint,
|
||||
account.pubkey,
|
||||
pool.pubkeys.holdingAccounts[0],
|
||||
pool.pubkeys.holdingAccounts[1],
|
||||
toAccount,
|
||||
pool.pubkeys.feeAccount,
|
||||
pool.pubkeys.program,
|
||||
programIds().token,
|
||||
tokenAmount,
|
||||
liquidityMaxAmount
|
||||
)
|
||||
);
|
||||
|
||||
let tx = await sendTransaction(connection, wallet, instructions.concat(cleanupInstructions), signers);
|
||||
|
||||
notify({
|
||||
message: 'Liquidity Returned. Thank you for your support.',
|
||||
type: 'success',
|
||||
description: `Transaction - ${tx}`,
|
||||
});
|
||||
|
||||
return tokenMatchAccount.info.mint.equals(WRAPPED_SOL_MINT) ? (wallet.publicKey as PublicKey) : toAccount;
|
||||
};
|
||||
|
||||
export const swap = async (
|
||||
connection: Connection,
|
||||
wallet: any,
|
||||
components: LiquidityComponent[],
|
||||
SLIPPAGE: number,
|
||||
pool?: PoolInfo
|
||||
) => {
|
||||
if (!pool || !components[0].account) {
|
||||
notify({
|
||||
type: 'error',
|
||||
message: `Pool doesn't exsist.`,
|
||||
description: `Swap trade cancelled`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Uniswap whitepaper: https://uniswap.org/whitepaper.pdf
|
||||
// see: https://uniswap.org/docs/v2/advanced-topics/pricing/
|
||||
// as well as native uniswap v2 oracle: https://uniswap.org/docs/v2/core-concepts/oracles/
|
||||
const amountIn = components[0].amount; // these two should include slippage
|
||||
const minAmountOut = components[1].amount * (1 - SLIPPAGE);
|
||||
const holdingA =
|
||||
pool.pubkeys.holdingMints[0]?.toBase58() === components[0].account.info.mint.toBase58()
|
||||
? pool.pubkeys.holdingAccounts[0]
|
||||
: pool.pubkeys.holdingAccounts[1];
|
||||
const holdingB =
|
||||
holdingA === pool.pubkeys.holdingAccounts[0] ? pool.pubkeys.holdingAccounts[1] : pool.pubkeys.holdingAccounts[0];
|
||||
|
||||
const poolMint = await cache.queryMint(connection, pool.pubkeys.mint);
|
||||
if (!poolMint.mintAuthority || !pool.pubkeys.feeAccount) {
|
||||
throw new Error('Mint doesnt have authority');
|
||||
}
|
||||
const authority = poolMint.mintAuthority;
|
||||
|
||||
const instructions: TransactionInstruction[] = [];
|
||||
const cleanupInstructions: TransactionInstruction[] = [];
|
||||
const signers: Account[] = [];
|
||||
|
||||
const accountRentExempt = await connection.getMinimumBalanceForRentExemption(AccountLayout.span);
|
||||
|
||||
const fromAccount = getWrappedAccount(
|
||||
instructions,
|
||||
cleanupInstructions,
|
||||
components[0].account,
|
||||
wallet.publicKey,
|
||||
amountIn + accountRentExempt,
|
||||
signers
|
||||
);
|
||||
|
||||
let toAccount = findOrCreateAccountByMint(
|
||||
wallet.publicKey,
|
||||
wallet.publicKey,
|
||||
instructions,
|
||||
cleanupInstructions,
|
||||
accountRentExempt,
|
||||
new PublicKey(components[1].mintAddress),
|
||||
signers
|
||||
);
|
||||
|
||||
// create approval for transfer transactions
|
||||
instructions.push(
|
||||
Token.createApproveInstruction(programIds().token, fromAccount, authority, wallet.publicKey, [], amountIn)
|
||||
);
|
||||
|
||||
let hostFeeAccount = SWAP_HOST_FEE_ADDRESS
|
||||
? findOrCreateAccountByMint(
|
||||
wallet.publicKey,
|
||||
SWAP_HOST_FEE_ADDRESS,
|
||||
instructions,
|
||||
cleanupInstructions,
|
||||
accountRentExempt,
|
||||
pool.pubkeys.mint,
|
||||
signers
|
||||
)
|
||||
: undefined;
|
||||
|
||||
// swap
|
||||
instructions.push(
|
||||
swapInstruction(
|
||||
pool.pubkeys.account,
|
||||
authority,
|
||||
fromAccount,
|
||||
holdingA,
|
||||
holdingB,
|
||||
toAccount,
|
||||
pool.pubkeys.mint,
|
||||
pool.pubkeys.feeAccount,
|
||||
pool.pubkeys.program,
|
||||
programIds().token,
|
||||
amountIn,
|
||||
minAmountOut,
|
||||
hostFeeAccount
|
||||
)
|
||||
);
|
||||
|
||||
let tx = await sendTransaction(connection, wallet, instructions.concat(cleanupInstructions), signers);
|
||||
|
||||
notify({
|
||||
message: 'Trade executed.',
|
||||
type: 'success',
|
||||
description: `Transaction - ${tx}`,
|
||||
});
|
||||
};
|
||||
|
||||
export const addLiquidity = async (
|
||||
connection: Connection,
|
||||
wallet: any,
|
||||
components: LiquidityComponent[],
|
||||
slippage: number,
|
||||
pool?: PoolInfo,
|
||||
options?: PoolConfig,
|
||||
depositType: string = 'both'
|
||||
) => {
|
||||
if (depositType === 'one' && pool) {
|
||||
await _addLiquidityExactOneExistingPool(pool, components[0], connection, wallet);
|
||||
} else if (!pool) {
|
||||
if (!options) {
|
||||
throw new Error('Options are required to create new pool.');
|
||||
}
|
||||
|
||||
await _addLiquidityNewPool(wallet, connection, components, options);
|
||||
} else {
|
||||
await _addLiquidityExistingPool(pool, components, connection, wallet);
|
||||
}
|
||||
};
|
||||
|
||||
const getHoldings = (connection: Connection, accounts: string[]) => {
|
||||
return accounts.map((acc) => cache.query(connection, new PublicKey(acc)));
|
||||
|
@ -510,7 +179,7 @@ export const usePools = () => {
|
|||
|
||||
export const usePoolForBasket = (mints: (string | undefined)[]) => {
|
||||
const connection = useConnection();
|
||||
const { pools } = useCachedPool();
|
||||
const { pools } = usePools();
|
||||
const [pool, setPool] = useState<PoolInfo>();
|
||||
const sortedMints = useMemo(() => [...mints].sort(), [...mints]); // eslint-disable-line
|
||||
useEffect(() => {
|
||||
|
@ -542,299 +211,6 @@ export const usePoolForBasket = (mints: (string | undefined)[]) => {
|
|||
return pool;
|
||||
};
|
||||
|
||||
export const useOwnedPools = (legacy = false) => {
|
||||
const { pools } = useCachedPool(legacy);
|
||||
const { userAccounts } = useUserAccounts();
|
||||
|
||||
const ownedPools = useMemo(() => {
|
||||
const map = userAccounts.reduce((acc, item) => {
|
||||
const key = item.info.mint.toBase58();
|
||||
acc.set(key, [...(acc.get(key) || []), item]);
|
||||
return acc;
|
||||
}, new Map<string, TokenAccount[]>());
|
||||
|
||||
return pools
|
||||
.filter((p) => map.has(p.pubkeys.mint.toBase58()) && p.legacy === legacy)
|
||||
.map((item) => {
|
||||
let feeAccount = item.pubkeys.feeAccount?.toBase58();
|
||||
return map.get(item.pubkeys.mint.toBase58())?.map((a) => {
|
||||
return {
|
||||
account: a as TokenAccount,
|
||||
isFeeAccount: feeAccount === a.pubkey.toBase58(),
|
||||
pool: item,
|
||||
};
|
||||
}) as {
|
||||
account: TokenAccount;
|
||||
isFeeAccount: boolean;
|
||||
pool: PoolInfo;
|
||||
}[];
|
||||
})
|
||||
.flat();
|
||||
}, [pools, userAccounts, legacy]);
|
||||
|
||||
return ownedPools;
|
||||
};
|
||||
|
||||
// Allow for this much price movement in the pool before adding liquidity to the pool aborts
|
||||
const SLIPPAGE = 0.005;
|
||||
|
||||
async function _addLiquidityExistingPool(
|
||||
pool: PoolInfo,
|
||||
components: LiquidityComponent[],
|
||||
connection: Connection,
|
||||
wallet: any
|
||||
) {
|
||||
notify({
|
||||
message: 'Adding Liquidity...',
|
||||
description: 'Please review transactions to approve.',
|
||||
type: 'warn',
|
||||
});
|
||||
|
||||
const poolMint = await cache.queryMint(connection, pool.pubkeys.mint);
|
||||
if (!poolMint.mintAuthority) {
|
||||
throw new Error('Mint doesnt have authority');
|
||||
}
|
||||
|
||||
if (!pool.pubkeys.feeAccount) {
|
||||
throw new Error('Invald fee account');
|
||||
}
|
||||
|
||||
const accountA = await cache.query(connection, pool.pubkeys.holdingAccounts[0]);
|
||||
const accountB = await cache.query(connection, pool.pubkeys.holdingAccounts[1]);
|
||||
|
||||
const reserve0 = accountA.info.amount.toNumber();
|
||||
const reserve1 = accountB.info.amount.toNumber();
|
||||
const fromA = accountA.info.mint.toBase58() === components[0].mintAddress ? components[0] : components[1];
|
||||
const fromB = fromA === components[0] ? components[1] : components[0];
|
||||
|
||||
if (!fromA.account || !fromB.account) {
|
||||
throw new Error('Missing account info.');
|
||||
}
|
||||
|
||||
const supply = poolMint.supply.toNumber();
|
||||
const authority = poolMint.mintAuthority;
|
||||
|
||||
// Uniswap whitepaper: https://uniswap.org/whitepaper.pdf
|
||||
// see: https://uniswap.org/docs/v2/advanced-topics/pricing/
|
||||
// as well as native uniswap v2 oracle: https://uniswap.org/docs/v2/core-concepts/oracles/
|
||||
const amount0 = fromA.amount;
|
||||
const amount1 = fromB.amount;
|
||||
|
||||
const liquidity = Math.min(
|
||||
(amount0 * (1 - SLIPPAGE) * supply) / reserve0,
|
||||
(amount1 * (1 - SLIPPAGE) * supply) / reserve1
|
||||
);
|
||||
const instructions: TransactionInstruction[] = [];
|
||||
const cleanupInstructions: TransactionInstruction[] = [];
|
||||
|
||||
const signers: Account[] = [];
|
||||
|
||||
const accountRentExempt = await connection.getMinimumBalanceForRentExemption(AccountLayout.span);
|
||||
const fromKeyA = getWrappedAccount(
|
||||
instructions,
|
||||
cleanupInstructions,
|
||||
fromA.account,
|
||||
wallet.publicKey,
|
||||
amount0 + accountRentExempt,
|
||||
signers
|
||||
);
|
||||
const fromKeyB = getWrappedAccount(
|
||||
instructions,
|
||||
cleanupInstructions,
|
||||
fromB.account,
|
||||
wallet.publicKey,
|
||||
amount1 + accountRentExempt,
|
||||
signers
|
||||
);
|
||||
|
||||
let toAccount = findOrCreateAccountByMint(
|
||||
wallet.publicKey,
|
||||
wallet.publicKey,
|
||||
instructions,
|
||||
[],
|
||||
accountRentExempt,
|
||||
pool.pubkeys.mint,
|
||||
signers,
|
||||
new Set<string>([pool.pubkeys.feeAccount.toBase58()])
|
||||
);
|
||||
|
||||
// create approval for transfer transactions
|
||||
instructions.push(
|
||||
Token.createApproveInstruction(programIds().token, fromKeyA, authority, wallet.publicKey, [], amount0)
|
||||
);
|
||||
|
||||
instructions.push(
|
||||
Token.createApproveInstruction(programIds().token, fromKeyB, authority, wallet.publicKey, [], amount1)
|
||||
);
|
||||
|
||||
// deposit
|
||||
instructions.push(
|
||||
depositPoolInstruction(
|
||||
pool.pubkeys.account,
|
||||
authority,
|
||||
fromKeyA,
|
||||
fromKeyB,
|
||||
pool.pubkeys.holdingAccounts[0],
|
||||
pool.pubkeys.holdingAccounts[1],
|
||||
pool.pubkeys.mint,
|
||||
toAccount,
|
||||
pool.pubkeys.program,
|
||||
programIds().token,
|
||||
liquidity,
|
||||
amount0,
|
||||
amount1
|
||||
)
|
||||
);
|
||||
|
||||
let tx = await sendTransaction(connection, wallet, instructions.concat(cleanupInstructions), signers);
|
||||
|
||||
notify({
|
||||
message: 'Pool Funded. Happy trading.',
|
||||
type: 'success',
|
||||
description: `Transaction - ${tx}`,
|
||||
});
|
||||
}
|
||||
|
||||
async function _addLiquidityExactOneExistingPool(
|
||||
pool: PoolInfo,
|
||||
component: LiquidityComponent,
|
||||
connection: Connection,
|
||||
wallet: any
|
||||
) {
|
||||
notify({
|
||||
message: 'Adding Liquidity...',
|
||||
description: 'Please review transactions to approve.',
|
||||
type: 'warn',
|
||||
});
|
||||
|
||||
const poolMint = await cache.queryMint(connection, pool.pubkeys.mint);
|
||||
if (!poolMint.mintAuthority) {
|
||||
throw new Error('Mint doesnt have authority');
|
||||
}
|
||||
|
||||
if (!pool.pubkeys.feeAccount) {
|
||||
throw new Error('Invald fee account');
|
||||
}
|
||||
|
||||
const accountA = await cache.query(connection, pool.pubkeys.holdingAccounts[0]);
|
||||
const accountB = await cache.query(connection, pool.pubkeys.holdingAccounts[1]);
|
||||
|
||||
const from = component;
|
||||
|
||||
if (!from.account) {
|
||||
throw new Error('Missing account info.');
|
||||
}
|
||||
const reserve =
|
||||
accountA.info.mint.toBase58() === from.mintAddress
|
||||
? accountA.info.amount.toNumber()
|
||||
: accountB.info.amount.toNumber();
|
||||
|
||||
const supply = poolMint.supply.toNumber();
|
||||
const authority = poolMint.mintAuthority;
|
||||
|
||||
// Uniswap whitepaper: https://uniswap.org/whitepaper.pdf
|
||||
// see: https://uniswap.org/docs/v2/advanced-topics/pricing/
|
||||
// as well as native uniswap v2 oracle: https://uniswap.org/docs/v2/core-concepts/oracles/
|
||||
const amount = from.amount;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const _liquidityTokenTempMath = (amount * (1 - SLIPPAGE) * supply) / reserve;
|
||||
const liquidityToken = 0;
|
||||
|
||||
const instructions: TransactionInstruction[] = [];
|
||||
const cleanupInstructions: TransactionInstruction[] = [];
|
||||
|
||||
const signers: Account[] = [];
|
||||
|
||||
const accountRentExempt = await connection.getMinimumBalanceForRentExemption(AccountLayout.span);
|
||||
const fromKey = getWrappedAccount(
|
||||
instructions,
|
||||
cleanupInstructions,
|
||||
from.account,
|
||||
wallet.publicKey,
|
||||
amount + accountRentExempt,
|
||||
signers
|
||||
);
|
||||
|
||||
let toAccount = findOrCreateAccountByMint(
|
||||
wallet.publicKey,
|
||||
wallet.publicKey,
|
||||
instructions,
|
||||
[],
|
||||
accountRentExempt,
|
||||
pool.pubkeys.mint,
|
||||
signers,
|
||||
new Set<string>([pool.pubkeys.feeAccount.toBase58()])
|
||||
);
|
||||
|
||||
// create approval for transfer transactions
|
||||
instructions.push(
|
||||
Token.createApproveInstruction(programIds().token, fromKey, authority, wallet.publicKey, [], amount)
|
||||
);
|
||||
|
||||
// deposit
|
||||
instructions.push(
|
||||
depositExactOneInstruction(
|
||||
pool.pubkeys.account,
|
||||
authority,
|
||||
fromKey,
|
||||
pool.pubkeys.holdingAccounts[0],
|
||||
pool.pubkeys.holdingAccounts[1],
|
||||
pool.pubkeys.mint,
|
||||
toAccount,
|
||||
pool.pubkeys.program,
|
||||
programIds().token,
|
||||
amount,
|
||||
liquidityToken
|
||||
)
|
||||
);
|
||||
|
||||
let tx = await sendTransaction(connection, wallet, instructions.concat(cleanupInstructions), signers);
|
||||
|
||||
notify({
|
||||
message: 'Pool Funded. Happy trading.',
|
||||
type: 'success',
|
||||
description: `Transaction - ${tx}`,
|
||||
});
|
||||
}
|
||||
|
||||
function findOrCreateAccountByMint(
|
||||
payer: PublicKey,
|
||||
owner: PublicKey,
|
||||
instructions: TransactionInstruction[],
|
||||
cleanupInstructions: TransactionInstruction[],
|
||||
accountRentExempt: number,
|
||||
mint: PublicKey, // use to identify same type
|
||||
signers: Account[],
|
||||
excluded?: Set<string>
|
||||
): PublicKey {
|
||||
const accountToFind = mint.toBase58();
|
||||
const account = getCachedAccount(
|
||||
(acc) =>
|
||||
acc.info.mint.toBase58() === accountToFind &&
|
||||
acc.info.owner.toBase58() === owner.toBase58() &&
|
||||
(excluded === undefined || !excluded.has(acc.pubkey.toBase58()))
|
||||
);
|
||||
const isWrappedSol = accountToFind === WRAPPED_SOL_MINT.toBase58();
|
||||
|
||||
let toAccount: PublicKey;
|
||||
if (account && !isWrappedSol) {
|
||||
toAccount = account.pubkey;
|
||||
} else {
|
||||
// creating depositor pool account
|
||||
const newToAccount = createSplAccount(instructions, payer, accountRentExempt, mint, owner, AccountLayout.span);
|
||||
|
||||
toAccount = newToAccount.publicKey;
|
||||
signers.push(newToAccount);
|
||||
|
||||
if (isWrappedSol) {
|
||||
cleanupInstructions.push(Token.createCloseAccountInstruction(programIds().token, toAccount, payer, payer, []));
|
||||
}
|
||||
}
|
||||
|
||||
return toAccount;
|
||||
}
|
||||
|
||||
function estimateProceedsFromInput(
|
||||
inputQuantityInPool: number,
|
||||
proceedsQuantityInPool: number,
|
||||
|
@ -934,248 +310,3 @@ export async function calculateDependentAmount(
|
|||
}
|
||||
return depAdjustedAmount / depPrecision;
|
||||
}
|
||||
|
||||
// TODO: add ui to customize curve type
|
||||
async function _addLiquidityNewPool(
|
||||
wallet: any,
|
||||
connection: Connection,
|
||||
components: LiquidityComponent[],
|
||||
options: PoolConfig
|
||||
) {
|
||||
notify({
|
||||
message: 'Creating new pool...',
|
||||
description: 'Please review transactions to approve.',
|
||||
type: 'warn',
|
||||
});
|
||||
|
||||
if (components.some((c) => !c.account)) {
|
||||
notify({
|
||||
message: 'You need to have balance for all legs in the basket...',
|
||||
description: 'Please review inputs.',
|
||||
type: 'error',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let instructions: TransactionInstruction[] = [];
|
||||
let cleanupInstructions: TransactionInstruction[] = [];
|
||||
|
||||
const liquidityTokenMint = new Account();
|
||||
// Create account for pool liquidity token
|
||||
instructions.push(
|
||||
SystemProgram.createAccount({
|
||||
fromPubkey: wallet.publicKey,
|
||||
newAccountPubkey: liquidityTokenMint.publicKey,
|
||||
lamports: await connection.getMinimumBalanceForRentExemption(MintLayout.span),
|
||||
space: MintLayout.span,
|
||||
programId: programIds().token,
|
||||
})
|
||||
);
|
||||
|
||||
const tokenSwapAccount = new Account();
|
||||
|
||||
const [authority, nonce] = await PublicKey.findProgramAddress(
|
||||
[tokenSwapAccount.publicKey.toBuffer()],
|
||||
programIds().swap
|
||||
);
|
||||
|
||||
// create mint for pool liquidity token
|
||||
instructions.push(
|
||||
Token.createInitMintInstruction(
|
||||
programIds().token,
|
||||
liquidityTokenMint.publicKey,
|
||||
LIQUIDITY_TOKEN_PRECISION,
|
||||
// pass control of liquidity mint to swap program
|
||||
authority,
|
||||
// swap program can freeze liquidity token mint
|
||||
null
|
||||
)
|
||||
);
|
||||
|
||||
// Create holding accounts for
|
||||
const accountRentExempt = await connection.getMinimumBalanceForRentExemption(AccountLayout.span);
|
||||
const holdingAccounts: Account[] = [];
|
||||
let signers: Account[] = [];
|
||||
|
||||
components.forEach((leg) => {
|
||||
if (!leg.account) {
|
||||
return;
|
||||
}
|
||||
|
||||
const mintPublicKey = leg.account.info.mint;
|
||||
// component account to store tokens I of N in liquidity poll
|
||||
holdingAccounts.push(
|
||||
createSplAccount(instructions, wallet.publicKey, accountRentExempt, mintPublicKey, authority, AccountLayout.span)
|
||||
);
|
||||
});
|
||||
|
||||
// creating depositor pool account
|
||||
const depositorAccount = createSplAccount(
|
||||
instructions,
|
||||
wallet.publicKey,
|
||||
accountRentExempt,
|
||||
liquidityTokenMint.publicKey,
|
||||
wallet.publicKey,
|
||||
AccountLayout.span
|
||||
);
|
||||
|
||||
// creating fee pool account its set from env variable or to creater of the pool
|
||||
// creater of the pool is not allowed in some versions of token-swap program
|
||||
const feeAccount = createSplAccount(
|
||||
instructions,
|
||||
wallet.publicKey,
|
||||
accountRentExempt,
|
||||
liquidityTokenMint.publicKey,
|
||||
SWAP_PROGRAM_OWNER_FEE_ADDRESS || wallet.publicKey,
|
||||
AccountLayout.span
|
||||
);
|
||||
|
||||
// create all accounts in one transaction
|
||||
let tx = await sendTransaction(connection, wallet, instructions, [
|
||||
liquidityTokenMint,
|
||||
depositorAccount,
|
||||
feeAccount,
|
||||
...holdingAccounts,
|
||||
...signers,
|
||||
]);
|
||||
|
||||
notify({
|
||||
message: 'Accounts created',
|
||||
description: `Transaction ${tx}`,
|
||||
type: 'success',
|
||||
});
|
||||
|
||||
notify({
|
||||
message: 'Adding Liquidity...',
|
||||
description: 'Please review transactions to approve.',
|
||||
type: 'warn',
|
||||
});
|
||||
|
||||
signers = [];
|
||||
instructions = [];
|
||||
cleanupInstructions = [];
|
||||
|
||||
instructions.push(
|
||||
SystemProgram.createAccount({
|
||||
fromPubkey: wallet.publicKey,
|
||||
newAccountPubkey: tokenSwapAccount.publicKey,
|
||||
lamports: await connection.getMinimumBalanceForRentExemption(programIds().swapLayout.span),
|
||||
space: programIds().swapLayout.span,
|
||||
programId: programIds().swap,
|
||||
})
|
||||
);
|
||||
|
||||
components.forEach((leg, i) => {
|
||||
if (!leg.account) {
|
||||
return;
|
||||
}
|
||||
|
||||
// create temporary account for wrapped sol to perform transfer
|
||||
const from = getWrappedAccount(
|
||||
instructions,
|
||||
cleanupInstructions,
|
||||
leg.account,
|
||||
wallet.publicKey,
|
||||
leg.amount + accountRentExempt,
|
||||
signers
|
||||
);
|
||||
|
||||
instructions.push(
|
||||
Token.createTransferInstruction(
|
||||
programIds().token,
|
||||
from,
|
||||
holdingAccounts[i].publicKey,
|
||||
wallet.publicKey,
|
||||
[],
|
||||
leg.amount
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
instructions.push(
|
||||
createInitSwapInstruction(
|
||||
tokenSwapAccount,
|
||||
authority,
|
||||
holdingAccounts[0].publicKey,
|
||||
holdingAccounts[1].publicKey,
|
||||
liquidityTokenMint.publicKey,
|
||||
feeAccount.publicKey,
|
||||
depositorAccount.publicKey,
|
||||
programIds().token,
|
||||
programIds().swap,
|
||||
nonce,
|
||||
options
|
||||
)
|
||||
);
|
||||
|
||||
// All instructions didn't fit in single transaction
|
||||
// initialize and provide inital liquidity to swap in 2nd (this prevents loss of funds)
|
||||
tx = await sendTransaction(connection, wallet, instructions.concat(cleanupInstructions), [
|
||||
tokenSwapAccount,
|
||||
...signers,
|
||||
]);
|
||||
|
||||
notify({
|
||||
message: 'Pool Funded. Happy trading.',
|
||||
type: 'success',
|
||||
description: `Transaction - ${tx}`,
|
||||
});
|
||||
}
|
||||
|
||||
function getWrappedAccount(
|
||||
instructions: TransactionInstruction[],
|
||||
cleanupInstructions: TransactionInstruction[],
|
||||
toCheck: TokenAccount,
|
||||
payer: PublicKey,
|
||||
amount: number,
|
||||
signers: Account[]
|
||||
) {
|
||||
if (!toCheck.info.isNative) {
|
||||
return toCheck.pubkey;
|
||||
}
|
||||
|
||||
const account = new Account();
|
||||
instructions.push(
|
||||
SystemProgram.createAccount({
|
||||
fromPubkey: payer,
|
||||
newAccountPubkey: account.publicKey,
|
||||
lamports: amount,
|
||||
space: AccountLayout.span,
|
||||
programId: programIds().token,
|
||||
})
|
||||
);
|
||||
|
||||
instructions.push(Token.createInitAccountInstruction(programIds().token, WRAPPED_SOL_MINT, account.publicKey, payer));
|
||||
|
||||
cleanupInstructions.push(
|
||||
Token.createCloseAccountInstruction(programIds().token, account.publicKey, payer, payer, [])
|
||||
);
|
||||
|
||||
signers.push(account);
|
||||
|
||||
return account.publicKey;
|
||||
}
|
||||
|
||||
function createSplAccount(
|
||||
instructions: TransactionInstruction[],
|
||||
payer: PublicKey,
|
||||
accountRentExempt: number,
|
||||
mint: PublicKey,
|
||||
owner: PublicKey,
|
||||
space: number
|
||||
) {
|
||||
const account = new Account();
|
||||
instructions.push(
|
||||
SystemProgram.createAccount({
|
||||
fromPubkey: payer,
|
||||
newAccountPubkey: account.publicKey,
|
||||
lamports: accountRentExempt,
|
||||
space,
|
||||
programId: programIds().token,
|
||||
})
|
||||
);
|
||||
|
||||
instructions.push(Token.createInitAccountInstruction(programIds().token, mint, account.publicKey, owner));
|
||||
|
||||
return account;
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ export const BorrowReserveView = () => {
|
|||
reserve={lendingReserve}
|
||||
/>
|
||||
</Col>
|
||||
<Col xs={24} xl={9}>
|
||||
<Col xs={24} xl={8}>
|
||||
<SideReserveOverview
|
||||
className="card-fill"
|
||||
reserve={lendingReserve}
|
||||
|
|
Loading…
Reference in New Issue