183 lines
4.5 KiB
Markdown
183 lines
4.5 KiB
Markdown
<!-- file: kb-wallet/USAGE.md -->
|
||
<!-- version: 1 -->
|
||
|
||
# Utilisation de kb-wallet
|
||
|
||
## Objectif
|
||
|
||
La crate fournit des wallets temporaires en mémoire ou persistés localement pour les démonstrations et tests d’intégration.
|
||
|
||
## Valider un alias
|
||
|
||
```rust
|
||
let alias = match kb_wallet::WalletAlias::parse(
|
||
"devnet-operator",
|
||
) {
|
||
std::result::Result::Ok(value) => value,
|
||
std::result::Result::Err(error) => {
|
||
return std::result::Result::Err(error);
|
||
},
|
||
};
|
||
|
||
assert_eq!(alias.as_str(), "devnet-operator");
|
||
```
|
||
|
||
Un alias doit contenir entre 1 et 64 octets, commencer par un caractère alphanumérique ASCII et ne contenir ensuite que des caractères alphanumériques, `_` ou `-`.
|
||
|
||
## Générer un wallet en mémoire
|
||
|
||
```rust
|
||
let alias = match kb_wallet::WalletAlias::parse(
|
||
"ephemeral",
|
||
) {
|
||
std::result::Result::Ok(value) => value,
|
||
std::result::Result::Err(error) => {
|
||
return std::result::Result::Err(error);
|
||
},
|
||
};
|
||
|
||
let wallet =
|
||
kb_wallet::TemporaryWallet::generate(alias);
|
||
let summary = wallet.summary();
|
||
|
||
assert!(summary.storage_path.is_none());
|
||
println!("public key={}", summary.public_key);
|
||
```
|
||
|
||
## Signer un message
|
||
|
||
```rust
|
||
let signature = match wallet.sign_message(
|
||
b"khadhroony demo authorization",
|
||
) {
|
||
std::result::Result::Ok(value) => value,
|
||
std::result::Result::Err(error) => {
|
||
return std::result::Result::Err(error);
|
||
},
|
||
};
|
||
|
||
println!("signature={signature}");
|
||
```
|
||
|
||
`as_signer()` retourne une référence au trait Solana `Signer` sans exposer les octets du keypair.
|
||
|
||
## Créer un stockage local
|
||
|
||
```rust
|
||
let store = match kb_wallet::TemporaryWalletStore::new(
|
||
"./data/wallets",
|
||
) {
|
||
std::result::Result::Ok(value) => value,
|
||
std::result::Result::Err(error) => {
|
||
return std::result::Result::Err(error);
|
||
},
|
||
};
|
||
|
||
println!(
|
||
"wallet directory={}",
|
||
store.directory().display()
|
||
);
|
||
```
|
||
|
||
## Créer un wallet persistant
|
||
|
||
```rust
|
||
let alias = match kb_wallet::WalletAlias::parse(
|
||
"devnet-payer",
|
||
) {
|
||
std::result::Result::Ok(value) => value,
|
||
std::result::Result::Err(error) => {
|
||
return std::result::Result::Err(error);
|
||
},
|
||
};
|
||
|
||
let wallet = match store.create(alias).await {
|
||
std::result::Result::Ok(value) => value,
|
||
std::result::Result::Err(error) => {
|
||
return std::result::Result::Err(error);
|
||
},
|
||
};
|
||
|
||
let summary = wallet.summary();
|
||
assert!(summary.storage_path.is_some());
|
||
```
|
||
|
||
`create` refuse d’écraser un fichier existant.
|
||
|
||
## Charger ou créer atomiquement
|
||
|
||
```rust
|
||
let alias = match kb_wallet::WalletAlias::parse(
|
||
"shared-devnet",
|
||
) {
|
||
std::result::Result::Ok(value) => value,
|
||
std::result::Result::Err(error) => {
|
||
return std::result::Result::Err(error);
|
||
},
|
||
};
|
||
|
||
let wallet = match store.load_or_create(alias).await {
|
||
std::result::Result::Ok(value) => value,
|
||
std::result::Result::Err(error) => {
|
||
return std::result::Result::Err(error);
|
||
},
|
||
};
|
||
|
||
println!("wallet={}", wallet.public_key());
|
||
```
|
||
|
||
## Vérifier l’existence et le chemin
|
||
|
||
```rust
|
||
let path = store.wallet_path(&alias);
|
||
let exists = match store.exists(&alias).await {
|
||
std::result::Result::Ok(value) => value,
|
||
std::result::Result::Err(error) => {
|
||
return std::result::Result::Err(error);
|
||
},
|
||
};
|
||
|
||
println!("path={}, exists={exists}", path.display());
|
||
```
|
||
|
||
## Politique non secrète
|
||
|
||
```rust
|
||
let policy = kb_wallet::WalletPolicy {
|
||
signing_enabled: true,
|
||
lamport_spend_limit: std::option::Option::Some(
|
||
1_000_000,
|
||
),
|
||
};
|
||
|
||
assert!(policy.signing_enabled);
|
||
```
|
||
|
||
`WalletPolicy` transporte une intention de politique. Son application effective appartient à la couche d’exécution.
|
||
|
||
## Erreurs et invariants
|
||
|
||
- les octets secrets ne sont jamais exposés par l’API publique ;
|
||
- les résumés ne contiennent que l’alias, la clé publique et le chemin ;
|
||
- un fichier existant n’est pas écrasé ;
|
||
- les liens symboliques et fichiers non réguliers sont refusés ;
|
||
- sur Unix, les permissions privées sont vérifiées ;
|
||
- les buffers secrets temporaires sont effacés ;
|
||
- cette crate ne décide pas si une transaction est autorisée.
|
||
|
||
## Tests de référence
|
||
|
||
- validation des alias ;
|
||
- génération et signature sans persistance ;
|
||
- création, chargement et `load_or_create` ;
|
||
- refus d’écrasement ;
|
||
- rejet des keypairs corrompus ;
|
||
- vérification des permissions Unix privées ;
|
||
- rejet des liens symboliques et permissions trop ouvertes.
|
||
|
||
## Limites durables
|
||
|
||
- le format persistant actuel est le tableau JSON standard du keypair Solana ;
|
||
- la crate ne signe pas automatiquement une transaction ;
|
||
- elle ne transmet aucun secret à une interface frontend.
|