Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: poll recovery state of Safe #2767

Merged
merged 11 commits into from
Nov 13, 2023
Merged

feat: poll recovery state of Safe #2767

merged 11 commits into from
Nov 13, 2023

Conversation

iamacook
Copy link
Member

@iamacook iamacook commented Nov 7, 2023

What it solves

Resolves #2752

How this PR fixes it

This adds a new recovery slice to Redux. When a Safe is opened, and subsequently every ten minutes, the modules of it are parsed and for every Delay Modifier, details loaded.

type RecoveryQueueItem = TransactionAddedEvent & {
  timestamp: number
  validFrom: BigNumber
  expiresAt: BigNumber | null
}

type RecoveryState = Array<{
  address: string
  modules: Array<string>
  txExpiration: BigNumber
  txCooldown: BigNumber
  txNonce: BigNumber
  queueNonce: BigNumber
  queue: Array<QueuedTransactionAdded>
}>

How to test it

Open a Safe with a Delay Modifier enabled, e.g. gor:0xAecDFD3A19f777F0c03e6bf99AAfB59937d6467b and observe the state load in Redux.

Screenshots

image

Checklist

  • I've tested the branch on mobile 📱
  • I've documented how it affects the analytics (if at all) 📊
  • I've written a unit/e2e test for it (if applicable) 🧑‍💻

@iamacook iamacook self-assigned this Nov 7, 2023
Copy link

github-actions bot commented Nov 7, 2023

Branch preview

✅ Deploy successful!

https://recover_state--walletweb.review-wallet-web.5afe.dev

@iamacook iamacook linked an issue Nov 7, 2023 that may be closed by this pull request
4 tasks
Copy link

github-actions bot commented Nov 7, 2023

ESLint Summary View Full Report

Annotations are provided inline on the Files Changed tab. You can also see all annotations that were generated on the annotations page.

Type Occurrences Fixable
Errors 0 0
Warnings 0 0
Ignored 0 N/A
  • Result: ✅ success
  • Annotations: 0 total

Report generated by eslint-plus-action

Copy link

github-actions bot commented Nov 7, 2023

Coverage report

St.
Category Percentage Covered / Total
🟡 Statements
75.35% (+0.17% 🔼)
9567/12697
🔴 Branches
49.81% (+0.33% 🔼)
1963/3941
🔴 Functions
58.17% (+0.25% 🔼)
1442/2479
🟡 Lines
76.98% (+0.13% 🔼)
8660/11249
Show new covered files 🐣
St.
File Statements Branches Functions Lines
🟢
... / recoverySlice.ts
77.78% 100% 0% 100%
🟡
... / delay-modifier.ts
68% 50% 60% 68%
🟡
... / proxies.ts
71.43% 100% 75% 71.43%
🟢
... / useLoadRecovery.ts
100% 100% 100% 100%
🟢
... / recovery-state.ts
100% 100% 100% 100%

Test suite run success

1078 tests passing in 147 suites.

Report generated by 🧪jest coverage report action from f70fff8

@iamacook iamacook requested a review from schmanu November 8, 2023 10:06
@iamacook iamacook marked this pull request as ready for review November 8, 2023 10:06
Comment on lines 31 to 50
const queue = await Promise.all(
transactionsAdded
// Only queued transactions with queueNonce >= current txNonce
.filter(({ args }) => args.queueNonce.gte(txNonce))
.map(async (event) => {
const txBlock = await event.getBlock()

const validFrom = BigNumber.from(txBlock.timestamp).add(txCooldown)
const expiresAt = txExpiration.isZero()
? null // Never expires
: validFrom.add(txExpiration)

return {
...event,
timestamp: txBlock.timestamp,
validFrom,
expiresAt,
}
}),
)
Copy link
Member

Choose a reason for hiding this comment

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

I would extract this into its own function.

Copy link
Member Author

Choose a reason for hiding this comment

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

I've extracted it and added test coverage for it (and all other loading related logic) in 181b21d.

Copy link
Member

@katspaugh katspaugh left a comment

Choose a reason for hiding this comment

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

Some unit tests would be good.

@iamacook iamacook marked this pull request as draft November 9, 2023 16:25
@iamacook iamacook marked this pull request as ready for review November 9, 2023 21:20
Comment on lines +149 to +150
cy.get('p').contains('1').should('exist')
cy.get('p').contains('2').should('exist')
Copy link
Member Author

Choose a reason for hiding this comment

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

This was failing as in #2768 (comment).

Comment on lines 20 to 77
export const _getQueuedTransactionsAdded = (
transactionsAdded: Array<TransactionAddedEvent>,
txNonce: BigNumber,
): Array<TransactionAddedEvent> => {
// Only queued transactions with queueNonce >= current txNonce
return transactionsAdded.filter(({ args }) => args.queueNonce.gte(txNonce))
}

export const _getRecoveryQueueItem = async (
transactionAdded: TransactionAddedEvent,
txCooldown: BigNumber,
txExpiration: BigNumber,
): Promise<RecoveryQueueItem> => {
const txBlock = await transactionAdded.getBlock()

const validFrom = BigNumber.from(txBlock.timestamp).add(txCooldown)
const expiresAt = txExpiration.isZero()
? null // Never expires
: validFrom.add(txExpiration)

return {
...transactionAdded,
timestamp: txBlock.timestamp,
validFrom,
expiresAt,
}
}

export const _getRecoveryState = async (delayModifier: Delay): Promise<RecoveryState[number]> => {
const transactionAddedFilter = delayModifier.filters.TransactionAdded()

const [[modules], txExpiration, txCooldown, txNonce, queueNonce, transactionsAdded] = await Promise.all([
delayModifier.getModulesPaginated(SENTINEL_ADDRESS, MAX_PAGE_SIZE),
delayModifier.txExpiration(),
delayModifier.txCooldown(),
delayModifier.txNonce(),
delayModifier.queueNonce(),
delayModifier.queryFilter(transactionAddedFilter),
])

const queuedTransactionsAdded = _getQueuedTransactionsAdded(transactionsAdded, txNonce)

const queue = await Promise.all(
queuedTransactionsAdded.map((transactionAdded) =>
_getRecoveryQueueItem(transactionAdded, txCooldown, txExpiration),
),
)

return {
address: delayModifier.address,
modules,
txExpiration,
txCooldown,
txNonce,
queueNonce,
queue,
}
}
Copy link
Member

Choose a reason for hiding this comment

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

One might ask at this point why they are in the hook and not in the services/recovery, but up to you.

Copy link
Member Author

Choose a reason for hiding this comment

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

I moved the parsing logic to the @/services/recovery folder in d646122.

delayModifier.txCooldown(),
delayModifier.txNonce(),
delayModifier.queueNonce(),
delayModifier.queryFilter(transactionAddedFilter),
Copy link
Member

Choose a reason for hiding this comment

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

I think on some networks the size of logs that can be queried is limited.
And in general it is adviced to query the on-chain data in chunks (see here)

A good first step could be to at least limit the starting block to the block in which the Safe was deployed or the module was enabled. And for later polls we could remember the last checked block and start polling from there.

Copy link
Member Author

Choose a reason for hiding this comment

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

I've created a separate issue to focus on this specifically. However, I adjusted the query logic to only request from the Safe creation block in f70fff8. What do you think?

Copy link
Member

@schmanu schmanu left a comment

Choose a reason for hiding this comment

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

LGTM! We can tackle the optimization in a separate issue :)

@iamacook iamacook merged commit c785f26 into recovery-epic Nov 13, 2023
11 checks passed
@iamacook iamacook deleted the recover-state branch November 13, 2023 15:57
@github-actions github-actions bot locked and limited conversation to collaborators Nov 13, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Recovery] Proposal data loading/caching
4 participants