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

wip #252

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft

wip #252

wants to merge 2 commits into from

Conversation

onmax
Copy link
Member

@onmax onmax commented Jan 21, 2025

This PR introduces the Nimiq Wallet Playground.

The user will be able to enter https://wallet-testnet.nimiq.com/?demo and start playing with the Wallet with no account whatsoever.

This will be useful for the coming new nimiq.com/wallet page. As soon this feature goes live, soon after the new page will be updated.

The user will be able to open the Wallet and do different actions such as:

  • Navigate the app. Go to Settings, network, view different accounts...
  • Buy fake NIM
  • Fake Swap cryptos
  • Fake staking

Live preview

  1. Go to the branch selector and select playground branch.
  2. Open the Nimiq Wallet Playground Testnet

Development

Use the playground branch, install the new dependencies and open http://localhost:8081?demo

Tip

One good thing about this new feature is that we no longer have to run Keyguard and the Hub in parallel. Very useful if you are working on UI stuff.

Note

You need to enable polygon in config.local to see USDC and USDT.

Package Dependencies

Demo Mode Implementation

I've tried to touch as little code from the current application as possible, as we don't want to introduce any problems for current users. All demo related code can be found in stores/Demo.ts. I decided not to create multiple files on purpose, even though the code is a bit spaghetti in my opinion.

main.ts

We don't want to write anything to the user's storage, so when the application is initialised, the first thing it does is check whether the ?demo parameter exists or not. If it exists, we also "inject" the ?demo parameter after each route change.

We do use ?demo as query param and not path param since it is easier to propagate and not mess with the router

const { isDemoEnabled } = useDemoStore();
if (!isDemoEnabled.value) {
    // Normal app initialization
    await initStorage();
    initTrials();
    await initHubApi();
    syncFromHub();
} else {
    // Demo mode initialization
    useDemoStore().initialize(router);
}

Hub API

We don't want to launch the Hub API when the demo is active. So a new "mock" implementation of the Hub API has been introduced:

const hubApi = checkIfDemoIsActive() ? DemoHubApi.create() : new HubApi(Config.hubEndpoint);

This demo, will block any attempt to open the hub popup and instead handle the opening of the new "DemoModalFallback" which will let the user know that the playground functionality is limited and they have reached the end of the playground

Sometimes the HubAPI will not display this modal and will instead fake the operation. For example, if you are exchanging two currencies, the Hub API will create a fake exchange and you will see the whole process.

You can see the DemoHubApi in the ./stores/Demo.ts and the "Faked Flows" section in this PR.

Fake accounts & transactions

To add some realism, we insert fake transactions in NIM, BTC, USDC and USDT. The transactions in NIM have customised messages using cultural references from around the world. Fun fact: the NIM amount is 140418, which is a date: 14th of april, 2018.

We are prioritizing realism, so instead of using a Math.random for the values of each transaction we do use a ratio of the total amount that the user has now. This allows us to confidently know that the balance shown in the overview matches the transaction history.

Intercept fetch request

We rely on some HTTP APIs to fetch some data like the /limits for the swaps. In those cases, we intercept the fetch request and return the value we want.

Faked flows

One of the reasons of the Nimiq Wallet Playground is to let the user play without an account. Therefore the most notorious and important flows have been faked.

These are the faked flows:

  • Buy NIM: see replaceBuyNimFlow function
  • Stake NIM: see replaceStakingFlow function

Communication with the host

Since this feature will be used as an iframe, we would like let the host and the app talk to each other. Therefore, we have the function attachIframeListeners.

Basically, the user has the option to click: "Buy", "stake" or "swap" in the website. The selector has will have one of the options highlighted if the user is within that flow.

Therefore, this communication needs to be two-way, meaning that if the user changes the flow from the application, the application needs to communicate this to the host, or if the user changes the flow from the selector, the host needs a request to initialise to that flow.

Custom CSS + Visual cues

When the playground is enabled we add also some visual cues to the user to let them know where to click. This cues are added from Demo.ts@setupVisualCues function.

We also inject some CSS to make some minor adjustments.

Further work

At the moment there are some things we can improve:

Translations

Should we translate the transactions messages and labels?

Error while redirecting

Error: Redirected when going from "/?demo=" to "/staking" via a navigation guard.
    at createRouterError (vue-router.esm.js:2056:15)
    at createNavigationRedirectedError (vue-router.esm.js:2015:10)
    at eval (vue-router.esm.js:2386:17)
    at eval (Demo.ts:138:1)
    at iterator (vue-router.esm.js:2372:7)
    at step (vue-router.esm.js:2097:9)
    at eval (vue-router.esm.js:2098:11)
    at eval (vue-router.esm.js:2394:11)
    at eval (router.ts:529:1)

Is there a way to ignore it? It does not block the experience, but it is annoying.

Fallback modal

We could improve the current fallback modal. There are certain scenarios where the user has done something that triggers the Hub API. In those cases, this fallback modal is displayed. We need to make sure that the user understands that they are in a playground mode and that the functionality is limited.

See screenshot

image


Personal TODOs to make this PR ready for review

  • Setup Wallet with no storage and "playground" mode
  • Create dummy account with dummy data
  • Hijack requests to HubApi
  • Implement fake buy
  • Implement fake sell
  • Fix Identicons in list
  • Implement visual clues
  • Implement iframe messages to change visual clues both ways
  • Implement fake Staking
  • Adjust stake
  • Unstake
  • Fix staked amount
  • Undo changes in sidebar.
  • Undo changes in Buy Modal.
  • Fake BTC account
  • Fake Swaps
  • Display swapped amount
  • Disable changing staking amount
  • Fake USDT account
  • Fake USDC account

@onmax onmax force-pushed the playground branch 4 times, most recently from 45bdb4a to 1489d07 Compare January 22, 2025 11:28
@@ -53,7 +53,7 @@
"v-click-outside": "^3.0.1",
"vue": "^2.6.11",
"vue-i18n": "^8.15.5",
"vue-router": "^3.1.6",
"vue-router": "^3.5.0",
Copy link
Member Author

@onmax onmax Jan 22, 2025

Choose a reason for hiding this comment

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

I am working on the wallet playground. I want to add some routes, but since it's only for playground mode, I don't want to do it in router.ts, but rather dynamically.

I had to update vue-router to be able to add routes to specific children using addRoute. Maybe there is another way, but also it doesn't hurt to update now, as it is something less for the future :).

There are no breaking changes between 3.1 and 3.5: https://github.com/vuejs/vue-router/blob/dev/CHANGELOG.md#350-2021-01-25 except for a few TS issues, which you can find in this commit.

@sisou @danimoh do you agree with this decision?

@onmax onmax force-pushed the playground branch 4 times, most recently from 734d254 to db45aee Compare January 24, 2025 08:14
@onmax onmax force-pushed the playground branch 3 times, most recently from 0595750 to c2ee053 Compare February 25, 2025 10:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant