wip - margin trade with orca

This commit is contained in:
tjs 2022-05-24 14:10:01 -04:00
parent e7d5b7cff9
commit d4097e5fc2
3 changed files with 2752 additions and 0 deletions

59
ts/client/package.json Normal file
View File

@ -0,0 +1,59 @@
{
"name": "@blockworks-foundation/mango-client",
"version": "0.1.0",
"description": "Typescript Client for mango-v4 program.",
"main": "lib/src/index.js",
"types": "lib/src/index.d.ts",
"repository": "https://github.com/blockworks-foundation/mango-v4",
"scripts": {
"build": "tsc",
"clean": "rm -rf dist",
"example1-user": "ts-node src/scripts/example1-user.ts",
"example1-admin": "ts-node src/scripts/example1-admin.ts",
"format": "prettier --check .",
"lint": "eslint . --ext ts --ext tsx --ext js --quiet",
"type-check": "tsc --pretty --noEmit"
},
"author": {
"name": "Blockworks Foundation",
"email": "hello@blockworks.foundation",
"url": "https://blockworks.foundation"
},
"devDependencies": {
"@tsconfig/recommended": "^1.0.1",
"@types/chai": "^4.3.0",
"@types/mocha": "^9.1.0",
"@types/node": "^14.14.37",
"@typescript-eslint/eslint-plugin": "^4.14.2",
"@typescript-eslint/parser": "^4.14.2",
"chai": "^4.3.4",
"eslint": "^7.28.0",
"eslint-config-prettier": "^7.2.0",
"mocha": "^9.1.3",
"prettier": "^2.0.5",
"ts-mocha": "^8.0.0",
"ts-node": "^9.1.1",
"typedoc": "^0.22.5",
"typescript": "^4.4.4"
},
"publishConfig": {
"access": "public"
},
"prettier": {
"singleQuote": true,
"trailingComma": "all"
},
"dependencies": {
"@orca-so/sdk": "^1.2.24",
"@project-serum/anchor": "^0.24.2",
"@project-serum/serum": "^0.13.65",
"@solana/spl-token": "^0.2.0",
"@types/bs58": "^4.0.1",
"big.js": "^6.1.1",
"bs58": "^5.0.0"
},
"resolutions": {
"@solana/spl-token": "^0.2.0"
},
"license": "MIT"
}

View File

@ -2,6 +2,8 @@ import { AnchorProvider, BN, Program, Provider } from '@project-serum/anchor';
import { getFeeRates, getFeeTier, Market } from '@project-serum/serum';
import { Order } from '@project-serum/serum/lib/market';
import * as spl from '@solana/spl-token';
import { TokenSwap } from '@solana/spl-token-swap';
import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
import {
AccountMeta,
Keypair,
@ -12,6 +14,9 @@ import {
TransactionSignature,
} from '@solana/web3.js';
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 { Group } from './accounts/group';
import { I80F48 } from './accounts/I80F48';
@ -803,6 +808,72 @@ export class MangoClient {
.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 healthRemainingAccounts: PublicKey[] =
await this.buildHealthRemainingAccounts(group, mangoAccount);
const parsedHealthAccounts = healthRemainingAccounts.map(
(pk) =>
({
pubkey: pk,
isWritable: false,
isSigner: false,
} as AccountMeta),
);
const inputBank = group.banksMap.get(inputToken);
const outputBank = group.banksMap.get(outputToken);
if (!inputBank || !outputBank) throw new Error('Invalid token');
const targetProgramId = ORCA_TOKEN_SWAP_ID_DEVNET;
const instruction = await this.buildOrcaInstruction(
targetProgramId,
inputBank,
outputBank,
amountIn, // todo: convert to u64?
minimumAmountOut, // todo: convert to u64?
);
const targetRemainingAccounts = instruction.keys;
const withdraws = []; // todo:
const cpiData = instruction.data; // todo: is it just 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,
])
.rpc();
}
/// static
static connect(provider?: Provider, devnet?: boolean): MangoClient {
@ -871,4 +942,45 @@ export class MangoClient {
return healthRemainingAccounts;
}
private async buildOrcaInstruction(
orcaTokenSwapId,
inputBank,
outputBank,
amountInU64,
minimumAmountOutU64,
) {
const poolParams = orcaDevnetPoolConfigs[OrcaDevnetPoolConfig.SOL_USDC];
const [authorityForPoolAddress] = await PublicKey.findProgramAddress(
[poolParams.address.toBuffer()],
orcaTokenSwapId,
);
const userTransferAuthority = new Keypair();
/*
Orca 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
*/
const swapInstruction = TokenSwap.swapInstruction(
poolParams.address,
authorityForPoolAddress,
userTransferAuthority.publicKey, // what is this?
inputBank.vault, // inputTokenUserAddress
inputBank.mint, // inputToken.addr
outputBank.mint, // outputToken.addr
outputBank.vault, // outputTokenUserAddress
poolParams.poolTokenMint,
poolParams.feeAccount,
null, // hostFeeAccount
orcaTokenSwapId,
TOKEN_PROGRAM_ID,
amountInU64,
minimumAmountOutU64,
);
return swapInstruction;
}
}

2581
ts/client/yarn.lock Normal file

File diff suppressed because it is too large Load Diff