@w3lib/solana-batch-call 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (220) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/README.md +129 -9
  3. package/dist/accountReader.d.ts +57 -0
  4. package/dist/accountReader.d.ts.map +1 -0
  5. package/dist/accountReader.js +149 -0
  6. package/dist/accountReader.js.map +1 -0
  7. package/dist/address.d.ts +9 -0
  8. package/dist/address.d.ts.map +1 -1
  9. package/dist/address.js +36 -6
  10. package/dist/address.js.map +1 -1
  11. package/dist/approvals.d.ts +5 -3
  12. package/dist/approvals.d.ts.map +1 -1
  13. package/dist/approvals.js +25 -36
  14. package/dist/approvals.js.map +1 -1
  15. package/dist/balances.d.ts +178 -0
  16. package/dist/balances.d.ts.map +1 -0
  17. package/dist/balances.js +524 -0
  18. package/dist/balances.js.map +1 -0
  19. package/dist/batchPlan.d.ts +52 -0
  20. package/dist/batchPlan.d.ts.map +1 -0
  21. package/dist/batchPlan.js +64 -0
  22. package/dist/batchPlan.js.map +1 -0
  23. package/dist/bytes.d.ts +31 -0
  24. package/dist/bytes.d.ts.map +1 -0
  25. package/dist/bytes.js +74 -0
  26. package/dist/bytes.js.map +1 -0
  27. package/dist/claim.d.ts +163 -0
  28. package/dist/claim.d.ts.map +1 -0
  29. package/dist/claim.js +197 -0
  30. package/dist/claim.js.map +1 -0
  31. package/dist/client.d.ts +26 -41
  32. package/dist/client.d.ts.map +1 -1
  33. package/dist/client.js +41 -986
  34. package/dist/client.js.map +1 -1
  35. package/dist/clientConfig.d.ts +11 -0
  36. package/dist/clientConfig.d.ts.map +1 -0
  37. package/dist/clientConfig.js +3 -0
  38. package/dist/clientConfig.js.map +1 -0
  39. package/dist/decode.d.ts +22 -0
  40. package/dist/decode.d.ts.map +1 -0
  41. package/dist/decode.js +160 -0
  42. package/dist/decode.js.map +1 -0
  43. package/dist/describe.d.ts +26 -0
  44. package/dist/describe.d.ts.map +1 -0
  45. package/dist/describe.js +58 -0
  46. package/dist/describe.js.map +1 -0
  47. package/dist/fees.d.ts.map +1 -1
  48. package/dist/fees.js +2 -12
  49. package/dist/fees.js.map +1 -1
  50. package/dist/history.d.ts +125 -0
  51. package/dist/history.d.ts.map +1 -0
  52. package/dist/history.js +220 -0
  53. package/dist/history.js.map +1 -0
  54. package/dist/historyHelius.d.ts +52 -0
  55. package/dist/historyHelius.d.ts.map +1 -0
  56. package/dist/historyHelius.js +125 -0
  57. package/dist/historyHelius.js.map +1 -0
  58. package/dist/index.d.ts +3 -3
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +1 -1
  61. package/dist/index.js.map +1 -1
  62. package/dist/layout.d.ts +21 -0
  63. package/dist/layout.d.ts.map +1 -1
  64. package/dist/layout.js +50 -69
  65. package/dist/layout.js.map +1 -1
  66. package/dist/liquidity/common.js +2 -2
  67. package/dist/liquidity/common.js.map +1 -1
  68. package/dist/liquidity/orca.d.ts +6 -0
  69. package/dist/liquidity/orca.d.ts.map +1 -1
  70. package/dist/liquidity/orca.js +14 -3
  71. package/dist/liquidity/orca.js.map +1 -1
  72. package/dist/liquidity/raydiumClmm.d.ts +6 -0
  73. package/dist/liquidity/raydiumClmm.d.ts.map +1 -1
  74. package/dist/liquidity/raydiumClmm.js +12 -5
  75. package/dist/liquidity/raydiumClmm.js.map +1 -1
  76. package/dist/lp.d.ts +55 -12
  77. package/dist/lp.d.ts.map +1 -1
  78. package/dist/lp.js +158 -70
  79. package/dist/lp.js.map +1 -1
  80. package/dist/lpMath.d.ts +22 -0
  81. package/dist/lpMath.d.ts.map +1 -1
  82. package/dist/lpMath.js +21 -0
  83. package/dist/lpMath.js.map +1 -1
  84. package/dist/portfolio.d.ts.map +1 -1
  85. package/dist/portfolio.js +3 -8
  86. package/dist/portfolio.js.map +1 -1
  87. package/dist/programs.d.ts +19 -0
  88. package/dist/programs.d.ts.map +1 -0
  89. package/dist/programs.js +175 -0
  90. package/dist/programs.js.map +1 -0
  91. package/dist/reclaim.d.ts +192 -0
  92. package/dist/reclaim.d.ts.map +1 -0
  93. package/dist/reclaim.js +399 -0
  94. package/dist/reclaim.js.map +1 -0
  95. package/dist/risk.js +2 -2
  96. package/dist/risk.js.map +1 -1
  97. package/dist/rpc.d.ts +30 -7
  98. package/dist/rpc.d.ts.map +1 -1
  99. package/dist/rpc.js +404 -111
  100. package/dist/rpc.js.map +1 -1
  101. package/dist/simulate.d.ts +106 -0
  102. package/dist/simulate.d.ts.map +1 -0
  103. package/dist/simulate.js +395 -0
  104. package/dist/simulate.js.map +1 -0
  105. package/dist/source.d.ts +8 -4
  106. package/dist/source.d.ts.map +1 -1
  107. package/dist/source.js +11 -4
  108. package/dist/source.js.map +1 -1
  109. package/dist/subpaths/approvals.d.ts +3 -3
  110. package/dist/subpaths/approvals.d.ts.map +1 -1
  111. package/dist/subpaths/approvals.js.map +1 -1
  112. package/dist/subpaths/claim.d.ts +31 -0
  113. package/dist/subpaths/claim.d.ts.map +1 -0
  114. package/dist/subpaths/claim.js +31 -0
  115. package/dist/subpaths/claim.js.map +1 -0
  116. package/dist/subpaths/history.d.ts +21 -0
  117. package/dist/subpaths/history.d.ts.map +1 -0
  118. package/dist/subpaths/history.js +22 -0
  119. package/dist/subpaths/history.js.map +1 -0
  120. package/dist/subpaths/lp.d.ts +2 -2
  121. package/dist/subpaths/lp.d.ts.map +1 -1
  122. package/dist/subpaths/lp.js +2 -2
  123. package/dist/subpaths/lp.js.map +1 -1
  124. package/dist/subpaths/reclaim.d.ts +34 -0
  125. package/dist/subpaths/reclaim.d.ts.map +1 -0
  126. package/dist/subpaths/reclaim.js +34 -0
  127. package/dist/subpaths/reclaim.js.map +1 -0
  128. package/dist/subpaths/simulate.d.ts +22 -0
  129. package/dist/subpaths/simulate.d.ts.map +1 -0
  130. package/dist/subpaths/simulate.js +23 -0
  131. package/dist/subpaths/simulate.js.map +1 -0
  132. package/dist/swap/index.js +3 -3
  133. package/dist/swap/index.js.map +1 -1
  134. package/dist/tokenDetails.d.ts +12 -0
  135. package/dist/tokenDetails.d.ts.map +1 -0
  136. package/dist/tokenDetails.js +196 -0
  137. package/dist/tokenDetails.js.map +1 -0
  138. package/dist/tokenMeta.d.ts +63 -0
  139. package/dist/tokenMeta.d.ts.map +1 -0
  140. package/dist/tokenMeta.js +226 -0
  141. package/dist/tokenMeta.js.map +1 -0
  142. package/dist/tradeCheck.js +3 -3
  143. package/dist/tradeCheck.js.map +1 -1
  144. package/dist/util.d.ts +22 -0
  145. package/dist/util.d.ts.map +1 -0
  146. package/dist/util.js +107 -0
  147. package/dist/util.js.map +1 -0
  148. package/dist/write/chain.d.ts +51 -0
  149. package/dist/write/chain.d.ts.map +1 -0
  150. package/dist/write/chain.js +184 -0
  151. package/dist/write/chain.js.map +1 -0
  152. package/dist/write/collect.js +2 -2
  153. package/dist/write/collect.js.map +1 -1
  154. package/dist/write/errors.d.ts +10 -0
  155. package/dist/write/errors.d.ts.map +1 -0
  156. package/dist/write/errors.js +77 -0
  157. package/dist/write/errors.js.map +1 -0
  158. package/dist/write/instructions.d.ts +2 -0
  159. package/dist/write/instructions.d.ts.map +1 -1
  160. package/dist/write/instructions.js +16 -0
  161. package/dist/write/instructions.js.map +1 -1
  162. package/dist/write/pack.d.ts +28 -0
  163. package/dist/write/pack.d.ts.map +1 -0
  164. package/dist/write/pack.js +125 -0
  165. package/dist/write/pack.js.map +1 -0
  166. package/dist/write/send.d.ts +23 -9
  167. package/dist/write/send.d.ts.map +1 -1
  168. package/dist/write/send.js +53 -351
  169. package/dist/write/send.js.map +1 -1
  170. package/dist/write/tracker.d.ts +24 -0
  171. package/dist/write/tracker.d.ts.map +1 -0
  172. package/dist/write/tracker.js +129 -0
  173. package/dist/write/tracker.js.map +1 -0
  174. package/package.json +21 -1
  175. package/src/accountReader.ts +187 -0
  176. package/src/address.ts +41 -6
  177. package/src/approvals.ts +36 -44
  178. package/src/balances.ts +678 -0
  179. package/src/batchPlan.ts +117 -0
  180. package/src/bytes.ts +89 -0
  181. package/src/claim.ts +327 -0
  182. package/src/client.ts +59 -1239
  183. package/src/clientConfig.ts +12 -0
  184. package/src/decode.ts +176 -0
  185. package/src/describe.ts +77 -0
  186. package/src/fees.ts +2 -9
  187. package/src/history.ts +325 -0
  188. package/src/historyHelius.ts +136 -0
  189. package/src/index.ts +13 -1
  190. package/src/layout.ts +63 -82
  191. package/src/liquidity/common.ts +2 -2
  192. package/src/liquidity/orca.ts +15 -5
  193. package/src/liquidity/raydiumClmm.ts +13 -5
  194. package/src/lp.ts +226 -75
  195. package/src/lpMath.ts +38 -0
  196. package/src/portfolio.ts +8 -11
  197. package/src/programs.ts +216 -0
  198. package/src/reclaim.ts +550 -0
  199. package/src/risk.ts +2 -2
  200. package/src/rpc.ts +476 -118
  201. package/src/simulate.ts +517 -0
  202. package/src/source.ts +14 -5
  203. package/src/subpaths/approvals.ts +3 -2
  204. package/src/subpaths/claim.ts +54 -0
  205. package/src/subpaths/history.ts +38 -0
  206. package/src/subpaths/lp.ts +5 -1
  207. package/src/subpaths/reclaim.ts +58 -0
  208. package/src/subpaths/simulate.ts +37 -0
  209. package/src/swap/index.ts +3 -3
  210. package/src/tokenDetails.ts +240 -0
  211. package/src/tokenMeta.ts +270 -0
  212. package/src/tradeCheck.ts +3 -3
  213. package/src/util.ts +110 -0
  214. package/src/write/chain.ts +218 -0
  215. package/src/write/collect.ts +2 -2
  216. package/src/write/errors.ts +82 -0
  217. package/src/write/instructions.ts +17 -0
  218. package/src/write/pack.ts +142 -0
  219. package/src/write/send.ts +74 -407
  220. package/src/write/tracker.ts +152 -0
@@ -0,0 +1,82 @@
1
+ import { SYSTEM_PROGRAM_ID, TOKEN_2022_PROGRAM_ID, TOKEN_PROGRAM_ID } from '../constants.js'
2
+
3
+ // 交易错误的可读说明(发送、/swap 的交易检查、/fees 共用)
4
+
5
+ export function errorText(err: unknown): string {
6
+ return err instanceof Error ? err.message : String(err)
7
+ }
8
+
9
+ // ---- 交易错误 ----
10
+
11
+ const TX_ERRORS: Record<string, string> = {
12
+ InsufficientFundsForFee: 'insufficient SOL for the transaction fee',
13
+ AccountNotFound: 'fee payer account not found (it has no SOL)',
14
+ BlockhashNotFound: 'blockhash not found',
15
+ AlreadyProcessed: 'transaction already processed',
16
+ }
17
+
18
+ /**
19
+ * 日志里最有用的一行:程序打印的 “Program log: Error: …”,其次是系统程序直接打印的说明(如 “Transfer: insufficient lamports …”,
20
+ * 不以 “Program ” 开头),最后才是运行时的 “Program … failed: custom program error: 0x1”
21
+ */
22
+ function logDetail(logs: readonly string[]): string | undefined {
23
+ const reversed = [...logs].reverse()
24
+ const programError = reversed.find((line) => /^Program log: (Error|error)/.test(line))
25
+ if (programError) return programError.replace(/^Program log: /, '')
26
+ const plain = reversed.find((line) => !line.startsWith('Program '))
27
+ if (plain) return plain
28
+ return reversed.find((line) => / failed: /.test(line))?.replace(/^Program \w+ failed: /, '')
29
+ }
30
+
31
+ // 常见程序的自定义错误码(上链失败时没有日志,只有错误码)
32
+ const SYSTEM_ERRORS = ['account already in use', 'insufficient lamports', 'invalid program id', 'invalid account data length']
33
+ const TOKEN_ERRORS: Record<number, string> = {
34
+ 0: 'account not rent-exempt',
35
+ 1: 'insufficient funds',
36
+ 2: 'invalid mint',
37
+ 3: 'account not associated with this mint',
38
+ 4: 'owner does not match',
39
+ 9: 'account is not initialized',
40
+ 11: 'non-native account can only be closed if its balance is zero',
41
+ 17: 'account is frozen',
42
+ 18: 'mint decimals mismatch',
43
+ }
44
+
45
+ function customErrorText(program: string | undefined, code: number): string | undefined {
46
+ if (program === SYSTEM_PROGRAM_ID) return SYSTEM_ERRORS[code]
47
+ if (program === TOKEN_PROGRAM_ID || program === TOKEN_2022_PROGRAM_ID) return TOKEN_ERRORS[code]
48
+ return undefined
49
+ }
50
+
51
+ /**
52
+ * 交易错误的可读说明:优先取日志(见 logDetail),否则按错误类型;
53
+ * programs 是每条指令的程序(按下标),用来翻译常见程序的自定义错误码
54
+ */
55
+ export function transactionErrorText(err: unknown, logs?: readonly string[] | null, programs?: readonly string[]): string {
56
+ const detail = logDetail(logs ?? [])
57
+ if (typeof err === 'string') {
58
+ return TX_ERRORS[err] ?? err
59
+ }
60
+ const instruction = (err as { InstructionError?: [number, unknown] } | null)?.InstructionError
61
+ if (instruction) {
62
+ const [index, reason] = instruction
63
+ const custom = (reason as { Custom?: number } | null)?.Custom
64
+ const known = custom === undefined ? undefined : customErrorText(programs?.[index], custom)
65
+ return detail ?? known ?? (typeof reason === 'string' ? reason : JSON.stringify(reason))
66
+ }
67
+ if ((err as { InsufficientFundsForRent?: unknown } | null)?.InsufficientFundsForRent) {
68
+ return 'account would be left with less SOL than the rent-exempt minimum'
69
+ }
70
+ return detail ?? JSON.stringify(err)
71
+ }
72
+
73
+ export function isBudgetExceeded(err: unknown, logs?: readonly string[] | null): boolean {
74
+ const reason = (err as { InstructionError?: [number, unknown] } | null)?.InstructionError?.[1]
75
+ return reason === 'ComputationalBudgetExceeded' || (logs ?? []).some((l) => /exceeded CUs meter|compute units/i.test(l) && /exceed/i.test(l))
76
+ }
77
+
78
+ /** 用户在钱包里拒绝签名 */
79
+ export function isRejection(err: unknown): boolean {
80
+ const e = err as { code?: unknown; name?: unknown; message?: unknown } | null
81
+ return e?.code === 4001 || /reject|denied|cancel|declined/i.test(`${String(e?.name ?? '')} ${String(e?.message ?? '')}`)
82
+ }
@@ -74,6 +74,23 @@ export function closeAccount(account: string, destination: string, owner: string
74
74
  }
75
75
  }
76
76
 
77
+ /** SPL Token / Token-2022 BurnChecked:销毁代币账户里的代币(校验 mint 和精度),owner 签名 */
78
+ export function burnChecked(account: string, mint: string, owner: string, amount: bigint, decimals: number, tokenProgram: string): Instruction {
79
+ return {
80
+ programId: tokenProgram,
81
+ keys: [
82
+ { pubkey: account, isSigner: false, isWritable: true },
83
+ { pubkey: mint, isSigner: false, isWritable: true },
84
+ { pubkey: owner, isSigner: true, isWritable: false },
85
+ ],
86
+ data: bytes(10, (v) => {
87
+ v.setUint8(0, 15)
88
+ v.setBigUint64(1, amount, true)
89
+ v.setUint8(9, decimals)
90
+ }),
91
+ }
92
+ }
93
+
77
94
  /** 撤销代币账户的授权(Approve 设置的 delegate),owner 签名 */
78
95
  export function revoke(account: string, owner: string, tokenProgram: string): Instruction {
79
96
  return {
@@ -0,0 +1,142 @@
1
+ import { MAX_COMPUTE_UNITS, setComputeUnitLimit, setComputeUnitPrice } from './instructions.js'
2
+ import { MAX_ACCOUNT_LOCKS, PACKET_DATA_SIZE, compileMessage, transactionSize, type Instruction } from './transaction.js'
3
+
4
+ /** 打包用的占位 blockhash(大小与真实值相同) */
5
+ export const PLACEHOLDER_BLOCKHASH = '11111111111111111111111111111111'
6
+
7
+ /** 计算预算指令(上限 + 单价):发送时排在最前面 */
8
+ export function budgetInstructions(units: number, price: bigint): Instruction[] {
9
+ return [setComputeUnitLimit(units), setComputeUnitPrice(price)]
10
+ }
11
+
12
+ /** 加上计算预算指令后,这些指令能否放进一笔交易(完整编译一次;不超过 1232 字节和 64 个账户) */
13
+ export function fitsInTransaction(payer: string, instructions: readonly Instruction[]): boolean {
14
+ const message = compileMessage(payer, [...budgetInstructions(MAX_COMPUTE_UNITS, 0n), ...instructions], PLACEHOLDER_BLOCKHASH)
15
+ return transactionSize(message) <= PACKET_DATA_SIZE && message.accountKeys.length <= MAX_ACCOUNT_LOCKS
16
+ }
17
+
18
+ function compactLength(n: number): number {
19
+ return n < 0x80 ? 1 : n < 0x4000 ? 2 : 3
20
+ }
21
+
22
+ /**
23
+ * 增量估算 legacy 交易的大小(与 compileMessage + transactionSize 的结果相同):
24
+ * 签名数 + 64 × 签名数 + 3 字节头 + 账户数 + 32 × 账户数 + 32 字节 blockhash + 指令数 + 各指令(程序下标 1 + 账户数 + 账户下标 + 数据长度 + 数据)。
25
+ * 只记累计的账户集合(是否签名者)和指令字节,加一个调用只看它自己的指令
26
+ */
27
+ class SizeEstimate {
28
+ /** 账户 → 是否签名者 */
29
+ readonly #signer = new Map<string, boolean>()
30
+ #signers = 0
31
+ #instructions = 0
32
+ #instructionBytes = 0
33
+
34
+ constructor(payer: string) {
35
+ this.#signer.set(payer, true)
36
+ this.#signers = 1
37
+ this.add(budgetInstructions(MAX_COMPUTE_UNITS, 0n))
38
+ }
39
+
40
+ /** 加入这些指令后的大小和账户数(不修改状态) */
41
+ probe(instructions: readonly Instruction[]): { size: number; accounts: number } {
42
+ let accounts = this.#signer.size
43
+ let signers = this.#signers
44
+ let bytes = this.#instructionBytes
45
+ const added = new Map<string, boolean>()
46
+ const touch = (pubkey: string, isSigner: boolean) => {
47
+ // 本次已经加过 / 升级过的以 added 为准(累计集合里是非签名者 false 时,?? 不会回落,不能先查累计集合)
48
+ const known = added.has(pubkey) ? added.get(pubkey) : this.#signer.get(pubkey)
49
+ if (known === undefined) {
50
+ accounts++
51
+ if (isSigner) signers++
52
+ added.set(pubkey, isSigner)
53
+ } else if (isSigner && !known) {
54
+ signers++
55
+ added.set(pubkey, true)
56
+ }
57
+ }
58
+ for (const ix of instructions) {
59
+ ix.keys.forEach((k) => touch(k.pubkey, k.isSigner))
60
+ touch(ix.programId, false)
61
+ bytes += 1 + compactLength(ix.keys.length) + ix.keys.length + compactLength(ix.data.length) + ix.data.length
62
+ }
63
+ const count = this.#instructions + instructions.length
64
+ const size = compactLength(signers) + 64 * signers + 3 + compactLength(accounts) + 32 * accounts + 32 + compactLength(count) + bytes
65
+ return { size, accounts }
66
+ }
67
+
68
+ fits(instructions: readonly Instruction[]): boolean {
69
+ const { size, accounts } = this.probe(instructions)
70
+ return size <= PACKET_DATA_SIZE && accounts <= MAX_ACCOUNT_LOCKS
71
+ }
72
+
73
+ add(instructions: readonly Instruction[]): void {
74
+ for (const ix of instructions) {
75
+ for (const k of [...ix.keys.map((key) => [key.pubkey, key.isSigner] as const), [ix.programId, false] as const]) {
76
+ const [pubkey, isSigner] = k
77
+ const known = this.#signer.get(pubkey)
78
+ if (known === undefined) {
79
+ this.#signer.set(pubkey, isSigner)
80
+ if (isSigner) this.#signers++
81
+ } else if (isSigner && !known) {
82
+ this.#signer.set(pubkey, true)
83
+ this.#signers++
84
+ }
85
+ }
86
+ this.#instructionBytes += 1 + compactLength(ix.keys.length) + ix.keys.length + compactLength(ix.data.length) + ix.data.length
87
+ this.#instructions++
88
+ }
89
+ }
90
+ }
91
+
92
+ export interface PackOptions {
93
+ /** 每笔交易最多几个调用,默认不限(只受交易大小 / 账户数限制) */
94
+ batchSize?: number
95
+ /** 只能单独成一笔交易的调用(如计算单元和优先费用固定的扫空转账) */
96
+ alone?: (index: number) => boolean
97
+ }
98
+
99
+ /** 打包结果的一笔交易:包含的调用下标;tooLarge 为 true 时是单个调用自己就放不进一笔交易 */
100
+ export interface Pack {
101
+ indices: number[]
102
+ tooLarge: boolean
103
+ }
104
+
105
+ /**
106
+ * 把调用按顺序打包成交易(batchCall / batchTransfer / batchCollect 的发送和 /reclaim、/claim 的批量计划共用):
107
+ * 相邻的调用放进同一笔,直到加上计算预算指令后超过 1232 字节或 64 个账户、或达到 batchSize;alone 的调用单独成一笔;
108
+ * 单个调用自己就放不进的单独成一笔并标记 tooLarge。
109
+ * 大小按累计的账户集合和指令字节增量估算(每加一个调用只看它自己的指令),每笔打完再完整编译校验一次
110
+ */
111
+ export function packUnits(payer: string, units: ReadonlyArray<{ instructions: readonly Instruction[] }>, options: PackOptions = {}): Pack[] {
112
+ const batchSize = options.batchSize ?? Number.POSITIVE_INFINITY
113
+ const alone = options.alone ?? (() => false)
114
+ const packs: Pack[] = []
115
+ let i = 0
116
+ while (i < units.length) {
117
+ const estimate = new SizeEstimate(payer)
118
+ const first = (units[i] as { instructions: readonly Instruction[] }).instructions
119
+ if (!estimate.fits(first)) {
120
+ packs.push({ indices: [i], tooLarge: true })
121
+ i++
122
+ continue
123
+ }
124
+ estimate.add(first)
125
+ const indices = [i++]
126
+ if (!alone(indices[0] as number)) {
127
+ while (i < units.length && indices.length < batchSize && !alone(i)) {
128
+ const next = (units[i] as { instructions: readonly Instruction[] }).instructions
129
+ if (!estimate.fits(next)) break
130
+ estimate.add(next)
131
+ indices.push(i++)
132
+ }
133
+ }
134
+ // 完整编译校验一次(估算与编译结果应当一致;万一不一致,去掉末尾的调用直到放得下,去掉的留给下一笔)
135
+ while (indices.length > 1 && !fitsInTransaction(payer, indices.flatMap((k) => (units[k] as { instructions: readonly Instruction[] }).instructions))) {
136
+ indices.pop()
137
+ i--
138
+ }
139
+ packs.push({ indices, tooLarge: false })
140
+ }
141
+ return packs
142
+ }