Skip to main content

Wallets

What Is a Wallet?​

A wallet is a cryptographic identity on a ULedger chain. It consists of:

  • A keypair (public key + private key) generated from BIP39 entropy.
  • An address derived as SHA256(lowercase(publicKey)): deterministic, not random.
  • A parent reference: the wallet that created this one (empty for root wallets).
  • An auth group map: role-based CRUD permission sets.
  • A capabilities list: fine-grained, scoped, expirable permissions.
  • A satellite wallets list: addresses of all direct child wallets.
  • An enabled flag: disabled wallets cannot sign or submit transactions.
  • A key type: the cryptographic algorithm (fixed at creation, must match the chain).

Wallets do not store funds in the traditional sense. They hold permissions, sign transactions, and serve as the identity anchor for all actions on the chain.


Wallet Data Structure​

UL_Wallet {
PublicKey string // Compressed hex public key
Address string // SHA256(lowercase(publicKey))
Parent string // Parent wallet address ("" = root)
Entity string // Primary entity affiliation backlink
Enabled bool
SatelliteWallets []string // Direct children
AuthGroups map[string]UL_AuthPermission // "admin" and "wallet" groups
Capabilities []Capability // Scoped permissions
KeyType string // secp256k1 | ed25519 | mldsa87 | bls12377
}

UL_AuthPermission {
Create bool
Read bool
Update bool
Delete bool
}

Wallet Key Types​

Key type is set at chain creation and applies to all wallets on that chain.

Key TypeAlgorithmNotes
secp256k1ECDSA on secp256k1 curveBitcoin/Ethereum compatible; widely supported.
ed25519EdDSA on Curve25519Faster verification; smaller signatures.
mldsa87ML-DSA-87 (CRYSTALS-Dilithium level 5)Post-quantum; recommended for long-term audit chains.
bls12377BLS on BLS12-377 curveSignature aggregation; specialized use cases.

Wallet private keys are generated from BIP39 mnemonic phrases (optionally passphrase-protected) and stored in .ukey files. The private key never leaves the SDK process; only signatures and public keys are transmitted to the network.


Wallet Hierarchy​

Wallets form a tree. Every wallet except root wallets has a Parent address pointing to the wallet that created it.

Root Wallet (Parent = "")
├── Child Wallet A (Parent = Root)
│ ├── Grandchild Wallet A1 (Parent = Child A)
│ └── Grandchild Wallet A2 (Parent = Child A)
└── Child Wallet B (Parent = Root)
└── Grandchild Wallet B1 (Parent = Child B)

Parent wallets record all direct children in their SatelliteWallets array. This allows a full subtree traversal starting from any wallet.

Hierarchy Rules​

  • A root wallet has Parent == "" and, before being linked to an entity, must not already have an entity affiliation.
  • A child wallet inherits no more permissions than its parent holds. Capability inheritance is enforced at creation: a child's capabilities must be a strict subset of the parent's.
  • Disabling a parent wallet via ALTER_WALLET cascades via BFS across all descendants; every satellite wallet is disabled atomically. This is the only subtree operation that is atomic.
  • Re-enabling a parent does not automatically re-enable children. Re-enabling must be done explicitly per wallet.

Auth Groups​

Every wallet carries two standard auth groups: admin and wallet.

admin Group​

Controls administrative access to the wallet itself and its entity. A wallet with full admin permissions (Create+Read+Update+Delete) can:

  • Alter the wallet's own settings.
  • Link the wallet to an entity as an admin-role member.
  • Create child wallets.

wallet Group​

Controls wallet creation and update capabilities within the wallet's authority scope.

Full admin example:
AuthGroups = {
"admin": { Create: true, Read: true, Update: true, Delete: true },
"wallet": { Create: true, Read: true, Update: true, Delete: true }
}

Read-only wallet:
AuthGroups = {
"admin": { Create: false, Read: true, Update: false, Delete: false },
"wallet": { Create: false, Read: true, Update: false, Delete: false }
}

Important: Auth groups control administrative permissions. Fine-grained action permissions (e.g., "invoke this contract") are handled by Capabilities, not auth groups. See Capabilities.


Wallet Lifecycle​

1. Generate​

# Generate wallets with secp256k1 keys
go run ./cmd/generate_wallets --type=secp256k1

# Generate wallets with an authority group assigned
go run ./cmd/generate_wallets --type=mldsa87 --auth=admin

Generates .ukey files in the ./wallets directory. Each file contains the keypair for one wallet.

2. Register​

go run ./cmd/register_wallets

Submits TX_CREATE_WALLET transactions for all wallets in ./wallets, on-boarding them to the blockchain. Until registered, a wallet address is not recognized by the chain.

3. Alter​

go run ./cmd/alter_wallets

Submits ALTER_WALLET transactions to update auth groups, attach capabilities, enable/disable, or modify the wallet's configuration.

4. Create Child Wallets​

A registered wallet with wallet.Create == true in its auth groups can create child wallets by submitting TX_CREATE_WALLET transactions that reference itself as parent.

5. Disable / Cascade​

# Via SDK: submit ALTER_WALLET with Enabled = false

Disabling a wallet submits ALTER_WALLET. The processor performs a BFS cascade, disabling all satellite wallets atomically. This is the emergency stop for an entire agent subtree.


A wallet has a single Entity field (its primary entity affiliation). This field is set only in specific circumstances:

When wallet.Entity is setTrigger
Root wallet creates entityThe creating wallet becomes the entity's owner
Admin-role wallet linked to entityAdmin-role link sets the backlink
Ownership transferredNew owner wallet's backlink is updated
Recovery executedRecovered wallet's backlink is updated

Member-role links do not set wallet.Entity. A wallet linked to an entity with a member role and specific permission bits has power within that entity, but its primary affiliation is not changed. This allows wallets to participate in multiple entities without conflating their primary home.


Wallet Files (.ukey Format)​

Wallet private keys are stored as .ukey files. The filename is the wallet's address (public key hash). Example:

./wallets-uis-mldsa/8e620db359101eb28bf9db4f08c2677349f7747d1c59528774f2193318b8c1c7.ukey

The SDK loads these files when signing transactions. Keep .ukey files secure; they contain the raw private key material.