Skip to content
Merged

Dev #121

Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 18 additions & 7 deletions scripts/sanity/secure-ownable/broadcaster-update-tests.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -473,15 +473,26 @@ class BroadcasterUpdateTests extends BaseSecureOwnableTest {
this.getRoleWalletObject('owner')
);

// Try to get the txId from pending transactions
const expectedOpType = this.getOperationType('BROADCASTER_UPDATE');

// Try to find the broadcaster-update request among all pending transactions.
// Other workflows (e.g. ERC20 mint) may leave unrelated pending txs around.
for (let i = 0; i < 5; i++) {
const pending = await this.callContractMethod(this.contract.methods.getPendingTransactions());
if (pending.length > 0) {
const txId = pending[0];
const txRecord = await this.callContractMethod(this.contract.methods.getTransaction(txId));
if (txRecord.params.operationType === this.getOperationType('BROADCASTER_UPDATE')) {
console.log(` ✅ Broadcaster update request created`);
return txRecord;
if (pending && pending.length > 0) {
for (const txId of pending) {
const txRecord = await this.callContractMethod(this.contract.methods.getTransaction(txId));
const op = txRecord && txRecord.params && txRecord.params.operationType;
if (
op &&
(op === expectedOpType ||
(typeof op === 'string' &&
typeof expectedOpType === 'string' &&
op.toLowerCase() === expectedOpType.toLowerCase()))
) {
console.log(` ✅ Broadcaster update request created (txId: ${txRecord.txId || txId})`);
return txRecord;
}
Comment on lines +482 to +495

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don’t return the first matching broadcaster-update tx.

This helper creates a new request immediately above, but Lines 483-494 return the first pending BROADCASTER_UPDATE they find. If another broadcaster-update request is already pending, the test can attach to the stale tx instead of the one it just created. createBroadcasterRequestAndDeriveTxId() already scopes its fallback by requester and searches newest-first; this helper should apply the same constraint here.

💡 Proposed fix
         for (let i = 0; i < 5; i++) {
             const pending = await this.callContractMethod(this.contract.methods.getPendingTransactions());
             if (pending && pending.length > 0) {
-                for (const txId of pending) {
+                let newestMatch = null;
+                for (const txId of pending) {
                     const txRecord = await this.callContractMethod(this.contract.methods.getTransaction(txId));
                     const op = txRecord && txRecord.params && txRecord.params.operationType;
+                    const requester = txRecord && txRecord.params && txRecord.params.requester;
                     if (
                         op &&
                         (op === expectedOpType ||
                             (typeof op === 'string' &&
                                 typeof expectedOpType === 'string' &&
-                                op.toLowerCase() === expectedOpType.toLowerCase()))
+                                op.toLowerCase() === expectedOpType.toLowerCase())) &&
+                        requester &&
+                        requester.toLowerCase() === this.roles.owner.toLowerCase()
                     ) {
-                        console.log(`  ✅ Broadcaster update request created (txId: ${txRecord.txId || txId})`);
-                        return txRecord;
+                        if (!newestMatch || BigInt(txRecord.txId) > BigInt(newestMatch.txId)) {
+                            newestMatch = txRecord;
+                        }
                     }
                 }
+                if (newestMatch) {
+                    console.log(`  ✅ Broadcaster update request created (txId: ${newestMatch.txId})`);
+                    return newestMatch;
+                }
             }
📝 Committable suggestion

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

Suggested change
if (pending && pending.length > 0) {
for (const txId of pending) {
const txRecord = await this.callContractMethod(this.contract.methods.getTransaction(txId));
const op = txRecord && txRecord.params && txRecord.params.operationType;
if (
op &&
(op === expectedOpType ||
(typeof op === 'string' &&
typeof expectedOpType === 'string' &&
op.toLowerCase() === expectedOpType.toLowerCase()))
) {
console.log(` ✅ Broadcaster update request created (txId: ${txRecord.txId || txId})`);
return txRecord;
}
if (pending && pending.length > 0) {
let newestMatch = null;
for (const txId of pending) {
const txRecord = await this.callContractMethod(this.contract.methods.getTransaction(txId));
const op = txRecord && txRecord.params && txRecord.params.operationType;
const requester = txRecord && txRecord.params && txRecord.params.requester;
if (
op &&
(op === expectedOpType ||
(typeof op === 'string' &&
typeof expectedOpType === 'string' &&
op.toLowerCase() === expectedOpType.toLowerCase())) &&
requester &&
requester.toLowerCase() === this.roles.owner.toLowerCase()
) {
if (!newestMatch || BigInt(txRecord.txId) > BigInt(newestMatch.txId)) {
newestMatch = txRecord;
}
}
}
if (newestMatch) {
console.log(` ✅ Broadcaster update request created (txId: ${newestMatch.txId})`);
return newestMatch;
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/sanity/secure-ownable/broadcaster-update-tests.cjs` around lines 482
- 495, The current loop over pending transactions returns the first
BROADCASTER_UPDATE matching expectedOpType, which may pick a stale request;
modify the search in the block that calls
this.callContractMethod(this.contract.methods.getTransaction(txId)) so it
filters transactions by the same requester identity used by
createBroadcasterRequestAndDeriveTxId() and iterates newest-first (reverse the
pending array) before returning; specifically ensure you check
txRecord.params.requester (or the equivalent requester field) matches the
requester used when creating the request and only then return the txRecord when
op matches expectedOpType.

}
}
await new Promise(resolve => setTimeout(resolve, 1000));
Expand Down