Merge remote-tracking branch 'origin/deploy' into dev
This commit is contained in:
commit
0aabd28cdc
|
@ -8262,14 +8262,28 @@
|
|||
},
|
||||
{
|
||||
"name": "changeAmount",
|
||||
"docs": [
|
||||
"The amount by which the user's token position changed at the end",
|
||||
"",
|
||||
"So if the user repaid the approved_amount in full, it'd be 0.",
|
||||
"",
|
||||
"Does NOT include the loan_origination_fee or deposit_fee, so the true",
|
||||
"change is `change_amount - loan_origination_fee - deposit_fee`."
|
||||
],
|
||||
"type": "i128"
|
||||
},
|
||||
{
|
||||
"name": "loan",
|
||||
"docs": [
|
||||
"The amount that was a loan (<= approved_amount, depends on user's deposits)"
|
||||
],
|
||||
"type": "i128"
|
||||
},
|
||||
{
|
||||
"name": "loanOriginationFee",
|
||||
"docs": [
|
||||
"The fee paid on the loan, not included in `loan` or `change_amount`"
|
||||
],
|
||||
"type": "i128"
|
||||
},
|
||||
{
|
||||
|
@ -8286,7 +8300,19 @@
|
|||
},
|
||||
{
|
||||
"name": "depositFee",
|
||||
"docs": [
|
||||
"Deposit fee paid for positive change_amount.",
|
||||
"",
|
||||
"Not factored into change_amount."
|
||||
],
|
||||
"type": "i128"
|
||||
},
|
||||
{
|
||||
"name": "approvedAmount",
|
||||
"docs": [
|
||||
"The amount that was transfered out to the user"
|
||||
],
|
||||
"type": "u64"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@blockworks-foundation/mango-v4",
|
||||
"version": "0.18.14",
|
||||
"version": "0.19.14",
|
||||
"description": "Typescript Client for mango-v4 program.",
|
||||
"repository": "https://github.com/blockworks-foundation/mango-v4",
|
||||
"author": {
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
"mint": "So11111111111111111111111111111111111111112",
|
||||
"tokenIndex": 5,
|
||||
"bankNum": 0,
|
||||
"active": true
|
||||
"active": true,
|
||||
"decimals": 99999
|
||||
},
|
||||
{
|
||||
"name": "USDT",
|
||||
|
@ -21,7 +22,8 @@
|
|||
"mint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB",
|
||||
"tokenIndex": 1,
|
||||
"bankNum": 0,
|
||||
"active": true
|
||||
"active": true,
|
||||
"decimals": 99999
|
||||
},
|
||||
{
|
||||
"name": "USDC",
|
||||
|
@ -29,7 +31,8 @@
|
|||
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
|
||||
"tokenIndex": 0,
|
||||
"bankNum": 0,
|
||||
"active": true
|
||||
"active": true,
|
||||
"decimals": 99999
|
||||
},
|
||||
{
|
||||
"name": "BTC",
|
||||
|
@ -37,7 +40,8 @@
|
|||
"mint": "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E",
|
||||
"tokenIndex": 2,
|
||||
"bankNum": 0,
|
||||
"active": true
|
||||
"active": true,
|
||||
"decimals": 99999
|
||||
},
|
||||
{
|
||||
"name": "soETH",
|
||||
|
@ -45,7 +49,8 @@
|
|||
"mint": "2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk",
|
||||
"tokenIndex": 4,
|
||||
"bankNum": 0,
|
||||
"active": true
|
||||
"active": true,
|
||||
"decimals": 99999
|
||||
},
|
||||
{
|
||||
"name": "ETH",
|
||||
|
@ -53,7 +58,8 @@
|
|||
"mint": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs",
|
||||
"tokenIndex": 3,
|
||||
"bankNum": 0,
|
||||
"active": true
|
||||
"active": true,
|
||||
"decimals": 99999
|
||||
},
|
||||
{
|
||||
"name": "MSOL",
|
||||
|
@ -61,7 +67,8 @@
|
|||
"mint": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So",
|
||||
"tokenIndex": 6,
|
||||
"bankNum": 0,
|
||||
"active": true
|
||||
"active": true,
|
||||
"decimals": 99999
|
||||
}
|
||||
],
|
||||
"stubOracles": [
|
||||
|
|
|
@ -662,7 +662,7 @@ async function createAndPopulateAlt() {
|
|||
);
|
||||
|
||||
console.log(`ALT: set at index 0 for group...`);
|
||||
sig = await client.altSet(group, createIx[1], 0);
|
||||
sig = (await client.altSet(group, createIx[1], 0)).signature;
|
||||
console.log(`...https://explorer.solana.com/tx/${sig}`);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
|
|
@ -0,0 +1,245 @@
|
|||
import { AnchorProvider, Wallet } from '@coral-xyz/anchor';
|
||||
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
|
||||
import fs from 'fs';
|
||||
import { TokenIndex } from '../src/accounts/bank';
|
||||
import { Group } from '../src/accounts/group';
|
||||
import { MangoClient } from '../src/client';
|
||||
import { DefaultTokenRegisterParams } from '../src/clientIxParamBuilder';
|
||||
import { MANGO_V4_ID } from '../src/constants';
|
||||
import { toNative } from '../src/utils';
|
||||
|
||||
const MAINNET_MINTS = new Map([
|
||||
['USDC', 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'], // 0
|
||||
['SOL', 'So11111111111111111111111111111111111111112'], // 1
|
||||
]);
|
||||
const MAINNET_ORACLES = new Map([
|
||||
['USDC', 'Gnt27xtC473ZT2Mw5u8wZ68Z3gULkSTb5DuxJy7eJotD'],
|
||||
['SOL', 'H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG'],
|
||||
]);
|
||||
const MAINNET_SERUM3_MARKETS = new Map([
|
||||
['SOL/USDC', '8BnEgHoWFysVcuFFX7QztDmzuH8r5ZFvyP3sYwn1XTh6'],
|
||||
]);
|
||||
const {
|
||||
MB_CLUSTER_URL,
|
||||
MB_PAYER_KEYPAIR,
|
||||
GROUP_NUM,
|
||||
}: {
|
||||
MB_CLUSTER_URL: string;
|
||||
MB_PAYER_KEYPAIR: string;
|
||||
GROUP_NUM: number;
|
||||
} = process.env as any;
|
||||
|
||||
const defaultOracleConfig = {
|
||||
confFilter: 0.1,
|
||||
maxStalenessSlots: null,
|
||||
};
|
||||
|
||||
const defaultInterestRate = {
|
||||
adjustmentFactor: 0.0,
|
||||
util0: 0.0,
|
||||
rate0: 0.0,
|
||||
util1: 0.0,
|
||||
rate1: 0.0,
|
||||
maxRate: 0.51,
|
||||
};
|
||||
|
||||
const defaultTokenParams = {
|
||||
...DefaultTokenRegisterParams,
|
||||
oracleConfig: defaultOracleConfig,
|
||||
interestRateParams: defaultInterestRate,
|
||||
loanOriginationFeeRate: 0.0,
|
||||
loanFeeRate: 0.0,
|
||||
initAssetWeight: 0,
|
||||
maintAssetWeight: 0,
|
||||
initLiabWeight: 1,
|
||||
maintLiabWeight: 1,
|
||||
liquidationFee: 0,
|
||||
minVaultToDepositsRatio: 1,
|
||||
netBorrowLimitPerWindowQuote: 0,
|
||||
};
|
||||
|
||||
async function buildAdminClient(): Promise<[MangoClient, Keypair]> {
|
||||
const admin = Keypair.fromSecretKey(
|
||||
Buffer.from(JSON.parse(fs.readFileSync(MB_PAYER_KEYPAIR!, 'utf-8'))),
|
||||
);
|
||||
const options = AnchorProvider.defaultOptions();
|
||||
const connection = new Connection(MB_CLUSTER_URL!, options);
|
||||
const adminWallet = new Wallet(admin);
|
||||
const adminProvider = new AnchorProvider(connection, adminWallet, options);
|
||||
const client = await MangoClient.connect(
|
||||
adminProvider,
|
||||
'mainnet-beta',
|
||||
MANGO_V4_ID['mainnet-beta'],
|
||||
{
|
||||
idsSource: 'get-program-accounts',
|
||||
},
|
||||
);
|
||||
return [client, admin];
|
||||
}
|
||||
|
||||
async function buildUserClient(): Promise<[MangoClient, Group, Keypair]> {
|
||||
const options = AnchorProvider.defaultOptions();
|
||||
const connection = new Connection(MB_CLUSTER_URL!, options);
|
||||
|
||||
const user = Keypair.fromSecretKey(
|
||||
Buffer.from(JSON.parse(fs.readFileSync(MB_PAYER_KEYPAIR, 'utf-8'))),
|
||||
);
|
||||
const userWallet = new Wallet(user);
|
||||
const userProvider = new AnchorProvider(connection, userWallet, options);
|
||||
|
||||
const client = await MangoClient.connect(
|
||||
userProvider,
|
||||
'mainnet-beta',
|
||||
MANGO_V4_ID['mainnet-beta'],
|
||||
);
|
||||
const group = await client.getGroupForCreator(user.publicKey, GROUP_NUM);
|
||||
return [client, group, user];
|
||||
}
|
||||
|
||||
async function createGroup(): Promise<void> {
|
||||
const result = await buildAdminClient();
|
||||
const client = result[0];
|
||||
const admin = result[1];
|
||||
|
||||
const insuranceMint = new PublicKey(MAINNET_MINTS.get('USDC')!);
|
||||
await client.groupCreate(GROUP_NUM, false, 2, insuranceMint);
|
||||
const group = await client.getGroupForCreator(admin.publicKey, GROUP_NUM);
|
||||
console.log(`...registered group ${group.publicKey}`);
|
||||
}
|
||||
|
||||
async function registerTokens(): Promise<void> {
|
||||
const result = await buildAdminClient();
|
||||
const client = result[0];
|
||||
const admin = result[1];
|
||||
|
||||
const group = await client.getGroupForCreator(admin.publicKey, GROUP_NUM);
|
||||
|
||||
const usdcMainnetMint = new PublicKey(MAINNET_MINTS.get('USDC')!);
|
||||
const usdcMainnetOracle = new PublicKey(MAINNET_ORACLES.get('USDC')!);
|
||||
let sig = await client.tokenRegister(
|
||||
group,
|
||||
usdcMainnetMint,
|
||||
usdcMainnetOracle,
|
||||
0,
|
||||
'USDC',
|
||||
defaultTokenParams,
|
||||
);
|
||||
console.log(`registered usdc ${sig}`);
|
||||
|
||||
const solMainnetMint = new PublicKey(MAINNET_MINTS.get('SOL')!);
|
||||
const solMainnetOracle = new PublicKey(MAINNET_ORACLES.get('SOL')!);
|
||||
sig = await client.tokenRegister(
|
||||
group,
|
||||
solMainnetMint,
|
||||
solMainnetOracle,
|
||||
1,
|
||||
'SOL',
|
||||
defaultTokenParams,
|
||||
);
|
||||
console.log(`registered sol ${sig}`);
|
||||
}
|
||||
|
||||
async function registerSerum3Market(): Promise<void> {
|
||||
const result = await buildAdminClient();
|
||||
const client = result[0];
|
||||
const admin = result[1];
|
||||
|
||||
const group = await client.getGroupForCreator(admin.publicKey, GROUP_NUM);
|
||||
await client.serum3RegisterMarket(
|
||||
group,
|
||||
new PublicKey(MAINNET_SERUM3_MARKETS.get('SOL/USDC')!),
|
||||
group.getFirstBankByTokenIndex(1 as TokenIndex),
|
||||
group.getFirstBankByTokenIndex(0 as TokenIndex),
|
||||
0,
|
||||
'SOL/USDC',
|
||||
);
|
||||
}
|
||||
|
||||
async function doUserAction(): Promise<void> {
|
||||
const result = await buildUserClient();
|
||||
const client = result[0];
|
||||
const group = result[1];
|
||||
const user = result[2];
|
||||
|
||||
let mangoAccount = await client.getMangoAccountForOwner(
|
||||
group,
|
||||
user.publicKey,
|
||||
0,
|
||||
);
|
||||
|
||||
if (!mangoAccount) {
|
||||
await client.createMangoAccount(group, 0);
|
||||
mangoAccount = await client.getMangoAccountForOwner(
|
||||
group,
|
||||
user.publicKey,
|
||||
0,
|
||||
);
|
||||
}
|
||||
|
||||
// await client.tokenDeposit(
|
||||
// group,
|
||||
// mangoAccount!,
|
||||
// new PublicKey(MAINNET_MINTS.get('SOL')!),
|
||||
// 0.01,
|
||||
// );
|
||||
|
||||
// await client.tcsStopLossOnDeposit(
|
||||
// group,
|
||||
// mangoAccount!,
|
||||
// group.getFirstBankByTokenIndex(1 as TokenIndex),
|
||||
// group.getFirstBankByTokenIndex(0 as TokenIndex),
|
||||
// group.getFirstBankByTokenIndex(1 as TokenIndex).uiPrice * 1.1,
|
||||
// false,
|
||||
// null,
|
||||
// null,
|
||||
// null,
|
||||
// );
|
||||
|
||||
await mangoAccount?.reload(client);
|
||||
mangoAccount
|
||||
?.tokenConditionalSwapsActive()
|
||||
.map((tcs) => console.log(tcs.toString(group)));
|
||||
}
|
||||
|
||||
async function doUserAction2(): Promise<void> {
|
||||
const result = await buildUserClient();
|
||||
const client = result[0];
|
||||
const group = result[1];
|
||||
const user = result[2];
|
||||
|
||||
let mangoAccount = await client.getMangoAccountForOwner(
|
||||
group,
|
||||
user.publicKey,
|
||||
1,
|
||||
);
|
||||
|
||||
if (!mangoAccount) {
|
||||
await client.createMangoAccount(group, 1);
|
||||
mangoAccount = await client.getMangoAccountForOwner(
|
||||
group,
|
||||
user.publicKey,
|
||||
1,
|
||||
);
|
||||
}
|
||||
|
||||
await client.tokenDeposit(
|
||||
group,
|
||||
mangoAccount!,
|
||||
new PublicKey(MAINNET_MINTS.get('USDC')!),
|
||||
5,
|
||||
);
|
||||
}
|
||||
|
||||
async function main(): Promise<void> {
|
||||
try {
|
||||
// await createGroup();
|
||||
// await registerTokens();
|
||||
// await registerSerum3Market();
|
||||
await doUserAction();
|
||||
// await doUserAction2();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
|
@ -0,0 +1,72 @@
|
|||
import { PublicKey } from '@solana/web3.js';
|
||||
import { Group } from '../src/accounts/group';
|
||||
import { isSwitchboardOracle } from '../src/accounts/oracle';
|
||||
import { MangoClient } from '../src/client';
|
||||
import { buildFetch } from '../src/utils';
|
||||
|
||||
function getNameForBank(group: Group, oracle: PublicKey): string {
|
||||
let match: any[] = Array.from(group.banksMapByName.values())
|
||||
.flat()
|
||||
.filter((b) => b.oracle.equals(oracle));
|
||||
if (match.length > 0) {
|
||||
return match[0].name;
|
||||
}
|
||||
|
||||
match = Array.from(group.perpMarketsMapByName.values()).filter((p) =>
|
||||
p.oracle.equals(oracle),
|
||||
);
|
||||
if (match.length > 0) {
|
||||
return match[0].name;
|
||||
}
|
||||
|
||||
throw new Error(`No token or perp market found for ${oracle}`);
|
||||
}
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const client = await MangoClient.connectDefault(process.env.MB_CLUSTER_URL!);
|
||||
const group = await client.getGroup(
|
||||
new PublicKey('78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX'),
|
||||
);
|
||||
|
||||
const oracles1 = Array.from(group.banksMapByName.values()).map(
|
||||
(b) => b[0].oracle,
|
||||
);
|
||||
const oracles2 = Array.from(group.perpMarketsMapByName.values()).map(
|
||||
(p) => p.oracle,
|
||||
);
|
||||
const oracles = oracles1.concat(oracles2);
|
||||
|
||||
const ais = await client.program.provider.connection.getMultipleAccountsInfo(
|
||||
oracles,
|
||||
);
|
||||
|
||||
const switcboardOracles: PublicKey[] = ais
|
||||
.map((ai, i) => [isSwitchboardOracle(ai!), oracles[i]])
|
||||
.filter((r) => r[0])
|
||||
.map((r) => r[1]) as PublicKey[];
|
||||
|
||||
for (const o of switcboardOracles) {
|
||||
const r = await (
|
||||
await buildFetch()
|
||||
)('https://stats.switchboard.xyz/logs', {
|
||||
headers: {
|
||||
accept: '*/*',
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
body: `{"cluster":"solana-mainnet","query":"${o.toString()}","number":100,"severity":"INFO"}`,
|
||||
method: 'POST',
|
||||
});
|
||||
|
||||
console.log(`${getNameForBank(group, o)} ${o}`);
|
||||
|
||||
(await r.json()).forEach((e: { message: string; timestamp: string }) => {
|
||||
if (e.message.toLowerCase().includes('error')) {
|
||||
console.log(`${e.timestamp}: ${e.message}`);
|
||||
}
|
||||
});
|
||||
|
||||
console.log(``);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
|
@ -138,7 +138,7 @@ export class Group {
|
|||
),
|
||||
this.reloadMintInfos(client, ids),
|
||||
this.reloadSerum3Markets(client, ids).then(() =>
|
||||
this.reloadSerum3ExternalMarkets(client),
|
||||
this.reloadSerum3ExternalMarkets(client, ids),
|
||||
),
|
||||
]);
|
||||
// console.timeEnd('group.reload');
|
||||
|
@ -274,23 +274,63 @@ export class Group {
|
|||
);
|
||||
}
|
||||
|
||||
public async reloadSerum3ExternalMarkets(client: MangoClient): Promise<void> {
|
||||
const externalMarkets = await Promise.all(
|
||||
Array.from(this.serum3MarketsMapByExternal.values()).map((serum3Market) =>
|
||||
Market.load(
|
||||
client.program.provider.connection,
|
||||
serum3Market.serumMarketExternal,
|
||||
{ commitment: client.program.provider.connection.commitment },
|
||||
OPENBOOK_PROGRAM_ID[client.cluster],
|
||||
public async reloadSerum3ExternalMarkets(
|
||||
client: MangoClient,
|
||||
ids?: Id,
|
||||
): Promise<void> {
|
||||
let markets: Market[] = [];
|
||||
const externalMarketIds = ids?.getSerum3ExternalMarkets();
|
||||
|
||||
if (ids && externalMarketIds && externalMarketIds.length) {
|
||||
markets = await Promise.all(
|
||||
(
|
||||
await client.program.provider.connection.getMultipleAccountsInfo(
|
||||
externalMarketIds,
|
||||
)
|
||||
).map(
|
||||
(account, index) =>
|
||||
new Market(
|
||||
Market.getLayout(OPENBOOK_PROGRAM_ID[client.cluster]).decode(
|
||||
account?.data,
|
||||
),
|
||||
ids.banks.find(
|
||||
(b) =>
|
||||
b.tokenIndex ===
|
||||
this.serum3MarketsMapByExternal.get(
|
||||
externalMarketIds[index].toString(),
|
||||
)?.baseTokenIndex,
|
||||
)?.decimals || 6,
|
||||
ids.banks.find(
|
||||
(b) =>
|
||||
b.tokenIndex ===
|
||||
this.serum3MarketsMapByExternal.get(
|
||||
externalMarketIds[index].toString(),
|
||||
)?.quoteTokenIndex,
|
||||
)?.decimals || 6,
|
||||
{ commitment: client.program.provider.connection.commitment },
|
||||
OPENBOOK_PROGRAM_ID[client.cluster],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
);
|
||||
} else {
|
||||
markets = await Promise.all(
|
||||
Array.from(this.serum3MarketsMapByExternal.values()).map(
|
||||
(serum3Market) =>
|
||||
Market.load(
|
||||
client.program.provider.connection,
|
||||
serum3Market.serumMarketExternal,
|
||||
{ commitment: client.program.provider.connection.commitment },
|
||||
OPENBOOK_PROGRAM_ID[client.cluster],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
this.serum3ExternalMarketsMap = new Map(
|
||||
Array.from(this.serum3MarketsMapByExternal.values()).map(
|
||||
(serum3Market, index) => [
|
||||
serum3Market.serumMarketExternal.toBase58(),
|
||||
externalMarkets[index],
|
||||
markets[index],
|
||||
],
|
||||
),
|
||||
);
|
||||
|
@ -463,7 +503,6 @@ export class Group {
|
|||
await client.program.provider.connection.getMultipleAccountsInfo(
|
||||
vaultPks,
|
||||
);
|
||||
const coder = new BorshAccountsCoder(client.program.idl);
|
||||
this.vaultAmountsMap = new Map(
|
||||
vaultAccounts.map((vaultAi, i) => {
|
||||
if (!vaultAi) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { AnchorProvider, BN } from '@coral-xyz/anchor';
|
||||
import { utf8 } from '@coral-xyz/anchor/dist/cjs/utils/bytes';
|
||||
import { OpenOrders, Order, Orderbook } from '@project-serum/serum/lib/market';
|
||||
import { AccountInfo, PublicKey, TransactionSignature } from '@solana/web3.js';
|
||||
import { AccountInfo, PublicKey } from '@solana/web3.js';
|
||||
import { MangoClient } from '../client';
|
||||
import { OPENBOOK_PROGRAM_ID, RUST_I64_MAX, RUST_I64_MIN } from '../constants';
|
||||
import { I80F48, I80F48Dto, ONE_I80F48, ZERO_I80F48 } from '../numbers/I80F48';
|
||||
|
@ -13,6 +13,7 @@ import {
|
|||
toUiDecimalsForQuote,
|
||||
toUiSellPerBuyTokenPrice,
|
||||
} from '../utils';
|
||||
import { MangoSignatureStatus } from '../utils/rpc';
|
||||
import { Bank, TokenIndex } from './bank';
|
||||
import { Group } from './group';
|
||||
import { HealthCache } from './healthCache';
|
||||
|
@ -888,7 +889,7 @@ export class MangoAccount {
|
|||
public async serum3SettleFundsForAllMarkets(
|
||||
client: MangoClient,
|
||||
group: Group,
|
||||
): Promise<TransactionSignature[]> {
|
||||
): Promise<MangoSignatureStatus[]> {
|
||||
// Future: collect ixs, batch them, and send them in fewer txs
|
||||
return await Promise.all(
|
||||
this.serum3Active().map((s) => {
|
||||
|
@ -906,7 +907,7 @@ export class MangoAccount {
|
|||
public async serum3CancelAllOrdersForAllMarkets(
|
||||
client: MangoClient,
|
||||
group: Group,
|
||||
): Promise<TransactionSignature[]> {
|
||||
): Promise<MangoSignatureStatus[]> {
|
||||
// Future: collect ixs, batch them, and send them in in fewer txs
|
||||
return await Promise.all(
|
||||
this.serum3Active().map((s) => {
|
||||
|
@ -1874,6 +1875,26 @@ export class TokenConditionalSwap {
|
|||
return this.expiryTimestamp.toNumber();
|
||||
}
|
||||
|
||||
// TODO: will be replaced by onchain enum in next release
|
||||
private getTokenConditionalSwapDisplayPriceStyle(group: Group): boolean {
|
||||
const buyBank = this.getBuyToken(group);
|
||||
const sellBank = this.getSellToken(group);
|
||||
|
||||
// If we are tp/sl'ing SOL borrow, then price is stored in sol/usdc
|
||||
// then don't flip
|
||||
if (sellBank.tokenIndex == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// E.g.
|
||||
// If we are tp/sl'ing SOL deposit, then price is stored in usdc/sol
|
||||
if (this.maxSell.eq(U64_MAX_BN)) {
|
||||
true; // dont flip, i.e. continue using sellTokenPerBuyTokenUi price
|
||||
}
|
||||
// Flip the price if we know we are selling an exact amount of SOL
|
||||
return false; // flip, i.e. use buyTokenPerSellTokenUi price
|
||||
}
|
||||
|
||||
private priceLimitToUi(
|
||||
group: Group,
|
||||
sellTokenPerBuyTokenNative: number,
|
||||
|
@ -1891,7 +1912,7 @@ export class TokenConditionalSwap {
|
|||
// buytoken/selltoken or selltoken/buytoken
|
||||
|
||||
// Buy limit / close short
|
||||
if (this.maxSell.eq(U64_MAX_BN)) {
|
||||
if (this.getTokenConditionalSwapDisplayPriceStyle(group)) {
|
||||
return roundTo5(sellTokenPerBuyTokenUi);
|
||||
}
|
||||
|
||||
|
@ -1909,20 +1930,44 @@ export class TokenConditionalSwap {
|
|||
}
|
||||
|
||||
getThresholdPriceUi(group: Group): number {
|
||||
const a = I80F48.fromNumber(this.priceLowerLimit);
|
||||
const b = I80F48.fromNumber(this.priceUpperLimit);
|
||||
|
||||
const buyBank = this.getBuyToken(group);
|
||||
const sellBank = this.getSellToken(group);
|
||||
const o = buyBank.price.div(sellBank.price);
|
||||
|
||||
const a = toUiSellPerBuyTokenPrice(this.priceLowerLimit, sellBank, buyBank);
|
||||
const b = toUiSellPerBuyTokenPrice(this.priceUpperLimit, sellBank, buyBank);
|
||||
|
||||
const o = buyBank.uiPrice / sellBank.uiPrice;
|
||||
|
||||
// Choose the price closest to oracle
|
||||
if (o.sub(a).abs().lt(o.sub(b).abs())) {
|
||||
if (Math.abs(o - a) < Math.abs(o - b)) {
|
||||
return this.getPriceLowerLimitUi(group);
|
||||
}
|
||||
return this.getPriceUpperLimitUi(group);
|
||||
}
|
||||
|
||||
getCurrentPairPriceUi(group: Group): number {
|
||||
const buyBank = this.getBuyToken(group);
|
||||
const sellBank = this.getSellToken(group);
|
||||
const sellTokenPerBuyTokenUi = toUiSellPerBuyTokenPrice(
|
||||
buyBank.price.div(sellBank.price).toNumber(),
|
||||
sellBank,
|
||||
buyBank,
|
||||
);
|
||||
|
||||
// Below are workarounds to know when to show an inverted price in ui
|
||||
// We want to identify if the pair user is wanting to trade is
|
||||
// buytoken/selltoken or selltoken/buytoken
|
||||
|
||||
// Buy limit / close short
|
||||
if (this.getTokenConditionalSwapDisplayPriceStyle(group)) {
|
||||
return roundTo5(sellTokenPerBuyTokenUi);
|
||||
}
|
||||
|
||||
// Stop loss / take profit
|
||||
const buyTokenPerSellTokenUi = 1 / sellTokenPerBuyTokenUi;
|
||||
return roundTo5(buyTokenPerSellTokenUi);
|
||||
}
|
||||
|
||||
// in percent
|
||||
getPricePremium(): number {
|
||||
return this.pricePremiumRate * 100;
|
||||
|
@ -1945,16 +1990,20 @@ export class TokenConditionalSwap {
|
|||
}
|
||||
|
||||
toString(group: Group): string {
|
||||
return `getMaxBuy ${this.getMaxBuyUi(
|
||||
return `${
|
||||
group.getFirstBankByTokenIndex(this.buyTokenIndex).name +
|
||||
'/' +
|
||||
group.getFirstBankByTokenIndex(this.sellTokenIndex).name
|
||||
} , getMaxBuy ${this.getMaxBuyUi(group)}, getMaxSell ${this.getMaxSellUi(
|
||||
group,
|
||||
)}, getMaxSell ${this.getMaxSellUi(group)}, bought ${this.getBoughtUi(
|
||||
group,
|
||||
)}, sold ${this.getSoldUi(
|
||||
)}, bought ${this.getBoughtUi(group)}, sold ${this.getSoldUi(
|
||||
group,
|
||||
)}, getPriceLowerLimitUi ${this.getPriceLowerLimitUi(
|
||||
group,
|
||||
)}, getPriceUpperLimitUi ${this.getPriceUpperLimitUi(
|
||||
group,
|
||||
)}, getCurrentPairPriceUi ${this.getCurrentPairPriceUi(
|
||||
group,
|
||||
)}, getThresholdPriceUi ${this.getThresholdPriceUi(
|
||||
group,
|
||||
)}, getPricePremium ${this.getPricePremium()}, expiry ${this.expiryTimestamp.toString()}`;
|
||||
|
|
|
@ -408,6 +408,13 @@ export class PerpMarket {
|
|||
return funding;
|
||||
}
|
||||
|
||||
public getInstantaneousFundingRatePerSecond(
|
||||
bids: BookSide,
|
||||
asks: BookSide,
|
||||
): number {
|
||||
return this.getInstantaneousFundingRate(bids, asks) / (24 * 60 * 60);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Returns instantaneous funding rate for the day. How is it actually applied - funding is
|
||||
|
|
|
@ -90,7 +90,7 @@ import {
|
|||
toNative,
|
||||
toNativeSellPerBuyTokenPrice,
|
||||
} from './utils';
|
||||
import { sendTransaction } from './utils/rpc';
|
||||
import { MangoSignatureStatus, sendTransaction } from './utils/rpc';
|
||||
import { NATIVE_MINT, TOKEN_PROGRAM_ID } from './utils/spl';
|
||||
|
||||
export const DEFAULT_TOKEN_CONDITIONAL_SWAP_COUNT = 8;
|
||||
|
@ -109,6 +109,7 @@ export type MangoClientOptions = {
|
|||
estimateFee?: boolean;
|
||||
txConfirmationCommitment?: Commitment;
|
||||
openbookFeesToDao?: boolean;
|
||||
prependedGlobalAdditionalInstructions?: TransactionInstruction[];
|
||||
};
|
||||
|
||||
export class MangoClient {
|
||||
|
@ -118,6 +119,7 @@ export class MangoClient {
|
|||
private estimateFee: boolean;
|
||||
private txConfirmationCommitment: Commitment;
|
||||
private openbookFeesToDao: boolean;
|
||||
private prependedGlobalAdditionalInstructions: TransactionInstruction[] = [];
|
||||
|
||||
constructor(
|
||||
public program: Program<MangoV4>,
|
||||
|
@ -130,6 +132,8 @@ export class MangoClient {
|
|||
this.estimateFee = opts?.estimateFee || false;
|
||||
this.postSendTxCallback = opts?.postSendTxCallback;
|
||||
this.openbookFeesToDao = opts?.openbookFeesToDao ?? true;
|
||||
this.prependedGlobalAdditionalInstructions =
|
||||
opts.prependedGlobalAdditionalInstructions ?? [];
|
||||
this.txConfirmationCommitment =
|
||||
opts?.txConfirmationCommitment ??
|
||||
(program.provider as AnchorProvider).opts.commitment ??
|
||||
|
@ -151,7 +155,7 @@ export class MangoClient {
|
|||
public async sendAndConfirmTransaction(
|
||||
ixs: TransactionInstruction[],
|
||||
opts: any = {},
|
||||
): Promise<string> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
let prioritizationFee: number;
|
||||
if (opts.prioritizationFee) {
|
||||
prioritizationFee = opts.prioritizationFee;
|
||||
|
@ -160,9 +164,9 @@ export class MangoClient {
|
|||
} else {
|
||||
prioritizationFee = this.prioritizationFee;
|
||||
}
|
||||
return await sendTransaction(
|
||||
const status = await sendTransaction(
|
||||
this.program.provider as AnchorProvider,
|
||||
ixs,
|
||||
[...this.prependedGlobalAdditionalInstructions, ...ixs],
|
||||
opts.alts ?? [],
|
||||
{
|
||||
postSendTxCallback: this.postSendTxCallback,
|
||||
|
@ -171,13 +175,14 @@ export class MangoClient {
|
|||
...opts,
|
||||
},
|
||||
);
|
||||
return status;
|
||||
}
|
||||
|
||||
private async sendAndConfirmTransactionForGroup(
|
||||
public async sendAndConfirmTransactionForGroup(
|
||||
group: Group,
|
||||
ixs: TransactionInstruction[],
|
||||
opts: any = {},
|
||||
): Promise<string> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
return await this.sendAndConfirmTransaction(ixs, {
|
||||
alts: group.addressLookupTablesList,
|
||||
...opts,
|
||||
|
@ -188,7 +193,7 @@ export class MangoClient {
|
|||
group: Group,
|
||||
bank: Bank,
|
||||
tokenAccountPk: PublicKey,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const admin = (this.program.provider as AnchorProvider).wallet.publicKey;
|
||||
const ix = await this.program.methods
|
||||
.adminTokenWithdrawFees()
|
||||
|
@ -207,7 +212,7 @@ export class MangoClient {
|
|||
group: Group,
|
||||
perpMarket: PerpMarket,
|
||||
tokenAccountPk: PublicKey,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const bank = group.getFirstBankByTokenIndex(perpMarket.settleTokenIndex);
|
||||
const admin = (this.program.provider as AnchorProvider).wallet.publicKey;
|
||||
const ix = await this.program.methods
|
||||
|
@ -230,7 +235,7 @@ export class MangoClient {
|
|||
testing: boolean,
|
||||
version: number,
|
||||
insuranceMintPk: PublicKey,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const adminPk = (this.program.provider as AnchorProvider).wallet.publicKey;
|
||||
const ix = await this.program.methods
|
||||
.groupCreate(groupNum, testing ? 1 : 0, version)
|
||||
|
@ -256,7 +261,7 @@ export class MangoClient {
|
|||
feesSwapMangoAccount?: PublicKey,
|
||||
feesMngoTokenIndex?: TokenIndex,
|
||||
feesExpiryInterval?: BN,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const ix = await this.program.methods
|
||||
.groupEdit(
|
||||
admin ?? null,
|
||||
|
@ -282,7 +287,7 @@ export class MangoClient {
|
|||
public async ixGateSet(
|
||||
group: Group,
|
||||
ixGateParams: IxGateParams,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const ix = await this.program.methods
|
||||
.ixGateSet(buildIxGate(ixGateParams))
|
||||
.accounts({
|
||||
|
@ -293,7 +298,7 @@ export class MangoClient {
|
|||
return await this.sendAndConfirmTransactionForGroup(group, [ix]);
|
||||
}
|
||||
|
||||
public async groupClose(group: Group): Promise<TransactionSignature> {
|
||||
public async groupClose(group: Group): Promise<MangoSignatureStatus> {
|
||||
const adminPk = (this.program.provider as AnchorProvider).wallet.publicKey;
|
||||
const ix = await this.program.methods
|
||||
.groupClose()
|
||||
|
@ -379,7 +384,7 @@ export class MangoClient {
|
|||
tokenIndex: number,
|
||||
name: string,
|
||||
params: TokenRegisterParams,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const ix = await this.program.methods
|
||||
.tokenRegister(
|
||||
tokenIndex,
|
||||
|
@ -424,7 +429,7 @@ export class MangoClient {
|
|||
oraclePk: PublicKey,
|
||||
tokenIndex: number,
|
||||
name: string,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const ix = await this.program.methods
|
||||
.tokenRegisterTrustless(tokenIndex, name)
|
||||
.accounts({
|
||||
|
@ -443,7 +448,7 @@ export class MangoClient {
|
|||
group: Group,
|
||||
mintPk: PublicKey,
|
||||
params: TokenEditParams,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const bank = group.getFirstBankByMint(mintPk);
|
||||
const mintInfo = group.mintInfosMapByTokenIndex.get(bank.tokenIndex)!;
|
||||
|
||||
|
@ -505,7 +510,7 @@ export class MangoClient {
|
|||
assetTokenIndex: TokenIndex,
|
||||
liabTokenIndex: TokenIndex,
|
||||
maxLiabTransfer?: number,
|
||||
): Promise<string> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const assetBank = group.getFirstBankByTokenIndex(assetTokenIndex);
|
||||
const liabBank = group.getFirstBankByTokenIndex(liabTokenIndex);
|
||||
const healthRemainingAccounts: PublicKey[] =
|
||||
|
@ -548,7 +553,7 @@ export class MangoClient {
|
|||
public async tokenDeregister(
|
||||
group: Group,
|
||||
mintPk: PublicKey,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const bank = group.getFirstBankByMint(mintPk);
|
||||
const adminPk = (this.program.provider as AnchorProvider).wallet.publicKey;
|
||||
|
||||
|
@ -652,7 +657,7 @@ export class MangoClient {
|
|||
group: Group,
|
||||
mintPk: PublicKey,
|
||||
price: number,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const ix = await this.program.methods
|
||||
.stubOracleCreate({ val: I80F48.fromNumber(price).getData() })
|
||||
.accounts({
|
||||
|
@ -668,7 +673,7 @@ export class MangoClient {
|
|||
public async stubOracleClose(
|
||||
group: Group,
|
||||
oracle: PublicKey,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const ix = await this.program.methods
|
||||
.stubOracleClose()
|
||||
.accounts({
|
||||
|
@ -685,7 +690,7 @@ export class MangoClient {
|
|||
group: Group,
|
||||
oraclePk: PublicKey,
|
||||
price: number,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const ix = await this.program.methods
|
||||
.stubOracleSet({ val: I80F48.fromNumber(price).getData() })
|
||||
.accounts({
|
||||
|
@ -734,7 +739,7 @@ export class MangoClient {
|
|||
serum3Count?: number,
|
||||
perpCount?: number,
|
||||
perpOoCount?: number,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const ix = await this.program.methods
|
||||
.accountCreate(
|
||||
accountNumber ?? 0,
|
||||
|
@ -761,7 +766,7 @@ export class MangoClient {
|
|||
serum3Count: number,
|
||||
perpCount: number,
|
||||
perpOoCount: number,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const ix = await this.program.methods
|
||||
.accountExpand(tokenCount, serum3Count, perpCount, perpOoCount)
|
||||
.accounts({
|
||||
|
@ -782,7 +787,7 @@ export class MangoClient {
|
|||
perpCount: number,
|
||||
perpOoCount: number,
|
||||
tokenConditionalSwapCount: number,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const ix = await this.accountExpandV2Ix(
|
||||
group,
|
||||
account,
|
||||
|
@ -828,7 +833,7 @@ export class MangoClient {
|
|||
delegate?: PublicKey,
|
||||
temporaryDelegate?: PublicKey,
|
||||
delegateExpiry?: number,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const ix = await this.program.methods
|
||||
.accountEdit(
|
||||
name ?? null,
|
||||
|
@ -849,7 +854,7 @@ export class MangoClient {
|
|||
public async computeAccountData(
|
||||
group: Group,
|
||||
mangoAccount: MangoAccount,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const healthRemainingAccounts: PublicKey[] =
|
||||
this.buildHealthRemainingAccounts(group, [mangoAccount], [], []);
|
||||
|
||||
|
@ -874,7 +879,7 @@ export class MangoClient {
|
|||
group: Group,
|
||||
mangoAccount: MangoAccount,
|
||||
freeze: boolean,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const ix = await this.program.methods
|
||||
.accountToggleFreeze(freeze)
|
||||
.accounts({
|
||||
|
@ -900,7 +905,7 @@ export class MangoClient {
|
|||
private async getMangoAccountFromPk(
|
||||
mangoAccountPk: PublicKey,
|
||||
): Promise<MangoAccount> {
|
||||
return await this.getMangoAccountFromAi(
|
||||
return this.getMangoAccountFromAi(
|
||||
mangoAccountPk,
|
||||
(await this.program.provider.connection.getAccountInfo(
|
||||
mangoAccountPk,
|
||||
|
@ -908,10 +913,10 @@ export class MangoClient {
|
|||
);
|
||||
}
|
||||
|
||||
public async getMangoAccountFromAi(
|
||||
public getMangoAccountFromAi(
|
||||
mangoAccountPk: PublicKey,
|
||||
ai: AccountInfo<Buffer>,
|
||||
): Promise<MangoAccount> {
|
||||
): MangoAccount {
|
||||
const decodedMangoAccount = this.program.coder.accounts.decode(
|
||||
'mangoAccount',
|
||||
ai.data,
|
||||
|
@ -1190,7 +1195,7 @@ export class MangoClient {
|
|||
group: Group,
|
||||
mangoAccount: MangoAccount,
|
||||
forceClose = false,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const ix = await this.program.methods
|
||||
.accountClose(forceClose)
|
||||
.accounts({
|
||||
|
@ -1207,7 +1212,7 @@ export class MangoClient {
|
|||
public async emptyAndCloseMangoAccount(
|
||||
group: Group,
|
||||
mangoAccount: MangoAccount,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
// Work on a deep cloned mango account, since we would deactivating positions
|
||||
// before deactivation reaches on-chain state in order to simplify building a fresh list
|
||||
// of healthRemainingAccounts to each subsequent ix
|
||||
|
@ -1292,7 +1297,7 @@ export class MangoClient {
|
|||
group: Group,
|
||||
mangoAccount: MangoAccount,
|
||||
maxBuyback?: number,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const ix = await this.accountBuybackFeesWithMngoIx(
|
||||
group,
|
||||
mangoAccount,
|
||||
|
@ -1307,7 +1312,7 @@ export class MangoClient {
|
|||
mintPk: PublicKey,
|
||||
amount: number,
|
||||
reduceOnly = false,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const decimals = group.getMintDecimals(mintPk);
|
||||
const nativeAmount = toNative(amount, decimals);
|
||||
return await this.tokenDepositNative(
|
||||
|
@ -1325,23 +1330,22 @@ export class MangoClient {
|
|||
mintPk: PublicKey,
|
||||
nativeAmount: BN,
|
||||
reduceOnly = false,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const bank = group.getFirstBankByMint(mintPk);
|
||||
|
||||
const tokenAccountPk = await getAssociatedTokenAddress(
|
||||
mintPk,
|
||||
mangoAccount.owner,
|
||||
true,
|
||||
);
|
||||
|
||||
let wrappedSolAccount: Keypair | undefined;
|
||||
let wrappedSolAccount: PublicKey | undefined;
|
||||
let preInstructions: TransactionInstruction[] = [];
|
||||
let postInstructions: TransactionInstruction[] = [];
|
||||
if (mintPk.equals(NATIVE_MINT)) {
|
||||
// Generate a random seed for wrappedSolAccount.
|
||||
const seed = Keypair.generate().publicKey.toBase58().slice(0, 32);
|
||||
// Calculate a publicKey that will be controlled by the `mangoAccount.owner`.
|
||||
const wrappedSolAccount = await PublicKey.createWithSeed(
|
||||
wrappedSolAccount = await PublicKey.createWithSeed(
|
||||
mangoAccount.owner,
|
||||
seed,
|
||||
TOKEN_PROGRAM_ID,
|
||||
|
@ -1386,7 +1390,7 @@ export class MangoClient {
|
|||
bank: bank.publicKey,
|
||||
vault: bank.vault,
|
||||
oracle: bank.oracle,
|
||||
tokenAccount: wrappedSolAccount?.publicKey ?? tokenAccountPk,
|
||||
tokenAccount: wrappedSolAccount ?? tokenAccountPk,
|
||||
tokenAuthority: mangoAccount.owner,
|
||||
})
|
||||
.remainingAccounts(
|
||||
|
@ -1410,7 +1414,7 @@ export class MangoClient {
|
|||
mintPk: PublicKey,
|
||||
amount: number,
|
||||
allowBorrow: boolean,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const nativeAmount = toNative(amount, group.getMintDecimals(mintPk));
|
||||
const ixes = await this.tokenWithdrawNativeIx(
|
||||
group,
|
||||
|
@ -1493,7 +1497,7 @@ export class MangoClient {
|
|||
mintPk: PublicKey,
|
||||
nativeAmount: BN,
|
||||
allowBorrow: boolean,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const ixs = await this.tokenWithdrawNativeIx(
|
||||
group,
|
||||
mangoAccount,
|
||||
|
@ -1513,7 +1517,7 @@ export class MangoClient {
|
|||
quoteBank: Bank,
|
||||
marketIndex: number,
|
||||
name: string,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const ix = await this.program.methods
|
||||
.serum3RegisterMarket(marketIndex, name)
|
||||
.accounts({
|
||||
|
@ -1535,7 +1539,7 @@ export class MangoClient {
|
|||
reduceOnly: boolean | null,
|
||||
forceClose: boolean | null,
|
||||
name: string | null,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const serum3Market =
|
||||
group.serum3MarketsMapByMarketIndex.get(serum3MarketIndex);
|
||||
const ix = await this.program.methods
|
||||
|
@ -1552,7 +1556,7 @@ export class MangoClient {
|
|||
public async serum3deregisterMarket(
|
||||
group: Group,
|
||||
externalMarketPk: PublicKey,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const serum3Market = group.serum3MarketsMapByExternal.get(
|
||||
externalMarketPk.toBase58(),
|
||||
)!;
|
||||
|
@ -1625,7 +1629,7 @@ export class MangoClient {
|
|||
group: Group,
|
||||
mangoAccount: MangoAccount,
|
||||
externalMarketPk: PublicKey,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const serum3Market: Serum3Market = group.serum3MarketsMapByExternal.get(
|
||||
externalMarketPk.toBase58(),
|
||||
)!;
|
||||
|
@ -1701,7 +1705,7 @@ export class MangoClient {
|
|||
group: Group,
|
||||
mangoAccount: MangoAccount,
|
||||
externalMarketPk: PublicKey,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const ix = await this.serum3CloseOpenOrdersIx(
|
||||
group,
|
||||
mangoAccount,
|
||||
|
@ -1723,7 +1727,7 @@ export class MangoClient {
|
|||
mangoAccount: MangoAccount,
|
||||
externalMarketPk: PublicKey,
|
||||
limit?: number,
|
||||
): Promise<string> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const serum3Market = group.serum3MarketsMapByExternal.get(
|
||||
externalMarketPk.toBase58(),
|
||||
)!;
|
||||
|
@ -1918,7 +1922,7 @@ export class MangoClient {
|
|||
orderType: Serum3OrderType,
|
||||
clientOrderId: number,
|
||||
limit: number,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const placeOrderIxes = await this.serum3PlaceOrderIx(
|
||||
group,
|
||||
mangoAccount,
|
||||
|
@ -1982,7 +1986,7 @@ export class MangoClient {
|
|||
mangoAccount: MangoAccount,
|
||||
externalMarketPk: PublicKey,
|
||||
limit?: number,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
return await this.sendAndConfirmTransactionForGroup(group, [
|
||||
await this.serum3CancelAllOrdersIx(
|
||||
group,
|
||||
|
@ -2076,7 +2080,7 @@ export class MangoClient {
|
|||
group: Group,
|
||||
mangoAccount: MangoAccount,
|
||||
externalMarketPk: PublicKey,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const ix = await this.serum3SettleFundsV2Ix(
|
||||
group,
|
||||
mangoAccount,
|
||||
|
@ -2126,7 +2130,7 @@ export class MangoClient {
|
|||
externalMarketPk: PublicKey,
|
||||
side: Serum3Side,
|
||||
orderId: BN,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const ixes = await Promise.all([
|
||||
this.serum3CancelOrderIx(
|
||||
group,
|
||||
|
@ -2173,7 +2177,7 @@ export class MangoClient {
|
|||
settlePnlLimitFactor: number,
|
||||
settlePnlLimitWindowSize: number,
|
||||
positivePnlLiquidationFee: number,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const bids = new Keypair();
|
||||
const asks = new Keypair();
|
||||
const eventQueue = new Keypair();
|
||||
|
@ -2272,7 +2276,7 @@ export class MangoClient {
|
|||
group: Group,
|
||||
perpMarketIndex: PerpMarketIndex,
|
||||
params: PerpEditParams,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const perpMarket = group.getPerpMarketByMarketIndex(perpMarketIndex);
|
||||
|
||||
const ix = await this.program.methods
|
||||
|
@ -2325,7 +2329,7 @@ export class MangoClient {
|
|||
perpMarketIndex: PerpMarketIndex,
|
||||
accountA: MangoAccount,
|
||||
accountB: MangoAccount,
|
||||
): Promise<string> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const perpMarket = group.getPerpMarketByMarketIndex(perpMarketIndex);
|
||||
|
||||
const ix = await this.program.methods
|
||||
|
@ -2344,7 +2348,7 @@ export class MangoClient {
|
|||
public async perpCloseMarket(
|
||||
group: Group,
|
||||
perpMarketIndex: PerpMarketIndex,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const perpMarket = group.getPerpMarketByMarketIndex(perpMarketIndex);
|
||||
|
||||
const ix = await this.program.methods
|
||||
|
@ -2410,7 +2414,7 @@ export class MangoClient {
|
|||
group: Group,
|
||||
mangoAccount: MangoAccount,
|
||||
perpMarketIndex: PerpMarketIndex,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const ix = await this.perpDeactivatePositionIx(
|
||||
group,
|
||||
mangoAccount,
|
||||
|
@ -2423,7 +2427,7 @@ export class MangoClient {
|
|||
group: Group,
|
||||
mangoAccount: MangoAccount,
|
||||
slippage = 0.01, // 1%, 100bps
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
if (mangoAccount.perpActive().length == 0) {
|
||||
throw new Error(`No perp positions found.`);
|
||||
}
|
||||
|
@ -2447,7 +2451,7 @@ export class MangoClient {
|
|||
pa.marketIndex,
|
||||
isLong ? PerpOrderSide.ask : PerpOrderSide.bid,
|
||||
pm.uiPrice * (isLong ? 1 - slippage : 1 + slippage), // Try to cross the spread to guarantee matching
|
||||
pa.getBasePositionUi(pm) * 1.01, // Send a larger size to ensure full order is closed
|
||||
Math.abs(pa.getBasePositionUi(pm) * 1.01), // Send a larger size to ensure full order is closed
|
||||
undefined,
|
||||
Date.now(),
|
||||
PerpOrderType.immediateOrCancel,
|
||||
|
@ -2485,7 +2489,7 @@ export class MangoClient {
|
|||
reduceOnly?: boolean,
|
||||
expiryTimestamp?: number,
|
||||
limit?: number,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const ix = await this.perpPlaceOrderV2Ix(
|
||||
group,
|
||||
mangoAccount,
|
||||
|
@ -2633,7 +2637,7 @@ export class MangoClient {
|
|||
reduceOnly?: boolean,
|
||||
expiryTimestamp?: number,
|
||||
limit?: number,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const ix = await this.perpPlaceOrderPeggedV2Ix(
|
||||
group,
|
||||
mangoAccount,
|
||||
|
@ -2774,6 +2778,26 @@ export class MangoClient {
|
|||
.instruction();
|
||||
}
|
||||
|
||||
public async perpCancelOrderByClientOrderIdIx(
|
||||
group: Group,
|
||||
mangoAccount: MangoAccount,
|
||||
perpMarketIndex: PerpMarketIndex,
|
||||
clientOrderId: BN,
|
||||
): Promise<TransactionInstruction> {
|
||||
const perpMarket = group.getPerpMarketByMarketIndex(perpMarketIndex);
|
||||
return await this.program.methods
|
||||
.perpCancelOrderByClientOrderId(new BN(clientOrderId))
|
||||
.accounts({
|
||||
group: group.publicKey,
|
||||
account: mangoAccount.publicKey,
|
||||
owner: (this.program.provider as AnchorProvider).wallet.publicKey,
|
||||
perpMarket: perpMarket.publicKey,
|
||||
bids: perpMarket.bids,
|
||||
asks: perpMarket.asks,
|
||||
})
|
||||
.instruction();
|
||||
}
|
||||
|
||||
public async perpCancelOrderIx(
|
||||
group: Group,
|
||||
mangoAccount: MangoAccount,
|
||||
|
@ -2799,7 +2823,7 @@ export class MangoClient {
|
|||
mangoAccount: MangoAccount,
|
||||
perpMarketIndex: PerpMarketIndex,
|
||||
orderId: BN,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const ix = await this.perpCancelOrderIx(
|
||||
group,
|
||||
mangoAccount,
|
||||
|
@ -2815,7 +2839,7 @@ export class MangoClient {
|
|||
mangoAccount: MangoAccount,
|
||||
perpMarketIndex: PerpMarketIndex,
|
||||
limit: number,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const ix = await this.perpCancelAllOrdersIx(
|
||||
group,
|
||||
mangoAccount,
|
||||
|
@ -2851,7 +2875,7 @@ export class MangoClient {
|
|||
group: Group,
|
||||
mangoAccount: MangoAccount,
|
||||
allMangoAccounts?: MangoAccount[],
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
if (!allMangoAccounts) {
|
||||
allMangoAccounts = await client.getAllMangoAccounts(group, true);
|
||||
}
|
||||
|
@ -2932,7 +2956,7 @@ export class MangoClient {
|
|||
settler: MangoAccount,
|
||||
perpMarketIndex: PerpMarketIndex,
|
||||
maxSettleAmount?: number,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
return await this.sendAndConfirmTransactionForGroup(group, [
|
||||
await this.perpSettlePnlIx(
|
||||
group,
|
||||
|
@ -2956,7 +2980,7 @@ export class MangoClient {
|
|||
unprofitableAccount: MangoAccount,
|
||||
settler: MangoAccount,
|
||||
perpMarketIndex: PerpMarketIndex,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
return await this.sendAndConfirmTransactionForGroup(group, [
|
||||
await this.perpSettlePnlIx(
|
||||
group,
|
||||
|
@ -3012,7 +3036,7 @@ export class MangoClient {
|
|||
account: MangoAccount,
|
||||
perpMarketIndex: PerpMarketIndex,
|
||||
maxSettleAmount?: number,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
return await this.sendAndConfirmTransactionForGroup(group, [
|
||||
await this.perpSettleFeesIx(
|
||||
group,
|
||||
|
@ -3064,7 +3088,7 @@ export class MangoClient {
|
|||
perpMarketIndex: PerpMarketIndex,
|
||||
accounts: PublicKey[],
|
||||
limit: number,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
return await this.sendAndConfirmTransactionForGroup(group, [
|
||||
await this.perpConsumeEventsIx(group, perpMarketIndex, accounts, limit),
|
||||
]);
|
||||
|
@ -3162,7 +3186,7 @@ export class MangoClient {
|
|||
userDefinedInstructions: TransactionInstruction[];
|
||||
userDefinedAlts: AddressLookupTableAccount[];
|
||||
flashLoanType: FlashLoanType;
|
||||
}): Promise<TransactionSignature> {
|
||||
}): Promise<MangoSignatureStatus> {
|
||||
const isDelegate = (
|
||||
this.program.provider as AnchorProvider
|
||||
).wallet.publicKey.equals(mangoAccount.delegate);
|
||||
|
@ -3325,7 +3349,7 @@ export class MangoClient {
|
|||
public async tokenUpdateIndexAndRate(
|
||||
group: Group,
|
||||
mintPk: PublicKey,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
return await this.sendAndConfirmTransactionForGroup(group, [
|
||||
await this.tokenUpdateIndexAndRateIx(group, mintPk),
|
||||
]);
|
||||
|
@ -3365,7 +3389,7 @@ export class MangoClient {
|
|||
assetMintPk: PublicKey,
|
||||
liabMintPk: PublicKey,
|
||||
maxLiabTransfer: number,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const assetBank: Bank = group.getFirstBankByMint(assetMintPk);
|
||||
const liabBank: Bank = group.getFirstBankByMint(liabMintPk);
|
||||
|
||||
|
@ -3415,7 +3439,7 @@ export class MangoClient {
|
|||
maxSellUi: number | null,
|
||||
pricePremium: number | null,
|
||||
expiryTimestamp: number | null,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
if (account.getTokenBalanceUi(sellBank) < 0) {
|
||||
throw new Error(
|
||||
`Only allowed to take profits on deposits! Current balance ${account.getTokenBalanceUi(
|
||||
|
@ -3424,13 +3448,24 @@ export class MangoClient {
|
|||
);
|
||||
}
|
||||
|
||||
if (!thresholdPriceInSellPerBuyToken) {
|
||||
thresholdPriceUi = 1 / thresholdPriceUi;
|
||||
}
|
||||
const thresholdPrice = toNativeSellPerBuyTokenPrice(
|
||||
thresholdPriceUi,
|
||||
sellBank,
|
||||
buyBank,
|
||||
);
|
||||
const lowerLimit = 0;
|
||||
const upperLimit = thresholdPrice;
|
||||
|
||||
return await this.tokenConditionalSwapCreate(
|
||||
group,
|
||||
account,
|
||||
sellBank,
|
||||
buyBank,
|
||||
thresholdPriceUi,
|
||||
thresholdPriceInSellPerBuyToken,
|
||||
lowerLimit,
|
||||
upperLimit,
|
||||
Number.MAX_SAFE_INTEGER,
|
||||
maxSellUi ?? account.getTokenBalanceUi(sellBank),
|
||||
'TakeProfitOnDeposit',
|
||||
|
@ -3438,6 +3473,7 @@ export class MangoClient {
|
|||
true,
|
||||
false,
|
||||
expiryTimestamp,
|
||||
thresholdPriceInSellPerBuyToken,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -3451,7 +3487,7 @@ export class MangoClient {
|
|||
maxSellUi: number | null,
|
||||
pricePremium: number | null,
|
||||
expiryTimestamp: number | null,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
if (account.getTokenBalanceUi(sellBank) < 0) {
|
||||
throw new Error(
|
||||
`Only allowed to set a stop loss on deposits! Current balance ${account.getTokenBalanceUi(
|
||||
|
@ -3460,13 +3496,24 @@ export class MangoClient {
|
|||
);
|
||||
}
|
||||
|
||||
if (!thresholdPriceInSellPerBuyToken) {
|
||||
thresholdPriceUi = 1 / thresholdPriceUi;
|
||||
}
|
||||
const thresholdPrice = toNativeSellPerBuyTokenPrice(
|
||||
thresholdPriceUi,
|
||||
sellBank,
|
||||
buyBank,
|
||||
);
|
||||
const lowerLimit = thresholdPrice;
|
||||
const upperLimit = Number.MAX_SAFE_INTEGER;
|
||||
|
||||
return await this.tokenConditionalSwapCreate(
|
||||
group,
|
||||
account,
|
||||
sellBank,
|
||||
buyBank,
|
||||
thresholdPriceUi,
|
||||
thresholdPriceInSellPerBuyToken,
|
||||
lowerLimit,
|
||||
upperLimit,
|
||||
Number.MAX_SAFE_INTEGER,
|
||||
maxSellUi ?? account.getTokenBalanceUi(sellBank),
|
||||
'StopLossOnDeposit',
|
||||
|
@ -3474,6 +3521,7 @@ export class MangoClient {
|
|||
true,
|
||||
false,
|
||||
expiryTimestamp,
|
||||
thresholdPriceInSellPerBuyToken,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -3488,7 +3536,7 @@ export class MangoClient {
|
|||
pricePremium: number | null,
|
||||
allowMargin: boolean | null,
|
||||
expiryTimestamp: number | null,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
if (account.getTokenBalanceUi(buyBank) > 0) {
|
||||
throw new Error(
|
||||
`Only allowed to take profits on borrows! Current balance ${account.getTokenBalanceUi(
|
||||
|
@ -3497,13 +3545,24 @@ export class MangoClient {
|
|||
);
|
||||
}
|
||||
|
||||
if (!thresholdPriceInSellPerBuyToken) {
|
||||
thresholdPriceUi = 1 / thresholdPriceUi;
|
||||
}
|
||||
const thresholdPrice = toNativeSellPerBuyTokenPrice(
|
||||
thresholdPriceUi,
|
||||
sellBank,
|
||||
buyBank,
|
||||
);
|
||||
const lowerLimit = thresholdPrice;
|
||||
const upperLimit = Number.MAX_SAFE_INTEGER;
|
||||
|
||||
return await this.tokenConditionalSwapCreate(
|
||||
group,
|
||||
account,
|
||||
sellBank,
|
||||
buyBank,
|
||||
thresholdPriceUi,
|
||||
thresholdPriceInSellPerBuyToken,
|
||||
lowerLimit,
|
||||
upperLimit,
|
||||
maxBuyUi ?? -account.getTokenBalanceUi(buyBank),
|
||||
Number.MAX_SAFE_INTEGER,
|
||||
'TakeProfitOnBorrow',
|
||||
|
@ -3511,6 +3570,7 @@ export class MangoClient {
|
|||
false,
|
||||
allowMargin ?? false,
|
||||
expiryTimestamp,
|
||||
thresholdPriceInSellPerBuyToken,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -3525,7 +3585,7 @@ export class MangoClient {
|
|||
pricePremium: number | null,
|
||||
allowMargin: boolean | null,
|
||||
expiryTimestamp: number | null,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
if (account.getTokenBalanceUi(buyBank) > 0) {
|
||||
throw new Error(
|
||||
`Only allowed to set stop loss on borrows! Current balance ${account.getTokenBalanceUi(
|
||||
|
@ -3534,13 +3594,24 @@ export class MangoClient {
|
|||
);
|
||||
}
|
||||
|
||||
if (!thresholdPriceInSellPerBuyToken) {
|
||||
thresholdPriceUi = 1 / thresholdPriceUi;
|
||||
}
|
||||
const thresholdPrice = toNativeSellPerBuyTokenPrice(
|
||||
thresholdPriceUi,
|
||||
sellBank,
|
||||
buyBank,
|
||||
);
|
||||
const lowerLimit = 0;
|
||||
const upperLimit = thresholdPrice;
|
||||
|
||||
return await this.tokenConditionalSwapCreate(
|
||||
group,
|
||||
account,
|
||||
sellBank,
|
||||
buyBank,
|
||||
thresholdPriceUi,
|
||||
thresholdPriceInSellPerBuyToken,
|
||||
lowerLimit,
|
||||
upperLimit,
|
||||
maxBuyUi ?? -account.getTokenBalanceUi(buyBank),
|
||||
Number.MAX_SAFE_INTEGER,
|
||||
'StopLossOnBorrow',
|
||||
|
@ -3548,6 +3619,7 @@ export class MangoClient {
|
|||
false,
|
||||
allowMargin ?? false,
|
||||
expiryTimestamp,
|
||||
thresholdPriceInSellPerBuyToken,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -3556,8 +3628,8 @@ export class MangoClient {
|
|||
account: MangoAccount,
|
||||
sellBank: Bank,
|
||||
buyBank: Bank,
|
||||
thresholdPriceUi: number,
|
||||
thresholdPriceInSellPerBuyToken: boolean,
|
||||
lowerLimit: number,
|
||||
upperLimit: number,
|
||||
maxBuyUi: number,
|
||||
maxSellUi: number,
|
||||
tcsIntention:
|
||||
|
@ -3570,50 +3642,43 @@ export class MangoClient {
|
|||
allowCreatingDeposits: boolean,
|
||||
allowCreatingBorrows: boolean,
|
||||
expiryTimestamp: number | null,
|
||||
): Promise<TransactionSignature> {
|
||||
const maxBuy =
|
||||
maxBuyUi == Number.MAX_SAFE_INTEGER
|
||||
? U64_MAX_BN
|
||||
: toNative(maxBuyUi, buyBank.mintDecimals);
|
||||
const maxSell =
|
||||
maxSellUi == Number.MAX_SAFE_INTEGER
|
||||
? U64_MAX_BN
|
||||
: toNative(maxSellUi, sellBank.mintDecimals);
|
||||
|
||||
if (!thresholdPriceInSellPerBuyToken) {
|
||||
thresholdPriceUi = 1 / thresholdPriceUi;
|
||||
displayPriceInSellTokenPerBuyToken: boolean,
|
||||
): Promise<MangoSignatureStatus> {
|
||||
let maxBuy, maxSell, buyAmountInUsd, sellAmountInUsd;
|
||||
if (maxBuyUi == Number.MAX_SAFE_INTEGER) {
|
||||
maxBuy = U64_MAX_BN;
|
||||
} else {
|
||||
buyAmountInUsd = maxBuyUi * buyBank.uiPrice;
|
||||
maxBuy = toNative(maxBuyUi, buyBank.mintDecimals);
|
||||
}
|
||||
if (maxSellUi == Number.MAX_SAFE_INTEGER) {
|
||||
maxSell = U64_MAX_BN;
|
||||
} else {
|
||||
sellAmountInUsd = maxSellUi * sellBank.uiPrice;
|
||||
maxSell = toNative(maxSellUi, sellBank.mintDecimals);
|
||||
}
|
||||
|
||||
let lowerLimit, upperLimit;
|
||||
const thresholdPrice = toNativeSellPerBuyTokenPrice(
|
||||
thresholdPriceUi,
|
||||
sellBank,
|
||||
buyBank,
|
||||
);
|
||||
const sellTokenPerBuyTokenPrice = buyBank.price
|
||||
.div(sellBank.price)
|
||||
.toNumber();
|
||||
|
||||
if (
|
||||
tcsIntention == 'TakeProfitOnDeposit' ||
|
||||
tcsIntention == 'StopLossOnBorrow' ||
|
||||
(tcsIntention == null && thresholdPrice > sellTokenPerBuyTokenPrice)
|
||||
) {
|
||||
lowerLimit = thresholdPrice;
|
||||
upperLimit = Number.MAX_SAFE_INTEGER;
|
||||
} else {
|
||||
lowerLimit = 0;
|
||||
upperLimit = thresholdPrice;
|
||||
// Used for computing optimal premium
|
||||
let liqorTcsChunkSizeInUsd = Math.min(buyAmountInUsd, sellAmountInUsd);
|
||||
if (liqorTcsChunkSizeInUsd > 5000) {
|
||||
liqorTcsChunkSizeInUsd = 5000;
|
||||
}
|
||||
// For small TCS swaps, reduce chunk size to 1000 USD
|
||||
else {
|
||||
liqorTcsChunkSizeInUsd = 1000;
|
||||
}
|
||||
|
||||
if (!pricePremium) {
|
||||
if (maxBuy.eq(U64_MAX_BN)) {
|
||||
maxSell.toNumber() * sellBank.uiPrice;
|
||||
}
|
||||
const buyTokenPriceImpact = group.getPriceImpactByTokenIndex(
|
||||
buyBank.tokenIndex,
|
||||
5000,
|
||||
liqorTcsChunkSizeInUsd,
|
||||
);
|
||||
const sellTokenPriceImpact = group.getPriceImpactByTokenIndex(
|
||||
sellBank.tokenIndex,
|
||||
5000,
|
||||
liqorTcsChunkSizeInUsd,
|
||||
);
|
||||
pricePremium =
|
||||
((1 + buyTokenPriceImpact / 100) * (1 + sellTokenPriceImpact / 100) -
|
||||
|
@ -3650,7 +3715,7 @@ export class MangoClient {
|
|||
pricePremiumRate,
|
||||
allowCreatingDeposits,
|
||||
allowCreatingBorrows,
|
||||
thresholdPriceInSellPerBuyToken
|
||||
displayPriceInSellTokenPerBuyToken
|
||||
? TokenConditionalSwapDisplayPriceStyle.sellTokenPerBuyToken
|
||||
: TokenConditionalSwapDisplayPriceStyle.buyTokenPerSellToken,
|
||||
intention,
|
||||
|
@ -3672,7 +3737,7 @@ export class MangoClient {
|
|||
allowCreatingBorrows: boolean,
|
||||
priceDisplayStyle: TokenConditionalSwapDisplayPriceStyle,
|
||||
intention: TokenConditionalSwapIntention,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const buyBank: Bank = group.getFirstBankByMint(buyMintPk);
|
||||
const sellBank: Bank = group.getFirstBankByMint(sellMintPk);
|
||||
const tcsIx = await this.program.methods
|
||||
|
@ -3720,7 +3785,7 @@ export class MangoClient {
|
|||
group: Group,
|
||||
account: MangoAccount,
|
||||
tokenConditionalSwapId: BN,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const tokenConditionalSwapIndex = account.tokenConditionalSwaps.findIndex(
|
||||
(tcs) => tcs.id.eq(tokenConditionalSwapId),
|
||||
);
|
||||
|
@ -3752,7 +3817,7 @@ export class MangoClient {
|
|||
public async tokenConditionalSwapCancelAll(
|
||||
group: Group,
|
||||
account: MangoAccount,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const ixs = await Promise.all(
|
||||
account.tokenConditionalSwaps
|
||||
.filter((tcs) => tcs.hasData)
|
||||
|
@ -3785,7 +3850,7 @@ export class MangoClient {
|
|||
tokenConditionalSwapId: BN,
|
||||
maxBuyTokenToLiqee: number,
|
||||
maxSellTokenToLiqor: number,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const tokenConditionalSwapIndex = liqee.tokenConditionalSwaps.findIndex(
|
||||
(tcs) => tcs.id.eq(tokenConditionalSwapId),
|
||||
);
|
||||
|
@ -3841,7 +3906,7 @@ export class MangoClient {
|
|||
group: Group,
|
||||
addressLookupTable: PublicKey,
|
||||
index: number,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const ix = await this.program.methods
|
||||
.altSet(index)
|
||||
.accounts({
|
||||
|
@ -3859,7 +3924,7 @@ export class MangoClient {
|
|||
addressLookupTable: PublicKey,
|
||||
index: number,
|
||||
pks: PublicKey[],
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const ix = await this.program.methods
|
||||
.altExtend(index, pks)
|
||||
.accounts({
|
||||
|
@ -4143,7 +4208,7 @@ export class MangoClient {
|
|||
reduceOnly?: boolean,
|
||||
expiryTimestamp?: number,
|
||||
limit?: number,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const transactionInstructions: TransactionInstruction[] = [];
|
||||
const [cancelOrderIx, placeOrderIx] = await Promise.all([
|
||||
this.perpCancelOrderIx(group, mangoAccount, perpMarketIndex, orderId),
|
||||
|
@ -4181,7 +4246,7 @@ export class MangoClient {
|
|||
orderType: Serum3OrderType,
|
||||
clientOrderId: number,
|
||||
limit: number,
|
||||
): Promise<TransactionSignature> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const transactionInstructions: TransactionInstruction[] = [];
|
||||
const [cancelOrderIx, settleIx, placeOrderIx] = await Promise.all([
|
||||
this.serum3CancelOrderIx(
|
||||
|
|
|
@ -8,7 +8,14 @@ export class Id {
|
|||
public publicKey: string,
|
||||
public serum3ProgramId: string,
|
||||
public mangoProgramId: string,
|
||||
public banks: { name: string; publicKey: string; active: boolean }[],
|
||||
public banks: {
|
||||
name: string;
|
||||
mint: string;
|
||||
tokenIndex: number;
|
||||
publicKey: string;
|
||||
active: boolean;
|
||||
decimals: number;
|
||||
}[],
|
||||
public stubOracles: { name: string; publicKey: string }[],
|
||||
public mintInfos: { name: string; publicKey: string }[],
|
||||
public serum3Markets: {
|
||||
|
@ -23,7 +30,7 @@ export class Id {
|
|||
public getBanks(): PublicKey[] {
|
||||
return Array.from(
|
||||
this.banks
|
||||
.filter((perpMarket) => perpMarket.active)
|
||||
.filter((bank) => bank.active)
|
||||
.map((bank) => new PublicKey(bank.publicKey)),
|
||||
);
|
||||
}
|
||||
|
@ -43,19 +50,26 @@ export class Id {
|
|||
public getSerum3Markets(): PublicKey[] {
|
||||
return Array.from(
|
||||
this.serum3Markets
|
||||
.filter((perpMarket) => perpMarket.active)
|
||||
.filter((serum3Market) => serum3Market.active)
|
||||
.map((serum3Market) => new PublicKey(serum3Market.publicKey)),
|
||||
);
|
||||
}
|
||||
|
||||
public getSerum3ExternalMarkets(): PublicKey[] {
|
||||
return Array.from(
|
||||
this.serum3Markets
|
||||
.filter((serum3Market) => serum3Market.active)
|
||||
.map((serum3Market) => new PublicKey(serum3Market.marketExternal)),
|
||||
);
|
||||
}
|
||||
|
||||
public getPerpMarkets(): PublicKey[] {
|
||||
return Array.from(
|
||||
this.perpMarkets
|
||||
.filter((perpMarket) => perpMarket.active)
|
||||
.map((perpMarket) => new PublicKey(perpMarket.publicKey)),
|
||||
this.perpMarkets.map((perpMarket) => new PublicKey(perpMarket.publicKey)),
|
||||
);
|
||||
}
|
||||
|
||||
// DEPRECATED
|
||||
static fromIdsByName(name: string): Id {
|
||||
const groupConfig = ids.groups.find((id) => id['name'] === name);
|
||||
if (!groupConfig) throw new Error(`No group config ${name} found in Ids!`);
|
||||
|
@ -73,6 +87,7 @@ export class Id {
|
|||
);
|
||||
}
|
||||
|
||||
// DEPRECATED
|
||||
static fromIdsByPk(groupPk: PublicKey): Id {
|
||||
const groupConfig = ids.groups.find(
|
||||
(id) => id['publicKey'] === groupPk.toString(),
|
||||
|
@ -115,6 +130,8 @@ export class Id {
|
|||
tokenIndex: t.tokenIndex,
|
||||
bankNum: b.bankNum,
|
||||
publicKey: b.publicKey,
|
||||
active: t.active,
|
||||
decimals: t.decimals,
|
||||
})),
|
||||
),
|
||||
groupConfig.stubOracles.map((s) => ({
|
||||
|
@ -126,15 +143,18 @@ export class Id {
|
|||
mint: t.mint,
|
||||
tokenIndex: t.tokenIndex,
|
||||
publicKey: t.mintInfo,
|
||||
active: t.active,
|
||||
})),
|
||||
groupConfig.serum3Markets.map((s) => ({
|
||||
name: s.name,
|
||||
publicKey: s.publicKey,
|
||||
marketExternal: s.marketExternal,
|
||||
marketExternal: s.serumMarketExternal,
|
||||
active: s.active,
|
||||
})),
|
||||
groupConfig.perpMarkets.map((p) => ({
|
||||
name: p.name,
|
||||
publicKey: p.publicKey,
|
||||
active: p.active,
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -26,4 +26,5 @@ export * from './router';
|
|||
export * from './stats';
|
||||
export * from './types';
|
||||
export * from './utils';
|
||||
export * from './utils/rpc';
|
||||
export { Group, MANGO_V4_ID, MangoClient, OracleProvider, StubOracle };
|
||||
|
|
|
@ -8262,14 +8262,28 @@ export type MangoV4 = {
|
|||
},
|
||||
{
|
||||
"name": "changeAmount",
|
||||
"docs": [
|
||||
"The amount by which the user's token position changed at the end",
|
||||
"",
|
||||
"So if the user repaid the approved_amount in full, it'd be 0.",
|
||||
"",
|
||||
"Does NOT include the loan_origination_fee or deposit_fee, so the true",
|
||||
"change is `change_amount - loan_origination_fee - deposit_fee`."
|
||||
],
|
||||
"type": "i128"
|
||||
},
|
||||
{
|
||||
"name": "loan",
|
||||
"docs": [
|
||||
"The amount that was a loan (<= approved_amount, depends on user's deposits)"
|
||||
],
|
||||
"type": "i128"
|
||||
},
|
||||
{
|
||||
"name": "loanOriginationFee",
|
||||
"docs": [
|
||||
"The fee paid on the loan, not included in `loan` or `change_amount`"
|
||||
],
|
||||
"type": "i128"
|
||||
},
|
||||
{
|
||||
|
@ -8286,7 +8300,19 @@ export type MangoV4 = {
|
|||
},
|
||||
{
|
||||
"name": "depositFee",
|
||||
"docs": [
|
||||
"Deposit fee paid for positive change_amount.",
|
||||
"",
|
||||
"Not factored into change_amount."
|
||||
],
|
||||
"type": "i128"
|
||||
},
|
||||
{
|
||||
"name": "approvedAmount",
|
||||
"docs": [
|
||||
"The amount that was transfered out to the user"
|
||||
],
|
||||
"type": "u64"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -20831,14 +20857,28 @@ export const IDL: MangoV4 = {
|
|||
},
|
||||
{
|
||||
"name": "changeAmount",
|
||||
"docs": [
|
||||
"The amount by which the user's token position changed at the end",
|
||||
"",
|
||||
"So if the user repaid the approved_amount in full, it'd be 0.",
|
||||
"",
|
||||
"Does NOT include the loan_origination_fee or deposit_fee, so the true",
|
||||
"change is `change_amount - loan_origination_fee - deposit_fee`."
|
||||
],
|
||||
"type": "i128"
|
||||
},
|
||||
{
|
||||
"name": "loan",
|
||||
"docs": [
|
||||
"The amount that was a loan (<= approved_amount, depends on user's deposits)"
|
||||
],
|
||||
"type": "i128"
|
||||
},
|
||||
{
|
||||
"name": "loanOriginationFee",
|
||||
"docs": [
|
||||
"The fee paid on the loan, not included in `loan` or `change_amount`"
|
||||
],
|
||||
"type": "i128"
|
||||
},
|
||||
{
|
||||
|
@ -20855,7 +20895,19 @@ export const IDL: MangoV4 = {
|
|||
},
|
||||
{
|
||||
"name": "depositFee",
|
||||
"docs": [
|
||||
"Deposit fee paid for positive change_amount.",
|
||||
"",
|
||||
"Not factored into change_amount."
|
||||
],
|
||||
"type": "i128"
|
||||
},
|
||||
{
|
||||
"name": "approvedAmount",
|
||||
"docs": [
|
||||
"The amount that was transfered out to the user"
|
||||
],
|
||||
"type": "u64"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ export function computePriceImpactOnJup(
|
|||
(pi) => pi.symbol == tokenName && pi.target_amount == closestTo,
|
||||
);
|
||||
if (filteredPis.length > 0) {
|
||||
return (filteredPis[0].max_price_impact_percent * 10000) / 100;
|
||||
return (filteredPis[0].avg_price_impact_percent * 10000) / 100;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -5,16 +5,27 @@ import {
|
|||
ComputeBudgetProgram,
|
||||
MessageV0,
|
||||
Signer,
|
||||
TransactionConfirmationStatus,
|
||||
TransactionError,
|
||||
TransactionInstruction,
|
||||
TransactionSignature,
|
||||
VersionedTransaction,
|
||||
} from '@solana/web3.js';
|
||||
|
||||
export interface MangoSignatureStatus {
|
||||
slot: number;
|
||||
confirmations: number | null;
|
||||
err: TransactionError | null;
|
||||
confirmationStatus?: TransactionConfirmationStatus;
|
||||
signature: TransactionSignature;
|
||||
}
|
||||
|
||||
export async function sendTransaction(
|
||||
provider: AnchorProvider,
|
||||
ixs: TransactionInstruction[],
|
||||
alts: AddressLookupTableAccount[],
|
||||
opts: any = {},
|
||||
): Promise<string> {
|
||||
): Promise<MangoSignatureStatus> {
|
||||
const connection = provider.connection;
|
||||
const latestBlockhash =
|
||||
opts.latestBlockhash ??
|
||||
|
@ -102,7 +113,7 @@ export async function sendTransaction(
|
|||
});
|
||||
}
|
||||
|
||||
return signature;
|
||||
return { signature, ...status };
|
||||
}
|
||||
|
||||
export const createComputeBudgetIx = (
|
||||
|
|
Loading…
Reference in New Issue