Merge branch 'ts/orca-margin-trade' into dev
This commit is contained in:
commit
1ae00aed0a
|
@ -10,6 +10,7 @@
|
||||||
"clean": "rm -rf dist",
|
"clean": "rm -rf dist",
|
||||||
"example1-user": "ts-node ts/client/src/scripts/example1-user.ts",
|
"example1-user": "ts-node ts/client/src/scripts/example1-user.ts",
|
||||||
"example1-admin": "ts-node ts/client/src/scripts/example1-admin.ts",
|
"example1-admin": "ts-node ts/client/src/scripts/example1-admin.ts",
|
||||||
|
"scratch": "ts-node ts/client/src/scripts/scratch.ts",
|
||||||
"format": "prettier --check .",
|
"format": "prettier --check .",
|
||||||
"lint": "eslint . --ext ts --ext tsx --ext js --quiet",
|
"lint": "eslint . --ext ts --ext tsx --ext js --quiet",
|
||||||
"type-check": "tsc --pretty --noEmit",
|
"type-check": "tsc --pretty --noEmit",
|
||||||
|
@ -25,6 +26,7 @@
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tsconfig/recommended": "^1.0.1",
|
"@tsconfig/recommended": "^1.0.1",
|
||||||
|
"@types/bs58": "^4.0.1",
|
||||||
"@types/chai": "^4.3.0",
|
"@types/chai": "^4.3.0",
|
||||||
"@types/mocha": "^9.1.0",
|
"@types/mocha": "^9.1.0",
|
||||||
"@types/node": "^14.14.37",
|
"@types/node": "^14.14.37",
|
||||||
|
@ -40,9 +42,6 @@
|
||||||
"typedoc": "^0.22.5",
|
"typedoc": "^0.22.5",
|
||||||
"typescript": "^4.4.4"
|
"typescript": "^4.4.4"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
|
||||||
"@types/bn.js": "^4.11.6"
|
|
||||||
},
|
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
|
@ -51,10 +50,10 @@
|
||||||
"trailingComma": "all"
|
"trailingComma": "all"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@orca-so/sdk": "^1.2.24",
|
||||||
"@project-serum/anchor": "^0.24.2",
|
"@project-serum/anchor": "^0.24.2",
|
||||||
"@project-serum/serum": "^0.13.65",
|
"@project-serum/serum": "^0.13.65",
|
||||||
"@solana/spl-token": "^0.2.0",
|
"@solana/spl-token": "~0.1.8",
|
||||||
"@types/bs58": "^4.0.1",
|
|
||||||
"big.js": "^6.1.1",
|
"big.js": "^6.1.1",
|
||||||
"bs58": "^5.0.0"
|
"bs58": "^5.0.0"
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,6 +10,7 @@ export class Bank {
|
||||||
public depositIndex: I80F48;
|
public depositIndex: I80F48;
|
||||||
public borrowIndex: I80F48;
|
public borrowIndex: I80F48;
|
||||||
public indexedTotalDeposits: I80F48;
|
public indexedTotalDeposits: I80F48;
|
||||||
|
public indexedTotalBorrows: I80F48;
|
||||||
|
|
||||||
static from(
|
static from(
|
||||||
publicKey: PublicKey,
|
publicKey: PublicKey,
|
||||||
|
@ -106,6 +107,7 @@ export class Bank {
|
||||||
this.depositIndex = I80F48.from(depositIndex);
|
this.depositIndex = I80F48.from(depositIndex);
|
||||||
this.borrowIndex = I80F48.from(borrowIndex);
|
this.borrowIndex = I80F48.from(borrowIndex);
|
||||||
this.indexedTotalDeposits = I80F48.from(indexedTotalDeposits);
|
this.indexedTotalDeposits = I80F48.from(indexedTotalDeposits);
|
||||||
|
this.indexedTotalBorrows = I80F48.from(indexedTotalBorrows);
|
||||||
}
|
}
|
||||||
|
|
||||||
toString(): string {
|
toString(): string {
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
import { AnchorProvider, BN, Program, Provider } from '@project-serum/anchor';
|
import { AnchorProvider, BN, Program, Provider } from '@project-serum/anchor';
|
||||||
import { getFeeRates, getFeeTier, Market } from '@project-serum/serum';
|
import { getFeeRates, getFeeTier, Market } from '@project-serum/serum';
|
||||||
import { Order } from '@project-serum/serum/lib/market';
|
import { Order } from '@project-serum/serum/lib/market';
|
||||||
import * as spl from '@solana/spl-token';
|
import {
|
||||||
|
closeAccount,
|
||||||
|
initializeAccount,
|
||||||
|
WRAPPED_SOL_MINT,
|
||||||
|
} from '@project-serum/serum/lib/token-instructions';
|
||||||
|
import { TokenSwap } from '@solana/spl-token-swap';
|
||||||
|
import { TOKEN_PROGRAM_ID, u64 } from '@solana/spl-token';
|
||||||
import {
|
import {
|
||||||
AccountMeta,
|
AccountMeta,
|
||||||
Keypair,
|
Keypair,
|
||||||
|
@ -10,8 +16,14 @@ import {
|
||||||
SystemProgram,
|
SystemProgram,
|
||||||
SYSVAR_RENT_PUBKEY,
|
SYSVAR_RENT_PUBKEY,
|
||||||
TransactionSignature,
|
TransactionSignature,
|
||||||
|
TransactionInstruction,
|
||||||
|
LAMPORTS_PER_SOL,
|
||||||
|
Signer,
|
||||||
} from '@solana/web3.js';
|
} from '@solana/web3.js';
|
||||||
import bs58 from 'bs58';
|
import bs58 from 'bs58';
|
||||||
|
import { ORCA_TOKEN_SWAP_ID_DEVNET } from '@orca-so/sdk';
|
||||||
|
import { orcaDevnetPoolConfigs } from '@orca-so/sdk/dist/constants/devnet/pools';
|
||||||
|
import { OrcaPoolConfig as OrcaDevnetPoolConfig } from '@orca-so/sdk/dist/public/devnet/pools';
|
||||||
import { Bank, getMintInfoForTokenIndex } from './accounts/bank';
|
import { Bank, getMintInfoForTokenIndex } from './accounts/bank';
|
||||||
import { Group } from './accounts/group';
|
import { Group } from './accounts/group';
|
||||||
import { I80F48 } from './accounts/I80F48';
|
import { I80F48 } from './accounts/I80F48';
|
||||||
|
@ -25,6 +37,9 @@ import {
|
||||||
Serum3Side,
|
Serum3Side,
|
||||||
} from './accounts/serum3';
|
} from './accounts/serum3';
|
||||||
import { IDL, MangoV4 } from './mango_v4';
|
import { IDL, MangoV4 } from './mango_v4';
|
||||||
|
import { getAssociatedTokenAddress, toNativeDecimals, toU64 } from './utils';
|
||||||
|
import { getTokenDecimals } from './constants/tokens';
|
||||||
|
import { MarginTradeWithdraw } from './types';
|
||||||
|
|
||||||
export const MANGO_V4_ID = new PublicKey(
|
export const MANGO_V4_ID = new PublicKey(
|
||||||
'm43thNJ58XCjL798ZSq6JGAG1BnWskhdq5or6kcnfsD',
|
'm43thNJ58XCjL798ZSq6JGAG1BnWskhdq5or6kcnfsD',
|
||||||
|
@ -285,22 +300,56 @@ export class MangoClient {
|
||||||
) {
|
) {
|
||||||
const bank = group.banksMap.get(tokenName)!;
|
const bank = group.banksMap.get(tokenName)!;
|
||||||
|
|
||||||
const tokenAccountPk = await spl.getAssociatedTokenAddress(
|
const tokenAccountPk = await getAssociatedTokenAddress(
|
||||||
bank.mint,
|
bank.mint,
|
||||||
mangoAccount.owner,
|
mangoAccount.owner,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let wrappedSolAccount: Keypair | undefined;
|
||||||
|
let preInstructions: TransactionInstruction[] = [];
|
||||||
|
let postInstructions: TransactionInstruction[] = [];
|
||||||
|
let additionalSigners: Signer[] = [];
|
||||||
|
if (bank.mint.equals(WRAPPED_SOL_MINT)) {
|
||||||
|
wrappedSolAccount = new Keypair();
|
||||||
|
const lamports = Math.round(amount * LAMPORTS_PER_SOL) + 1e7;
|
||||||
|
|
||||||
|
preInstructions = [
|
||||||
|
SystemProgram.createAccount({
|
||||||
|
fromPubkey: mangoAccount.owner,
|
||||||
|
newAccountPubkey: wrappedSolAccount.publicKey,
|
||||||
|
lamports,
|
||||||
|
space: 165,
|
||||||
|
programId: TOKEN_PROGRAM_ID,
|
||||||
|
}),
|
||||||
|
initializeAccount({
|
||||||
|
account: wrappedSolAccount.publicKey,
|
||||||
|
mint: WRAPPED_SOL_MINT,
|
||||||
|
owner: mangoAccount.owner,
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
postInstructions = [
|
||||||
|
closeAccount({
|
||||||
|
source: wrappedSolAccount.publicKey,
|
||||||
|
destination: mangoAccount.owner,
|
||||||
|
owner: mangoAccount.owner,
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
additionalSigners.push(wrappedSolAccount);
|
||||||
|
}
|
||||||
|
|
||||||
const healthRemainingAccounts: PublicKey[] =
|
const healthRemainingAccounts: PublicKey[] =
|
||||||
await this.buildHealthRemainingAccounts(group, mangoAccount, bank);
|
await this.buildHealthRemainingAccounts(group, mangoAccount, [bank]);
|
||||||
|
|
||||||
|
const tokenDecimals = getTokenDecimals(tokenName);
|
||||||
|
|
||||||
return await this.program.methods
|
return await this.program.methods
|
||||||
.deposit(new BN(amount))
|
.deposit(toNativeDecimals(amount, tokenDecimals))
|
||||||
.accounts({
|
.accounts({
|
||||||
group: group.publicKey,
|
group: group.publicKey,
|
||||||
account: mangoAccount.publicKey,
|
account: mangoAccount.publicKey,
|
||||||
bank: bank.publicKey,
|
bank: bank.publicKey,
|
||||||
vault: bank.vault,
|
vault: bank.vault,
|
||||||
tokenAccount: tokenAccountPk,
|
tokenAccount: wrappedSolAccount?.publicKey ?? tokenAccountPk,
|
||||||
tokenAuthority: (this.program.provider as AnchorProvider).wallet
|
tokenAuthority: (this.program.provider as AnchorProvider).wallet
|
||||||
.publicKey,
|
.publicKey,
|
||||||
})
|
})
|
||||||
|
@ -310,7 +359,10 @@ export class MangoClient {
|
||||||
({ pubkey: pk, isWritable: false, isSigner: false } as AccountMeta),
|
({ pubkey: pk, isWritable: false, isSigner: false } as AccountMeta),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.rpc();
|
.preInstructions(preInstructions)
|
||||||
|
.postInstructions(postInstructions)
|
||||||
|
.signers(additionalSigners)
|
||||||
|
.rpc({ skipPreflight: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
public async withdraw(
|
public async withdraw(
|
||||||
|
@ -322,13 +374,13 @@ export class MangoClient {
|
||||||
) {
|
) {
|
||||||
const bank = group.banksMap.get(tokenName)!;
|
const bank = group.banksMap.get(tokenName)!;
|
||||||
|
|
||||||
const tokenAccountPk = await spl.getAssociatedTokenAddress(
|
const tokenAccountPk = await getAssociatedTokenAddress(
|
||||||
bank.mint,
|
bank.mint,
|
||||||
mangoAccount.owner,
|
mangoAccount.owner,
|
||||||
);
|
);
|
||||||
|
|
||||||
const healthRemainingAccounts: PublicKey[] =
|
const healthRemainingAccounts: PublicKey[] =
|
||||||
await this.buildHealthRemainingAccounts(group, mangoAccount, bank);
|
await this.buildHealthRemainingAccounts(group, mangoAccount, [bank]);
|
||||||
|
|
||||||
return await this.program.methods
|
return await this.program.methods
|
||||||
.withdraw(new BN(amount), allowBorrow)
|
.withdraw(new BN(amount), allowBorrow)
|
||||||
|
@ -820,6 +872,81 @@ export class MangoClient {
|
||||||
.rpc();
|
.rpc();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// margin trade (orca)
|
||||||
|
|
||||||
|
public async marginTrade({
|
||||||
|
group,
|
||||||
|
mangoAccount,
|
||||||
|
inputToken,
|
||||||
|
amountIn,
|
||||||
|
outputToken,
|
||||||
|
minimumAmountOut,
|
||||||
|
}: {
|
||||||
|
group: Group;
|
||||||
|
mangoAccount: MangoAccount;
|
||||||
|
inputToken: string;
|
||||||
|
amountIn: number;
|
||||||
|
outputToken: string;
|
||||||
|
minimumAmountOut: number;
|
||||||
|
}): Promise<TransactionSignature> {
|
||||||
|
const inputBank = group.banksMap.get(inputToken);
|
||||||
|
const outputBank = group.banksMap.get(outputToken);
|
||||||
|
|
||||||
|
if (!inputBank || !outputBank) throw new Error('Invalid token');
|
||||||
|
|
||||||
|
const healthRemainingAccounts: PublicKey[] =
|
||||||
|
await this.buildHealthRemainingAccounts(group, mangoAccount, [
|
||||||
|
inputBank,
|
||||||
|
outputBank,
|
||||||
|
]);
|
||||||
|
const parsedHealthAccounts = healthRemainingAccounts.map(
|
||||||
|
(pk) =>
|
||||||
|
({
|
||||||
|
pubkey: pk,
|
||||||
|
isWritable:
|
||||||
|
pk.equals(inputBank.publicKey) || pk.equals(outputBank.publicKey)
|
||||||
|
? true
|
||||||
|
: false,
|
||||||
|
isSigner: false,
|
||||||
|
} as AccountMeta),
|
||||||
|
);
|
||||||
|
|
||||||
|
const targetProgramId = ORCA_TOKEN_SWAP_ID_DEVNET;
|
||||||
|
|
||||||
|
const { instruction, signers } = await this.buildOrcaInstruction(
|
||||||
|
targetProgramId,
|
||||||
|
inputBank,
|
||||||
|
outputBank,
|
||||||
|
toU64(amountIn, 9),
|
||||||
|
toU64(minimumAmountOut, 6),
|
||||||
|
);
|
||||||
|
const targetRemainingAccounts = instruction.keys;
|
||||||
|
|
||||||
|
const withdraws: MarginTradeWithdraw[] = [
|
||||||
|
{ index: 3, amount: toU64(amountIn, 9) },
|
||||||
|
];
|
||||||
|
const cpiData = instruction.data;
|
||||||
|
|
||||||
|
return await this.program.methods
|
||||||
|
.marginTrade(new BN(parsedHealthAccounts.length), withdraws, cpiData)
|
||||||
|
.accounts({
|
||||||
|
group: group.publicKey,
|
||||||
|
account: mangoAccount.publicKey,
|
||||||
|
owner: (this.program.provider as AnchorProvider).wallet.publicKey,
|
||||||
|
})
|
||||||
|
.remainingAccounts([
|
||||||
|
...parsedHealthAccounts,
|
||||||
|
{
|
||||||
|
pubkey: targetProgramId,
|
||||||
|
isWritable: false,
|
||||||
|
isSigner: false,
|
||||||
|
} as AccountMeta,
|
||||||
|
...targetRemainingAccounts,
|
||||||
|
])
|
||||||
|
.signers(signers)
|
||||||
|
.rpc({ skipPreflight: true });
|
||||||
|
}
|
||||||
|
|
||||||
/// static
|
/// static
|
||||||
|
|
||||||
static connect(provider?: Provider, devnet?: boolean): MangoClient {
|
static connect(provider?: Provider, devnet?: boolean): MangoClient {
|
||||||
|
@ -839,7 +966,7 @@ export class MangoClient {
|
||||||
private async buildHealthRemainingAccounts(
|
private async buildHealthRemainingAccounts(
|
||||||
group: Group,
|
group: Group,
|
||||||
mangoAccount: MangoAccount,
|
mangoAccount: MangoAccount,
|
||||||
bank?: Bank /** TODO for serum3PlaceOrde we are just ingoring this atm */,
|
banks?: Bank[] /** TODO for serum3PlaceOrder we are just ingoring this atm */,
|
||||||
) {
|
) {
|
||||||
const healthRemainingAccounts: PublicKey[] = [];
|
const healthRemainingAccounts: PublicKey[] = [];
|
||||||
|
|
||||||
|
@ -847,8 +974,10 @@ export class MangoClient {
|
||||||
.filter((token) => token.tokenIndex !== 65535)
|
.filter((token) => token.tokenIndex !== 65535)
|
||||||
.map((token) => token.tokenIndex);
|
.map((token) => token.tokenIndex);
|
||||||
|
|
||||||
if (bank) {
|
if (banks?.length) {
|
||||||
tokenIndices.push(bank.tokenIndex);
|
for (const bank of banks) {
|
||||||
|
tokenIndices.push(bank.tokenIndex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mintInfos = await Promise.all(
|
const mintInfos = await Promise.all(
|
||||||
|
@ -888,4 +1017,46 @@ export class MangoClient {
|
||||||
|
|
||||||
return healthRemainingAccounts;
|
return healthRemainingAccounts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Orca ix references:
|
||||||
|
swap fn: https://github.com/orca-so/typescript-sdk/blob/main/src/model/orca/pool/orca-pool.ts#L162
|
||||||
|
swap ix: https://github.com/orca-so/typescript-sdk/blob/main/src/public/utils/web3/instructions/pool-instructions.ts#L41
|
||||||
|
*/
|
||||||
|
private async buildOrcaInstruction(
|
||||||
|
orcaTokenSwapId: PublicKey,
|
||||||
|
inputBank: Bank,
|
||||||
|
outputBank: Bank,
|
||||||
|
amountInU64: BN,
|
||||||
|
minimumAmountOutU64: BN,
|
||||||
|
) {
|
||||||
|
const poolParams = orcaDevnetPoolConfigs[OrcaDevnetPoolConfig.ORCA_SOL];
|
||||||
|
|
||||||
|
const [authorityForPoolAddress] = await PublicKey.findProgramAddress(
|
||||||
|
[poolParams.address.toBuffer()],
|
||||||
|
orcaTokenSwapId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const instruction = TokenSwap.swapInstruction(
|
||||||
|
poolParams.address,
|
||||||
|
authorityForPoolAddress,
|
||||||
|
inputBank.publicKey, // userTransferAuthority
|
||||||
|
inputBank.vault, // inputTokenUserAddress
|
||||||
|
poolParams.tokens[inputBank.mint.toString()].addr, // inputToken.addr
|
||||||
|
poolParams.tokens[outputBank.mint.toString()].addr, // outputToken.addr
|
||||||
|
outputBank.vault, // outputTokenUserAddress
|
||||||
|
poolParams.poolTokenMint,
|
||||||
|
poolParams.feeAccount,
|
||||||
|
null, // hostFeeAccount
|
||||||
|
orcaTokenSwapId,
|
||||||
|
TOKEN_PROGRAM_ID,
|
||||||
|
amountInU64,
|
||||||
|
minimumAmountOutU64,
|
||||||
|
);
|
||||||
|
|
||||||
|
instruction.keys[2].isSigner = false;
|
||||||
|
instruction.keys[2].isWritable = true;
|
||||||
|
|
||||||
|
return { instruction, signers: [] };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
export const getTokenDecimals = (symbol: string) => {
|
||||||
|
const tokenMeta = tokens.find((t) => t.symbol === symbol);
|
||||||
|
|
||||||
|
if (!tokenMeta) throw new Error('TokenDecimalError: Token not found');
|
||||||
|
|
||||||
|
return tokenMeta.decimals;
|
||||||
|
};
|
||||||
|
|
||||||
|
const tokens = [
|
||||||
|
{ symbol: 'USDC', decimals: 6 },
|
||||||
|
{ symbol: 'SOL', decimals: 9 },
|
||||||
|
{ symbol: 'BTC', decimals: 6 },
|
||||||
|
];
|
||||||
|
|
||||||
|
export default tokens;
|
|
@ -6,13 +6,18 @@ import { DEVNET_SERUM3_PROGRAM_ID } from '../constants';
|
||||||
|
|
||||||
const DEVNET_SERUM3_MARKETS = new Map([
|
const DEVNET_SERUM3_MARKETS = new Map([
|
||||||
['BTC/USDC', 'DW83EpHFywBxCHmyARxwj3nzxJd7MUdSeznmrdzZKNZB'],
|
['BTC/USDC', 'DW83EpHFywBxCHmyARxwj3nzxJd7MUdSeznmrdzZKNZB'],
|
||||||
|
['SOL/USDC', '5xWpt56U1NCuHoAEtpLeUrQcxDkEpNfScjfLFaRzLPgR'],
|
||||||
]);
|
]);
|
||||||
const DEVNET_MINTS = new Map([
|
const DEVNET_MINTS = new Map([
|
||||||
['USDC', '8FRFC6MoGGkMFQwngccyu69VnYbzykGeez7ignHVAFSN'],
|
['USDC', 'EmXq3Ni9gfudTiyNKzzYvpnQqnJEMRw2ttnVXoJXjLo1'], // use devnet usdc
|
||||||
['BTC', '3UNBZ6o52WTWwjac2kPUb4FyodhU1vFkRJheu1Sh2TvU'],
|
['BTC', '3UNBZ6o52WTWwjac2kPUb4FyodhU1vFkRJheu1Sh2TvU'],
|
||||||
|
['SOL', 'So11111111111111111111111111111111111111112'],
|
||||||
|
['ORCA', 'orcarKHSqC5CDDsGbho8GKvwExejWHxTqGzXgcewB9L'],
|
||||||
]);
|
]);
|
||||||
const DEVNET_ORACLES = new Map([
|
const DEVNET_ORACLES = new Map([
|
||||||
['BTC', 'HovQMDrbAgAYPCmHVSrezcSmkMtXSSUsLDFANExrZh2J'],
|
['BTC', 'HovQMDrbAgAYPCmHVSrezcSmkMtXSSUsLDFANExrZh2J'],
|
||||||
|
['SOL', 'J83w4HKfqxwcq3BEMMkPFSppX3gqekLyLJBexebFVkix'],
|
||||||
|
['ORCA', 'A1WttWF7X3Rg6ZRpB2YQUFHCRh1kiXV8sKKLV3S9neJV'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -106,6 +111,60 @@ async function main() {
|
||||||
await group.reload(client);
|
await group.reload(client);
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
|
|
||||||
|
// register token 2
|
||||||
|
console.log(`Registering SOL...`);
|
||||||
|
const solDevnetMint = new PublicKey(DEVNET_MINTS.get('SOL')!);
|
||||||
|
const solDevnetOracle = new PublicKey(DEVNET_ORACLES.get('SOL')!);
|
||||||
|
try {
|
||||||
|
await client.registerToken(
|
||||||
|
group,
|
||||||
|
solDevnetMint,
|
||||||
|
solDevnetOracle,
|
||||||
|
2, // tokenIndex
|
||||||
|
'SOL',
|
||||||
|
0.4,
|
||||||
|
0.07,
|
||||||
|
0.8,
|
||||||
|
0.9,
|
||||||
|
0.0005,
|
||||||
|
0.0005,
|
||||||
|
1.5,
|
||||||
|
0.8,
|
||||||
|
0.6,
|
||||||
|
1.2,
|
||||||
|
1.4,
|
||||||
|
0.02,
|
||||||
|
);
|
||||||
|
await group.reload(client);
|
||||||
|
} catch (error) {}
|
||||||
|
|
||||||
|
// register token 3
|
||||||
|
console.log(`Registering ORCA...`);
|
||||||
|
const orcaDevnetMint = new PublicKey(DEVNET_MINTS.get('ORCA')!);
|
||||||
|
const orcaDevnetOracle = new PublicKey(DEVNET_ORACLES.get('ORCA')!);
|
||||||
|
try {
|
||||||
|
await client.registerToken(
|
||||||
|
group,
|
||||||
|
orcaDevnetMint,
|
||||||
|
orcaDevnetOracle,
|
||||||
|
3, // tokenIndex
|
||||||
|
'ORCA',
|
||||||
|
0.4,
|
||||||
|
0.07,
|
||||||
|
0.8,
|
||||||
|
0.9,
|
||||||
|
0.0005,
|
||||||
|
0.0005,
|
||||||
|
1.5,
|
||||||
|
0.8,
|
||||||
|
0.6,
|
||||||
|
1.2,
|
||||||
|
1.4,
|
||||||
|
0.02,
|
||||||
|
);
|
||||||
|
await group.reload(client);
|
||||||
|
} catch (error) {}
|
||||||
|
|
||||||
// log tokens/banks
|
// log tokens/banks
|
||||||
for (const bank of await group.banksMap.values()) {
|
for (const bank of await group.banksMap.values()) {
|
||||||
console.log(
|
console.log(
|
||||||
|
@ -159,6 +218,7 @@ async function main() {
|
||||||
0.05,
|
0.05,
|
||||||
100,
|
100,
|
||||||
);
|
);
|
||||||
|
console.log('done');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
import fs from 'fs';
|
||||||
|
import * as os from 'os';
|
||||||
|
import { AnchorProvider, Wallet } from '@project-serum/anchor';
|
||||||
|
import { Market } from '@project-serum/serum';
|
||||||
|
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
|
||||||
|
|
||||||
|
import { MangoClient } from '../client';
|
||||||
|
|
||||||
|
const main = async () => {
|
||||||
|
const options = AnchorProvider.defaultOptions();
|
||||||
|
const connection = new Connection(
|
||||||
|
'https://mango.devnet.rpcpool.com',
|
||||||
|
options,
|
||||||
|
);
|
||||||
|
|
||||||
|
const admin = Keypair.fromSecretKey(
|
||||||
|
Buffer.from(
|
||||||
|
JSON.parse(
|
||||||
|
fs.readFileSync(os.homedir() + '/.config/solana/admin.json', 'utf-8'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
const adminWallet = new Wallet(admin);
|
||||||
|
console.log(`Admin ${adminWallet.publicKey.toBase58()}`);
|
||||||
|
const adminProvider = new AnchorProvider(connection, adminWallet, options);
|
||||||
|
const client = await MangoClient.connect(adminProvider, true);
|
||||||
|
|
||||||
|
const btcMint = new PublicKey('3UNBZ6o52WTWwjac2kPUb4FyodhU1vFkRJheu1Sh2TvU');
|
||||||
|
const usdcMint = new PublicKey(
|
||||||
|
'EmXq3Ni9gfudTiyNKzzYvpnQqnJEMRw2ttnVXoJXjLo1',
|
||||||
|
);
|
||||||
|
const serumProgramId = new PublicKey(
|
||||||
|
'DESVgJVGajEgKGXhb6XmqDHGz3VjdgP7rEVESBgxmroY',
|
||||||
|
);
|
||||||
|
|
||||||
|
const market = await Market.findAccountsByMints(
|
||||||
|
connection,
|
||||||
|
btcMint,
|
||||||
|
usdcMint,
|
||||||
|
serumProgramId,
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log('market', market);
|
||||||
|
};
|
||||||
|
|
||||||
|
main();
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { BN } from '@project-serum/anchor';
|
||||||
|
|
||||||
|
export class MarginTradeWithdraw {
|
||||||
|
static index: number;
|
||||||
|
static amount: BN;
|
||||||
|
}
|
|
@ -1,4 +1,10 @@
|
||||||
import { AccountMeta } from '@solana/web3.js';
|
import BN from 'bn.js';
|
||||||
|
import {
|
||||||
|
ASSOCIATED_TOKEN_PROGRAM_ID,
|
||||||
|
TOKEN_PROGRAM_ID,
|
||||||
|
u64,
|
||||||
|
} from '@solana/spl-token';
|
||||||
|
import { AccountMeta, PublicKey } from '@solana/web3.js';
|
||||||
|
|
||||||
export function debugAccountMetas(ams: AccountMeta[]) {
|
export function debugAccountMetas(ams: AccountMeta[]) {
|
||||||
for (const am of ams) {
|
for (const am of ams) {
|
||||||
|
@ -30,3 +36,43 @@ export async function findOrCreate<T>(
|
||||||
one = many[0];
|
one = many[0];
|
||||||
return one;
|
return one;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the address of the associated token account for a given mint and owner
|
||||||
|
*
|
||||||
|
* @param mint Token mint account
|
||||||
|
* @param owner Owner of the new account
|
||||||
|
* @param allowOwnerOffCurve Allow the owner account to be a PDA (Program Derived Address)
|
||||||
|
* @param programId SPL Token program account
|
||||||
|
* @param associatedTokenProgramId SPL Associated Token program account
|
||||||
|
*
|
||||||
|
* @return Address of the associated token account
|
||||||
|
*/
|
||||||
|
export async function getAssociatedTokenAddress(
|
||||||
|
mint: PublicKey,
|
||||||
|
owner: PublicKey,
|
||||||
|
allowOwnerOffCurve = false,
|
||||||
|
programId = TOKEN_PROGRAM_ID,
|
||||||
|
associatedTokenProgramId = ASSOCIATED_TOKEN_PROGRAM_ID,
|
||||||
|
): Promise<PublicKey> {
|
||||||
|
if (!allowOwnerOffCurve && !PublicKey.isOnCurve(owner.toBuffer()))
|
||||||
|
throw new Error('TokenOwnerOffCurve');
|
||||||
|
|
||||||
|
const [address] = await PublicKey.findProgramAddress(
|
||||||
|
[owner.toBuffer(), programId.toBuffer(), mint.toBuffer()],
|
||||||
|
associatedTokenProgramId,
|
||||||
|
);
|
||||||
|
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toNativeDecimals(amount: number, decimals: number): BN {
|
||||||
|
return new BN(Math.trunc(amount * Math.pow(10, decimals)));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toU64(amount: number, decimals): BN {
|
||||||
|
const bn = toNativeDecimals(amount, decimals).toString();
|
||||||
|
console.log('bn', bn);
|
||||||
|
|
||||||
|
return new u64(bn);
|
||||||
|
}
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
{
|
|
||||||
"extends": "@tsconfig/recommended/tsconfig.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"allowJs": true,
|
|
||||||
"checkJs": true,
|
|
||||||
"declaration": true,
|
|
||||||
"declarationDir": "dist",
|
|
||||||
"declarationMap": true,
|
|
||||||
"noErrorTruncation": true,
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"lib": [
|
|
||||||
"es2019"
|
|
||||||
],
|
|
||||||
"noImplicitAny": false,
|
|
||||||
"outDir": "dist",
|
|
||||||
"resolveJsonModule": true,
|
|
||||||
"sourceMap": true,
|
|
||||||
"strictNullChecks": true,
|
|
||||||
"target": "es6"
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"./src/**/*"
|
|
||||||
],
|
|
||||||
"exclude": [
|
|
||||||
"./src/**/*.test.js",
|
|
||||||
"node_modules",
|
|
||||||
"**/node_modules"
|
|
||||||
]
|
|
||||||
}
|
|
Loading…
Reference in New Issue