2022-09-27 06:13:53 -07:00
|
|
|
import { AnchorProvider } from '@project-serum/anchor';
|
2022-05-25 17:28:42 -07:00
|
|
|
import {
|
|
|
|
ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
|
|
TOKEN_PROGRAM_ID,
|
|
|
|
} from '@solana/spl-token';
|
2022-08-09 15:27:24 -07:00
|
|
|
import {
|
2022-09-27 06:13:53 -07:00
|
|
|
AddressLookupTableAccount,
|
|
|
|
MessageV0,
|
2022-08-09 15:27:24 -07:00
|
|
|
PublicKey,
|
2022-09-27 06:13:53 -07:00
|
|
|
Signer,
|
2022-08-09 15:27:24 -07:00
|
|
|
SystemProgram,
|
2022-08-11 08:44:12 -07:00
|
|
|
TransactionInstruction,
|
2022-09-27 06:13:53 -07:00
|
|
|
VersionedTransaction,
|
2022-08-09 15:27:24 -07:00
|
|
|
} from '@solana/web3.js';
|
2022-06-02 10:30:39 -07:00
|
|
|
import BN from 'bn.js';
|
2022-09-30 06:07:43 -07:00
|
|
|
import { QUOTE_DECIMALS } from './accounts/bank';
|
|
|
|
import { I80F48 } from './numbers/I80F48';
|
2022-06-02 10:30:39 -07:00
|
|
|
|
2022-09-30 06:07:43 -07:00
|
|
|
///
|
|
|
|
/// numeric helpers
|
|
|
|
///
|
2022-09-20 03:57:01 -07:00
|
|
|
export const U64_MAX_BN = new BN('18446744073709551615');
|
2022-06-02 10:30:39 -07:00
|
|
|
export const I64_MAX_BN = new BN('9223372036854775807').toTwos(64);
|
2022-04-02 02:52:28 -07:00
|
|
|
|
2022-09-30 06:07:43 -07:00
|
|
|
export function toNativeI80F48(uiAmount: number, decimals: number): I80F48 {
|
|
|
|
return I80F48.fromNumber(uiAmount * Math.pow(10, decimals));
|
2022-09-29 06:51:09 -07:00
|
|
|
}
|
|
|
|
|
2022-09-30 06:07:43 -07:00
|
|
|
export function toNative(uiAmount: number, decimals: number): BN {
|
|
|
|
return new BN((uiAmount * Math.pow(10, decimals)).toFixed(0));
|
2022-04-02 02:52:28 -07:00
|
|
|
}
|
2022-04-02 11:15:56 -07:00
|
|
|
|
2022-09-30 06:07:43 -07:00
|
|
|
export function toUiDecimals(
|
|
|
|
nativeAmount: BN | I80F48 | number,
|
|
|
|
decimals: number,
|
|
|
|
): number {
|
2022-10-28 04:43:24 -07:00
|
|
|
// TODO: remove BN and upgrade to bigint https://github.com/solana-labs/solana/issues/27440
|
2022-10-27 11:53:47 -07:00
|
|
|
if (nativeAmount instanceof BN) {
|
2022-10-28 04:43:24 -07:00
|
|
|
nativeAmount = I80F48.fromU64(nativeAmount);
|
|
|
|
}
|
|
|
|
if (nativeAmount instanceof I80F48) {
|
2022-09-30 06:07:43 -07:00
|
|
|
return nativeAmount
|
|
|
|
.div(I80F48.fromNumber(Math.pow(10, decimals)))
|
|
|
|
.toNumber();
|
|
|
|
}
|
|
|
|
return nativeAmount / Math.pow(10, decimals);
|
|
|
|
}
|
2022-08-31 02:36:44 -07:00
|
|
|
|
2022-09-30 06:07:43 -07:00
|
|
|
export function toUiDecimalsForQuote(
|
|
|
|
nativeAmount: BN | I80F48 | number,
|
|
|
|
): number {
|
|
|
|
return toUiDecimals(nativeAmount, QUOTE_DECIMALS);
|
2022-08-31 02:36:44 -07:00
|
|
|
}
|
|
|
|
|
2022-09-30 06:07:43 -07:00
|
|
|
export function toUiI80F48(nativeAmount: I80F48, decimals: number): I80F48 {
|
|
|
|
return nativeAmount.div(I80F48.fromNumber(Math.pow(10, decimals)));
|
2022-04-02 11:15:56 -07:00
|
|
|
}
|
2022-05-25 17:28:42 -07:00
|
|
|
|
2022-09-30 06:07:43 -07:00
|
|
|
///
|
|
|
|
/// web3js extensions
|
|
|
|
///
|
|
|
|
|
2022-05-25 17:28:42 -07:00
|
|
|
/**
|
|
|
|
* 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()))
|
2022-09-29 06:51:09 -07:00
|
|
|
throw new Error('TokenOwnerOffCurve!');
|
2022-05-25 17:28:42 -07:00
|
|
|
|
|
|
|
const [address] = await PublicKey.findProgramAddress(
|
|
|
|
[owner.toBuffer(), programId.toBuffer(), mint.toBuffer()],
|
|
|
|
associatedTokenProgramId,
|
|
|
|
);
|
|
|
|
|
|
|
|
return address;
|
|
|
|
}
|
|
|
|
|
2022-08-09 15:27:24 -07:00
|
|
|
export async function createAssociatedTokenAccountIdempotentInstruction(
|
|
|
|
payer: PublicKey,
|
|
|
|
owner: PublicKey,
|
|
|
|
mint: PublicKey,
|
|
|
|
): Promise<TransactionInstruction> {
|
|
|
|
const account = await getAssociatedTokenAddress(mint, owner);
|
|
|
|
return new TransactionInstruction({
|
|
|
|
keys: [
|
|
|
|
{ pubkey: payer, isSigner: true, isWritable: true },
|
|
|
|
{ pubkey: account, isSigner: false, isWritable: true },
|
|
|
|
{ pubkey: owner, isSigner: false, isWritable: false },
|
|
|
|
{ pubkey: mint, isSigner: false, isWritable: false },
|
|
|
|
{
|
|
|
|
pubkey: SystemProgram.programId,
|
|
|
|
isSigner: false,
|
|
|
|
isWritable: false,
|
|
|
|
},
|
|
|
|
{ pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
|
|
|
|
],
|
|
|
|
programId: ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
|
|
data: Buffer.from([0x1]),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-09-27 06:13:53 -07:00
|
|
|
export async function buildVersionedTx(
|
|
|
|
provider: AnchorProvider,
|
|
|
|
ix: TransactionInstruction[],
|
|
|
|
additionalSigners: Signer[] = [],
|
|
|
|
alts: AddressLookupTableAccount[] = [],
|
|
|
|
): Promise<VersionedTransaction> {
|
|
|
|
const message = MessageV0.compile({
|
|
|
|
payerKey: (provider as AnchorProvider).wallet.publicKey,
|
|
|
|
instructions: ix,
|
|
|
|
recentBlockhash: (await provider.connection.getLatestBlockhash()).blockhash,
|
|
|
|
addressLookupTableAccounts: alts,
|
|
|
|
});
|
|
|
|
const vTx = new VersionedTransaction(message);
|
|
|
|
vTx.sign([
|
|
|
|
((provider as AnchorProvider).wallet as any).payer as Signer,
|
|
|
|
...additionalSigners,
|
|
|
|
]);
|
|
|
|
return vTx;
|
|
|
|
}
|
2022-09-30 06:07:43 -07:00
|
|
|
|
|
|
|
///
|
|
|
|
/// ts extension
|
|
|
|
///
|
|
|
|
|
|
|
|
// https://stackoverflow.com/questions/70261755/user-defined-type-guard-function-and-type-narrowing-to-more-specific-type/70262876#70262876
|
|
|
|
export declare abstract class As<Tag extends keyof never> {
|
|
|
|
private static readonly $as$: unique symbol;
|
|
|
|
private [As.$as$]: Record<Tag, true>;
|
|
|
|
}
|