TS: add estimatePrioritizationFee

This commit is contained in:
Lou-Kamades 2023-08-09 16:13:55 -05:00
parent f462c62816
commit aace8a06e5
No known key found for this signature in database
GPG Key ID: 87A166E4D7C01F30
4 changed files with 145 additions and 6 deletions

View File

@ -62,7 +62,7 @@
"@project-serum/serum": "0.13.65",
"@pythnetwork/client": "~2.14.0",
"@solana/spl-token": "0.3.7",
"@solana/web3.js": "^1.73.2",
"@solana/web3.js": "^1.78.2",
"@switchboard-xyz/sbv2-lite": "^0.1.6",
"big.js": "^6.1.1",
"binance-api-node": "^0.12.0",

View File

@ -26,6 +26,7 @@ import {
SystemProgram,
TransactionInstruction,
TransactionSignature,
RecentPrioritizationFees,
} from '@solana/web3.js';
import bs58 from 'bs58';
import chunk from 'lodash/chunk';
@ -68,7 +69,12 @@ import {
buildIxGate,
TokenRegisterParams,
} from './clientIxParamBuilder';
import { MANGO_V4_ID, OPENBOOK_PROGRAM_ID, RUST_U64_MAX } from './constants';
import {
MANGO_V4_ID,
MAX_RECENT_PRIORITY_FEE_ACCOUNTS,
OPENBOOK_PROGRAM_ID,
RUST_U64_MAX,
} from './constants';
import { Id } from './ids';
import { IDL, MangoV4 } from './mango_v4';
import { I80F48 } from './numbers/I80F48';
@ -97,6 +103,7 @@ export type MangoClientOptions = {
idsSource?: IdsSource;
postSendTxCallback?: ({ txid }: { txid: string }) => void;
prioritizationFee?: number;
estimateFee?: boolean;
txConfirmationCommitment?: Commitment;
openbookFeesToDao?: boolean;
};
@ -105,6 +112,7 @@ export class MangoClient {
private idsSource: IdsSource;
private postSendTxCallback?: ({ txid }) => void;
private prioritizationFee: number;
private estimateFee: boolean;
private txConfirmationCommitment: Commitment;
private openbookFeesToDao: boolean;
@ -116,6 +124,7 @@ export class MangoClient {
) {
this.idsSource = opts?.idsSource || 'get-program-accounts';
this.prioritizationFee = opts?.prioritizationFee || 0;
this.estimateFee = opts?.estimateFee || false;
this.postSendTxCallback = opts?.postSendTxCallback;
this.openbookFeesToDao = opts?.openbookFeesToDao ?? true;
this.txConfirmationCommitment =
@ -140,13 +149,21 @@ export class MangoClient {
ixs: TransactionInstruction[],
opts: any = {},
): Promise<string> {
let prioritizationFee: number;
if (opts.prioritizationFee) {
prioritizationFee = opts.prioritizationFee;
} else if (this.estimateFee) {
prioritizationFee = await this.estimatePrioritizationFee(ixs);
} else {
prioritizationFee = this.prioritizationFee;
}
return await sendTransaction(
this.program.provider as AnchorProvider,
ixs,
opts.alts ?? [],
{
postSendTxCallback: this.postSendTxCallback,
prioritizationFee: this.prioritizationFee,
prioritizationFee,
txConfirmationCommitment: this.txConfirmationCommitment,
...opts,
},
@ -4193,4 +4210,55 @@ export class MangoClient {
transactionInstructions,
);
}
/**
* Returns an estimate of a prioritization fee for a set of instructions.
*
* The estimate is based on the exponential moving average of the prioritization fees of accounts that will be involved in the transaction.
*
* @param ixs - the instructions that make up the transaction
* @returns prioritizationFeeEstimate -- in microLamports
*/
public async estimatePrioritizationFee(
ixs: TransactionInstruction[],
): Promise<number> {
const accounts = [
...new Set(ixs.map((x) => x.keys.map((k) => k.pubkey)).flat()),
].slice(0, MAX_RECENT_PRIORITY_FEE_ACCOUNTS);
const priorityFees = await this.connection.getRecentPrioritizationFees({
lockedWritableAccounts: accounts,
});
// get max priority fee per slot (and sort by slot from old to new)
const flatFees = priorityFees.flat();
const maxFeeBySlot = flatFees.reduce(
(
acc: Record<number, RecentPrioritizationFees>,
fee: RecentPrioritizationFees,
) => {
if (
!acc[fee.slot] ||
fee.prioritizationFee > acc[fee.slot].prioritizationFee
) {
acc[fee.slot] = fee;
}
return acc;
},
{},
);
const maximumFees = Object.values(maxFeeBySlot).sort(
(a, b) => a.slot - b.slot,
);
// take the EMA
const smoothingFactor = 2 / (maximumFees.length + 1);
let ema = maximumFees[0].prioritizationFee;
for (let i = 1; i < maximumFees.length; i++) {
ema =
maximumFees[i].prioritizationFee * smoothingFactor +
ema * (1 - smoothingFactor);
}
return Math.ceil(1.2 * ema);
}
}

View File

@ -25,3 +25,4 @@ export const MANGO_V4_ID = {
export const USDC_MINT = new PublicKey(
'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
);
export const MAX_RECENT_PRIORITY_FEE_ACCOUNTS = 128;

View File

@ -37,6 +37,13 @@
dependencies:
regenerator-runtime "^0.13.11"
"@babel/runtime@^7.22.6":
version "7.22.10"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.10.tgz#ae3e9631fd947cb7e3610d3e9d8fef5f76696682"
integrity sha512-21t/fkKLMZI4pqP2wlmsQAWnYW1PDyKyyUV4vCi+B25ydmdaYTKXPwCj0BzSUnZf4seIiYvSA3jcZ3gdsMFkLQ==
dependencies:
regenerator-runtime "^0.14.0"
"@colors/colors@1.5.0":
version "1.5.0"
resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
@ -171,11 +178,23 @@
"@jridgewell/resolve-uri" "^3.0.3"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@noble/curves@^1.0.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.1.0.tgz#f13fc667c89184bc04cccb9b11e8e7bae27d8c3d"
integrity sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==
dependencies:
"@noble/hashes" "1.3.1"
"@noble/ed25519@^1.7.0":
version "1.7.3"
resolved "https://registry.yarnpkg.com/@noble/ed25519/-/ed25519-1.7.3.tgz#57e1677bf6885354b466c38e2b620c62f45a7123"
integrity sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ==
"@noble/hashes@1.3.1", "@noble/hashes@^1.3.0":
version "1.3.1"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9"
integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==
"@noble/hashes@^1.1.2":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.2.0.tgz#a3150eeb09cc7ab207ebf6d7b9ad311a9bdbed12"
@ -413,7 +432,7 @@
rpc-websockets "^7.5.0"
superstruct "^0.14.2"
"@solana/web3.js@^1.68.0", "@solana/web3.js@^1.73.2":
"@solana/web3.js@^1.68.0":
version "1.73.2"
resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.73.2.tgz#4b30cd402b35733dae3a7d0b638be26a7742b395"
integrity sha512-9WACF8W4Nstj7xiDw3Oom22QmrhBh0VyZyZ7JvvG3gOxLWLlX3hvm5nPVJOGcCE/9fFavBbCUb5A6CIuvMGdoA==
@ -435,6 +454,27 @@
rpc-websockets "^7.5.0"
superstruct "^0.14.2"
"@solana/web3.js@^1.78.2":
version "1.78.3"
resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.78.3.tgz#1214f17f51612e403c4dc7844c7a9694938bfbab"
integrity sha512-qhpnyIlrj/4Czw1dBFZK6KgZBk5FwuJhvMl0C7m94jhl90yDC8b6w4svKwPjhB+OOrdQAzHyRp0+ocEs/Liw7w==
dependencies:
"@babel/runtime" "^7.22.6"
"@noble/curves" "^1.0.0"
"@noble/hashes" "^1.3.0"
"@solana/buffer-layout" "^4.0.0"
agentkeepalive "^4.3.0"
bigint-buffer "^1.1.5"
bn.js "^5.2.1"
borsh "^0.7.0"
bs58 "^4.0.1"
buffer "6.0.3"
fast-stable-stringify "^1.0.0"
jayson "^4.1.0"
node-fetch "^2.6.12"
rpc-websockets "^7.5.1"
superstruct "^0.14.2"
"@switchboard-xyz/sbv2-lite@^0.1.6":
version "0.1.6"
resolved "https://registry.yarnpkg.com/@switchboard-xyz/sbv2-lite/-/sbv2-lite-0.1.6.tgz#dc3fbb5b3b028dbd3c688b991bcc48a670131ddb"
@ -672,6 +712,13 @@ agentkeepalive@^4.2.1:
depd "^1.1.2"
humanize-ms "^1.2.1"
agentkeepalive@^4.3.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923"
integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==
dependencies:
humanize-ms "^1.2.1"
ajv@^6.10.0, ajv@^6.12.4:
version "6.12.6"
resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz"
@ -858,7 +905,7 @@ bn.js@^4.11.9:
resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz"
integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==
bn.js@^5.0.0, bn.js@^5.1.0, bn.js@^5.1.2, bn.js@^5.1.3, bn.js@^5.2.0:
bn.js@^5.0.0, bn.js@^5.1.0, bn.js@^5.1.2, bn.js@^5.1.3, bn.js@^5.2.0, bn.js@^5.2.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70"
integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==
@ -1754,6 +1801,24 @@ jayson@^3.4.4:
uuid "^8.3.2"
ws "^7.4.5"
jayson@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/jayson/-/jayson-4.1.0.tgz#60dc946a85197317f2b1439d672a8b0a99cea2f9"
integrity sha512-R6JlbyLN53Mjku329XoRT2zJAE6ZgOQ8f91ucYdMCD4nkGCF9kZSrcGXpHIU4jeKj58zUZke2p+cdQchU7Ly7A==
dependencies:
"@types/connect" "^3.4.33"
"@types/node" "^12.12.54"
"@types/ws" "^7.4.4"
JSONStream "^1.3.5"
commander "^2.20.3"
delay "^5.0.0"
es6-promisify "^5.0.0"
eyes "^0.1.8"
isomorphic-ws "^4.0.1"
json-stringify-safe "^5.0.1"
uuid "^8.3.2"
ws "^7.4.5"
js-sha256@^0.9.0:
version "0.9.0"
resolved "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz"
@ -2071,7 +2136,7 @@ node-addon-api@^2.0.0:
resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz"
integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==
node-fetch@2, node-fetch@2.6.7, node-fetch@^2.6.1, node-fetch@^2.6.7, "node-fetch@npm:@blockworks-foundation/node-fetch@2.6.11":
node-fetch@2, node-fetch@2.6.7, node-fetch@^2.6.1, node-fetch@^2.6.12, node-fetch@^2.6.7, "node-fetch@npm:@blockworks-foundation/node-fetch@2.6.11":
version "2.6.11"
resolved "https://registry.yarnpkg.com/@blockworks-foundation/node-fetch/-/node-fetch-2.6.11.tgz#fb536ef0e6a960e7b7993f3c1d3b3bba9bdfbc56"
integrity sha512-HeDTxpIypSR4qCoqgUXGr8YL4OG1z7BbV4VhQ9iQs+pt2wV3MtqO+sQk2vXK3WDKu5C6BsbGmWE22BmIrcuOOw==
@ -2241,6 +2306,11 @@ regenerator-runtime@^0.13.11, regenerator-runtime@^0.13.4:
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9"
integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==
regenerator-runtime@^0.14.0:
version "0.14.0"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45"
integrity sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==
regexpp@^3.1.0, regexpp@^3.2.0:
version "3.2.0"
resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz"