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/multiple function access keys #156

Conversation

petersalomonsen
Copy link
Contributor

@petersalomonsen petersalomonsen commented Nov 25, 2023

@petersalomonsen petersalomonsen changed the title Feat/multiple funciton access keys Feat/multiple function access keys Nov 25, 2023
@frol
Copy link

frol commented Nov 25, 2023

@petersalomonsen I don't understand what is the intended flow here. I don't see "don't ask me again" checkbox, when I tried to "like" on DevHub, there was a popup prompt that redirected me to the wallet (MNW) with some unparsable transaction confirmation (it tried to display it as a function call confirmation but there was no function call). Please, record a screencast as otherwise I don't even understand how you see it can work.

@petersalomonsen
Copy link
Contributor Author

Sorry @frol I must have missed something when I published the first version. Unfortunately what you experienced was that you were not redirected to the wallet for the add_key transaction, but instead just sent for the add_like. This is because of a missing await for the add_key transaction, and I've corrected this now.

Here's a demonstration video as requested: https://youtu.be/0oG9_-KEi0Q?si=BEeUYz5E7wQApWNm

@frol
Copy link

frol commented Nov 26, 2023

@petersalomonsen This is a nice proof of concept, and I believe we should push it forward. Yet, there are a number of UX tweaks that need to be implemented:

  1. Instead of the browser prompt, there should be just a "Don't ask me again" checkbox similar to the SocialDB interactions on the BOS modal popup
  2. Use a regular Wallet login flow page. Using a generic transaction signing page does not provide relevant UX to the users:
image I would expect to see: image 3. Avoid refreshing the page after sending the transaction (once the access key is already there) - similarly to how it is done for SocialDB interactions (like on the NEAR Social feed does not refresh the page)

@petersalomonsen
Copy link
Contributor Author

Thanks @frol , good to hear that we can move forward on this. I agree to all of your 3 points, and I've started working on the UX experience ( not using a browser prompt ).

As you can see in the screenshot below, from my local dev environment, there's a checkbox to toggle if you want to create a function access key ( we can consider naming this "Don't ask me again", as you propose ):

image

When you check that toggle, I'm now trying to include the function access key transaction, so that you don't loose the like or post you are about to confirm. So as you can see in the screenshot below, when checked, another transaction, the "addKey" is also showing.

image

Not sure yet how to fix it so that the wallet says that "an application is requesting limited access to your account", but I'll try to figure that out.

Also totally agree that we should not reload the page, but right now I think this involves work on the DevHub code to handle transaction feedback. Everything we have right now is based on the fact that the page is reloading ( after a completed transaction ). I'll see what I can do there, but it might have to be a separate issue for DevHUB after this feature for creating function access keys is merged to the VM codebase.

Let me know what you think

@petersalomonsen
Copy link
Contributor Author

@frol @evgenykuzyakov I've done some UX tweaks now so that the adding of a new access key is part of the regular VM confirmation popup. Just as in the screenshots from the previous comment. Note that you only should tick the checkbox once, for the next calls you already have an access key stored, so you don't need to create it again. This might be confusing, so I will figure out how to make this more clear in the UI. "Don't ask again" might also be confusing since it could be misunderstood as you would not get the VM confirmation popup either.

@petersalomonsen
Copy link
Contributor Author

UX is improving bit by bit, so if you already have an access key stored, the popup will open with the checkbox checked, and also indicating which key that will be attempted for signing the transaction:

image

@frol
Copy link

frol commented Nov 28, 2023

"Don't ask again" might also be confusing since it could be misunderstood as you would not get the VM confirmation popup either.

@petersalomonsen That is how SocialDB interactions are done - they allow “don’t ask again” for the specific component interacting with SocialDB. From UX perspective, I believe it makes sense. Obviously, you don’t want to allow any component to interact with a contract on behalf of the user just because there is already an access key, but it doesn’t make a lot of sense to confirm every like with the popup either. Take inspiration from Social.set implementation

@petersalomonsen
Copy link
Contributor Author

"Don't ask again" might also be confusing since it could be misunderstood as you would not get the VM confirmation popup either.

@petersalomonsen That is how SocialDB interactions are done - they allow “don’t ask again” for the specific component interacting with SocialDB. From UX perspective, I believe it makes sense. Obviously, you don’t want to allow any component to interact with a contract on behalf of the user just because there is already an access key, but it doesn’t make a lot of sense to confirm every like with the popup either. Take inspiration from Social.set implementation

Thanks @frol , that's a good point. I'll look into how Social.set is solved, and try avoiding the VM confirmation popup as well.

@ailisp
Copy link

ailisp commented Dec 1, 2023

Looks great! I would also suggest to have this checked by default:
image

And I have a question when it's run out of function call key allowance, what will happen?

@frol
Copy link

frol commented Dec 1, 2023

@petersalomonsen On a general note, please, put yourself in the shoes of a regular user, they don't know about "access key" and why they would want to create one.

@petersalomonsen
Copy link
Contributor Author

petersalomonsen commented Dec 1, 2023

yes @frol . I'm moving forward in the direction you proposed with "Don't ask again", and not even showing the confirmation popup in the VM. @ailisp When the key runs out of allowance, we should detect that and pop up the confirmation dialogs again. It might be good to provide some optional detailed information for the user to explain what is happening behind the scenes.

@petersalomonsen
Copy link
Contributor Author

petersalomonsen commented Dec 1, 2023

@frol @ailisp See the updated progress. Now it's using the regular wallet login, it's executing the "pending" transaction after login. After that there is no need to confirm when posting or liking. Just for now I've added a small popup ( just for information ), that shows that there is a transaction going on ( not sure how we want to solve this yet ).

Also see the new demo video of the flow: https://youtu.be/CuwWv1zAKf4?si=lBUi9kXxRrhVjv-s

The preview URL also contains the latest version.

What's remaining, as I see is:

  • Try to avoid reloading after the transaction
  • Some indication on what's going on during sending the "Pending" transaction ( after login )
  • Handling out of allowance
  • Handling deleted function access keys ( that are not deleted in localstorage, but deleted on chain )

@petersalomonsen
Copy link
Contributor Author

Now the page does not reload after the transaction.

@@ -111,33 +172,42 @@ async function accountState(near, accountId) {
}

async function sendTransactions(near, functionCalls) {
if (functionCalls.length == 1) {
const { contractName, methodName, args, gas, deposit } = functionCalls[0];
//if (deposit == Big(0)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This check needs to be in place before merging, and also include the gas from the original transaction

if (
transactions[transactions.length - 1]?.receiverId !== contractName ||
newTotalGas.gt(MaxGasPerTransaction)
) {
transactions.push({
receiverId: contractName,
actions: [],
actions: actions ?? [],
Copy link
Contributor Author

Choose a reason for hiding this comment

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

actions is not used. should be removed

});
currentTotalGas = gas;
} else {
currentTotalGas = newTotalGas;
}
transactions[transactions.length - 1].actions.push(action);
if (!actions) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

there will not be actions here.

contractId: contractName,
methodName,
args,
//gas
Copy link
Contributor Author

Choose a reason for hiding this comment

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

need to include gas from the original transaction

@petersalomonsen
Copy link
Contributor Author

These are remaining, but could maybe be separate issues?

  • Some indication on what's going on during sending the "Pending" transaction ( after login )
  • Handling out of allowance
  • Handling deleted function access keys ( that are not deleted in localstorage, but deleted on chain )

@frol
Copy link

frol commented Dec 3, 2023

Some indication on what's going on during sending the "Pending" transaction ( after login )

Well, given that Social.set also lacks any indication on Pending transaction, indeed, we can address it across the board in a separate issue.

Handling out of allowance
Handling deleted function access keys ( that are not deleted in localstorage, but deleted on chain )

Social.set also does not handle it gracefully either. Let's address these in separate issues, indeed. Please, create follow-up issues.

@frol
Copy link

frol commented Dec 3, 2023

After that there is no need to confirm when posting or liking.

I hope it only whitelists interaction with the contract only for the given BOS component. We don't want random components on BOS to be able to interact with devhub contract without user's acknowledgement. Again, see Social.set behavior.

image

(Also, let's use the same UI layout and message in both dialogs if possible)

Just for now I've added a small popup ( just for information ), that shows that there is a transaction going on ( not sure how we want to solve this yet ).

Let's follow Social.set, it does not have any indication on BOS level, but exposes onCommit API (#105)

@petersalomonsen
Copy link
Contributor Author

I hope it only whitelists interaction with the contract only for the given BOS component. We don't want random components on BOS to be able to interact with devhub contract without user's acknowledgement. Again, see Social.set behavior.

That's a good point. I did not think of that.

So that's a remaining issue then before this can be merged, but I will look into it.

@petersalomonsen
Copy link
Contributor Author

Now I've fixed so that only interaction for the given BOS component is whitelisted, and you also only whitelist calling a specific method on the smart contract:

image

Given all the changes, I do feel the need for setting up a testing framework for this now. Are there any automatic tests of the VM anywhere?

@frol
Copy link

frol commented Dec 4, 2023

@petersalomonsen I see it is moving in the right direction and we are close to completion. Please, review your PR yourself, see if you can re-use any parts from Social.set implementation, and mark it as ready for review

@petersalomonsen
Copy link
Contributor Author

Yes, the only thing I would like to see resolved before moving to ready for review is to remove deposit and set a lower gas amount in the devhub widgets as described here: NEAR-DevHub/neardevhub-bos#549

Then I will be able to remove the overriding of deposit / gas that I had to do for demo purposes as you can see here:
https://github.com/NearSocial/VM/pull/156/files#diff-cc75698545c1506b569386ec69e64f50d829fc759a7fb175b256b88630782859R177

I will also go over the code a few more times and look for reusing of existing code.

@petersalomonsen petersalomonsen force-pushed the feat/multiple-funciton-access-keys branch from ea1823f to ede36f7 Compare December 6, 2023 16:28
@petersalomonsen petersalomonsen marked this pull request as ready for review December 6, 2023 16:51
@evgenykuzyakov
Copy link
Contributor

Overall, it's the right direction. Not sure about 2 things:

  • the TransactionResultContext implementation
  • pending transactions

@frol
Copy link

frol commented Dec 21, 2023

@petersalomonsen Thanks for the thorough testing.

Sender does not support adding access keys in a transaction, and does not have a wallet url for near-api-js to redirect too, resulting in that the "Don't ask again" feature is not supported, and an error message is displayed instead.

Well, Sender has a different operation model and it breaks UX even for SocialDB interactions requiring explicit confirmation of every single transaction, so we cannot do anything here.

I've tested with Meteor wallet now, and since the wallet selector interfaces does not support signing into multiple contracts, and since Meteor wallet does not have a walletUrl, the requestSigninmethod of near-api-js will not work either.

This is unexpected given that MeteorWallet is a browser wallet.

Not sure how to have the requestSignin experience also for MeteorWallet without modifying the wallet selector. I could do another PR for the wallet selector later to add support for this.

I expected all the wallets (except Sender) to support the most standard login flow :-(

This rabbit hole is too deep. Please, create an issue on the Wallet Selector repo first and share it in the "NEAR Wallet Builder Group"

@frol
Copy link

frol commented Dec 21, 2023

@evgenykuzyakov I think this current state already brings reasonable improvements to UX even if with some UX glitches on some of the wallets, so I suggest finishing the review and merging it as it is now and improving iteratively.

@petersalomonsen
Copy link
Contributor Author

petersalomonsen commented Dec 22, 2023

@frol Thanks for the feedback

This rabbit hole is too deep. Please, create an issue on the Wallet Selector repo first and share it in the "NEAR Wallet Builder Group"

That is done now: near/wallet-selector#1045

@petersalomonsen
Copy link
Contributor Author

Just discussed with @Megha-Dev-19 that Near.call does not return anything today. This is already an issue with the wallets that does not redirect, but either open a separate window or extension for confirming the transaction. A widget does not have any way to know when a transaction is finished, or the result of it.

With this PR, the cache will be invalidated when the transaction is finished. This helps a lot, since it will trigger re-rendering. It would be even better though, if Near.call returned a promise with the result of the transaction.

Should I add a promise result to Near.call @evgenykuzyakov @frol ?

@Megha-Dev-19
Copy link

thanks @petersalomonsen for adding this, it helped me fixed other issues as well, now I can initiate an action after the user approves/reject the txn since the cache is invalidated.
@frol Would really appreciate if we can get this merged asap 🙏

@frol
Copy link

frol commented Dec 31, 2023

It would be even better though, if Near.call returned a promise with the result of the transaction.
Should I add a promise result to Near.call @evgenykuzyakov @frol ?

I think we should mimic Social.set behavior with the onCommit and onCancel callbacks as you suggested in #105. I would make it a separate PR.

@petersalomonsen
Copy link
Contributor Author

It would be even better though, if Near.call returned a promise with the result of the transaction.
Should I add a promise result to Near.call @evgenykuzyakov @frol ?

I think we should mimic Social.set behavior with the onCommit and onCancel callbacks as you suggested in #105. I would make it a separate PR.

Thanks for reminding me, I had completely forgotten that I wrote that. There is already a PR for that also.

Copy link

@frol frol left a comment

Choose a reason for hiding this comment

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

Looks good to me.

@evgenykuzyakov please, review once again

Copy link
Contributor

@evgenykuzyakov evgenykuzyakov left a comment

Choose a reason for hiding this comment

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

Looks good. Minor comments

src/lib/components/ConfirmTransactions.js Outdated Show resolved Hide resolved
src/lib/components/ConfirmTransactions.js Outdated Show resolved Hide resolved
src/lib/components/ConfirmTransactions.js Outdated Show resolved Hide resolved
Comment on lines +83 to +84
async function createWalletConnectionForContract(near, contractId) {
const keyStore = getKeyStoreForContract(contractId);
Copy link
Contributor

Choose a reason for hiding this comment

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

We should probably check somewhere that the contractId doesn't match social.near (for the current network) to avoid some random issues.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

Do we check for this in the ConfirmTransaction?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No. And I believe if call a function on social.near, you might be offered don't ask again. This could be solved by also adding this check to eligibleForDontAskAgain.

Do we want to not offer the don't ask again feature for calls to near.social?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, let's not give this option for social.near.

src/lib/components/Widget.js Outdated Show resolved Hide resolved
@petersalomonsen
Copy link
Contributor Author

In the latest commit, there's also a try/catch when sending the pending transaction, so that if the transaction fails, the page will still be loaded ( without this, the page would just be blank, and reloading would not help ).

@evgenykuzyakov
Copy link
Contributor

Please rebase to dev branch

@petersalomonsen petersalomonsen force-pushed the feat/multiple-funciton-access-keys branch from 39a70ed to 24d3521 Compare January 5, 2024 05:41
@petersalomonsen
Copy link
Contributor Author

Please rebase to dev branch

Rebased to upstream/dev, and also a quick re-test. Also updated preview environment with the latest rebased: https://psalomobos.near.page/devhub.near/widget/app?page=post&id=2688

@petersalomonsen petersalomonsen changed the base branch from master to dev January 5, 2024 05:44
@evgenykuzyakov
Copy link
Contributor

Let's remove don't ask again for social.near

when sending transactions, offer to not ask for confirmation later
for transactions calling the same contract and method
@petersalomonsen petersalomonsen force-pushed the feat/multiple-funciton-access-keys branch from 24d3521 to 895a294 Compare January 6, 2024 04:39
@petersalomonsen
Copy link
Contributor Author

Let's remove don't ask again for social.near

OK this is now implemented in the latest push, and can be tested here, where you see that calling social.near does not present the "Don't ask again" option, while calling another contract does.

image image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
6 participants