Create Affinidi Wallet Demo#
What wallet actually is ?#
Name wallet create a lot of confusion. In real life you keep your kredit cards, money, identity cards in a wallet. Any crypto wallet have one and only one function that really matter - it is manage and give access to your private and public keys.
Wallet is more
key manager - manage access to a keys
signer - sign VCs , transactions, JWTs with your private key
Majority of crypto Wallets show a state of your account and etc. Affinity Wallet is more focused on VCs
Follow a video#
Create a wallet on edge#
get your API key production or register affinidi account on register
set env to prod
const { createWallet } = require('@affinidi/wallet-node-sdk')
import { EventComponent } from '@affinidi/wallet-core-sdk'
const walletFactory = createWallet(EventComponent.AffinidiCore)
const accessApiKey = '<your key>'
const options = {
env: 'prod',
accessApiKey: accessApiKey
}
All you need on edge is a password
const password = 'P@55w0rd!!'
Now we could generate you a wallet
const sdk = await walletFactory.createWallet(options, password)
const seed = sdk.encryptedSeed
const did = sdk.did
did
did:elem:EiBa0KyUWgvMdkt_ywullSPac2kyOkRP5JRtHSeICQ1t6Q;elem:initial-state=eyJwcm90ZWN0ZWQiOiJleUp2Y0dWeVlYUnBiMjRpT2lKamNtVmhkR1VpTENKcmFXUWlPaUlqY0hKcGJXRnllU0lzSW1Gc1p5STZJa1ZUTWpVMlN5SjkiLCJwYXlsb2FkIjoiZXlKQVkyOXVkR1Y0ZENJNkltaDBkSEJ6T2k4dmR6TnBaQzV2Y21jdmMyVmpkWEpwZEhrdmRqSWlMQ0p3ZFdKc2FXTkxaWGtpT2x0N0ltbGtJam9pSTNCeWFXMWhjbmtpTENKMWMyRm5aU0k2SW5OcFoyNXBibWNpTENKMGVYQmxJam9pVTJWamNESTFObXN4Vm1WeWFXWnBZMkYwYVc5dVMyVjVNakF4T0NJc0luQjFZbXhwWTB0bGVVaGxlQ0k2SWpBeU1tTmhOak5tWm1aaVpEaGlObVJrTjJVMU5HWmhPRGhpTnpaa05USTBOVGN3TUdGak9ERTJOVGRtWkRVNVlUQXpZamN6WlRRek1qVmlZVEZsTVRsaVlTSjlMSHNpYVdRaU9pSWpjbVZqYjNabGNua2lMQ0oxYzJGblpTSTZJbkpsWTI5MlpYSjVJaXdpZEhsd1pTSTZJbE5sWTNBeU5UWnJNVlpsY21sbWFXTmhkR2x2Ymt0bGVUSXdNVGdpTENKd2RXSnNhV05MWlhsSVpYZ2lPaUl3TXprd1pEWTNZbVppWm1NNE1HUXdNR1ZrWXpjd09EQmhOR001TVdZeFl6ZzBOREl3T0daaFltUXdNMlV4TlRoaE5Ua3hNR1kxWkRFMk1ERmxOamxsWWpVaWZWMHNJbUYxZEdobGJuUnBZMkYwYVc5dUlqcGJJaU53Y21sdFlYSjVJbDBzSW1GemMyVnlkR2x2YmsxbGRHaHZaQ0k2V3lJamNISnBiV0Z5ZVNKZGZRIiwic2lnbmF0dXJlIjoiTkJqblFlQVRuTXVJQUFrZTlEcFhDeXAzcmJzcnBsQWFRQ1A0ZEl2b3NfNVJZRnJTc2VDdnBSY3k1XzFOMUpObzB2WEpDdWVVVmZvaHJtNHROenM2cmcifQ
Wallet Internals#
Whats actually happens Our Wallet is clasical hierarchical deterministic wallet based on BIP-32 standard. It is mean that based on seed (32 bit random entropy) we generate all private , public keys and derived addresses etc.
All you need is seed. We never expose a seed or private keys ouside of wallet.
We use a user pasword to encrypt a seed. As a result user get encrypted seed and password that allow to create an instance of wallet any time All you need is securely store this pair and do not share it on public internet
Show code cell source
const plantumlEncoder = require('plantuml-encoder')
const tslab = require("tslab");
const diagram = plantumlEncoder.encode(`
@startuml
digraph G {
graph [rankdir = LR, splines=ortho];
node[shape=record];
User[label="User", height=4];
User2[label="User", height=4];
subgraph SDK {
graph [rankdir = LR, splines=ortho];
node[shape=record];
label = "SDK";
random[label="random", height=1];
encrypt[label="encrypt", height=2];
seedGenerator[label="seed Generator", height=1];
bip32[label="bip32", height=2];
didDocGenerator[label="DidDoc Generator", height=1];
registry[label="Registry", height=1];
}
random -> seedGenerator [label="32 bit"]
User -> seedGenerator [label="meta data"]
seedGenerator -> encrypt [label="seed"]
User -> encrypt [label="password"]
encrypt -> User2 [label="encrypted seed"]
User -> bip32 [label="meta data"]
seedGenerator -> bip32 [label="seed"]
bip32 -> didDocGenerator [label="public keys"]
bip32 -> didDocGenerator [label="private keys"]
bip32 -> registry [label="private keys"]
didDocGenerator -> registry [label="document"]
registry -> User2 [label="did"]
}
@enduml`)
const urldiagram = 'http://www.plantuml.com/plantuml/svg/' + diagram
tslab.display.html(`<img src="${urldiagram}"/>`)
Unlock wallet with seed and password#
Now you could unlock your wallet with seed and password
const sdk = await walletFactory.openWalletByEncryptedSeed(options, seed , password)
sdk.did === did
true
DID magic . lets resolve it#
Dids follow a URI schema and could be parsed Every did have a
schema . always equal to did
method
identifier Some did methods like element could have a initial parameters
const didParser = require('did-uri')
const parsedDid = didParser.parse(did)
parsedDid
{
reference: 'did:elem:EiBa0KyUWgvMdkt_ywullSPac2kyOkRP5JRtHSeICQ1t6Q;elem:initial-state=eyJwcm90ZWN0ZWQiOiJleUp2Y0dWeVlYUnBiMjRpT2lKamNtVmhkR1VpTENKcmFXUWlPaUlqY0hKcGJXRnllU0lzSW1Gc1p5STZJa1ZUTWpVMlN5SjkiLCJwYXlsb2FkIjoiZXlKQVkyOXVkR1Y0ZENJNkltaDBkSEJ6T2k4dmR6TnBaQzV2Y21jdmMyVmpkWEpwZEhrdmRqSWlMQ0p3ZFdKc2FXTkxaWGtpT2x0N0ltbGtJam9pSTNCeWFXMWhjbmtpTENKMWMyRm5aU0k2SW5OcFoyNXBibWNpTENKMGVYQmxJam9pVTJWamNESTFObXN4Vm1WeWFXWnBZMkYwYVc5dVMyVjVNakF4T0NJc0luQjFZbXhwWTB0bGVVaGxlQ0k2SWpBeU1tTmhOak5tWm1aaVpEaGlObVJrTjJVMU5HWmhPRGhpTnpaa05USTBOVGN3TUdGak9ERTJOVGRtWkRVNVlUQXpZamN6WlRRek1qVmlZVEZsTVRsaVlTSjlMSHNpYVdRaU9pSWpjbVZqYjNabGNua2lMQ0oxYzJGblpTSTZJbkpsWTI5MlpYSjVJaXdpZEhsd1pTSTZJbE5sWTNBeU5UWnJNVlpsY21sbWFXTmhkR2x2Ymt0bGVUSXdNVGdpTENKd2RXSnNhV05MWlhsSVpYZ2lPaUl3TXprd1pEWTNZbVppWm1NNE1HUXdNR1ZrWXpjd09EQmhOR001TVdZeFl6ZzBOREl3T0daaFltUXdNMlV4TlRoaE5Ua3hNR1kxWkRFMk1ERmxOamxsWWpVaWZWMHNJbUYxZEdobGJuUnBZMkYwYVc5dUlqcGJJaU53Y21sdFlYSjVJbDBzSW1GemMyVnlkR2x2YmsxbGRHaHZaQ0k2V3lJamNISnBiV0Z5ZVNKZGZRIiwic2lnbmF0dXJlIjoiTkJqblFlQVRuTXVJQUFrZTlEcFhDeXAzcmJzcnBsQWFRQ1A0ZEl2b3NfNVJZRnJTc2VDdnBSY3k1XzFOMUpObzB2WEpDdWVVVmZvaHJtNHROenM2cmcifQ',
did: 'did:elem:EiBa0KyUWgvMdkt_ywullSPac2kyOkRP5JRtHSeICQ1t6Q',
method: 'elem',
identifier: 'EiBa0KyUWgvMdkt_ywullSPac2kyOkRP5JRtHSeICQ1t6Q',
path: '',
fragment: '',
query: '',
param: ';elem:initial-state=eyJwcm90ZWN0ZWQiOiJleUp2Y0dWeVlYUnBiMjRpT2lKamNtVmhkR1VpTENKcmFXUWlPaUlqY0hKcGJXRnllU0lzSW1Gc1p5STZJa1ZUTWpVMlN5SjkiLCJwYXlsb2FkIjoiZXlKQVkyOXVkR1Y0ZENJNkltaDBkSEJ6T2k4dmR6TnBaQzV2Y21jdmMyVmpkWEpwZEhrdmRqSWlMQ0p3ZFdKc2FXTkxaWGtpT2x0N0ltbGtJam9pSTNCeWFXMWhjbmtpTENKMWMyRm5aU0k2SW5OcFoyNXBibWNpTENKMGVYQmxJam9pVTJWamNESTFObXN4Vm1WeWFXWnBZMkYwYVc5dVMyVjVNakF4T0NJc0luQjFZbXhwWTB0bGVVaGxlQ0k2SWpBeU1tTmhOak5tWm1aaVpEaGlObVJrTjJVMU5HWmhPRGhpTnpaa05USTBOVGN3TUdGak9ERTJOVGRtWkRVNVlUQXpZamN6WlRRek1qVmlZVEZsTVRsaVlTSjlMSHNpYVdRaU9pSWpjbVZqYjNabGNua2lMQ0oxYzJGblpTSTZJbkpsWTI5MlpYSjVJaXdpZEhsd1pTSTZJbE5sWTNBeU5UWnJNVlpsY21sbWFXTmhkR2x2Ymt0bGVUSXdNVGdpTENKd2RXSnNhV05MWlhsSVpYZ2lPaUl3TXprd1pEWTNZbVppWm1NNE1HUXdNR1ZrWXpjd09EQmhOR001TVdZeFl6ZzBOREl3T0daaFltUXdNMlV4TlRoaE5Ua3hNR1kxWkRFMk1ERmxOamxsWWpVaWZWMHNJbUYxZEdobGJuUnBZMkYwYVc5dUlqcGJJaU53Y21sdFlYSjVJbDBzSW1GemMyVnlkR2x2YmsxbGRHaHZaQ0k2V3lJamNISnBiV0Z5ZVNKZGZRIiwic2lnbmF0dXJlIjoiTkJqblFlQVRuTXVJQUFrZTlEcFhDeXAzcmJzcnBsQWFRQ1A0ZEl2b3NfNVJZRnJTc2VDdnBSY3k1XzFOMUpObzB2WEpDdWVVVmZvaHJtNHROenM2cmcifQ'
}
Key operation for every did is a resolution of a diddocument Our affinidi-registry service do this job quite well
const didDoc = await sdk.resolveDid(sdk.did)
JSON.stringify(didDoc, null , 2)
{
"@context": "https://w3id.org/security/v2",
"publicKey": [
{
"id": "did:elem:EiBa0KyUWgvMdkt_ywullSPac2kyOkRP5JRtHSeICQ1t6Q#primary",
"usage": "signing",
"type": "Secp256k1VerificationKey2018",
"publicKeyHex": "022ca63fffbd8b6dd7e54fa88b76d5245700ac81657fd59a03b73e4325ba1e19ba"
},
{
"id": "did:elem:EiBa0KyUWgvMdkt_ywullSPac2kyOkRP5JRtHSeICQ1t6Q#recovery",
"usage": "recovery",
"type": "Secp256k1VerificationKey2018",
"publicKeyHex": "0390d67bfbfc80d00edc7080a4c91f1c844208fabd03e158a5910f5d1601e69eb5"
}
],
"authentication": [
"did:elem:EiBa0KyUWgvMdkt_ywullSPac2kyOkRP5JRtHSeICQ1t6Q#primary"
],
"assertionMethod": [
"did:elem:EiBa0KyUWgvMdkt_ywullSPac2kyOkRP5JRtHSeICQ1t6Q#primary"
],
"id": "did:elem:EiBa0KyUWgvMdkt_ywullSPac2kyOkRP5JRtHSeICQ1t6Q"
}
unknown msg_type: comm_open
unknown msg_type: comm_msg
unknown msg_type: comm_open
unknown msg_type: comm_msg
unknown msg_type: comm_open
unknown msg_type: comm_msg
unknown msg_type: comm_open
unknown msg_type: comm_msg
As you can see we have two public keys as a part of document
signing used for sign operations
recovery could be used for key rotation and did document operations