Skip to content

Commit

Permalink
Merge pull request #8234 from LedgerHQ/bugfix/solana-priority-fees
Browse files Browse the repository at this point in the history
fix: solana priority fees [LIVE-11792]
  • Loading branch information
Justkant authored Nov 13, 2024
2 parents 387f182 + cad783e commit f232030
Show file tree
Hide file tree
Showing 17 changed files with 611 additions and 189 deletions.
6 changes: 6 additions & 0 deletions .changeset/small-hairs-flow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@ledgerhq/coin-solana": patch
"@ledgerhq/live-common": patch
---

fix: solana priority fees
8 changes: 8 additions & 0 deletions apps/ledger-live-desktop/scripts/resolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ module.exports = (path, options) => {
"@firebase/util",
"firebase",
"uuid",
"rpc-websockets",
"@solana/codecs",
"@solana/codecs-core",
"@solana/errors",
"@solana/codecs-data-structures",
"@solana/codecs-numbers",
"@solana/codecs-strings",
"@solana/options",
]);

if (pkgNamesToTarget.has(pkg.name)) {
Expand Down
1 change: 1 addition & 0 deletions apps/ledger-live-mobile/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ module.exports = {
{ outputName: "llm-sonar-executionTests-report.xml", reportedFilePath: "absolute" },
],
],
resolver: "<rootDir>/scripts/resolver.js",
moduleNameMapper: {
...pathsToModuleNameMapper(compilerOptions.paths),
"^react$": "<rootDir>/node_modules/react",
Expand Down
27 changes: 27 additions & 0 deletions apps/ledger-live-mobile/scripts/resolver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module.exports = (path, options) => {
// Call the defaultResolver, so we leverage its cache, error handling, etc.
return options.defaultResolver(path, {
...options,
// Use packageFilter to process parsed `package.json` before the resolution (see https://www.npmjs.com/package/resolve#resolveid-opts-cb)
packageFilter: pkg => {
const pkgNamesToTarget = new Set([
"rpc-websockets",
"@solana/codecs",
"@solana/codecs-core",
"@solana/errors",
"@solana/codecs-data-structures",
"@solana/codecs-numbers",
"@solana/codecs-strings",
"@solana/options",
]);

if (pkgNamesToTarget.has(pkg.name)) {
// console.log('>>>', pkg.name)
delete pkg["exports"];
delete pkg["module"];
}

return pkg;
},
});
};
4 changes: 2 additions & 2 deletions libs/coin-modules/coin-solana/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@
"@ledgerhq/logs": "workspace:^",
"@ledgerhq/types-cryptoassets": "workspace:^",
"@ledgerhq/types-live": "workspace:^",
"@solana/spl-token": "^0.3.7",
"@solana/web3.js": "1.77.3",
"@solana/spl-token": "0.4.9",
"@solana/web3.js": "1.95.4",
"bignumber.js": "^9.1.2",
"bs58": "^4.0.1",
"expect": "^27.4.6",
Expand Down
24 changes: 24 additions & 0 deletions libs/coin-modules/coin-solana/src/api/cached.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { makeLRUCache, minutes, seconds } from "@ledgerhq/live-network/cache";
import { PublicKey, TransactionInstruction, TransactionMessage } from "@solana/web3.js";
import hash from "object-hash";
import { ChainAPI } from "./chain";

Expand All @@ -8,6 +9,17 @@ const cacheKeyAssocTokenAccAddress = (owner: string, mint: string) => `${owner}:
const cacheKeyMinimumBalanceForRentExemption = (dataLengt: number) => dataLengt.toString();

const cacheKeyTransactions = (signatures: string[]) => hash([...signatures].sort());
const cacheKeyInstructions = (ixs: TransactionInstruction[], payer: PublicKey) => {
return hash(
new TransactionMessage({
instructions: ixs,
payerKey: payer,
recentBlockhash: payer.toString(),
})
.compileToLegacyMessage()
.serialize(),
);
};

const cacheKeyByArgs = (...args: any[]) => hash(args);

Expand Down Expand Up @@ -74,6 +86,18 @@ export function cached(api: ChainAPI): ChainAPI {

getEpochInfo: makeLRUCache(api.getEpochInfo, cacheKeyEmpty, minutes(1)),

getRecentPrioritizationFees: makeLRUCache(
api.getRecentPrioritizationFees,
cacheKeyByArgs,
seconds(30),
),

getSimulationComputeUnits: makeLRUCache(
api.getSimulationComputeUnits,
cacheKeyInstructions,
seconds(30),
),

config: api.config,
};
}
48 changes: 47 additions & 1 deletion libs/coin-modules/coin-solana/src/api/chain/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import {
sendAndConfirmRawTransaction,
SignaturesForAddressOptions,
StakeProgram,
TransactionInstruction,
ComputeBudgetProgram,
VersionedTransaction,
TransactionMessage,
} from "@solana/web3.js";
import { makeLRUCache, minutes } from "@ledgerhq/live-network/cache";
import { getEnv } from "@ledgerhq/live-env";
Expand Down Expand Up @@ -72,6 +76,15 @@ export type ChainAPI = Readonly<{

getEpochInfo: () => ReturnType<Connection["getEpochInfo"]>;

getRecentPrioritizationFees: (
accounts: string[],
) => ReturnType<Connection["getRecentPrioritizationFees"]>;

getSimulationComputeUnits: (
instructions: Array<TransactionInstruction>,
payer: PublicKey,
) => Promise<number | null>;

config: Config;
}>;

Expand All @@ -88,7 +101,7 @@ export function getChainAPI(
logger === undefined
? undefined
: (url, options, fetch) => {
logger(url, options);
logger(url.toString(), options);
fetch(url, options);
};

Expand Down Expand Up @@ -208,6 +221,39 @@ export function getChainAPI(

getEpochInfo: () => connection().getEpochInfo().catch(remapErrors),

getRecentPrioritizationFees: (accounts: string[]) => {
return connection()
.getRecentPrioritizationFees({
lockedWritableAccounts: accounts.map(acc => new PublicKey(acc)),
})
.catch(remapErrors);
},

getSimulationComputeUnits: async (instructions, payer) => {
// https://solana.com/developers/guides/advanced/how-to-request-optimal-compute
const testInstructions = [
// Set an arbitrarily high number in simulation
// so we can be sure the transaction will succeed
// and get the real compute units used
ComputeBudgetProgram.setComputeUnitLimit({ units: 1_400_000 }),
...instructions,
];
const testTransaction = new VersionedTransaction(
new TransactionMessage({
instructions: testInstructions,
payerKey: payer,
// RecentBlockhash can by any public key during simulation
// since 'replaceRecentBlockhash' is set to 'true' below
recentBlockhash: PublicKey.default.toString(),
}).compileToV0Message(),
);
const rpcResponse = await connection().simulateTransaction(testTransaction, {
replaceRecentBlockhash: true,
sigVerify: false,
});
return rpcResponse.value.err ? null : rpcResponse.value.unitsConsumed || null;
},

config,
};
}
Loading

0 comments on commit f232030

Please sign in to comment.