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>
|
||||||
<Menu theme={theme} defaultSelectedKeys={[defaultKey]} selectable={false} mode="inline" className="bottom-links">
|
<Menu theme={theme} defaultSelectedKeys={[defaultKey]} selectable={false} mode="inline" className="bottom-links">
|
||||||
<Menu.Item key="16" icon={<ForkOutlined />}>
|
<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
|
Fork
|
||||||
</a>
|
</a>
|
||||||
</Menu.Item>,
|
</Menu.Item>,
|
||||||
<Menu.Item key="15" icon={<GithubOutlined />}>
|
<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
|
Github
|
||||||
</a>
|
</a>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
|
|
@ -7,7 +7,6 @@ import { PoolInfo, TokenAccount } from './../models';
|
||||||
import { chunks } from './../utils/utils';
|
import { chunks } from './../utils/utils';
|
||||||
import { EventEmitter } from './../utils/eventEmitter';
|
import { EventEmitter } from './../utils/eventEmitter';
|
||||||
import { useUserAccounts } from '../hooks/useUserAccounts';
|
import { useUserAccounts } from '../hooks/useUserAccounts';
|
||||||
import { usePools } from '../utils/pools';
|
|
||||||
import { WRAPPED_SOL_MINT, programIds } from '../utils/ids';
|
import { WRAPPED_SOL_MINT, programIds } from '../utils/ids';
|
||||||
|
|
||||||
const AccountsContext = React.createContext<any>(null);
|
const AccountsContext = React.createContext<any>(null);
|
||||||
|
@ -347,7 +346,6 @@ export function AccountsProvider({ children = null as any }) {
|
||||||
const [tokenAccounts, setTokenAccounts] = useState<TokenAccount[]>([]);
|
const [tokenAccounts, setTokenAccounts] = useState<TokenAccount[]>([]);
|
||||||
const [userAccounts, setUserAccounts] = useState<TokenAccount[]>([]);
|
const [userAccounts, setUserAccounts] = useState<TokenAccount[]>([]);
|
||||||
const { nativeAccount } = UseNativeAccount();
|
const { nativeAccount } = UseNativeAccount();
|
||||||
const { pools } = usePools();
|
|
||||||
|
|
||||||
const selectUserAccounts = useCallback(() => {
|
const selectUserAccounts = useCallback(() => {
|
||||||
return cache
|
return cache
|
||||||
|
@ -419,7 +417,6 @@ export function AccountsProvider({ children = null as any }) {
|
||||||
<AccountsContext.Provider
|
<AccountsContext.Provider
|
||||||
value={{
|
value={{
|
||||||
userAccounts,
|
userAccounts,
|
||||||
pools,
|
|
||||||
nativeAccount,
|
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 * as BufferLayout from 'buffer-layout';
|
||||||
import { programIds } from '../utils/ids';
|
|
||||||
import { publicKey, uint64 } from '../utils/layout';
|
import { publicKey, uint64 } from '../utils/layout';
|
||||||
import { CurveType, PoolConfig } from './pool';
|
|
||||||
|
|
||||||
export { TokenSwap } from '@solana/spl-token-swap';
|
export { TokenSwap } from '@solana/spl-token-swap';
|
||||||
|
|
||||||
|
@ -70,369 +66,3 @@ export const TokenSwapLayout: typeof BufferLayout.Structure = BufferLayout.struc
|
||||||
FEE_LAYOUT,
|
FEE_LAYOUT,
|
||||||
CURVE_NODE,
|
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 { useEffect, useMemo, useState } from 'react';
|
||||||
import { Token, MintLayout, AccountLayout } from '@solana/spl-token';
|
import { MintLayout, AccountLayout } from '@solana/spl-token';
|
||||||
import { notify } from './notifications';
|
import { programIds } from './ids';
|
||||||
import { programIds, SWAP_HOST_FEE_ADDRESS, SWAP_PROGRAM_OWNER_FEE_ADDRESS, WRAPPED_SOL_MINT } from './ids';
|
|
||||||
import {
|
import {
|
||||||
LiquidityComponent,
|
|
||||||
PoolInfo,
|
PoolInfo,
|
||||||
TokenAccount,
|
|
||||||
createInitSwapInstruction,
|
|
||||||
TokenSwapLayout,
|
TokenSwapLayout,
|
||||||
depositPoolInstruction,
|
|
||||||
TokenSwapLayoutLegacyV0 as TokenSwapLayoutV0,
|
TokenSwapLayoutLegacyV0 as TokenSwapLayoutV0,
|
||||||
TokenSwapLayoutV1,
|
TokenSwapLayoutV1,
|
||||||
swapInstruction,
|
|
||||||
PoolConfig,
|
|
||||||
depositExactOneInstruction,
|
|
||||||
withdrawExactOneInstruction,
|
|
||||||
withdrawPoolInstruction,
|
|
||||||
} from './../models';
|
} from './../models';
|
||||||
import { sendTransaction, useConnection } from '../contexts/connection';
|
import { useConnection } from '../contexts/connection';
|
||||||
import { cache, getCachedAccount, getMultipleAccounts, TokenAccountParser, useCachedPool } from '../contexts/accounts';
|
import { cache, getMultipleAccounts, TokenAccountParser } from '../contexts/accounts';
|
||||||
import { useUserAccounts } from '../hooks/useUserAccounts';
|
|
||||||
|
|
||||||
const LIQUIDITY_TOKEN_PRECISION = 8;
|
|
||||||
|
|
||||||
export const LIQUIDITY_PROVIDER_FEE = 0.003;
|
export const LIQUIDITY_PROVIDER_FEE = 0.003;
|
||||||
export const SERUM_FEE = 0.0005;
|
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[]) => {
|
const getHoldings = (connection: Connection, accounts: string[]) => {
|
||||||
return accounts.map((acc) => cache.query(connection, new PublicKey(acc)));
|
return accounts.map((acc) => cache.query(connection, new PublicKey(acc)));
|
||||||
|
@ -510,7 +179,7 @@ export const usePools = () => {
|
||||||
|
|
||||||
export const usePoolForBasket = (mints: (string | undefined)[]) => {
|
export const usePoolForBasket = (mints: (string | undefined)[]) => {
|
||||||
const connection = useConnection();
|
const connection = useConnection();
|
||||||
const { pools } = useCachedPool();
|
const { pools } = usePools();
|
||||||
const [pool, setPool] = useState<PoolInfo>();
|
const [pool, setPool] = useState<PoolInfo>();
|
||||||
const sortedMints = useMemo(() => [...mints].sort(), [...mints]); // eslint-disable-line
|
const sortedMints = useMemo(() => [...mints].sort(), [...mints]); // eslint-disable-line
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -542,299 +211,6 @@ export const usePoolForBasket = (mints: (string | undefined)[]) => {
|
||||||
return pool;
|
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(
|
function estimateProceedsFromInput(
|
||||||
inputQuantityInPool: number,
|
inputQuantityInPool: number,
|
||||||
proceedsQuantityInPool: number,
|
proceedsQuantityInPool: number,
|
||||||
|
@ -934,248 +310,3 @@ export async function calculateDependentAmount(
|
||||||
}
|
}
|
||||||
return depAdjustedAmount / depPrecision;
|
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}
|
reserve={lendingReserve}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs={24} xl={9}>
|
<Col xs={24} xl={8}>
|
||||||
<SideReserveOverview
|
<SideReserveOverview
|
||||||
className="card-fill"
|
className="card-fill"
|
||||||
reserve={lendingReserve}
|
reserve={lendingReserve}
|
||||||
|
|
Loading…
Reference in New Issue