releade v0.2.0

This commit is contained in:
Maximilian Schneider 2022-08-18 07:12:20 +02:00
parent 671ad88c11
commit 6437cdb701
2 changed files with 88 additions and 74 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "@blockworks-foundation/mango-client", "name": "@blockworks-foundation/mango-client",
"version": "0.1.19", "version": "0.2.0",
"description": "Library for interacting with Mango Markets' solana smart contracts.", "description": "Library for interacting with Mango Markets' solana smart contracts.",
"repository": "blockworks-foundation/mango-client-ts", "repository": "blockworks-foundation/mango-client-ts",
"author": { "author": {

View File

@ -1,9 +1,14 @@
import { import {
Account, Account,
AccountInfo, Commitment, AccountInfo,
Commitment,
Connection, Connection,
PublicKey, RpcResponseAndContext, SimulatedTransactionResponse, PublicKey,
SystemProgram, Transaction, TransactionConfirmationStatus, RpcResponseAndContext,
SimulatedTransactionResponse,
SystemProgram,
Transaction,
TransactionConfirmationStatus,
TransactionInstruction, TransactionInstruction,
TransactionSignature, TransactionSignature,
} from '@solana/web3.js'; } from '@solana/web3.js';
@ -21,7 +26,7 @@ import {
zeros, zeros,
} from '@project-serum/serum/lib/layout'; } from '@project-serum/serum/lib/layout';
export const zeroKey = new PublicKey(new Uint8Array(32)) export const zeroKey = new PublicKey(new Uint8Array(32));
export async function sleep(ms) { export async function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms)); return new Promise((resolve) => setTimeout(resolve, ms));
@ -57,16 +62,16 @@ export async function awaitTransactionSignatureConfirmation(
txid: TransactionSignature, txid: TransactionSignature,
timeout: number, timeout: number,
connection: Connection, connection: Connection,
confirmLevel: TransactionConfirmationStatus confirmLevel: TransactionConfirmationStatus,
) { ) {
let done = false; let done = false;
const confirmLevels: (TransactionConfirmationStatus | null)[] = ['finalized'] const confirmLevels: (TransactionConfirmationStatus | null)[] = ['finalized'];
if (confirmLevel === 'confirmed') { if (confirmLevel === 'confirmed') {
confirmLevels.push('confirmed') confirmLevels.push('confirmed');
} else if (confirmLevel === 'processed') { } else if (confirmLevel === 'processed') {
confirmLevels.push('confirmed') confirmLevels.push('confirmed');
confirmLevels.push('processed') confirmLevels.push('processed');
} }
const result = await new Promise((resolve, reject) => { const result = await new Promise((resolve, reject) => {
@ -113,7 +118,12 @@ export async function awaitTransactionSignatureConfirmation(
console.log('REST error for', txid, result); console.log('REST error for', txid, result);
done = true; done = true;
reject(result.err); reject(result.err);
} else if (!(result.confirmations || confirmLevels.includes(result.confirmationStatus))) { } else if (
!(
result.confirmations ||
confirmLevels.includes(result.confirmationStatus!)
)
) {
console.log('REST not confirmed', txid, result); console.log('REST not confirmed', txid, result);
} else { } else {
console.log('REST confirmed', txid, result); console.log('REST confirmed', txid, result);
@ -135,27 +145,27 @@ export async function awaitTransactionSignatureConfirmation(
return result; return result;
} }
export async function createAccountInstruction( export async function createAccountInstruction(
connection: Connection, connection: Connection,
payer: PublicKey, payer: PublicKey,
space: number, space: number,
owner: PublicKey, owner: PublicKey,
lamports?: number lamports?: number,
): Promise<{ account: Account, instruction: TransactionInstruction }> { ): Promise<{ account: Account; instruction: TransactionInstruction }> {
const account = new Account(); const account = new Account();
const instruction = SystemProgram.createAccount({ const instruction = SystemProgram.createAccount({
fromPubkey: payer, fromPubkey: payer,
newAccountPubkey: account.publicKey, newAccountPubkey: account.publicKey,
lamports: lamports ? lamports : await connection.getMinimumBalanceForRentExemption(space), lamports: lamports
? lamports
: await connection.getMinimumBalanceForRentExemption(space),
space, space,
programId: owner programId: owner,
}) });
return { account, instruction }; return { account, instruction };
} }
const MINT_LAYOUT = struct([blob(44), u8('decimals'), blob(37)]); const MINT_LAYOUT = struct([blob(44), u8('decimals'), blob(37)]);
export async function getMintDecimals( export async function getMintDecimals(
@ -180,16 +190,14 @@ function throwIfNull<T>(value: T | null, message = 'account not found'): T {
return value; return value;
} }
export function uiToNative(amount: number, decimals: number): BN { export function uiToNative(amount: number, decimals: number): BN {
return new BN(Math.round(amount * Math.pow(10, decimals))) return new BN(Math.round(amount * Math.pow(10, decimals)));
} }
export function nativeToUi(amount: number, decimals: number): number { export function nativeToUi(amount: number, decimals: number): number {
return amount / Math.pow(10, decimals) return amount / Math.pow(10, decimals);
} }
export async function getFilteredProgramAccounts( export async function getFilteredProgramAccounts(
connection: Connection, connection: Connection,
programId: PublicKey, programId: PublicKey,
@ -221,24 +229,25 @@ export async function getFilteredProgramAccounts(
} }
export async function promiseUndef(): Promise<undefined> { export async function promiseUndef(): Promise<undefined> {
return undefined return undefined;
} }
export const getUnixTs = () => { export const getUnixTs = () => {
return new Date().getTime() / 1000; return new Date().getTime() / 1000;
} };
export const ACCOUNT_LAYOUT = struct([ export const ACCOUNT_LAYOUT = struct([
blob(32, 'mint'), blob(32, 'mint'),
blob(32, 'owner'), blob(32, 'owner'),
nu64('amount'), nu64('amount'),
blob(93) blob(93),
]); ]);
export function parseTokenAccountData( export function parseTokenAccountData(data: Buffer): {
data: Buffer, mint: PublicKey;
): { mint: PublicKey; owner: PublicKey; amount: number } { owner: PublicKey;
amount: number;
} {
let { mint, owner, amount } = ACCOUNT_LAYOUT.decode(data); let { mint, owner, amount } = ACCOUNT_LAYOUT.decode(data);
return { return {
mint: new PublicKey(mint), mint: new PublicKey(mint),
@ -247,69 +256,76 @@ export function parseTokenAccountData(
}; };
} }
export function parseTokenAccount( export function parseTokenAccount(data: Buffer): {
data: Buffer mint: PublicKey;
): { mint: PublicKey; owner: PublicKey; amount: BN } { owner: PublicKey;
amount: BN;
const decoded = AccountLayout.decode(data) } {
const decoded = AccountLayout.decode(data);
return { return {
mint: decoded.mint, mint: decoded.mint,
owner: decoded.owner, owner: decoded.owner,
amount: decoded.amount amount: decoded.amount,
} };
} }
export async function getMultipleAccounts( export async function getMultipleAccounts(
connection: Connection, connection: Connection,
publicKeys: PublicKey[], publicKeys: PublicKey[],
commitment?: Commitment commitment?: Commitment,
): Promise<{ publicKey: PublicKey; accountInfo: AccountInfo<Buffer> }[]> { ): Promise<{ publicKey: PublicKey; accountInfo: AccountInfo<Buffer> }[]> {
const publickKeyStrs = publicKeys.map((pk) => (pk.toBase58())); const publickKeyStrs = publicKeys.map((pk) => pk.toBase58());
const args = commitment ? [publickKeyStrs, {commitment}] : [publickKeyStrs]; const args = commitment ? [publickKeyStrs, { commitment }] : [publickKeyStrs];
// @ts-ignore // @ts-ignore
const resp = await connection._rpcRequest('getMultipleAccounts', args); const resp = await connection._rpcRequest('getMultipleAccounts', args);
if (resp.error) { if (resp.error) {
throw new Error(resp.error.message); throw new Error(resp.error.message);
} }
return resp.result.value.map( return resp.result.value.map(({ data, executable, lamports, owner }, i) => ({
({ data, executable, lamports, owner } , i) => ({ publicKey: publicKeys[i],
publicKey: publicKeys[i], accountInfo: {
accountInfo: { data: Buffer.from(data[0], 'base64'),
data: Buffer.from(data[0], 'base64'), executable,
executable, owner: new PublicKey(owner),
owner: new PublicKey(owner), lamports,
lamports, },
}, }));
}),
);
} }
export async function findLargestTokenAccountForOwner( export async function findLargestTokenAccountForOwner(
connection: Connection, connection: Connection,
owner: PublicKey, owner: PublicKey,
mint: PublicKey mint: PublicKey,
): Promise<{ publicKey: PublicKey; tokenAccount: { mint: PublicKey; owner: PublicKey; amount: number} }> { ): Promise<{
publicKey: PublicKey;
const response = await connection.getTokenAccountsByOwner(owner, {mint, programId: TOKEN_PROGRAM_ID}, connection.commitment) tokenAccount: { mint: PublicKey; owner: PublicKey; amount: number };
}> {
const response = await connection.getTokenAccountsByOwner(
owner,
{ mint, programId: TOKEN_PROGRAM_ID },
connection.commitment,
);
let max = -1; let max = -1;
let maxTokenAccount: null | { mint: PublicKey; owner: PublicKey; amount: number} = null let maxTokenAccount: null | {
let maxPubkey: null | PublicKey = null mint: PublicKey;
owner: PublicKey;
amount: number;
} = null;
let maxPubkey: null | PublicKey = null;
for (const { pubkey, account } of response.value) { for (const { pubkey, account } of response.value) {
const tokenAccount = parseTokenAccountData(account.data);
const tokenAccount = parseTokenAccountData(account.data)
if (tokenAccount.amount > max) { if (tokenAccount.amount > max) {
maxTokenAccount = tokenAccount maxTokenAccount = tokenAccount;
max = tokenAccount.amount max = tokenAccount.amount;
maxPubkey = pubkey maxPubkey = pubkey;
} }
} }
if (maxPubkey && maxTokenAccount) { if (maxPubkey && maxTokenAccount) {
return {publicKey: maxPubkey, tokenAccount: maxTokenAccount} return { publicKey: maxPubkey, tokenAccount: maxTokenAccount };
} else { } else {
throw new Error("No accounts for this token") throw new Error('No accounts for this token');
} }
} }
@ -344,11 +360,7 @@ const EVENT = struct([
u64('clientOrderId'), u64('clientOrderId'),
]); ]);
export function decodeRecentEvents(buffer: Buffer, lastSeenSeqNum?: number) {
export function decodeRecentEvents(
buffer: Buffer,
lastSeenSeqNum?: number,
) {
const header = EVENT_QUEUE_HEADER.decode(buffer); const header = EVENT_QUEUE_HEADER.decode(buffer);
const nodes: any[] = []; const nodes: any[] = [];
@ -357,15 +369,17 @@ export function decodeRecentEvents(
(buffer.length - EVENT_QUEUE_HEADER.span) / EVENT.span, (buffer.length - EVENT_QUEUE_HEADER.span) / EVENT.span,
); );
const newEventsCount = header.seqNum - lastSeenSeqNum const newEventsCount = header.seqNum - lastSeenSeqNum;
for (let i = newEventsCount; i > 0; --i) { for (let i = newEventsCount; i > 0; --i) {
const nodeIndex = (header.head + header.count + allocLen - i) % allocLen const nodeIndex = (header.head + header.count + allocLen - i) % allocLen;
const decodedItem = EVENT.decode(buffer, EVENT_QUEUE_HEADER.span + nodeIndex * EVENT.span) const decodedItem = EVENT.decode(
nodes.push(decodedItem) buffer,
EVENT_QUEUE_HEADER.span + nodeIndex * EVENT.span,
);
nodes.push(decodedItem);
} }
} }
return { header, nodes }; return { header, nodes };
} }