Precompile advanced order#2685
Conversation
| /// subnet are skipped. | ||
| #[pallet::call_index(1)] | ||
| #[pallet::weight(T::WeightInfo::execute_batched_orders(orders.len() as u32))] | ||
| pub fn execute_batched_orders( |
There was a problem hiding this comment.
[HIGH] Batched execution is not atomic after collecting user assets
execute_batched_orders pulls TAO/staked alpha from every order signer into the pallet account via collect_assets, then makes later fallible calls (net_pool_swap, distribution transfers, zero-output checks). Without a transaction boundary, an error after collect_assets can return Err while leaving balances/stake already moved into or through the pallet account and orders not marked fulfilled. A public relayer can trigger this with valid signed orders plus a later slippage/zero-output/distribution failure, locking or misrouting user funds. Wrap the whole batched dispatch in a FRAME transaction so any later error rolls back the asset collection and intermediate transfers.
| pub fn execute_batched_orders( | |
| #[frame_support::transactional] | |
| pub fn execute_batched_orders( |
| let available = | ||
| Self::get_stake_for_hotkey_and_coldkey_on_subnet(from_hotkey, from_coldkey, netuid); | ||
| ensure!(available >= amount, Error::<T>::NotEnoughStakeToWithdraw); | ||
| Self::decrease_stake_for_hotkey_and_coldkey_on_subnet( | ||
| from_hotkey, | ||
| from_coldkey, | ||
| netuid, | ||
| amount, | ||
| ); | ||
| Self::increase_stake_for_hotkey_and_coldkey_on_subnet( | ||
| to_hotkey, to_coldkey, netuid, amount, | ||
| ); | ||
| LastColdkeyHotkeyStakeBlock::<T>::insert( | ||
| to_coldkey, | ||
| to_hotkey, | ||
| Self::get_current_block_as_u64(), | ||
| ); | ||
| if validate_receiver { | ||
| ensure!( | ||
| Self::hotkey_account_exists(to_hotkey), | ||
| Error::<T>::HotKeyAccountNotExists | ||
| ); | ||
| Self::set_stake_operation_limit(to_hotkey, to_coldkey, netuid); | ||
| } |
There was a problem hiding this comment.
[HIGH] Stake transfer mutates balances before receiver validation
transfer_staked_alpha decreases the sender stake, increases receiver stake, and writes the rate-limit block before checking hotkey_account_exists(to_hotkey) when validate_receiver is true. In the new batched limit-order distribution path, a buy order with an unregistered destination hotkey can therefore make this helper return Err after stake has already been moved. Validate the receiver before any stake mutation, then set the receiver rate limit after the successful move.
| let available = | |
| Self::get_stake_for_hotkey_and_coldkey_on_subnet(from_hotkey, from_coldkey, netuid); | |
| ensure!(available >= amount, Error::<T>::NotEnoughStakeToWithdraw); | |
| Self::decrease_stake_for_hotkey_and_coldkey_on_subnet( | |
| from_hotkey, | |
| from_coldkey, | |
| netuid, | |
| amount, | |
| ); | |
| Self::increase_stake_for_hotkey_and_coldkey_on_subnet( | |
| to_hotkey, to_coldkey, netuid, amount, | |
| ); | |
| LastColdkeyHotkeyStakeBlock::<T>::insert( | |
| to_coldkey, | |
| to_hotkey, | |
| Self::get_current_block_as_u64(), | |
| ); | |
| if validate_receiver { | |
| ensure!( | |
| Self::hotkey_account_exists(to_hotkey), | |
| Error::<T>::HotKeyAccountNotExists | |
| ); | |
| Self::set_stake_operation_limit(to_hotkey, to_coldkey, netuid); | |
| } | |
| if validate_receiver { | |
| ensure!( | |
| Self::hotkey_account_exists(to_hotkey), | |
| Error::<T>::HotKeyAccountNotExists | |
| ); | |
| } | |
| let available = | |
| Self::get_stake_for_hotkey_and_coldkey_on_subnet(from_hotkey, from_coldkey, netuid); | |
| ensure!(available >= amount, Error::<T>::NotEnoughStakeToWithdraw); | |
| Self::decrease_stake_for_hotkey_and_coldkey_on_subnet( | |
| from_hotkey, | |
| from_coldkey, | |
| netuid, | |
| amount, | |
| ); | |
| Self::increase_stake_for_hotkey_and_coldkey_on_subnet( | |
| to_hotkey, to_coldkey, netuid, amount, | |
| ); | |
| LastColdkeyHotkeyStakeBlock::<T>::insert( | |
| to_coldkey, | |
| to_hotkey, | |
| Self::get_current_block_as_u64(), | |
| ); | |
| if validate_receiver { | |
| Self::set_stake_operation_limit(to_hotkey, to_coldkey, netuid); | |
| } |
🛡️ AI Review — Skeptic (security review)VERDICT: VULNERABLE BASELINE scrutiny: open-junius has repo write permission, an account older than two years, substantial contribution history, and no trusted Gittensor allowlist match; branch is precompile-advanced-order -> devnet-ready. No trusted review prompt files or Findings
Prior-comment reconciliation
ConclusionThe PR appears legitimate, but it still weakens the persistent contract-test CI entrypoint by skipping the existing suite. That is a security-relevant test bypass and should block merge until the full suite is restored. 📜 Previous run (superseded)
# 🔍 AI Review — Auditor (domain review) has not yet run on this PR. |
|
🔄 AI review updated — Skeptic: VULNERABLE |
| #[pallet::call_index(1)] | ||
| #[pallet::weight(T::WeightInfo::execute_batched_orders(orders.len() as u32))] | ||
| pub fn execute_batched_orders( |
There was a problem hiding this comment.
[HIGH] Batched execution is not atomic after collecting user assets
execute_batched_orders can transfer TAO/staked alpha into the pallet account in collect_assets, then return Err from net_pool_swap, distribute_alpha_pro_rata, or distribute_tao_pro_rata. Without a transaction boundary on the extrinsic, those earlier balance/stake mutations are not rolled back, so a failing batch can strand or move user assets while the order remains unfulfilled. Wrap the whole batched extrinsic in #[frame_support::transactional] or otherwise make every post-collection failure non-fatal and fully accounted.
| #[pallet::call_index(1)] | |
| #[pallet::weight(T::WeightInfo::execute_batched_orders(orders.len() as u32))] | |
| pub fn execute_batched_orders( | |
| #[pallet::call_index(1)] | |
| #[pallet::weight(T::WeightInfo::execute_batched_orders(orders.len() as u32))] | |
| #[frame_support::transactional] | |
| pub fn execute_batched_orders( |
| let available = | ||
| Self::get_stake_for_hotkey_and_coldkey_on_subnet(from_hotkey, from_coldkey, netuid); | ||
| ensure!(available >= amount, Error::<T>::NotEnoughStakeToWithdraw); | ||
| Self::decrease_stake_for_hotkey_and_coldkey_on_subnet( | ||
| from_hotkey, | ||
| from_coldkey, | ||
| netuid, | ||
| amount, | ||
| ); | ||
| Self::increase_stake_for_hotkey_and_coldkey_on_subnet( | ||
| to_hotkey, to_coldkey, netuid, amount, | ||
| ); | ||
| LastColdkeyHotkeyStakeBlock::<T>::insert( | ||
| to_coldkey, | ||
| to_hotkey, | ||
| Self::get_current_block_as_u64(), | ||
| ); | ||
| if validate_receiver { | ||
| ensure!( | ||
| Self::hotkey_account_exists(to_hotkey), | ||
| Error::<T>::HotKeyAccountNotExists | ||
| ); | ||
| Self::set_stake_operation_limit(to_hotkey, to_coldkey, netuid); | ||
| } |
There was a problem hiding this comment.
[HIGH] Stake transfer mutates balances before receiver validation
When validate_receiver is true, this function decreases the sender stake, increases the receiver stake, and writes LastColdkeyHotkeyStakeBlock before checking hotkey_account_exists(to_hotkey). If that receiver check fails, the function returns an error after mutating stake accounting. In the current batched-order path this compounds the missing atomicity issue; the receiver-side validation needs to happen before any stake movement.
| let available = | |
| Self::get_stake_for_hotkey_and_coldkey_on_subnet(from_hotkey, from_coldkey, netuid); | |
| ensure!(available >= amount, Error::<T>::NotEnoughStakeToWithdraw); | |
| Self::decrease_stake_for_hotkey_and_coldkey_on_subnet( | |
| from_hotkey, | |
| from_coldkey, | |
| netuid, | |
| amount, | |
| ); | |
| Self::increase_stake_for_hotkey_and_coldkey_on_subnet( | |
| to_hotkey, to_coldkey, netuid, amount, | |
| ); | |
| LastColdkeyHotkeyStakeBlock::<T>::insert( | |
| to_coldkey, | |
| to_hotkey, | |
| Self::get_current_block_as_u64(), | |
| ); | |
| if validate_receiver { | |
| ensure!( | |
| Self::hotkey_account_exists(to_hotkey), | |
| Error::<T>::HotKeyAccountNotExists | |
| ); | |
| Self::set_stake_operation_limit(to_hotkey, to_coldkey, netuid); | |
| } | |
| if validate_receiver { | |
| ensure!( | |
| Self::hotkey_account_exists(to_hotkey), | |
| Error::<T>::HotKeyAccountNotExists | |
| ); | |
| } | |
| let available = | |
| Self::get_stake_for_hotkey_and_coldkey_on_subnet(from_hotkey, from_coldkey, netuid); | |
| ensure!(available >= amount, Error::<T>::NotEnoughStakeToWithdraw); | |
| Self::decrease_stake_for_hotkey_and_coldkey_on_subnet( | |
| from_hotkey, | |
| from_coldkey, | |
| netuid, | |
| amount, | |
| ); | |
| Self::increase_stake_for_hotkey_and_coldkey_on_subnet( | |
| to_hotkey, to_coldkey, netuid, amount, | |
| ); | |
| LastColdkeyHotkeyStakeBlock::<T>::insert( | |
| to_coldkey, | |
| to_hotkey, | |
| Self::get_current_block_as_u64(), | |
| ); | |
| if validate_receiver { | |
| Self::set_stake_operation_limit(to_hotkey, to_coldkey, netuid); | |
| } |
|
🔄 AI review updated — Skeptic: VULNERABLE |
| let pallet_hotkey = T::PalletHotkey::get(); | ||
|
|
||
| // Pull all input assets into the pallet intermediary before touching the pool. | ||
| Self::collect_assets( |
There was a problem hiding this comment.
[HIGH] Batched execution is not atomic after collecting user assets
execute_batched_orders still starts by moving every buyer's TAO and seller's staked alpha into the pallet intermediary, then performs the net pool swap, pro-rata distributions, fee forwarding, order-status writes, and event emission as separate fallible steps. There is no outer #[transactional] / with_transaction boundary around the whole batch. If any later transfer or swap fails after this line, earlier collect_assets transfers are not rolled back, so users can lose assets while the extrinsic returns an error and some orders remain unfilled. Wrap the full do_execute_batched_orders asset-collection/swap/distribution/status-write flow in a transaction, or prevalidate every fallible post-collection transfer so no failure is possible after user assets are pulled.
| Self::decrease_stake_for_hotkey_and_coldkey_on_subnet( | ||
| from_hotkey, | ||
| from_coldkey, | ||
| netuid, | ||
| amount, | ||
| ); | ||
| Self::increase_stake_for_hotkey_and_coldkey_on_subnet( | ||
| to_hotkey, to_coldkey, netuid, amount, | ||
| ); | ||
| LastColdkeyHotkeyStakeBlock::<T>::insert( | ||
| to_coldkey, | ||
| to_hotkey, | ||
| Self::get_current_block_as_u64(), | ||
| ); | ||
| if validate_receiver { |
There was a problem hiding this comment.
[HIGH] Stake transfer mutates balances before receiver validation
transfer_staked_alpha decreases the sender's stake, increases the receiver's stake, and writes LastColdkeyHotkeyStakeBlock before checking validate_receiver. The batch distributor calls this with validate_receiver = true for buyers, so a bad buyer hotkey can make the function return HotKeyAccountNotExists after stake has already been moved out of the pallet intermediary. Because this helper is not transactional and the outer batch is not transactional, that failure leaves mutated stake/accounting behind. Validate to_hotkey before lines 138-151, or make this helper transactional so receiver-validation failures roll back the mutations.
| let (amount_in, amount_out) = if order.order_type.is_buy() { | ||
| // partial fill validations have passed, it is safe here to do this | ||
| let tao_in = TaoBalance::from(signed_order.partial_fill.unwrap_or(order.amount)); | ||
| // Deduct fee from TAO input before swapping. | ||
| let fee_tao = TaoBalance::from(order.fee_rate.mul_floor(tao_in.to_u64())); | ||
| let tao_after_fee = tao_in.saturating_sub(fee_tao); | ||
|
|
||
| let alpha_out = T::SwapInterface::buy_alpha( |
There was a problem hiding this comment.
[MEDIUM] Direct buy execution can fill an order without collecting its fee
For buy orders, the pallet only passes tao_after_fee into buy_alpha, so the subtensor-side balance validation only proves the signer can pay the net swap amount. The fee is then forwarded best-effort from the signer after the swap. A signer with exactly amount - fee free TAO can have the order execute and be marked fulfilled, while forward_fee fails and leaves the fee unpaid. This makes the signed fee field unenforceable in the direct execute_orders path. Require/fund the gross buy amount atomically, or make buy fee transfer a hard precondition before marking the order executed.
|
🔄 AI review updated — Skeptic: VULNERABLE |
| /// Thin orchestrator for `execute_batched_orders`. | ||
| fn do_execute_batched_orders( |
There was a problem hiding this comment.
[HIGH] Batched execution is not atomic after collecting user assets
do_execute_batched_orders performs multiple fallible mutations in sequence: it first pulls buyer TAO and seller stake into the pallet account, then swaps, distributes outputs, writes order status, and finally forwards fees. Because the function has no transaction boundary, any failure after an earlier transfer leaves those earlier asset movements committed while the extrinsic returns an error. A malformed batch can therefore strand funds/stake in the pallet intermediary or partially settle only some orders. Wrap the whole batch execution in a FRAME transaction, or otherwise prove every later fallible operation before moving assets.
| /// Thin orchestrator for `execute_batched_orders`. | |
| fn do_execute_batched_orders( | |
| /// Thin orchestrator for `execute_batched_orders`. | |
| #[frame_support::transactional] | |
| fn do_execute_batched_orders( |
| )?; | ||
|
|
||
| // Forward the fee TAO to the order's fee recipient. | ||
| Self::forward_fee(&order.signer, &order.fee_recipient, fee_tao); |
There was a problem hiding this comment.
[MEDIUM] Direct buy execution can fill an order without collecting its fee
The buy path subtracts fee_tao from the signed amount and calls buy_alpha with only tao_after_fee. buy_alpha(..., validate: true) therefore only checks and removes the net amount from the signer. The fee transfer is attempted afterward through forward_fee, which swallows transfer failures, so a signer with enough balance for the net swap but not the fee can still receive alpha and have the order marked fulfilled without paying the signed fee. Collect/escrow the gross TAO up front, or make fee collection a mandatory part of a transaction-wrapped single-order execution.
|
🔄 AI review updated — Skeptic: VULNERABLE |
| } | ||
|
|
||
| /// Thin orchestrator for `execute_batched_orders`. | ||
| fn do_execute_batched_orders( |
There was a problem hiding this comment.
[HIGH] Batched execution is not atomic after collecting user assets
execute_batched_orders still enters do_execute_batched_orders without a transaction boundary, then debits user TAO/alpha in collect_assets before later fallible ? calls in the pool swap and distribution steps. If any later step fails, prior balance/stake transfers and any pool mutation can persist while the extrinsic returns an error, leaving user assets stranded or partially settled. Wrap the whole orchestrator in a transactional boundary, or move all fallible validation ahead of collection and make the post-collection path infallible.
| fn do_execute_batched_orders( | |
| #[frame_support::transactional] | |
| fn do_execute_batched_orders( |
| )?; | ||
|
|
||
| // Forward the fee TAO to the order's fee recipient. | ||
| Self::forward_fee(&order.signer, &order.fee_recipient, fee_tao); |
There was a problem hiding this comment.
[MEDIUM] Direct buy execution can fill an order without collecting its fee
For buy orders, buy_alpha only debits tao_after_fee; the fee is then attempted with best-effort forward_fee, which emits FeeTransferFailed but does not revert. A signer funded with exactly tao_after_fee can receive the alpha, have the order marked executed, and avoid paying the signed fee. Collect the gross amount atomically, or make fee transfer failure revert before marking the order filled.
|
🔄 AI review updated — Skeptic: VULNERABLE |
| } | ||
|
|
||
| /// Thin orchestrator for `execute_batched_orders`. | ||
| fn do_execute_batched_orders( |
There was a problem hiding this comment.
[HIGH] Batched execution is not atomic after collecting user assets
do_execute_batched_orders performs a multi-step settlement without a #[transactional] boundary. After collect_assets pulls gross TAO/alpha into the pallet account, later fallible calls (net_pool_swap, pro-rata distributions, order-status writes, and collect_fees) can still return Err. FRAME does not automatically roll back prior balance/storage mutations on DispatchError, so a failed batch can leave users debited, the pallet credited, or orders partially settled. Wrap the whole batched settlement in a transaction, or pre-validate every later fallible condition before moving assets.
| let fee_tao = TaoBalance::from(order.fee_rate.mul_floor(tao_in.to_u64())); | ||
| let tao_after_fee = tao_in.saturating_sub(fee_tao); | ||
|
|
||
| let alpha_out = T::SwapInterface::buy_alpha( |
There was a problem hiding this comment.
[MEDIUM] Direct buy execution can fill an order without collecting its fee
The buy path spends only tao_after_fee in buy_alpha, then tries to transfer the fee afterward. A signer with enough balance for tao_after_fee but not the fee can get the alpha purchase applied, then make forward_fee fail. In best-effort execute_orders (should_fail = false), that error is swallowed as OrderSkipped, and there is no transactional wrapper around try_execute_order to roll back the already-applied buy. Collect/reserve the gross input before the swap, or make each per-order attempt transactional so skipped failures cannot retain prior side effects.
|
🔄 AI review updated — Skeptic: VULNERABLE |
| } | ||
|
|
||
| /// Thin orchestrator for `execute_batched_orders`. | ||
| fn do_execute_batched_orders( |
There was a problem hiding this comment.
[HIGH] Batched execution is not atomic after collecting user assets
do_execute_batched_orders collects buyer TAO and seller alpha into the pallet account, then performs several later fallible steps: residual pool swap, pro-rata distributions, order status writes, and fee forwarding. Because this orchestrator is not transactional, any error after collect_assets can return Err while already-moving assets or partially-written settlement state remains committed. This can strand user funds in the pallet intermediary or leave a partially settled batch. Wrap the whole batch orchestrator in a storage transaction so any later failure rolls back the prior transfers and status changes.
| fn do_execute_batched_orders( | |
| #[frame_support::transactional] | |
| fn do_execute_batched_orders( |
|
|
||
| /// Attempt to execute one signed order. Returns an error on any | ||
| /// validation or execution failure without panicking. | ||
| fn try_execute_order( |
There was a problem hiding this comment.
[HIGH] Single-order execution is not atomic after swap side effects
try_execute_order performs the buy/sell swap before later fallible operations such as fee forwarding and status insertion. For a buy order, buy_alpha only validates/removes tao_after_fee; if the signer has enough balance for the net swap but not the fee, the swap succeeds, forward_fee fails, execute_orders treats the order as skipped, and the order remains executable without the fee being paid. The same missing transaction also makes should_fail = true misleading: returning Err does not by itself roll back prior successful order executions. Make this helper transactional so every failed order attempt reverts its own swap/fee/status side effects.
| fn try_execute_order( | |
| #[frame_support::transactional] | |
| fn try_execute_order( |
|
🔄 AI review updated — Skeptic: VULNERABLE |
| { | ||
| "scripts": { | ||
| "test": "TS_NODE_PREFER_TS_EXTS=1 TS_NODE_TRANSPILE_ONLY=1 mocha --timeout 999999 --retries 3 --file src/setup.ts --require ts-node/register --extension ts \"test/**/*.ts\"" | ||
| "test": "TS_NODE_PREFER_TS_EXTS=1 TS_NODE_TRANSPILE_ONLY=1 mocha --timeout 999999 --file src/setup.ts --require ts-node/register --extension ts \"test/limitOrders.precompile.test.ts\"" |
There was a problem hiding this comment.
[HIGH] Contract test script now skips the existing suite
contract-tests/run-ci.sh invokes yarn run test, so changing this script from test/**/*.ts to only test/limitOrders.precompile.test.ts makes the contract-test workflow stop running every existing contract test. That is a persistent CI bypass: future precompile or EVM regressions can merge without exercising the previous suite. Keep the broad glob so the new limit-order test is added to the suite rather than replacing it.
| "test": "TS_NODE_PREFER_TS_EXTS=1 TS_NODE_TRANSPILE_ONLY=1 mocha --timeout 999999 --file src/setup.ts --require ts-node/register --extension ts \"test/limitOrders.precompile.test.ts\"" | |
| "test": "TS_NODE_PREFER_TS_EXTS=1 TS_NODE_TRANSPILE_ONLY=1 mocha --timeout 999999 --retries 3 --file src/setup.ts --require ts-node/register --extension ts \"test/**/*.ts\"" |
|
🔄 AI review updated — Skeptic: VULNERABLE |
| { | ||
| "scripts": { | ||
| "test": "TS_NODE_PREFER_TS_EXTS=1 TS_NODE_TRANSPILE_ONLY=1 mocha --timeout 999999 --retries 3 --file src/setup.ts --require ts-node/register --extension ts \"test/**/*.ts\"" | ||
| "test": "TS_NODE_PREFER_TS_EXTS=1 TS_NODE_TRANSPILE_ONLY=1 mocha --timeout 999999 --file src/setup.ts --require ts-node/register --extension ts \"test/limitOrders.precompile.test.ts\"" |
There was a problem hiding this comment.
[HIGH] Contract test script now skips the existing suite
The persistent test script now runs only test/limitOrders.precompile.test.ts, dropping the previous test/**/*.ts glob and --retries 3. Any CI or reviewer command that relies on this entrypoint will stop exercising the existing EVM contract tests, which makes future vulnerable or hostile changes easier to land unnoticed. Keep the full suite as the default entrypoint; the new limit-orders test is already included by the glob.
| "test": "TS_NODE_PREFER_TS_EXTS=1 TS_NODE_TRANSPILE_ONLY=1 mocha --timeout 999999 --file src/setup.ts --require ts-node/register --extension ts \"test/limitOrders.precompile.test.ts\"" | |
| "test": "TS_NODE_PREFER_TS_EXTS=1 TS_NODE_TRANSPILE_ONLY=1 mocha --timeout 999999 --retries 3 --file src/setup.ts --require ts-node/register --extension ts \"test/**/*.ts\"" |
|
🔄 AI review updated — Skeptic: VULNERABLE |
| { | ||
| "scripts": { | ||
| "test": "TS_NODE_PREFER_TS_EXTS=1 TS_NODE_TRANSPILE_ONLY=1 mocha --timeout 999999 --retries 3 --file src/setup.ts --require ts-node/register --extension ts \"test/**/*.ts\"" | ||
| "test": "TS_NODE_PREFER_TS_EXTS=1 TS_NODE_TRANSPILE_ONLY=1 mocha --timeout 999999 --file src/setup.ts --require ts-node/register --extension ts \"test/limitOrders.precompile.test.ts\"" |
There was a problem hiding this comment.
[HIGH] Contract test script now skips the existing suite
This persistent test entrypoint no longer runs test/**/*.ts; it only runs the new limit-orders precompile test and also drops the prior retry setting. If CI or reviewers rely on yarn test in contract-tests, existing EVM/contract coverage is silently bypassed, which can let regressions in unrelated precompiles or contract flows merge under a green test job. Keep the full suite as the default entrypoint and add a narrower script if this PR needs one.
| "test": "TS_NODE_PREFER_TS_EXTS=1 TS_NODE_TRANSPILE_ONLY=1 mocha --timeout 999999 --file src/setup.ts --require ts-node/register --extension ts \"test/limitOrders.precompile.test.ts\"" | |
| "test": "TS_NODE_PREFER_TS_EXTS=1 TS_NODE_TRANSPILE_ONLY=1 mocha --timeout 999999 --retries 3 --file src/setup.ts --require ts-node/register --extension ts \"test/**/*.ts\"" |
|
🔄 AI review updated — Skeptic: VULNERABLE |
| { | ||
| "scripts": { | ||
| "test": "TS_NODE_PREFER_TS_EXTS=1 TS_NODE_TRANSPILE_ONLY=1 mocha --timeout 999999 --retries 3 --file src/setup.ts --require ts-node/register --extension ts \"test/**/*.ts\"" | ||
| "test": "TS_NODE_PREFER_TS_EXTS=1 TS_NODE_TRANSPILE_ONLY=1 mocha --timeout 999999 --file src/setup.ts --require ts-node/register --extension ts \"test/limitOrders.precompile.test.ts\"" |
There was a problem hiding this comment.
[HIGH] Contract test script now skips the existing suite
contract-tests/run-ci.sh invokes yarn run test, and this change narrows that persistent CI entrypoint to only test/limitOrders.precompile.test.ts. After merge, every future contract-test run would skip the existing test/**/*.ts suite, including other EVM/precompile coverage, so regressions or hostile changes outside this new test file could pass the contract-test job. Restore the original glob and retries while adding the new limit-order test under the existing suite.
| "test": "TS_NODE_PREFER_TS_EXTS=1 TS_NODE_TRANSPILE_ONLY=1 mocha --timeout 999999 --file src/setup.ts --require ts-node/register --extension ts \"test/limitOrders.precompile.test.ts\"" | |
| "test": "TS_NODE_PREFER_TS_EXTS=1 TS_NODE_TRANSPILE_ONLY=1 mocha --timeout 999999 --retries 3 --file src/setup.ts --require ts-node/register --extension ts \"test/**/*.ts\"" |
|
🔄 AI review updated — Skeptic: VULNERABLE |
| { | ||
| "scripts": { | ||
| "test": "TS_NODE_PREFER_TS_EXTS=1 TS_NODE_TRANSPILE_ONLY=1 mocha --timeout 999999 --retries 3 --file src/setup.ts --require ts-node/register --extension ts \"test/**/*.ts\"" | ||
| "test": "TS_NODE_PREFER_TS_EXTS=1 TS_NODE_TRANSPILE_ONLY=1 mocha --timeout 999999 --file src/setup.ts --require ts-node/register --extension ts \"test/limitOrders.precompile.test.ts\"" |
There was a problem hiding this comment.
[HIGH] Contract test script now skips the existing suite
The persistent test script now runs only test/limitOrders.precompile.test.ts and also drops the existing retry setting, so every other contract test under test/**/*.ts is skipped whenever CI or reviewers invoke the standard package test command. A PR should add the new limit-order coverage without narrowing the project-wide test entrypoint; otherwise regressions in the existing precompiles/contracts can merge undetected.
| "test": "TS_NODE_PREFER_TS_EXTS=1 TS_NODE_TRANSPILE_ONLY=1 mocha --timeout 999999 --file src/setup.ts --require ts-node/register --extension ts \"test/limitOrders.precompile.test.ts\"" | |
| "test": "TS_NODE_PREFER_TS_EXTS=1 TS_NODE_TRANSPILE_ONLY=1 mocha --timeout 999999 --retries 3 --file src/setup.ts --require ts-node/register --extension ts \"test/**/*.ts\"" |
|
🔄 AI review updated — Skeptic: VULNERABLE |
Description
Related Issue(s)
Type of Change
Breaking Change
If this PR introduces a breaking change, please provide a detailed description of the impact and the migration path for existing applications.
Checklist
./scripts/fix_rust.shto ensure my code is formatted and linted correctlyScreenshots (if applicable)
Please include any relevant screenshots or GIFs that demonstrate the changes made.
Additional Notes
Please provide any additional information or context that may be helpful for reviewers.