Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 91 additions & 32 deletions packages/extension/src/ui/action/views/swap/libs/solana-gasvals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,46 +23,86 @@ type TaggedVersionedTransaction = {
hasThirdPartySignatures: boolean;
};

type TaggedTransaction = TaggedLegacyTransaction | TaggedVersionedTransaction;
// Add support for raw transaction data
type RawTransaction = {
kind: 'legacy' | 'versioned';
serialized: string;
hasThirdPartySignatures: boolean;
isRawData: boolean;
from: string;
to: string;
type: string;
thirdPartySignatures: any[];
};

type TaggedTransaction =
| TaggedLegacyTransaction
| TaggedVersionedTransaction
| RawTransaction;

function getTxBlockHash(tx: TaggedTransaction): undefined | string {
// Skip blockhash for raw transactions
if ('isRawData' in tx && tx.isRawData) {
return undefined;
}

let recentBlockHash: undefined | string;
switch (tx.kind) {
case 'legacy':
recentBlockHash = tx.instance.recentBlockhash;
recentBlockHash = (tx as TaggedLegacyTransaction).instance
.recentBlockhash;
break;
case 'versioned':
recentBlockHash = tx.instance.message.recentBlockhash;
recentBlockHash = (tx as TaggedVersionedTransaction).instance.message
.recentBlockhash;
break;
default:
tx satisfies never;
throw new Error(`Unexpected Solana transaction kind ${(tx as any).kind}`);
}
return recentBlockHash;
}

function setTxBlockHash(tx: TaggedTransaction, blockHash: string): void {
switch (tx.kind) {
case 'legacy':
tx.instance.recentBlockhash = blockHash;
break;
case 'versioned':
tx.instance.message.recentBlockhash = blockHash;
break;
default:
tx satisfies never;
throw new Error(`Unexpected Solana transaction kind ${(tx as any).kind}`);
function setTxBlockHash(tx: TaggedTransaction, blockhash: string) {
// Check if this is raw transaction data (unprocessed)
if ('isRawData' in tx && tx.isRawData) {
console.log('Skipping blockhash update for raw transaction data');
return; // Don't try to set blockhash on raw transactions
}

// Check if this has an instance (processed transaction)
if ('instance' in tx && tx.instance) {
switch (tx.kind) {
case 'legacy':
(tx as TaggedLegacyTransaction).instance.recentBlockhash = blockhash;
break;
case 'versioned':
(tx as TaggedVersionedTransaction).instance.message.recentBlockhash =
blockhash;
break;
default:
console.warn(`Unexpected Solana transaction kind: ${(tx as any).kind}`);
break;
}
} else {
console.log('Transaction has no instance - skipping blockhash update');
}
}

function getTxMessage(tx: TaggedTransaction): Message | VersionedMessage {
function getTxMessage(
tx: TaggedTransaction,
): Message | VersionedMessage | null {
// Return null for raw transactions - we can't get the message without deserializing
if ('isRawData' in tx && tx.isRawData) {
return null;
}

let msg: Message | VersionedMessage;
switch (tx.kind) {
case 'legacy':
msg = tx.instance.compileMessage();
msg = (tx as TaggedLegacyTransaction).instance.compileMessage();
break;
case 'versioned':
msg = tx.instance.message;
msg = (tx as TaggedVersionedTransaction).instance.message;
break;
default:
throw new Error(`Unexpected Solana transaction kind ${(tx as any).kind}`);
Expand All @@ -75,32 +115,44 @@ function getTxMessage(tx: TaggedTransaction): Message | VersionedMessage {
* (not nice but convenient)
*/
export const getSolanaTransactionFees = async (
txs: (TaggedLegacyTransaction | TaggedVersionedTransaction)[],
txs: TaggedTransaction[],
network: SolanaNetwork,
price: number,
additionalFee: ReturnType<typeof toBN>,
): Promise<Pick<GasFeeType, GasPriceTypes.REGULAR>> => {
let feesumlamp = additionalFee;
const conn = ((await network.api()) as SolanaAPI).web3;
let latestBlockHash = await conn.getLatestBlockhash();

for (let txi = 0, len = txs.length; txi < len; txi++) {
const tx = txs[txi];

/** For logging / debugging */
let txkind: string;
switch (tx.kind) {
case 'legacy':
txkind = 'legacy';
break;
case 'versioned':
txkind = `versioned (${tx.instance.version})`;
break;
case undefined:
txkind = 'legacy';
break;
default:
txkind = `unknown (${(tx as SolanaVersionedTransaction).version})`;
break;
if ('isRawData' in tx && tx.isRawData) {
txkind = `raw-${tx.kind}`;
} else {
switch (tx.kind) {
case 'legacy':
txkind = 'legacy';
break;
case 'versioned':
txkind = `versioned (${(tx as TaggedVersionedTransaction).instance.version})`;
break;
default:
txkind = `unknown (${(tx as any).kind})`;
break;
}
}

// Handle raw transactions differently
if ('isRawData' in tx && tx.isRawData) {
// Use a reasonable default fee for raw transactions
// Most Solana transactions cost around 5000-10000 lamports
const defaultFee = 10000; // 0.00001 SOL
feesumlamp = feesumlamp.add(toBN(defaultFee));

continue;
}

// Use the latest block hash in-case it's fallen too far behind
Expand Down Expand Up @@ -149,6 +201,13 @@ export const getSolanaTransactionFees = async (

/** Base fee + priority fee (Don't know why this returns null sometimes) */
const msg = getTxMessage(tx);
if (msg === null) {
// This shouldn't happen for non-raw transactions
console.error(`Cannot get message for transaction ${txi + 1}`);
fee = 10000; // Use default fee
break;
}

const feeResult = await conn.getFeeForMessage(msg);
if (feeResult.value == null) {
const recentBlockHash = getTxBlockHash(tx);
Expand Down
56 changes: 16 additions & 40 deletions packages/extension/src/ui/action/views/swap/libs/swap-txs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@ import BitcoinAPI from '@/providers/bitcoin/libs/api';
import { getTxInfo as getBTCTxInfo } from '@/providers/bitcoin/libs/utils';
import { toBN } from 'web3-utils';
import { BTCTxInfo } from '@/providers/bitcoin/ui/types';
import {
VersionedTransaction as SolanaVersionedTransaction,
Transaction as SolanaLegacyTransaction,
} from '@solana/web3.js';

export const getSubstrateNativeTransation = async (
network: SubstrateNetwork,
Expand Down Expand Up @@ -113,42 +109,22 @@ export const getSwapTransactions = async (
const allTxs = await Promise.all(txPromises);
return allTxs;
} else if (netInfo.type === NetworkType.Solana) {
const solTxs: (
| {
kind: 'legacy';
instance: SolanaLegacyTransaction;
hasThirdPartySignatures: boolean;
}
| {
kind: 'versioned';
instance: SolanaVersionedTransaction;
hasThirdPartySignatures: boolean;
}
)[] = (transactions as EnkryptSolanaTransaction[]).map(function (enkSolTx) {
switch (enkSolTx.kind) {
case 'legacy':
return {
kind: 'legacy',
hasThirdPartySignatures: enkSolTx.thirdPartySignatures.length > 0,
instance: SolanaLegacyTransaction.from(
Buffer.from(enkSolTx.serialized, 'base64'),
),
};
case 'versioned':
return {
kind: 'versioned',
hasThirdPartySignatures: enkSolTx.thirdPartySignatures.length > 0,
instance: SolanaVersionedTransaction.deserialize(
Buffer.from(enkSolTx.serialized, 'base64'),
),
};
default:
throw new Error(
`Cannot deserialize Solana transaction: Unexpected kind: ${enkSolTx.kind}`,
);
}
});
return solTxs;
return (transactions as EnkryptSolanaTransaction[]).map(
function (enkSolTx) {
// Return the raw transaction data with original structure
return {
kind: enkSolTx.kind,
serialized: enkSolTx.serialized,
from: enkSolTx.from,
to: enkSolTx.to,
type: enkSolTx.type,
thirdPartySignatures: enkSolTx.thirdPartySignatures,
hasThirdPartySignatures: enkSolTx.thirdPartySignatures.length > 0,
// Mark as raw so other parts of your code know this is unprocessed
isRawData: true,
};
},
);
} else if (netInfo.type === NetworkType.Substrate) {
if (transactions.length > 1)
throw new Error(`Subtrate chains can only have maximum one transaction`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@

<transaction-fee-view
v-model="isOpenSelectFee"
:fees="gasCostValues"
:fees="gasCostValues as GasFeeType"
:selected="selectedFee"
:is-header="true"
@gas-type-changed="selectFee"
Expand Down Expand Up @@ -309,8 +309,19 @@ onMounted(async () => {
network.value = (await getNetworkByName(selectedNetwork))!;
account.value = await KeyRing.getAccount(swapData.fromAddress);
isWindowPopup.value = account.value.isHardware;

swapData.trades.forEach((trade, index) => {
console.log(`Trade ${index + 1}:`, {
provider: trade.provider,
fromAmount: trade.fromTokenAmount.toString(),
toAmount: trade.toTokenAmount.toString(),
additionalFees: trade.additionalNativeFees.toString(),
});
});
Comment on lines +313 to +320
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Remove or conditionally enable debug logging

Debug console.log statements should not be in production code.

-  swapData.trades.forEach((trade, index) => {
-    console.log(`Trade ${index + 1}:`, {
-      provider: trade.provider,
-      fromAmount: trade.fromTokenAmount.toString(),
-      toAmount: trade.toTokenAmount.toString(),
-      additionalFees: trade.additionalNativeFees.toString(),
-    });
-  });
+  if (import.meta.env.DEV) {
+    swapData.trades.forEach((trade, index) => {
+      console.log(`Trade ${index + 1}:`, {
+        provider: trade.provider,
+        fromAmount: trade.fromTokenAmount.toString(),
+        toAmount: trade.toTokenAmount.toString(),
+        additionalFees: trade.additionalNativeFees.toString(),
+      });
+    });
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
swapData.trades.forEach((trade, index) => {
console.log(`Trade ${index + 1}:`, {
provider: trade.provider,
fromAmount: trade.fromTokenAmount.toString(),
toAmount: trade.toTokenAmount.toString(),
additionalFees: trade.additionalNativeFees.toString(),
});
});
if (import.meta.env.DEV) {
swapData.trades.forEach((trade, index) => {
console.log(`Trade ${index + 1}:`, {
provider: trade.provider,
fromAmount: trade.fromTokenAmount.toString(),
toAmount: trade.toTokenAmount.toString(),
additionalFees: trade.additionalNativeFees.toString(),
});
});
}
🤖 Prompt for AI Agents
In packages/extension/src/ui/action/views/swap/views/swap-best-offer/index.vue
around lines 313 to 320, the code contains console.log statements used for
debugging. Remove these console.log calls or wrap them in a conditional check
that ensures they only run in a development environment to prevent debug logs
from appearing in production.


let tempBestTrade = pickedTrade.value;
let tempFinalToFiat = 0;

for (const trade of swapData.trades) {
const toTokenFiat = new SwapToken(swapData.toToken).getRawToFiat(
trade.toTokenAmount,
Expand All @@ -326,12 +337,15 @@ onMounted(async () => {
}
const gasCostFiat = parseFloat(gasTier.fiatValue);
const finalToFiat = toTokenFiat - gasCostFiat;

if (finalToFiat > tempFinalToFiat) {
tempBestTrade = trade;
tempFinalToFiat = finalToFiat;
}
}

pickedTrade.value = tempBestTrade;

await setTransactionFees();
isLooking.value = false;
trackSwapEvents(SwapEventType.SwapVerify, {
Expand Down
14 changes: 14 additions & 0 deletions packages/extension/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import * as dotenv from 'dotenv';
dotenv.config({ path: './.env' });

import { fileURLToPath, URL } from 'node:url';
import { nodePolyfills } from 'vite-plugin-node-polyfills';
import { visualizer } from 'rollup-plugin-visualizer';
Expand Down Expand Up @@ -31,6 +34,11 @@ const getManifest = () => {
}
};

console.log('VITE_OKX_API_KEY:', process.env.VITE_OKX_API_KEY);
console.log('VITE_OKX_SECRET_KEY:', process.env.VITE_OKX_SECRET_KEY);
console.log('VITE_OKX_API_PASSPHRASE:', process.env.VITE_OKX_API_PASSPHRASE);
console.log('VITE_OKX_PROJECT_ID:', process.env.VITE_OKX_PROJECT_ID);

export default defineConfig({
legacy: {
skipWebSocketTokenCheck: true,
Expand All @@ -57,6 +65,12 @@ export default defineConfig({
BROWSER === 'firefox'
? JSON.stringify('FF-build')
: new Date().toLocaleString().replace(/\D/g, ''),
'globalThis.importMetaEnv': JSON.stringify({
VITE_OKX_API_KEY: process.env.VITE_OKX_API_KEY,
VITE_OKX_SECRET_KEY: process.env.VITE_OKX_SECRET_KEY,
VITE_OKX_API_PASSPHRASE: process.env.VITE_OKX_API_PASSPHRASE,
VITE_OKX_PROJECT_ID: process.env.VITE_OKX_PROJECT_ID,
}),
},
plugins: [
visualizer() as PluginOption,
Expand Down
3 changes: 3 additions & 0 deletions packages/swap/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
"@solana/spl-token": "^0.4.13",
"@solana/web3.js": "^1.98.2",
"bignumber.js": "^9.3.0",
"crypto-js": "^4.2.0",
"dotenv": "^16.4.1",
"eventemitter3": "^5.0.1",
"isomorphic-ws": "^5.0.0",
"json-rpc-2.0": "^1.7.0",
Expand All @@ -39,6 +41,7 @@
"ws": "^8.18.2"
},
"devDependencies": {
"@types/crypto-js": "^4.2.2",
"@types/node": "^22.15.24",
"@typescript-eslint/eslint-plugin": "^8.34.1",
"@typescript-eslint/parser": "^8.34.1",
Expand Down
10 changes: 10 additions & 0 deletions packages/swap/src/configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,16 @@ const FEE_CONFIGS: Partial<
fee: 0.03,
},
},
[ProviderName.okx]: {
[WalletIdentifier.enkrypt]: {
referrer: "HXWkRK9a4H1EuBiqP4sVfFsEpd2NasoQPScoXL1NgSE2",
fee: 0.01,
},
[WalletIdentifier.mew]: {
referrer: "CmrkoXWiTW37ZqUZcfJtxiKhy9eRMBQHq1nm8HpmRXH4",
fee: 0.03,
},
},
};

const TOKEN_LISTS: {
Expand Down
2 changes: 2 additions & 0 deletions packages/swap/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import {
import { sortByRank, sortNativeToFront } from "./utils/common";
import SwapToken from "./swapToken";
import { Jupiter } from "./providers/jupiter";
import { OKX } from "./providers/okx";

class Swap extends EventEmitter {
network: SupportedNetworkName;
Expand Down Expand Up @@ -119,6 +120,7 @@ class Swap extends EventEmitter {
new Jupiter(this.api as Web3Solana, this.network),
new Rango(this.api as Web3Solana, this.network),
new Changelly(this.api, this.network),
new OKX(this.api as Web3Solana, this.network),
];
break;
default:
Expand Down
Loading