Easier Superhero Wallet Integration in JS

Hello everybody,

in an effort to improve developer experience, we need to improve the integration of (AEX2) Web Wallets like the Superhero Wallet.

long story short, going with the example from the docs I propose we go for something like this

import Ae from '@aeternity/aepp-sdk/es/ae/universal' // or other flavor
import Node from '@aeternity/aepp-sdk/es/node' // or other flavor
import { AE_AMOUNT_FORMATS } from '@aeternity/aepp-sdk/es/utils/amount-formatter'

// New: 
import {AEX2wallet as webwallet} from '@aeternity/foobar/whatever'

const NODE_URL = 'https://testnet.aeternity.io'
const COMPILER_URL = 'COMPILER_URL' // required for using Contract

//old:
const ACCOUNT = MemoryAccount({ keypair: { secretKey: 'A_PRIV_KEY', publicKey: 'A_PUB_ADDRESS' } })

//optional new for web: 
const ACCOUNT = webwallet()

(async function () {
  const nodeInstance = await Node({ url: NODE_URL })
  const sdkInstance = await Ae({
     compilerUrl: COMPILER_URL,
     nodes: [ { name: 'test-net', instance: nodeInstance } ],
// note: allow this to remain an array if possible to prevent errors from people adjusting the existing example for noeJS
     accounts: [ ACCOUNT ]
  })

})()

Edit:

1.What I forgot about is: There must be some callback for the fact that the user rejected the browser wallet connection. Or do we treat it like a “no wallet installed” case ?

  1. If any of the two cases above are true, the SDK shall be set up in a state in which it is not able to do any TX, but perform calls like balance checks and dry-runs (with the default account). Is that even possible right now @davidyuk or do some stamp things require accounts to be always present or so ?
2 Likes

Is this “new”:

import {AEX2wallet as webwallet} from '@aeternity/foobar/whatever'

//optional new for web: 
const ACCOUNT = webwallet()

and this old?


const NODE_URL = 'https://testnet.aeternity.io'
const COMPILER_URL = 'COMPILER_URL' // required for using Contract

const ACCOUNT = MemoryAccount({ keypair: { secretKey: 'A_PRIV_KEY', publicKey: 'A_PUB_ADDRESS' } })

(async function () {
  const nodeInstance = await Node({ url: NODE_URL })
  const sdkInstance = await Ae({
     compilerUrl: COMPILER_URL,
     nodes: [ { name: 'test-net', instance: nodeInstance } ],
// note: allow this to remain an array if possible to prevent errors from people adjusting the existing example for noeJS
     accounts: [ ACCOUNT ]
  })

})()

if not, could you please state two separate examples for how you imagine it?

The “old” variation works if you have the private / public key already, which is not the case. For AEX2 you need a lot more code , see: https://github.com/aeternity/aepp-sdk-js/blob/develop/examples/browser/vuejs/connect-two-ae/aepp/src/components/Home.vue#L330. There are some optional things in there but generally this is what you need to do for AEX2.

In general I agree with the fact, that it should be less boilerplaty and easier to use.

4 Likes

Exactly. I think putting a function where the MemoryAccountsused to reside would be the most elegant solution from a developer perspective, with a way to pass some settings like:

const ACCOUNT = webwallet({stuff: things})

Which optional things were you referring to ?

But if you have a MemoryAccount you don’t need a wallet, it is your wallet, so you are comparing apples to pears.

Regarding the optional things I am referring to this: https://github.com/aeternity/aepp-sdk-js/blob/develop/examples/browser/vuejs/connect-two-ae/aepp/src/components/Home.vue#L330

In frontend-apps, you are not supposed to have memory accounts.

My suggestion to put the “wallet initializer” function to

//optional new for web: 
const ACCOUNT = webwallet()

originates from the thought to tell developers “Hey, no keys go here! Use the web wallet.”, it just would be intuitive to put it there. And as the wallet does not and cannot take any extra information about which node or compiler to talk to (right?), it should be no problem to just fire that function in that place.

I would also like to see an improved flow to setup a wallet connection from an app.
Currently, there is a lot of boilerplate a developer as to use to make it work.

Form my perspective there are two things:

  • We need to keep the existing implementation for developers that want to control the complete flow
  • We need a simple implementation for developer that just use the existing magic

I’m thinking of a function like this:

const wallet = await ConnectedWallet({nodeUrl, internalNodeUrl, confirmation: () => {...}})

The confirmation function should return true in case the wallet should be connected or false in case not. It will reduce the boilerplate code (see https://github.com/aeternity/aepp-sdk-js/blob/develop/examples/browser/vuejs/connect-two-ae/aepp/src/components/Home.vue#L330 ) and improve developer experience (expecially) newcomers.

Furthermore, I agree with @keno.chain that there is a difference between the MemoryAccount and the wallet connected. Let’s use this thread to discuss wallet integration instead of MemoryAccount.
What do you think? @keno.chain @nikitafuchs.chain @davidyuk

3 Likes

Ditch the MemoryWallets itself from all this guys, it’s the place where they were used to be put which is just logically related the most to what’s tried to be done here. You basically tell devs not to hard code keys to have accounts, but “take them from the extension”.

The callbacks are a good thing and could be provided inside here:
const ACCOUNT = webwallet(confirmation: () => {...}})

the good thing about this is that people won’t have to change much about their code, a simple injection of a few more lines and that’s it.

One thing I’m still wondering about on the side though: What is it that you all mean with “leaving things” to be done manually ? Of course we can’t leave nothing to the dAepp-developer to tell the browser wallet. Neither which node URL to use, nor which compiler, nor which network. Just as all this isn’t possible right now, right ?

There are 2 things:

  1. The MemoryAccount: I think there are still valid cases for the MemoryAccount. You only think in terms of a Frontend developer who‘s code lives in a browser. There you don‘t want that keypairs will be entered and use the browser extensions instead. However, the SDK is also used by nodejs backend developers. There might be cases were it still make sense to have a MemoryAccount.

  2. What I mean with „leave things manual“ is related to the AEX2 setup where there is currently a lot of boilerplate. I would like to create a function as part of the SDK which does all the boilerplate and results on only one function call. But to keep it compatible with existing implementations we can’t remove the stuff that is already there. Additionally, there might be cases we miss were developers still want to setup all the AEX2 stuff manually.

One question: when you say „webwallet“ is it still a AEX2 connection to something like a Browser Extension?

Guess I phrased my wording wrong. Memory accounts are all fine in the backend.
Yes, I’m using the term web-wallet synonymously to what metamask does in the Ethereum space.

AEX2 has everything in place that’s necessary to make this a one-liner, saying “Start talking with the browser add-on and call these functions upon certain events regarding the communication with that wallet” - that’s it.

The only thing this has to do with memory accounts is that I suggested placing this code-wise right where we used to define only memory accounts previously, because that spot is logically closely related and requires devs to change and learn next to nothing.

1 Like

“AEX-2” implementation in SDK is overcomplicated, I’m planning to improve it in a near future.

4 Likes