diff --git a/modules/sdk-coin-sol/CHANGELOG.md b/modules/sdk-coin-sol/CHANGELOG.md index eb912ffa27..7b19118507 100644 --- a/modules/sdk-coin-sol/CHANGELOG.md +++ b/modules/sdk-coin-sol/CHANGELOG.md @@ -7,182 +7,99 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline **Note:** Version bump only for package @bitgo/sdk-coin-sol - - - - ## [7.10.3](https://github.com/BitGo/BitGoJS/compare/@bitgo/sdk-coin-sol@7.10.2...@bitgo/sdk-coin-sol@7.10.3) (2025-12-11) **Note:** Version bump only for package @bitgo/sdk-coin-sol - - - - ## [7.10.2](https://github.com/BitGo/BitGoJS/compare/@bitgo/sdk-coin-sol@7.10.1...@bitgo/sdk-coin-sol@7.10.2) (2025-12-05) **Note:** Version bump only for package @bitgo/sdk-coin-sol - - - - ## [7.10.1](https://github.com/BitGo/BitGoJS/compare/@bitgo/sdk-coin-sol@7.10.0...@bitgo/sdk-coin-sol@7.10.1) (2025-12-04) **Note:** Version bump only for package @bitgo/sdk-coin-sol - - - - # [7.10.0](https://github.com/BitGo/BitGoJS/compare/@bitgo/sdk-coin-sol@7.9.0...@bitgo/sdk-coin-sol@7.10.0) (2025-11-26) - ### Features -* **sdk-coin-sol:** big endian support for verifyTransaction ([f1c06bc](https://github.com/BitGo/BitGoJS/commit/f1c06bc6bf0f448fbd1c2dbcd5062e7e6f012c83)) - - - - +- **sdk-coin-sol:** big endian support for verifyTransaction ([f1c06bc](https://github.com/BitGo/BitGoJS/commit/f1c06bc6bf0f448fbd1c2dbcd5062e7e6f012c83)) # [7.9.0](https://github.com/BitGo/BitGoJS/compare/@bitgo/sdk-coin-sol@7.8.0...@bitgo/sdk-coin-sol@7.9.0) (2025-11-19) - ### Features -* bump public types ([bab6c62](https://github.com/BitGo/BitGoJS/commit/bab6c624682c1317456376e6bf7e6691224405b9)) - - - - +- bump public types ([bab6c62](https://github.com/BitGo/BitGoJS/commit/bab6c624682c1317456376e6bf7e6691224405b9)) # [7.8.0](https://github.com/BitGo/BitGoJS/compare/@bitgo/sdk-coin-sol@7.7.0...@bitgo/sdk-coin-sol@7.8.0) (2025-11-13) - ### Features -* **sdk-coin-sol:** classify all WalletConnect transactions as custom using memo ([1f639da](https://github.com/BitGo/BitGoJS/commit/1f639da78dbc2c144ee0a4cc9741d03f036717bf)) - - - - +- **sdk-coin-sol:** classify all WalletConnect transactions as custom using memo ([1f639da](https://github.com/BitGo/BitGoJS/commit/1f639da78dbc2c144ee0a4cc9741d03f036717bf)) # [7.7.0](https://github.com/BitGo/BitGoJS/compare/@bitgo/sdk-coin-sol@7.6.3...@bitgo/sdk-coin-sol@7.7.0) (2025-11-12) - ### Features -* **sdk-coin-sol:** accepting idempotent ATA instructions ([2b41681](https://github.com/BitGo/BitGoJS/commit/2b41681b280d7852cf8b547ba3759137cb31dd30)) -* **sdk-coin-sol:** support SetComputeUnitLimit instructions ([307dca3](https://github.com/BitGo/BitGoJS/commit/307dca3b1728b49954e78dc2bfa56f6e22f22ba5)) - - - - +- **sdk-coin-sol:** accepting idempotent ATA instructions ([2b41681](https://github.com/BitGo/BitGoJS/commit/2b41681b280d7852cf8b547ba3759137cb31dd30)) +- **sdk-coin-sol:** support SetComputeUnitLimit instructions ([307dca3](https://github.com/BitGo/BitGoJS/commit/307dca3b1728b49954e78dc2bfa56f6e22f22ba5)) ## [7.6.3](https://github.com/BitGo/BitGoJS/compare/@bitgo/sdk-coin-sol@7.6.2...@bitgo/sdk-coin-sol@7.6.3) (2025-11-06) **Note:** Version bump only for package @bitgo/sdk-coin-sol - - - - ## [7.6.2](https://github.com/BitGo/BitGoJS/compare/@bitgo/sdk-coin-sol@7.6.1...@bitgo/sdk-coin-sol@7.6.2) (2025-10-31) **Note:** Version bump only for package @bitgo/sdk-coin-sol - - - - ## [7.6.1](https://github.com/BitGo/BitGoJS/compare/@bitgo/sdk-coin-sol@7.6.0...@bitgo/sdk-coin-sol@7.6.1) (2025-10-29) **Note:** Version bump only for package @bitgo/sdk-coin-sol - - - - # [7.6.0](https://github.com/BitGo/BitGoJS/compare/@bitgo/sdk-coin-sol@7.5.0...@bitgo/sdk-coin-sol@7.6.0) (2025-10-24) - ### Features -* **sdk-coin-sol:** implement isWalletAddress for address verfn ([e42fb85](https://github.com/BitGo/BitGoJS/commit/e42fb85505c1fe9d5fe7d18f227377e2d844af77)) -* **sdk-core:** add typing on fetch addresses ([f3dec74](https://github.com/BitGo/BitGoJS/commit/f3dec74befc76bb305a4f9ac72975e4de43787ff)) - - - - +- **sdk-coin-sol:** implement isWalletAddress for address verfn ([e42fb85](https://github.com/BitGo/BitGoJS/commit/e42fb85505c1fe9d5fe7d18f227377e2d844af77)) +- **sdk-core:** add typing on fetch addresses ([f3dec74](https://github.com/BitGo/BitGoJS/commit/f3dec74befc76bb305a4f9ac72975e4de43787ff)) # [7.5.0](https://github.com/BitGo/BitGoJS/compare/@bitgo/sdk-coin-sol@7.4.0...@bitgo/sdk-coin-sol@7.5.0) (2025-10-21) - ### Features -* **sdk-coin-sol:** add recentBlockhash to custom versioned solana tx flow ([191eb86](https://github.com/BitGo/BitGoJS/commit/191eb86aa851cc893b216f23ff0ad3f13423cc2d)) -* **sdk-coin-sol:** update verifyTransaction for versioned sol tx ([11b1723](https://github.com/BitGo/BitGoJS/commit/11b1723718c13f5ef26ef90174ad299edf64aa2a)) - - - - +- **sdk-coin-sol:** add recentBlockhash to custom versioned solana tx flow ([191eb86](https://github.com/BitGo/BitGoJS/commit/191eb86aa851cc893b216f23ff0ad3f13423cc2d)) +- **sdk-coin-sol:** update verifyTransaction for versioned sol tx ([11b1723](https://github.com/BitGo/BitGoJS/commit/11b1723718c13f5ef26ef90174ad299edf64aa2a)) # [7.4.0](https://github.com/BitGo/BitGoJS/compare/@bitgo/sdk-coin-sol@7.3.0...@bitgo/sdk-coin-sol@7.4.0) (2025-10-16) - ### Features -* bump public types ([ca817a6](https://github.com/BitGo/BitGoJS/commit/ca817a637015a33584fd68dbf5c36592b6a13608)) -* **sdk-coin-sol:** inject durable nonce for versioned transactions ([b6d7524](https://github.com/BitGo/BitGoJS/commit/b6d7524b06568c51626fce231a119e15abe86365)) - - - - +- bump public types ([ca817a6](https://github.com/BitGo/BitGoJS/commit/ca817a637015a33584fd68dbf5c36592b6a13608)) +- **sdk-coin-sol:** inject durable nonce for versioned transactions ([b6d7524](https://github.com/BitGo/BitGoJS/commit/b6d7524b06568c51626fce231a119e15abe86365)) # [7.3.0](https://github.com/BitGo/BitGoJS/compare/@bitgo/sdk-coin-sol@7.2.3...@bitgo/sdk-coin-sol@7.3.0) (2025-10-13) - ### Features -* support versioned sol transactions with customTx intent ([b33402f](https://github.com/BitGo/BitGoJS/commit/b33402f9a7c4724804a2f45737fcbd2562f6bb3e)) - - - - +- support versioned sol transactions with customTx intent ([b33402f](https://github.com/BitGo/BitGoJS/commit/b33402f9a7c4724804a2f45737fcbd2562f6bb3e)) ## [7.2.3](https://github.com/BitGo/BitGoJS/compare/@bitgo/sdk-coin-sol@7.2.2...@bitgo/sdk-coin-sol@7.2.3) (2025-10-10) - ### Bug Fixes -* upgrade public types version ([49cb5b1](https://github.com/BitGo/BitGoJS/commit/49cb5b1f07bf63ae0fab7feb5f55457f641ada9f)) - - - - +- upgrade public types version ([49cb5b1](https://github.com/BitGo/BitGoJS/commit/49cb5b1f07bf63ae0fab7feb5f55457f641ada9f)) ## [7.2.2](https://github.com/BitGo/BitGoJS/compare/@bitgo/sdk-coin-sol@7.2.1...@bitgo/sdk-coin-sol@7.2.2) (2025-10-09) - ### Bug Fixes -* run check-fmt on code files only ([9745196](https://github.com/BitGo/BitGoJS/commit/9745196b02b9678c740d290a4638ceb153a8fd75)) - - - - +- run check-fmt on code files only ([9745196](https://github.com/BitGo/BitGoJS/commit/9745196b02b9678c740d290a4638ceb153a8fd75)) ## [7.2.1](https://github.com/BitGo/BitGoJS/compare/@bitgo/sdk-coin-sol@7.2.0...@bitgo/sdk-coin-sol@7.2.1) (2025-10-08) - ### Bug Fixes -* add explicit 'files' in package json ([3b00373](https://github.com/BitGo/BitGoJS/commit/3b0037396f6ac16bb9380bd85bf37f2b133068f4)) - - - - +- add explicit 'files' in package json ([3b00373](https://github.com/BitGo/BitGoJS/commit/3b0037396f6ac16bb9380bd85bf37f2b133068f4)) # [7.2.0](https://github.com/BitGo/BitGoJS/compare/@bitgo/sdk-coin-sol@7.1.0...@bitgo/sdk-coin-sol@7.2.0) (2025-10-02) diff --git a/modules/sdk-coin-sol/scripts/README.md b/modules/sdk-coin-sol/scripts/README.md index 90754ddf88..e6f1fbbde2 100644 --- a/modules/sdk-coin-sol/scripts/README.md +++ b/modules/sdk-coin-sol/scripts/README.md @@ -5,15 +5,17 @@ Determines safe transaction limits for Solana legacy transactions (1232 byte limit). **Run:** + ```bash npx tsx modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts ``` **Output:** + - Console: Test results and recommended limits - File: `transaction-size-benchmark-results.json` **Tests:** + - Token transfers with ATA creation (new recipients) - Token transfers without ATA creation (existing accounts) - diff --git a/modules/sdk-coin-sol/scripts/transaction-size-benchmark-results.json b/modules/sdk-coin-sol/scripts/transaction-size-benchmark-results.json new file mode 100644 index 0000000000..bcb32e1f7a --- /dev/null +++ b/modules/sdk-coin-sol/scripts/transaction-size-benchmark-results.json @@ -0,0 +1,362 @@ +{ + "timestamp": "2025-12-26T06:44:40.505Z", + "solanaLegacyTxSizeLimit": 1232, + "withAtaCreation": { + "maxSafe": 9, + "conservative": 8, + "testResults": [ + { + "recipientCount": 1, + "withAtaCreation": true, + "instructionCount": 3, + "payloadSize": 478, + "isVersioned": false, + "success": true + }, + { + "recipientCount": 5, + "withAtaCreation": true, + "instructionCount": 11, + "payloadSize": 842, + "isVersioned": false, + "success": true + }, + { + "recipientCount": 6, + "withAtaCreation": true, + "instructionCount": 13, + "payloadSize": 933, + "isVersioned": false, + "success": true + }, + { + "recipientCount": 7, + "withAtaCreation": true, + "instructionCount": 15, + "payloadSize": 1024, + "isVersioned": false, + "success": true + }, + { + "recipientCount": 8, + "withAtaCreation": true, + "instructionCount": 17, + "payloadSize": 1115, + "isVersioned": false, + "success": true + }, + { + "recipientCount": 9, + "withAtaCreation": true, + "instructionCount": 19, + "payloadSize": 1206, + "isVersioned": false, + "success": true + }, + { + "recipientCount": 10, + "withAtaCreation": true, + "instructionCount": 21, + "payloadSize": 1232, + "isVersioned": false, + "success": false, + "error": "Transaction too large: 1297 > 1232", + "errorStack": "Error: Transaction too large: 1297 > 1232\n at invariant (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/utils/assert.ts:6:11)\n at _serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:860:5)\n at serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:832:17)\n at Transaction.toBroadcastFormat (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/src/lib/transaction.ts:275:33)\n at testTransactionSize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:87:29)\n at async runBenchmark (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:160:20)" + }, + { + "recipientCount": 12, + "withAtaCreation": true, + "instructionCount": 25, + "payloadSize": 1414, + "isVersioned": false, + "success": false, + "error": "Transaction too large: 1479 > 1232", + "errorStack": "Error: Transaction too large: 1479 > 1232\n at invariant (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/utils/assert.ts:6:11)\n at _serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:860:5)\n at serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:832:17)\n at Transaction.toBroadcastFormat (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/src/lib/transaction.ts:275:33)\n at testTransactionSize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:87:29)\n at async runBenchmark (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:160:20)" + }, + { + "recipientCount": 13, + "withAtaCreation": true, + "instructionCount": 27, + "payloadSize": 1505, + "isVersioned": false, + "success": false, + "error": "Transaction too large: 1570 > 1232", + "errorStack": "Error: Transaction too large: 1570 > 1232\n at invariant (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/utils/assert.ts:6:11)\n at _serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:860:5)\n at serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:832:17)\n at Transaction.toBroadcastFormat (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/src/lib/transaction.ts:275:33)\n at testTransactionSize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:87:29)\n at async runBenchmark (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:160:20)" + }, + { + "recipientCount": 14, + "withAtaCreation": true, + "instructionCount": 29, + "payloadSize": 1596, + "isVersioned": false, + "success": false, + "error": "Transaction too large: 1661 > 1232", + "errorStack": "Error: Transaction too large: 1661 > 1232\n at invariant (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/utils/assert.ts:6:11)\n at _serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:860:5)\n at serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:832:17)\n at Transaction.toBroadcastFormat (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/src/lib/transaction.ts:275:33)\n at testTransactionSize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:87:29)\n at async runBenchmark (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:160:20)" + }, + { + "recipientCount": 15, + "withAtaCreation": true, + "instructionCount": 31, + "payloadSize": 1687, + "isVersioned": false, + "success": false, + "error": "Transaction too large: 1752 > 1232", + "errorStack": "Error: Transaction too large: 1752 > 1232\n at invariant (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/utils/assert.ts:6:11)\n at _serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:860:5)\n at serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:832:17)\n at Transaction.toBroadcastFormat (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/src/lib/transaction.ts:275:33)\n at testTransactionSize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:87:29)\n at async runBenchmark (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:160:20)" + }, + { + "recipientCount": 16, + "withAtaCreation": true, + "instructionCount": 33, + "payloadSize": 1778, + "isVersioned": false, + "success": false, + "error": "Transaction too large: 1843 > 1232", + "errorStack": "Error: Transaction too large: 1843 > 1232\n at invariant (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/utils/assert.ts:6:11)\n at _serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:860:5)\n at serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:832:17)\n at Transaction.toBroadcastFormat (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/src/lib/transaction.ts:275:33)\n at testTransactionSize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:87:29)\n at async runBenchmark (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:160:20)" + }, + { + "recipientCount": 17, + "withAtaCreation": true, + "instructionCount": 35, + "payloadSize": 1869, + "isVersioned": false, + "success": false, + "error": "Transaction too large: 1934 > 1232", + "errorStack": "Error: Transaction too large: 1934 > 1232\n at invariant (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/utils/assert.ts:6:11)\n at _serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:860:5)\n at serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:832:17)\n at Transaction.toBroadcastFormat (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/src/lib/transaction.ts:275:33)\n at testTransactionSize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:87:29)\n at async runBenchmark (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:160:20)" + }, + { + "recipientCount": 18, + "withAtaCreation": true, + "instructionCount": 37, + "payloadSize": 1960, + "isVersioned": false, + "success": false, + "error": "Transaction too large: 2025 > 1232", + "errorStack": "Error: Transaction too large: 2025 > 1232\n at invariant (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/utils/assert.ts:6:11)\n at _serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:860:5)\n at serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:832:17)\n at Transaction.toBroadcastFormat (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/src/lib/transaction.ts:275:33)\n at testTransactionSize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:87:29)\n at async runBenchmark (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:160:20)" + }, + { + "recipientCount": 20, + "withAtaCreation": true, + "instructionCount": 41, + "payloadSize": 2048, + "isVersioned": false, + "success": false, + "error": "Transaction too large: 2113 > 1232", + "errorStack": "Error: Transaction too large: 2113 > 1232\n at invariant (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/utils/assert.ts:6:11)\n at _serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:860:5)\n at serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:832:17)\n at Transaction.toBroadcastFormat (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/src/lib/transaction.ts:275:33)\n at testTransactionSize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:87:29)\n at async runBenchmark (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:160:20)" + }, + { + "recipientCount": 25, + "withAtaCreation": true, + "instructionCount": 51, + "payloadSize": 2048, + "isVersioned": false, + "success": false, + "error": "Transaction too large: 2113 > 1232", + "errorStack": "Error: Transaction too large: 2113 > 1232\n at invariant (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/utils/assert.ts:6:11)\n at _serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:860:5)\n at serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:832:17)\n at Transaction.toBroadcastFormat (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/src/lib/transaction.ts:275:33)\n at testTransactionSize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:87:29)\n at async runBenchmark (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:160:20)" + }, + { + "recipientCount": 30, + "withAtaCreation": true, + "instructionCount": 0, + "payloadSize": 0, + "isVersioned": false, + "success": false, + "error": "encoding overruns Uint8Array", + "errorStack": "RangeError: encoding overruns Uint8Array\n at Blob.encode (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/buffer-layout/src/Layout.ts:2294:13)\n at (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/buffer-layout/src/Layout.ts:1059:25)\n at Array.reduce ()\n at Sequence.encode (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/buffer-layout/src/Layout.ts:1058:30)\n at Structure.encode (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/buffer-layout/src/Layout.ts:1205:26)\n at serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/message/legacy.ts:260:35)\n at _partialSign (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:724:30)\n at partialSign (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:717:10)\n at TokenTransferBuilder.buildLegacyTransaction (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/src/lib/transactionBuilder.ts:199:10)\n at TokenTransferBuilder.buildSolTransaction (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/src/lib/transactionBuilder.ts:155:19)" + } + ] + }, + "withoutAtaCreation": { + "maxSafe": 19, + "conservative": 17, + "testResults": [ + { + "recipientCount": 1, + "withAtaCreation": false, + "instructionCount": 2, + "payloadSize": 340, + "isVersioned": false, + "success": true + }, + { + "recipientCount": 10, + "withAtaCreation": false, + "instructionCount": 11, + "payloadSize": 781, + "isVersioned": false, + "success": true + }, + { + "recipientCount": 11, + "withAtaCreation": false, + "instructionCount": 12, + "payloadSize": 830, + "isVersioned": false, + "success": true + }, + { + "recipientCount": 12, + "withAtaCreation": false, + "instructionCount": 13, + "payloadSize": 879, + "isVersioned": false, + "success": true + }, + { + "recipientCount": 13, + "withAtaCreation": false, + "instructionCount": 14, + "payloadSize": 928, + "isVersioned": false, + "success": true + }, + { + "recipientCount": 14, + "withAtaCreation": false, + "instructionCount": 15, + "payloadSize": 977, + "isVersioned": false, + "success": true + }, + { + "recipientCount": 15, + "withAtaCreation": false, + "instructionCount": 16, + "payloadSize": 1026, + "isVersioned": false, + "success": true + }, + { + "recipientCount": 16, + "withAtaCreation": false, + "instructionCount": 17, + "payloadSize": 1075, + "isVersioned": false, + "success": true + }, + { + "recipientCount": 17, + "withAtaCreation": false, + "instructionCount": 18, + "payloadSize": 1124, + "isVersioned": false, + "success": true + }, + { + "recipientCount": 18, + "withAtaCreation": false, + "instructionCount": 19, + "payloadSize": 1173, + "isVersioned": false, + "success": true + }, + { + "recipientCount": 19, + "withAtaCreation": false, + "instructionCount": 20, + "payloadSize": 1222, + "isVersioned": false, + "success": true + }, + { + "recipientCount": 20, + "withAtaCreation": false, + "instructionCount": 21, + "payloadSize": 1206, + "isVersioned": false, + "success": false, + "error": "Transaction too large: 1271 > 1232", + "errorStack": "Error: Transaction too large: 1271 > 1232\n at invariant (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/utils/assert.ts:6:11)\n at _serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:860:5)\n at serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:832:17)\n at Transaction.toBroadcastFormat (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/src/lib/transaction.ts:275:33)\n at testTransactionSize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:87:29)\n at async runBenchmark (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:190:20)" + }, + { + "recipientCount": 30, + "withAtaCreation": false, + "instructionCount": 31, + "payloadSize": 1696, + "isVersioned": false, + "success": false, + "error": "Transaction too large: 1761 > 1232", + "errorStack": "Error: Transaction too large: 1761 > 1232\n at invariant (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/utils/assert.ts:6:11)\n at _serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:860:5)\n at serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:832:17)\n at Transaction.toBroadcastFormat (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/src/lib/transaction.ts:275:33)\n at testTransactionSize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:87:29)\n at async runBenchmark (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:190:20)" + }, + { + "recipientCount": 35, + "withAtaCreation": false, + "instructionCount": 36, + "payloadSize": 1941, + "isVersioned": false, + "success": false, + "error": "Transaction too large: 2006 > 1232", + "errorStack": "Error: Transaction too large: 2006 > 1232\n at invariant (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/utils/assert.ts:6:11)\n at _serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:860:5)\n at serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:832:17)\n at Transaction.toBroadcastFormat (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/src/lib/transaction.ts:275:33)\n at testTransactionSize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:87:29)\n at async runBenchmark (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:190:20)" + }, + { + "recipientCount": 38, + "withAtaCreation": false, + "instructionCount": 39, + "payloadSize": 2048, + "isVersioned": false, + "success": false, + "error": "Transaction too large: 2113 > 1232", + "errorStack": "Error: Transaction too large: 2113 > 1232\n at invariant (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/utils/assert.ts:6:11)\n at _serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:860:5)\n at serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:832:17)\n at Transaction.toBroadcastFormat (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/src/lib/transaction.ts:275:33)\n at testTransactionSize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:87:29)\n at async runBenchmark (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:190:20)" + }, + { + "recipientCount": 39, + "withAtaCreation": false, + "instructionCount": 40, + "payloadSize": 2048, + "isVersioned": false, + "success": false, + "error": "Transaction too large: 2113 > 1232", + "errorStack": "Error: Transaction too large: 2113 > 1232\n at invariant (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/utils/assert.ts:6:11)\n at _serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:860:5)\n at serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:832:17)\n at Transaction.toBroadcastFormat (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/src/lib/transaction.ts:275:33)\n at testTransactionSize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:87:29)\n at async runBenchmark (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:190:20)" + }, + { + "recipientCount": 40, + "withAtaCreation": false, + "instructionCount": 41, + "payloadSize": 2048, + "isVersioned": false, + "success": false, + "error": "Transaction too large: 2113 > 1232", + "errorStack": "Error: Transaction too large: 2113 > 1232\n at invariant (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/utils/assert.ts:6:11)\n at _serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:860:5)\n at serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:832:17)\n at Transaction.toBroadcastFormat (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/src/lib/transaction.ts:275:33)\n at testTransactionSize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:87:29)\n at async runBenchmark (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:190:20)" + }, + { + "recipientCount": 41, + "withAtaCreation": false, + "instructionCount": 42, + "payloadSize": 2048, + "isVersioned": false, + "success": false, + "error": "Transaction too large: 2113 > 1232", + "errorStack": "Error: Transaction too large: 2113 > 1232\n at invariant (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/utils/assert.ts:6:11)\n at _serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:860:5)\n at serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:832:17)\n at Transaction.toBroadcastFormat (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/src/lib/transaction.ts:275:33)\n at testTransactionSize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:87:29)\n at async runBenchmark (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:190:20)" + }, + { + "recipientCount": 42, + "withAtaCreation": false, + "instructionCount": 43, + "payloadSize": 2048, + "isVersioned": false, + "success": false, + "error": "Transaction too large: 2113 > 1232", + "errorStack": "Error: Transaction too large: 2113 > 1232\n at invariant (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/utils/assert.ts:6:11)\n at _serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:860:5)\n at serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:832:17)\n at Transaction.toBroadcastFormat (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/src/lib/transaction.ts:275:33)\n at testTransactionSize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:87:29)\n at async runBenchmark (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:190:20)" + }, + { + "recipientCount": 45, + "withAtaCreation": false, + "instructionCount": 46, + "payloadSize": 2048, + "isVersioned": false, + "success": false, + "error": "Transaction too large: 2113 > 1232", + "errorStack": "Error: Transaction too large: 2113 > 1232\n at invariant (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/utils/assert.ts:6:11)\n at _serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:860:5)\n at serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:832:17)\n at Transaction.toBroadcastFormat (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/src/lib/transaction.ts:275:33)\n at testTransactionSize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:87:29)\n at async runBenchmark (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:190:20)" + }, + { + "recipientCount": 50, + "withAtaCreation": false, + "instructionCount": 51, + "payloadSize": 2048, + "isVersioned": false, + "success": false, + "error": "Transaction too large: 2113 > 1232", + "errorStack": "Error: Transaction too large: 2113 > 1232\n at invariant (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/utils/assert.ts:6:11)\n at _serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:860:5)\n at serialize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/node_modules/@solana/web3.js/src/transaction/legacy.ts:832:17)\n at Transaction.toBroadcastFormat (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/src/lib/transaction.ts:275:33)\n at testTransactionSize (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:87:29)\n at async runBenchmark (/Users/rakeshreddy/Documents/BitGo/BitGoJS/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts:190:20)" + } + ] + } +} diff --git a/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts b/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts index c042ae045f..11cfaac30a 100644 --- a/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts +++ b/modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts @@ -1,26 +1,32 @@ /** * Transaction Size Benchmark Script * - * This script empirically tests Solana transaction size limits by building - * transactions with varying numbers of recipients and measuring the serialized - * payload size. This helps determine safe, conservative limits for production use. - * - * Solana Legacy Transaction Constraints: - * - Maximum transaction size: 1232 bytes - * - Each instruction includes program ID, accounts, and instruction data - * - Account metadata and signatures add to the total size + * Empirically determines Solana transaction size limits by testing various recipient counts. + * All test data is generated programmatically to ensure validity. * * Run: npx tsx modules/sdk-coin-sol/scripts/transaction-size-benchmark.ts */ -import { TransactionBuilderFactory, KeyPair } from '../src'; +import { TransactionBuilderFactory, KeyPair, Transaction } from '../src'; +import { SOLANA_TRANSACTION_MAX_SIZE } from '../src/lib/constants'; import { coins } from '@bitgo/statics'; +import * as crypto from 'crypto'; +import bs58 from 'bs58'; + +function generateBlockhash(): string { + return bs58.encode(crypto.randomBytes(32)); +} -const SOLANA_LEGACY_TX_SIZE_LIMIT = 1232; -const TEST_BLOCKHASH = 'GHtXQBsoZHVnNFa9YevAzFr17DJjgHXk3ycTKD5xD3Zi'; -const TEST_PRIVATE_KEY = '5jtsd9SmUH5mFZL7ywNNmqmxxdXw4FQ5GJQprXmrdX4LCuUwMBivCfUX2ar8hGdnLHDGrVKkshW1Ke21vZhPiLyr'; -const TEST_TOKEN = 'tsol:usdt'; -const TEST_AMOUNT = '1000000000'; +function generateTestConfig() { + const authAccount = new KeyPair(); + return { + blockhash: generateBlockhash(), + authAccount, + sender: authAccount.getKeys().pub, + token: 'tsol:usdt', + amount: '1000000000', + }; +} interface BenchmarkResult { recipientCount: number; @@ -33,110 +39,77 @@ interface BenchmarkResult { errorStack?: string; } -/** - * Generates an array of unique test recipient addresses - */ function generateRecipients(count: number): string[] { - const baseAddresses = [ - 'GYFtQoFCRvGS3WgJe32nRi8LarbSH81rp32SeTmd8mqT', - '9AKiRaA3NusuW9WcFz5NQ7K1vqf9FMLtb1hFXqc7imkx', - 'FiLHbfatU4keyGzZ1KjC57L3iYmVUi2azJ1ozSZsZWD6', - '6XKXKPfk5bHmHV4eL2ZFZ5ubcMu6YLed86niBfx7P4Pg', - 'CfhjtJ7W1HHmwXPo9HAkG25gDJPav64iN9Z3nx8eCWV8', - 'DNNSTu2fkj45u6oQuH1fBc3tyDjnnbvhAESrZGhH3uxa', - 'EHPBg7n93e1TWW7oXDwpivQTjZmpavzN9T6HEqAN4bz1', - 'EUZfVoaJgApESLe3Bx8d7xyqg1pucgeydBLQPiRhi6nE', - 'EqE7fJ89HZTAE8MxmJtxCqLhW1ozfhaqZigM5cYxRdHx', - 'CDFk1LXXbWqkd8q9cEsnc3nX44uKgrkDb48b9keBrt8H', - 'EFDfayERUomCbAKurccrAbEYmkyZ1ytazgkiBMBGM851', - 'EPPE9i37rnwWFzagoEHQtBM644p52q54UUGqemJPkAQu', - '3UKwF59ZmRPXq8ooQDjMmzYUiH861KwhJPzjcYfPXDTG', - 'Cr2yAAa7zEkSLJGebkscXQKNTpmgg5ECC4tCkZHHpNvG', - '8wQ2VzVEtYDzKaJ5XqGskkQAJZT5YJwHiUTPa7juCF4w', - '3URWW579b4ugLecHca69feGTM7LKPZ3jDrdTegosVE24', - '3pL2GxpS8QJoNXhXicnEQ2nvXxFbSy7CoJCRxiWtAuQs', - 'Cei1xdDuZmQxU6FNAcrrmM7aR7amF72osySgS8afpv5m', - '5Dd1qGYbbdudLi6uCdDodZw1CJ15j2zWnb7ZxQ68em5a', - '4fviuPUgg3uJp7J2eqLCmeuiHh6zUbn8iXm6JcECNH7T', - '4g9w2CsTR5h6urpuvm5R5w7UGPKUuCmrSSbj5BWAygq2', - '3PRwJ1PjrwF7rBCSsNjAH2s8Pr2XdbSm9koGcVLmrnaz', - '3p9ViY8efykqjixyZGVY2hPLVpHcfsUDKrrHqCUWyYPb', - '3oANXoBY6b5qgwRf1yES6kx1hf7rDGbEWkopcmXxau1u', - '3NqKx8uf3V1bTBtkniMzxVsuqW7SZmTnhJpRFuV6aAFz', - '3NVNrcyJjZmH7xytX2ayPZRucS1YBywwZ5DMzjGRtJvu', - '4iLLJqwHSdZPBbDPFpG8XiDazX8jMEam8fPQWwrG3qGP', - '3wbfKiB6uZuZ3KhjVcU9qc5M4yaWyx6mAUJA56tCD1vJ', - '4QheUEWRi8nesT94mRxiizZnAtRQTnk45jb4oaKMoo1f', - '4PowojicaKCxgupfPCZK5DT7QB1U3N7xh8Wq7N7VoCvw', - 'F3rTU6cFx9Aqa9jmuq5rSZN7p8bu1pmU9EbNBPeKHz7t', - '6XREPthmB7mTwLTHv54DZM14rgAuMa1NgXsmPeFgrqwu', - '5LTQgjYbbBsZj3V5rPmkcAkPcJcbCT8PQTskz2rWL3kW', - '7aG7LiNQ4hMNWwXTZRrpYVpPZDxY1Ea9YcbHuEjXXKVT', - 'DNyKPeaGfoPYzPmNG4osMZJdyJBZbeMUfNKAAt5RSw23', - 'DpFPcPk454MhoGv71DoaoHSJ5qWnKcVAo9euVoPWPprZ', - 'E4T6wq3aF4LivPfgr5sBKFUJLTZz7sND8duJDYK2EbXG', - 'EeM3aXzgt3Qf7tNV4RBe4vg83gtyGZqUQrJumzwtTUvN', - 'EqBF851o6HknqDy5Ji8PCtyxo48ACjBVPhC1NSpAKbEx', - 'EQVV74ZC332uKpZXrCVU7xzqTBBTdom3DERsEnRNqmAF', - 'EvnEyrSG5qSnxsCSqxdhbbKrcg2oiikKiTtYhwbAMnKT', - 'EBxE1QUeYuKsCCYuDsf6ngUV4ApmGUdc913b1oCLCwus', - '5GjFQdcCpB9Wj9CJFbMfKTfB7X9h6FSdqrxG6HaJAmUF', - 'EY1wKHGmTUK89aKjZ8qmycyx5gQjBDgeWPfKcwQf2Hvd', - 'EzLYbB2JcSPf9FwiWonD2XfEd3S89ghuMUH27UPvQzgJ', - '2n2xqWM9Z18LqxfJzkNrMMFWiDUFYA2k6WSgSnf6EnJs', - 'DesU7XscZjng8yj5VX6AZsk3hWSW4sQ3rTG2LuyQ2P4H', - 'Azz9EmNuhtjoYrhWvidWx1Hfd14SNBsYyzXhA9Tnoca8', - '5ne7phA48Jrvpn39AtupB8ZkCCAy8gLTfpGihZPuDqen', - ]; - - return baseAddresses.slice(0, Math.min(count, baseAddresses.length)); + const recipients: string[] = []; + for (let i = 0; i < count; i++) { + recipients.push(new KeyPair().getAddress()); + } + return recipients; } -/** - * Tests building a transaction with a specific number of recipients - */ async function testTransactionSize(recipientCount: number, withAtaCreation: boolean): Promise { const coinConfig = coins.get('tsol'); const factory = new TransactionBuilderFactory(coinConfig); - const authAccount = new KeyPair({ prv: TEST_PRIVATE_KEY }); - const sender = authAccount.getKeys().pub; + const testConfig = generateTestConfig(); const recipients = generateRecipients(recipientCount); try { const txBuilder = factory.getTokenTransferBuilder(); - txBuilder.nonce(TEST_BLOCKHASH); - txBuilder.sender(sender); + txBuilder.nonce(testConfig.blockhash); + txBuilder.sender(testConfig.sender); for (const recipientAddress of recipients) { txBuilder.send({ address: recipientAddress, - amount: TEST_AMOUNT, - tokenName: TEST_TOKEN, + amount: testConfig.amount, + tokenName: testConfig.token, }); if (withAtaCreation) { txBuilder.createAssociatedTokenAccount({ ownerAddress: recipientAddress, - tokenName: TEST_TOKEN, + tokenName: testConfig.token, }); } } txBuilder.memo('Benchmark test transaction'); - txBuilder.sign({ key: authAccount.getKeys().prv }); + txBuilder.sign({ key: testConfig.authAccount.getKeys().prv }); - const tx = await txBuilder.build(); - const payload = tx.signablePayload; + const tx = (await txBuilder.build()) as Transaction; const instructionCount = tx.toJson().instructionsData?.length || 0; const isVersioned = tx.isVersionedTransaction(); + let payloadSize = 0; + let serializationError: { message: string; stack?: string } | undefined; + + try { + const serialized = tx.toBroadcastFormat(); + payloadSize = Buffer.from(serialized, 'base64').length; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + const errorStack = error instanceof Error ? error.stack : undefined; + serializationError = { message: errorMessage, stack: errorStack }; + + try { + const payload = tx.signablePayload; + payloadSize = payload.length; + } catch { + payloadSize = 0; + } + } + + const isWithinLimit = !isVersioned && payloadSize <= SOLANA_TRANSACTION_MAX_SIZE && !serializationError; + return { recipientCount, withAtaCreation, instructionCount, - payloadSize: payload.length, + payloadSize, isVersioned, - success: true, + success: isWithinLimit, + error: serializationError?.message, + errorStack: serializationError?.stack, }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); @@ -155,9 +128,6 @@ async function testTransactionSize(recipientCount: number, withAtaCreation: bool } } -/** - * Performs binary search to find the maximum safe recipient count for LEGACY transactions - */ async function findMaxRecipients(withAtaCreation: boolean): Promise { let left = 1; let right = 50; @@ -167,8 +137,7 @@ async function findMaxRecipients(withAtaCreation: boolean): Promise { const mid = Math.floor((left + right) / 2); const result = await testTransactionSize(mid, withAtaCreation); - // Only consider legacy transactions within the size limit as safe - if (result.success && !result.isVersioned && result.payloadSize <= SOLANA_LEGACY_TX_SIZE_LIMIT) { + if (result.success && !result.isVersioned && result.payloadSize <= SOLANA_TRANSACTION_MAX_SIZE) { maxSafe = mid; left = mid + 1; } else { @@ -179,39 +148,31 @@ async function findMaxRecipients(withAtaCreation: boolean): Promise { return maxSafe; } -/** - * Main benchmark execution - */ async function runBenchmark(): Promise { console.log('Solana Transaction Size Benchmark'); - console.log('Limit: 1232 bytes for legacy transactions\n'); + console.log(`Limit: ${SOLANA_TRANSACTION_MAX_SIZE} bytes for legacy transactions\n`); - // Test WITH ATA creation console.log('[1/2] Testing WITH ATA Creation:'); const withAtaResults: BenchmarkResult[] = []; - const testCountsWithAta = [1, 5, 10, 12, 13, 14, 15, 16, 17, 18, 20, 25, 30]; + const testCountsWithAta = [1, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 20, 25, 30]; for (const count of testCountsWithAta) { const result = await testTransactionSize(count, true); withAtaResults.push(result); - if (result.success && result.payloadSize <= SOLANA_LEGACY_TX_SIZE_LIMIT) { + if (result.success) { const txType = result.isVersioned ? 'versioned' : 'legacy'; console.log( ` ${count} recipients: ${result.payloadSize} bytes, ${result.instructionCount} instructions (${txType})` ); } else { console.log(` ${count} recipients: FAILED`); - if (result.success && result.payloadSize > SOLANA_LEGACY_TX_SIZE_LIMIT) { - console.log( - ` Error: Transaction size ${result.payloadSize} bytes exceeds ${SOLANA_LEGACY_TX_SIZE_LIMIT} byte limit` - ); - } else { + if (result.error) { console.log(` Error: ${result.error}`); - if (result.errorStack) { - const stackLines = result.errorStack.split('\n').slice(0, 4); - console.log(` Stack: ${stackLines.join('\n ')}`); - } + } + if (result.errorStack) { + const stackLines = result.errorStack.split('\n').slice(0, 4); + console.log(` Stack: ${stackLines.join('\n ')}`); } } } @@ -221,32 +182,27 @@ async function runBenchmark(): Promise { console.log(`\n Maximum: ${maxWithAta} recipients`); console.log(` Conservative (10% buffer): ${conservativeWithAta} recipients\n`); - // Test WITHOUT ATA creation console.log('[2/2] Testing WITHOUT ATA Creation:'); const withoutAtaResults: BenchmarkResult[] = []; - const testCountsWithoutAta = [1, 10, 20, 30, 35, 38, 39, 40, 41, 42, 45, 50]; + const testCountsWithoutAta = [1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 35, 38, 39, 40, 41, 42, 45, 50]; for (const count of testCountsWithoutAta) { const result = await testTransactionSize(count, false); withoutAtaResults.push(result); - if (result.success && result.payloadSize <= SOLANA_LEGACY_TX_SIZE_LIMIT) { + if (result.success) { const txType = result.isVersioned ? 'versioned' : 'legacy'; console.log( ` ${count} recipients: ${result.payloadSize} bytes, ${result.instructionCount} instructions (${txType})` ); } else { console.log(` ${count} recipients: FAILED`); - if (result.success && result.payloadSize > SOLANA_LEGACY_TX_SIZE_LIMIT) { - console.log( - ` Error: Transaction size ${result.payloadSize} bytes exceeds ${SOLANA_LEGACY_TX_SIZE_LIMIT} byte limit` - ); - } else { + if (result.error) { console.log(` Error: ${result.error}`); - if (result.errorStack) { - const stackLines = result.errorStack.split('\n').slice(0, 4); - console.log(` Stack: ${stackLines.join('\n ')}`); - } + } + if (result.errorStack) { + const stackLines = result.errorStack.split('\n').slice(0, 4); + console.log(` Stack: ${stackLines.join('\n ')}`); } } } @@ -256,16 +212,14 @@ async function runBenchmark(): Promise { console.log(`\n Maximum: ${maxWithoutAta} recipients`); console.log(` Conservative (10% buffer): ${conservativeWithoutAta} recipients\n`); - // Summary console.log('RECOMMENDED LIMITS (for legacy transactions):'); console.log(` With ATA creation: ${conservativeWithAta} recipients`); console.log(` Without ATA creation: ${conservativeWithoutAta} recipients`); console.log('\nNote: Transactions exceeding limits may build as versioned transactions automatically.'); - // Export results const exportData = { timestamp: new Date().toISOString(), - solanaLegacyTxSizeLimit: SOLANA_LEGACY_TX_SIZE_LIMIT, + solanaLegacyTxSizeLimit: SOLANA_TRANSACTION_MAX_SIZE, withAtaCreation: { maxSafe: maxWithAta, conservative: conservativeWithAta, @@ -279,11 +233,12 @@ async function runBenchmark(): Promise { }; const fs = await import('fs'); - fs.writeFileSync('transaction-size-benchmark-results.json', JSON.stringify(exportData, null, 2)); - console.log('\nResults saved to: transaction-size-benchmark-results.json'); + const path = await import('path'); + const outputPath = path.join(__dirname, 'transaction-size-benchmark-results.json'); + fs.writeFileSync(outputPath, JSON.stringify(exportData, null, 2)); + console.log(`\nResults saved to: ${outputPath}`); } -// Execute benchmark runBenchmark() .then(() => { console.log('Benchmark completed successfully'); diff --git a/modules/sdk-coin-sol/src/lib/constants.ts b/modules/sdk-coin-sol/src/lib/constants.ts index f71b3956f9..33026c874e 100644 --- a/modules/sdk-coin-sol/src/lib/constants.ts +++ b/modules/sdk-coin-sol/src/lib/constants.ts @@ -9,6 +9,25 @@ export const STAKE_ACCOUNT_RENT_EXEMPT_AMOUNT = 2282880; export const UNAVAILABLE_TEXT = 'UNAVAILABLE'; +/** + * Maximum over-the-wire size of a Solana transaction (in bytes) + * + * Source: https://github.com/anza-xyz/agave/blob/v2.1.13/sdk/packet/src/lib.rs#L27-L29 + * + * Calculation: + * - IPv6 minimum MTU: 1280 bytes + * - IPv6 header: 40 bytes + * - Fragment/UDP header: 8 bytes + * - Result: 1280 - 40 - 8 = 1232 bytes + * + * This limit is designed to avoid packet fragmentation on typical internet infrastructure. + * Transactions exceeding this limit will fail to serialize with a RangeError during + * the encoding of the transaction message. + * + * Reference: https://solana.com/docs/core/transactions#transaction-size + */ +export const SOLANA_TRANSACTION_MAX_SIZE = 1232; + export const JITO_STAKE_POOL_ADDRESS = 'Jito4APyf642JPZPx3hGc6WWJ8zPKtRbRs4P815Awbb'; export const JITOSOL_MINT_ADDRESS = 'J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn'; export const JITO_STAKE_POOL_RESERVE_ACCOUNT = 'BgKUXdS29YcHCFrPm5M8oLHiTzZaMDjsebggjoaQ6KFL';