On general blockchain cryptography
m/1852h/1815h/3h/0/0
”m/1852h/1815h/3h/0/1
”m/1852h/1815h/3h/0/2
”m/1852h/1815h/3h/0/3
”On Cardano
m/1852h/1815h/3h/0/0
” + stake:”m/1852h/1815h/3h/2/0
”m/1852h/1815h/3h/0/1
” + stake:”m/1852h/1815h/3h/2/0
”m/1852h/1815h/3h/0/2
” + stake:”m/1852h/1815h/3h/2/0
”m/1852h/1815h/3h/0/3
” + stake:”m/1852h/1815h/3h/2/0
”HD wallets standard also define automatic address-scanning and special change-output properties not implemented on GameChanger Wallet as Workspaces design principle is based on single address mode and derivation sequence recoverability, composability and auditability rather than dynamic and gap-based address balance discovery where some times you can loose track of your “locker IDs”, of your own addresses, even if they are still yours, producing typical balance miss-calculations.
GameChanger Wallet assumes no derivation standard by default, and it proposes at least 4 official derivation schemes, also supported by Ledger and Trezor hardware wallets, to cover different use cases and anonymity requirements. Thanks to Workspaces, it will adapt to user’s needs as far as possible, making it not only a general purpose personal wallet, but also a multisig and script based wallet with a common user interface for all use cases. The universal wallet for Cardano
Let’s explore how HD wallet addresses on Cardano are created by replicating their derivation scheme using workspaces.
Wiping your test wallet workspace settings to continue with a clean setup is suggested to avoid mixing views with previous artifacts.
We will create only the first 5 base addresses, using a the accountIndex 5. Use the same seed phrase on another Cardano HD wallet software with same account number and you will get the same group of addresses.
{
"type": "script",
"title": "HD wallet addresses",
"description": "Exploring different ways to build addresses",
"run": {
"usingWorkspaces": {
"type": "loadConfig",
"updateId": "addresses-exercise-3",
"layers": [
{
"type": "Workspace",
"items": [
{
"namePattern": "hd_addresses",
"titlePattern": "HD Addresses",
"descriptionPattern": "Hierarchical Deterministic wallet addresses"
}
]
},
{
"type": "Key",
"workspaceIds": [
"hd_addresses"
],
"namePattern": "key_{kind}_{accountIndex}_{addressIndex}",
"items": [
// one common stake key
{
"kind": "stake",
"accountIndex": 5,
"addressIndex": 0
},
// 5 sequential spend keys
{
"kind": "spend",
"accountIndex": 5,
"addressIndex": 0
},
{
"kind": "spend",
"accountIndex": 5,
"addressIndex": 1
},
{
"kind": "spend",
"accountIndex": 5,
"addressIndex": 2
},
{
"kind": "spend",
"accountIndex": 5,
"addressIndex": 3
},
{
"kind": "spend",
"accountIndex": 5,
"addressIndex": 4
}
]
},
// let's define the 5 addresses, linking to keys by name reference
// the pattern? a common shared stake key credential and different sequential spend credentials
{
"type": "Address",
"workspaceIds": [
"hd_addresses"
],
"namePattern": "hd_address_{index}",
"items": [
{
"spendPubKeyName": "key_spend_5_0",
"stakePubKeyName": "key_spend_5_0"
},
{
"spendPubKeyName": "key_spend_5_1",
"stakePubKeyName": "key_spend_5_0"
},
{
"spendPubKeyName": "key_spend_5_2",
"stakePubKeyName": "key_spend_5_0"
},
{
"spendPubKeyName": "key_spend_5_3",
"stakePubKeyName": "key_spend_5_0"
},
{
"spendPubKeyName": "key_spend_5_4",
"stakePubKeyName": "key_spend_5_0"
}
]
}
]
}
}
}
🔍 See also: loadConfig, script
On your wallet, on Workspaces page, the new HD Addresses workspace will look similarly to this one on my wallet:
When you select the HD Addresses workspace as current, your Address Picker will look similarly to mine:
In my wallet pov, these are my generated addresses:
Artifact Name | Address |
---|---|
hd_address_0 | addr_test1qrc8240y84ju9q5daxxranwxwzuyhrh4x992q2rw8f4nck8 sw427g0t9c2pgm6vv8mxuvu9cfw802v225q5xuwnt83vqv47tzj |
hd_address_1 | addr_test1qzr0nhmntgdyd8htrvprugrwtyjt28t7y8vgrgyf72t2wa8 sw427g0t9c2pgm6vv8mxuvu9cfw802v225q5xuwnt83vqyed5ls |
hd_address_2 | addr_test1qzsvsu0cs5lefeldpw8a0p340jq8hhnajtgsrpwu00exaf8 sw427g0t9c2pgm6vv8mxuvu9cfw802v225q5xuwnt83vqyt3sr0 |
hd_address_3 | addr_test1qz0ve7s4jhlkju4emza48veusreddsd34a34yglv97r5q2l sw427g0t9c2pgm6vv8mxuvu9cfw802v225q5xuwnt83vq5v5l5m |
hd_address_4 | addr_test1qraykreqllc8zvvv2euegz3kec3esuv7eec0cf0vahfzpvl sw427g0t9c2pgm6vv8mxuvu9cfw802v225q5xuwnt83vqvwzfdq |
</br>
Can you spot any similarities between them?
The sub-string sw427g0t9c2pgm6vv8mxuvu9cfw802v225q5xuwnt83vq
is common to all my addresses under this specific account number
</br>
One of the reasons why the workspace system was invented was to give back to Cardano users what Bitcoin users had in first place: anonymity or pseudo-anonymity on the public ledger.
Bitcoin HD standard was designed to derive new, different, receiving addresses in such a way that judging by transaction inputs and outputs (UTXO model) one cannot know what user received the outputs. This is because differently from banks, on blockchains we have a public ledger of all transactions, and all our financial information is exposed, so it is important to retain privacy rights.
Cardano introduced the concept of extended key roles, introducing the stake role for it’s Proof of Stake features in addition to the basic spend role. These ideas were great and gave us more freedom and many possible use cases out of the box comparing with Bitcoin limitations.
As seen before, Cardano HD wallets share a constant stake credential across all their base addresses, this makes them all share a same character sequence. By using a simple block explorer anyone in the world can track all your addresses, and thus your balances and financial information.
One of the key goals of the Bitcoin’s HD standard gets accidentally broken in practice on it’s Cardano implementation.
This is why Workspaces are so important to us, because users have for the first time on Cardano a wallet that adapts the official standard, even with Ledger and Trezor support, in order to give them back their anonymity on the ledger, and this implies other benefits like multi-delegation properties allowing users to delegate each address to a different stake pool if desired.
Let’s explore our official workspace design for Anonymous Personal Accounts with Multi-delegation features. I won’t be coding this example this time, I will fork the source code the wallet uses when creating these accounts through the user interface.
Remember all wallet actions on GameChanger Wallet are completely open, you can always view the underlying gcscript code on the dapp connector interface to audit, modify, learn and build upon it.
Through sidebar menu go to Discover -> Accounts. On Create Or Extend Account Wallets panel, let’s add 5 addresses on the Anonymous Multi Delegation option, which design pattern was designed in a way to also support Ledger and Trezor hardware wallets. Click on Apply button.
On the dapp connector interface, if you go to advanced->code tabs, you will see this script:
{
"title": "Load wallet settings",
"description": "Load this wallet settings on this device. Settings can be derived child keys, built child addresses and others, all these inside different wallet workspaces. Workspaces are virtual groups of artifacts that allow users to have a specialized wallet experience like multi-delegation, multisig, or transact more anonymously.",
"type": "script",
"exportAs": "data",
"isolateCache": true,
"run": {
"configuration": {
"type": "loadConfig",
"updateId": "AccountsEditor_2024-04-20T21:54:39.408-03:00",
"layers": [
{
"type": "Workspace",
"items": [
{
"namePattern": "gc_anonpoolsHW",
"titlePattern": "Anonymous Multi Delegation",
"descriptionPattern": "Different spend and stake credentials, each address can be delegated to a different stake pool. Anonymous because there is nothing in common between them (opposite to HD wallets). Don't combine with other workspaces to increase anonymity. Compatible with hardware wallets"
}
]
},
{
"type": "Key",
"items": [
{
"accountIndex": 0,
"addressIndex": 0,
"namePattern": "gc_spend_0_0",
"kind": "spend",
"workspaceIds": [
"gc_anonpoolsHW"
]
},
{
"accountIndex": 0,
"addressIndex": 0,
"namePattern": "gc_stake_0_0",
"kind": "stake",
"workspaceIds": [
"gc_anonpoolsHW"
]
},
{
"addressIndex": 0,
"namePattern": "gc_spend_1_0",
"kind": "spend",
"accountIndex": 1,
"workspaceIds": [
"gc_anonpoolsHW"
]
},
{
"addressIndex": 0,
"namePattern": "gc_stake_1_0",
"kind": "stake",
"accountIndex": 1,
"workspaceIds": [
"gc_anonpoolsHW"
]
},
{
"addressIndex": 0,
"namePattern": "gc_spend_2_0",
"kind": "spend",
"accountIndex": 2,
"workspaceIds": [
"gc_anonpoolsHW"
]
},
{
"addressIndex": 0,
"namePattern": "gc_stake_2_0",
"kind": "stake",
"accountIndex": 2,
"workspaceIds": [
"gc_anonpoolsHW"
]
},
{
"addressIndex": 0,
"namePattern": "gc_spend_3_0",
"kind": "spend",
"accountIndex": 3,
"workspaceIds": [
"gc_anonpoolsHW"
]
},
{
"addressIndex": 0,
"namePattern": "gc_stake_3_0",
"kind": "stake",
"accountIndex": 3,
"workspaceIds": [
"gc_anonpoolsHW"
]
},
{
"addressIndex": 0,
"namePattern": "gc_spend_4_0",
"kind": "spend",
"accountIndex": 4,
"workspaceIds": [
"gc_anonpoolsHW"
]
},
{
"addressIndex": 0,
"namePattern": "gc_stake_4_0",
"kind": "stake",
"accountIndex": 4,
"workspaceIds": [
"gc_anonpoolsHW"
]
}
]
},
{
"type": "Address",
"items": [
{
"namePattern": "gc_anonpoolsHW_0_0",
"spendPubKeyName": "gc_spend_0_0",
"stakePubKeyName": "gc_stake_0_0",
"workspaceIds": [
"gc_anonpoolsHW"
]
},
{
"namePattern": "gc_anonpoolsHW_1_0",
"spendPubKeyName": "gc_spend_1_0",
"stakePubKeyName": "gc_stake_1_0",
"workspaceIds": [
"gc_anonpoolsHW"
]
},
{
"namePattern": "gc_anonpoolsHW_2_0",
"spendPubKeyName": "gc_spend_2_0",
"stakePubKeyName": "gc_stake_2_0",
"workspaceIds": [
"gc_anonpoolsHW"
]
},
{
"namePattern": "gc_anonpoolsHW_3_0",
"spendPubKeyName": "gc_spend_3_0",
"stakePubKeyName": "gc_stake_3_0",
"workspaceIds": [
"gc_anonpoolsHW"
]
},
{
"namePattern": "gc_anonpoolsHW_4_0",
"spendPubKeyName": "gc_spend_4_0",
"stakePubKeyName": "gc_stake_4_0",
"workspaceIds": [
"gc_anonpoolsHW"
]
}
]
}
]
}
}
}
🔍 See also: loadConfig, script
Can you identify the design pattern?
If you run the script, and then select Anonymous Multi Delegation workspace as current, on Address Picker you will have a group of addresses like mine:
Artifact Name | Address |
---|---|
gc_anonpoolsHW_0_0 | addr_test1qqptd68g4yzkrtn38srqvkk78c3stkvw4wvvsqsmaanny7lmzswelsnc0337p4eyyd68cy5mrgv29tqnfqjnzn2fvzlqy429lh |
gc_anonpoolsHW_1_0 | addr_test1qza0telv9kxmpshkqurv3gccfgx9xae7vc8dq5p73lpgqesur3p8evzcmtfxvw834sluhzysssu03lkr3k7v38pehskqwj8a9q |
gc_anonpoolsHW_2_0 | addr_test1qz40gpawsf8n29x8xf2gqgmsf3z3f9cvq7lcckk55mvmvhk0wae5tm6l8ekkfmljm43xavxtjusrfu6lna0q7hyjqdgqluux9z |
gc_anonpoolsHW_3_0 | addr_test1qqlwqt5c2kry94njcz8867kzr67tv9p8zszc5s9sk72krnpdqp3qlapnz0ncn0l3l3w7g8x45jmz67egn42rvpv242xq5krf5g |
gc_anonpoolsHW_4_0 | addr_test1qp0yq09rxfv70jkd37d598ckcpnaqk27dc3gvslk99cycxz92lphp6gzqlqaxakw4nd8hgjch4mcls4vlj7qm3n55cuslg0nmw |
</br>
Can you spot now any similarities between them?
If I’m careful with my transactions, with my on-chain footprint, would you be able to find my financial persona? any relationship between them querying the Cardano ledger?
</br>
For security reasons, users need means to identify and control which artifacts where generated using the official workspaces, and which ones where created by dapps, themselves, or other agents.
System Artifacts: are workspaces and named artifacts with names starting with the gc_
prefix. To create or update them you need a dapp connection call with system privileges. Only GameChanger Wallet user interface and Playground IDE can trigger dapp connections with these permissions.
End users can differentiate system from user-defined, or dapp-defined workspaces by checking the circle with the check mark on Workspace Picker.
The Default workspace is a special system workspace, the default one, one that is hardcoded on wallet’s code.
Previous: Addresses | Next: Multisig Wallets |