-
Notifications
You must be signed in to change notification settings - Fork 87
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(jumpstart): handle jumpstart state #4963
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4963 +/- ##
==========================================
+ Coverage 85.43% 85.48% +0.05%
==========================================
Files 721 724 +3
Lines 29435 29534 +99
Branches 5093 5100 +7
==========================================
+ Hits 25148 25248 +100
+ Misses 4048 4047 -1
Partials 239 239
... and 2 files with indirect coverage changes Continue to review full report in Codecov by Sentry.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looking great!! perhaps you want to add the jumpstart state to the redux blacklist or restore the initial state via the rehydrate action, but it seems like we wouldn't want to persist this store across app sessions?
src/jumpstart/saga.ts
Outdated
yield* put(jumpstartClaimStarted()) | ||
|
||
const transactionHashes = yield* call(jumpstartLinkHandler, privateKey, walletAddress) | ||
yield* fork(dispatchPendingTransactions, transactionHashes) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think we don't do a great job of handling multiple chains here. on one hand, we've made the dynamic config work for multichain by enabling a different contract address for each chain but in the code we're only looking for the defaultNetworkId
. in both the jumpstartLinkHandler
and 'dispatchPendingTransactions' sagas only look at the default network.
could we update this to be something like get all the supported networks based on what is there in the dynamic config -> for each chain, fork a saga that calls jumpstartLinkHandler with the chain id and then does the dispatchPendingTransactions for those transactions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that we should handle networks in a generic way and avoid network hardcoding. Thanks for pointing this out!
I ended up looping through all remote config networkIds, but I think it's suboptimal. If the amount of jumpstart-supported networks grows, we would have to loop trough them all, issuing network/blockchain request for every network because we have no idea for which specific network that link is. To avoid looping, perhaps we can encode network id within the jumpstart link?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, we probably want to refactor jumpstartLinkHandler from ContractKit to Viem to make it multichain?
For now, I just made it throw an error if network id isn't Celo.
const transactionHashes = [ | ||
...(await executeClaims(kit, jumpstart, publicKey, userAddress, 'erc20', privateKey)), | ||
...(await executeClaims(kit, jumpstart, publicKey, userAddress, 'erc721', privateKey)), | ||
] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: could we do a Promise.all here?
src/analytics/Properties.tsx
Outdated
interface WalletJumpstartProperties { | ||
[JumpstartEvents.jumpstart_started]: undefined | ||
[JumpstartEvents.jumpstart_succeeded]: undefined | ||
[JumpstartEvents.jumpstart_failed]: undefined |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i wonder if we need the jumpstart_started event, when it will always end with jumpstart_succeeded or jumpstart_failed? maybe i'm missing the extra information we get from this event.
i also wonder if it'd be nice to capture some data on how users are using this feature, e.g. the token and amounts that are being claimed. i guess we can also see this on the contract events directly, but maybe it helps with data analysis to capture this in analytics? i'm not sure, just a suggestion :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, jumpstart_started
is redundant.
added separate events for token/amount tracking:
jumpstart_claimed_token
with ERC20 claim detailsjumpstart_claimed_nft
with ERC721 claim details
I think it's worth keeping a bare jumpstart_succeeded
event as well, because getting claim details may fail (but it doesn't mean claim didn't succeeded)
1 build increased size
Celo (test) 1.79.0 (144)
|
Item | Install Size Change |
---|---|
main.jsbundle | ⬆️ 12.3 kB |
🛸 Powered by Emerge Tools
yes, this state shouldn't persist, because it's only for presentation purposes during current user session. added it to persist's |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looking great!! sorry i had a different thought while reviewing how we make the claim here, lmk what you think
userAddress: string | ||
): Promise<Hash[]> { | ||
if (networkId !== networkConfig.defaultNetworkId) { | ||
throw new Error(`Unsupported network id: ${networkId}`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, i was wondering why we need to do this, and then i saw that this function is using contract kit 😞 let's leave it for now and make a task to remove contract kit for later
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, here is the task: https://linear.app/valora/issue/RET-1019/[wallet]-refactor-jumstartlinkhandler-to-viem
src/jumpstart/saga.ts
Outdated
|
||
yield* fork(dispatchPendingTransactions, networkId, transactionHashes) | ||
} catch (error) { | ||
Logger.error(TAG, `Error handling jumpstart link for ${networkId}`, error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this claim saga is kicked off every time a jumpstart deep link is consumed, but presumably each deep link is only for one network. if we had multichain jumpstart, this logger.error would always be fired because some chains will always have no transactions found right? and we'd always be doing unnecessary work, to try to claim across chains when we should only do it for one chain? perhaps what would be more efficient is to have the jumpstart link contain the network id...what do you think? sorry, i know this is different to what i suggested last time
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, I agree that we have to store the chain id somewhere in the jumpstart link to avoid unnecessary looping over all supported networks.
should we have a separate task for that?
in the meanwhile we can assume that we get network id from the link, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes let's do that! since we create the link when the user makes the transaction, we'll already have this information and no reason why we can't add it to the link to make our lives easier
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's make the network id pathParts[3]
of the jumpstart link
src/jumpstart/slice.ts
Outdated
showLoading: boolean | ||
showError: boolean |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just checking, do we need both loading and error state at the same time?
If not, I'd advise to model it differently to avoid impossible states.
For instance:
Line 6 in 2b89723
type Status = 'idle' | 'loading' | 'success' | 'error' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point, thanks! refactored it to have just one consistent property:
export interface State {
claimStatus: 'idle' | 'loading' | 'error'
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks great!! a few non blocking annoying comments, do with them what you want :)
@@ -43,27 +39,23 @@ describe('jumpstartLinkHandler', () => { | |||
it('calls executeClaims with correct parameters', async () => { | |||
;(fetchWithTimeout as jest.Mock).mockImplementation(() => ({ | |||
ok: true, | |||
json: async () => ({ transactionHash: '0xTEST' }), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: maybe this can be different from the contractAddress
?
src/app/saga.ts
Outdated
@@ -298,12 +299,6 @@ export function* handleDeepLink(action: OpenDeepLink) { | |||
const { isSecureOrigin } = action | |||
Logger.debug(TAG, 'Handling deep link', deepLink) | |||
|
|||
const walletAddress = yield* select(walletAddressSelector) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: i wonder if we should leave this here and continue to expect the wallet address as a param in the jumpstartClaim saga. only the jumpstartClaim saga is technically needing the wallet address right now, so i understand why you made the change.
it's been annoying in the past for deep links to be processed when wallet address is not available. for example, the opened_via_invite_url event ended up being unhelpful because the walletAddress was undefined and we couldn't match inviters and invitees. the logic in the wallet has changed now where this saga shouldn't be triggered unless the walletAddress is available, but that is done in a hook and perhaps nice to fail early here if something goes wrong?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but failing early will mean we don't show the user any feedback about the error, right?
we could add a generic alert, but failing inside the specific handler means we could communicate what specific situation we are processing, and what error we've encountered
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm yes, i guess i can see it both ways.
failing early here = we assert all deep links should be handled after the wallet is initialized and it does not matter whether the deep link strictly needs the wallet address in the logic. even if the logic succeeds, our instrumentation will be broken becuase the wallet address is missing.
failing contextually = we have more information about where it failed, but we will allow silent instrumentation failures.
i have a preference for the first scenario, because i cannot think of a scenario where we'd want to process a deep link when a wallet is not initialised?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. There may be a logic requiring a wallet address not directly in a deep link handler, down the user journey, like when link handler fires a navigate event.
src/jumpstart/saga.ts
Outdated
|
||
const token = tokensById[tokenId] | ||
if (!token) { | ||
Logger.error(TAG, 'Claimed unknown tokenId', tokenId) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logger.error(TAG, 'Claimed unknown tokenId', tokenId) | |
Logger.warn(TAG, 'Claimed unknown tokenId', tokenId) |
seems that we wouldn't want to investigate this right?
src/jumpstart/saga.ts
Outdated
tokenId: tokenId.toString(), | ||
}) | ||
} catch (error) { | ||
Logger.error(TAG, 'Error adding pending NFT transaction', error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here, i wonder if we should downgrade these to .warn since the pending transactions is a nice to have visual feedback rather than core functionality?
### Description 1. Introducing new slice to the redux state for jumpstart link handling: ``` jumpstart: { showLoading: boolean showError: boolean } ``` This state is expected to be used for rendering UI components displaying the jumpstart link handling state to the user. The actual components will follow in the subsequent PR once the design discussions converge. 2. After successful jumpstart claim two types of pending transactions are dispatched (getting tx data trough blockchain RPC calls): * Payment received (for ERC-20 claim) * NFT received (for ERC-721 claim) Those transactions are expected to be replaced with blockchain-api data once it's fetched. 3. Added analytics events for jumpstart handler lifecycle: * claim succeeded * claim failed * ERC20 token claimed * ERC721 nft claimed ### Test plan * Updated unit tests ### Related issues - Related to RET-1004 ### Backwards compatibility Y ### Network scalability If a new NetworkId and/or Network are added in the future, the changes in this PR will: - [x] Continue to work without code changes, OR trigger a compilation error (guaranteeing we find it when a new network is added)
Description
This state is expected to be used for rendering UI components displaying the jumpstart link handling state to the user. The actual components will follow in the subsequent PR once the design discussions converge.
Those transactions are expected to be replaced with blockchain-api data once it's fetched.
Test plan
Related issues
Backwards compatibility
Y
Network scalability
If a new NetworkId and/or Network are added in the future, the changes in this PR will: