diff --git a/CHANGELOG.md b/CHANGELOG.md index 281cd11..2609d08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,4 +17,8 @@ ### 1.0.1 (2024-7-25) -- Updated entry point in json package \ No newline at end of file +- Updated entry point in json package + +### 1.0.2 (2025-05-05) + +- Updating solana transaction function for lefi swap which supports different type of solana transaction diff --git a/package-lock.json b/package-lock.json index 465cbc7..4f922e5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,16 @@ { "name": "@getsafle/vault-sol-controller", - "version": "1.0.1", + "version": "1.0.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@getsafle/vault-sol-controller", - "version": "1.0.1", + "version": "1.0.2", "license": "MIT", "dependencies": { "@solana/spl-token": "^0.4.8", - "@solana/web3.js": "^1.95.1", + "@solana/web3.js": "^1.98.2", "bip39": "^3.1.0", "bs58": "^5.0.0", "ed25519-hd-key": "^1.3.0", @@ -280,12 +280,10 @@ } }, "node_modules/@babel/runtime": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz", - "integrity": "sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz", + "integrity": "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==", + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -715,16 +713,17 @@ } }, "node_modules/@solana/web3.js": { - "version": "1.95.1", - "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.95.1.tgz", - "integrity": "sha512-mRX/AjV6QbiOXpWcy5Rz1ZWEH2lVkwO7T0pcv9t97ACpv3/i3tPiqXwk0JIZgSR3wOSTiT26JfygnJH2ulS6dQ==", + "version": "1.98.2", + "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.98.2.tgz", + "integrity": "sha512-BqVwEG+TaG2yCkBMbD3C4hdpustR4FpuUFRPUmqRZYYlPI9Hg4XMWxHWOWRzHE9Lkc9NDjzXFX7lDXSgzC7R1A==", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.24.8", + "@babel/runtime": "^7.25.0", "@noble/curves": "^1.4.2", "@noble/hashes": "^1.4.0", "@solana/buffer-layout": "^4.0.1", + "@solana/codecs-numbers": "^2.1.0", "agentkeepalive": "^4.5.0", - "bigint-buffer": "^1.1.5", "bn.js": "^5.2.1", "borsh": "^0.7.0", "bs58": "^4.0.1", @@ -736,6 +735,56 @@ "superstruct": "^2.0.2" } }, + "node_modules/@solana/web3.js/node_modules/@solana/codecs-core": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.1.0.tgz", + "integrity": "sha512-SR7pKtmJBg2mhmkel2NeHA1pz06QeQXdMv8WJoIR9m8F/hw80K/612uaYbwTt2nkK0jg/Qn/rNSd7EcJ4SBGjw==", + "license": "MIT", + "dependencies": { + "@solana/errors": "2.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/web3.js/node_modules/@solana/codecs-numbers": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.1.0.tgz", + "integrity": "sha512-XMu4yw5iCgQnMKsxSWPPOrGgtaohmupN3eyAtYv3K3C/MJEc5V90h74k5B1GUCiHvcrdUDO9RclNjD9lgbjFag==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "2.1.0", + "@solana/errors": "2.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/web3.js/node_modules/@solana/errors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-2.1.0.tgz", + "integrity": "sha512-l+GxAv0Ar4d3c3PlZdA9G++wFYZREEbbRyAFP8+n8HSg0vudCuzogh/13io6hYuUhG/9Ve8ARZNamhV7UScKNw==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "commander": "^13.1.0" + }, + "bin": { + "errors": "bin/cli.mjs" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, "node_modules/@solana/web3.js/node_modules/base-x": { "version": "3.0.10", "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.10.tgz", @@ -752,6 +801,27 @@ "base-x": "^3.0.2" } }, + "node_modules/@solana/web3.js/node_modules/chalk": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@solana/web3.js/node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/@swc/helpers": { "version": "0.5.12", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.12.tgz", @@ -2721,11 +2791,6 @@ "node": ">=8.10.0" } }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" - }, "node_modules/release-zalgo": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", diff --git a/package.json b/package.json index 90bfdb8..4d8450b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@getsafle/vault-sol-controller", - "version": "1.0.1", + "version": "1.0.2", "description": "Solana chain controller for Safle Vault", "main": "src/index.js", "scripts": { @@ -17,7 +17,7 @@ "license": "MIT", "dependencies": { "@solana/spl-token": "^0.4.8", - "@solana/web3.js": "^1.95.1", + "@solana/web3.js": "^1.98.2", "bip39": "^3.1.0", "bs58": "^5.0.0", "ed25519-hd-key": "^1.3.0", diff --git a/src/helper/generateTransactionObject.js b/src/helper/generateTransactionObject.js index f4809d7..cb877a3 100644 --- a/src/helper/generateTransactionObject.js +++ b/src/helper/generateTransactionObject.js @@ -1,9 +1,26 @@ -const solanaWeb3 = require('@solana/web3.js'); -const { getOrCreateAssociatedTokenAccount, createTransferInstruction} = require("@solana/spl-token"); +const solanaWeb3 = require("@solana/web3.js"); +const { + getOrCreateAssociatedTokenAccount, + createTransferInstruction, +} = require("@solana/spl-token"); -const { solana_transaction: { NATIVE_TRANSFER, TOKEN_TRANSFER }} = require("../config"); +const { + solana_transaction: { NATIVE_TRANSFER, TOKEN_TRANSFER }, +} = require("../config"); async function generateTransactionObject(transaction, signer, connection) { + // ✅ Handle base64 versioned transaction (bypasses normal logic) + if (transaction.serializedTx) { + const rawBuffer = Buffer.from(transaction.serializedTx, "base64"); + const versionedTx = solanaWeb3.VersionedTransaction.deserialize(rawBuffer); + + // ✅ Sign the deserialized versioned transaction + versionedTx.sign([signer]); + + return versionedTx; + } + + // 🔁 Legacy transaction types const { txnType } = transaction; let rawTransaction = {}; @@ -48,16 +65,14 @@ async function generateTransactionObject(transaction, signer, connection) { ); } - // set the desired priority fee in microLamport - if(transaction?.priorityFee && transaction?.priorityFee > 0) { + // ⏫ Optional: Add priority fee if needed + if (transaction?.priorityFee && transaction?.priorityFee > 0) { const addPriorityFee = solanaWeb3.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: transaction.priorityFee, }); - rawTransaction.add(addPriorityFee); } return rawTransaction; } - module.exports = generateTransactionObject; diff --git a/src/index.js b/src/index.js index 689e877..0a82852 100644 --- a/src/index.js +++ b/src/index.js @@ -1,9 +1,8 @@ const bs58 = require("bs58"); -const nacl = require('tweetnacl'); +const nacl = require("tweetnacl"); const helper = require("./helper"); const ObservableStore = require("obs-store"); -const solanaWeb3 = require('@solana/web3.js'); - +const solanaWeb3 = require("@solana/web3.js"); const { solana: { HD_PATH }, @@ -61,7 +60,7 @@ class KeyringController { } async signMessage(message, _address) { - const { mnemonic, address } = this.store.getState() + const { mnemonic, address } = this.store.getState(); const idx = address.indexOf(_address); if (idx < 0) @@ -87,34 +86,55 @@ class KeyringController { try { const signer = helper.setupAccount(mnemonic, helper.getHDPath(idx)); - const connection = new solanaWeb3.Connection(network, "confirmed"); - const rawTx = await helper.generateTransactionObject(transaction, signer, connection); - - const rawSignedTxn = await helper.signTransaction(rawTx, signer, connection, []); - - const signedTxn = rawSignedTxn.serialize().toString("hex"); - - return { signedTransaction: signedTxn }; + // 🔄 Generate the transaction object (legacy or versioned) + const rawTx = await helper.generateTransactionObject( + transaction, + signer, + connection + ); + + // 🔁 Return serialized transaction in hex + if (transaction.serializedTx) { + // 🔐 Sign if it's not already signed + if ( + rawTx.signatures && + rawTx.signatures.some((sig) => sig === undefined || sig.length === 0) + ) { + rawTx.sign([signer]); + } + const signedTxn = Buffer.from(rawTx.serialize()).toString("hex"); + return { signedTransaction: signedTxn }; + } else { + const rawSignedTxn = await helper.signTransaction( + rawTx, + signer, + connection, + [] + ); + + const signedTxn = rawSignedTxn.serialize().toString("hex"); + return { signedTransaction: signedTxn }; + } } catch (err) { throw err; } } async sendTransaction(rawTransaction) { - try { - const { network } = this.store.getState() - const stringBuff = Buffer.from(rawTransaction, 'hex') - - const connection = new solanaWeb3.Connection(network, "confirmed") - const transactionDetails = await connection.sendRawTransaction(stringBuff) - return { transactionDetails: transactionDetails } + const { network } = this.store.getState(); + const stringBuff = Buffer.from(rawTransaction, "hex"); + const connection = new solanaWeb3.Connection(network, "confirmed"); + const transactionDetails = await connection.sendRawTransaction( + stringBuff + ); + return { transactionDetails: transactionDetails }; } catch (err) { console.log(err); - throw err + throw err; } } @@ -126,18 +146,28 @@ class KeyringController { if (idx < 0) throw "Invalid address, the address is not available in the wallet"; - const signer = helper.setupAccount(mnemonic, helper.getHDPath(idx)); + const signer = helper.setupAccount(mnemonic, helper.getHDPath(idx)); - const connection = new solanaWeb3.Connection(network, "confirmed"); + const connection = new solanaWeb3.Connection(network, "confirmed"); - const rawTx = await helper.generateTransactionObject(rawTransaction, signer, connection); - - const rawSignedTxn = await helper.signTransaction(rawTx, signer, connection, []); + const rawTx = await helper.generateTransactionObject( + rawTransaction, + signer, + connection + ); - const fees = await connection.getFeeForMessage(rawSignedTxn.compileMessage()); + const rawSignedTxn = await helper.signTransaction( + rawTx, + signer, + connection, + [] + ); - return { fees: fees.value }; + const fees = await connection.getFeeForMessage( + rawSignedTxn.compileMessage() + ); + return { fees: fees.value }; } persistAllAddress(_address) { @@ -156,13 +186,16 @@ class KeyringController { const getBalance = async (address, network) => { try { - const _network = helper.getNetwork(network) - const connection = new solanaWeb3.Connection(_network, "confirmed") - const accInfo = await connection.getAccountInfo(new solanaWeb3.PublicKey(address), 'confirmed') - return { balance: accInfo ? accInfo.lamports : 0 } + const _network = helper.getNetwork(network); + const connection = new solanaWeb3.Connection(_network, "confirmed"); + const accInfo = await connection.getAccountInfo( + new solanaWeb3.PublicKey(address), + "confirmed" + ); + return { balance: accInfo ? accInfo.lamports : 0 }; } catch (err) { - throw err + throw err; } -} +}; module.exports = { KeyringController, getBalance };