Skip to content

Commit

Permalink
feat: 💥 Add param to newKeychainTransaction method to allow many se…
Browse files Browse the repository at this point in the history
…rvices
  • Loading branch information
redDwarf03 committed Dec 23, 2024
1 parent f78d1a8 commit acd5642
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 10 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 7.0.0-beta

- BREAKING CHANGES: Add param to `newKeychainTransaction` method to allow many services instead of only one

# 6.0.0-beta

- fix: :technologist: Fix default transaction confirmation ratio to 0.5.
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,13 @@ It supports the Archethic Cryptography rules which are:
- `seed` Keychain's seed
- `authorizedPublicKeys` List of authorized public keys able to decrypt the wallet
- `originPrivateKey` Key to make the origin signature of the transaction
- `blockchainTxVersion` The blockchain transaction version to be used.
- `servicesMap` (Optional) A map where:
- Keys are service names (as `String`),
- Values are derivation paths (as `String`) associated with the respective services.

If provided, the keychain will include these services with their respective derivation paths.


#### newAccessKeychainTransaction(String seed, Uint8List keychainAddress, Uint8List originPrivateKey)
Creates a new keychain access transaction to allow a seed and its key to access a keychain
Expand Down
16 changes: 11 additions & 5 deletions lib/src/services/api_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -560,18 +560,24 @@ class ApiService with JsonRPCUtil {
/// - [seed] : Keychain's seed
/// - [authorizedPublicKeys] : Authorized public keys able to decrypt the keychain
/// - [originPrivateKey] : Origin private key to attest the transaction
/// - [derivationPath] : derivation path associated to service name
/// - [blockchainTxVersion]: The blockchain transaction version to be used.
/// - [servicesMap]: (Optional) A map where:
/// - Keys are service names (as `String`),
/// - Values are derivation paths (as `String`) associated with the respective services.
/// If provided, the keychain will include these services with their respective derivation paths.
///
Transaction newKeychainTransaction(
String seed,
List<String> authorizedPublicKeys,
Uint8List originPrivateKey,
int blockchainTxVersion, {
String? serviceName,
String? derivationPath,
Map<String, String>? servicesMap,
}) {
var keychain = Keychain(seed: hexToUint8List(seed));
if (serviceName!.isNotEmpty && derivationPath!.isNotEmpty) {
keychain = keychain.copyWithService(serviceName, derivationPath);
if (servicesMap!.isNotEmpty) {
servicesMap.forEach((serviceName, derivationPath) {
keychain = keychain.copyWithService(serviceName, derivationPath);
});
}

final aesKey = uint8ListToHex(
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: archethic_lib_dart
description: Archethic dart library for Flutter for Node and Browser. This library aims to provide a easy way to create Archethic transaction and to send them over the network
homepage: https://github.com/archethic-foundation/libdart

version: 6.0.0-beta
version: 7.0.0-beta

environment:
sdk: ">=3.5.3 <4.0.0"
Expand Down
99 changes: 95 additions & 4 deletions test/keychain_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,7 @@ void main() {
],
Uint8List.fromList(hexToUint8List(originPrivateKey)),
blockchainTxVersion,
serviceName: kServiceName,
derivationPath: kDerivationPath,
servicesMap: {kServiceName: kDerivationPath},
);
dev.log(
'keychainTransaction: ${keychainTransaction.toNodeRPC()}',
Expand Down Expand Up @@ -337,8 +336,7 @@ void main() {
],
Uint8List.fromList(hexToUint8List(originPrivateKey)),
blockchainTxVersion,
serviceName: kServiceName,
derivationPath: kDerivationPath,
servicesMap: {kServiceName: kDerivationPath},
);
dev.log(
'keychainTransaction: ${keychainTransaction.toNodeRPC()}',
Expand Down Expand Up @@ -374,6 +372,99 @@ void main() {
},
);

test(
'should create a keychain with many services',
tags: <String>[TestTags.integration],
() async {
final walletSeed = generateRandomSeed();
const endpoint = 'https://testnet.archethic.net';
final apiService = ApiService(endpoint);
final walletKeyPair = crypto.deriveKeyPair(walletSeed, 0);

/// Generate keyChain Seed from random value
final keychainSeed = uint8ListToHex(
Uint8List.fromList(
List<int>.generate(32, (int i) => Random.secure().nextInt(256)),
),
);
dev.log('keychainSeed: $keychainSeed');

/// Many services for wallet
const kServiceName1 = 'main-uco-1';
const kDerivationPathWithoutIndex1 = "m/650'/$kServiceName1/";
const index = '0';
const kDerivationPath1 = '$kDerivationPathWithoutIndex1$index';
dev.log('kDerivationPath1: $kDerivationPath1');

const kServiceName2 = 'main-uco-2';
const kDerivationPathWithoutIndex2 = "m/650'/$kServiceName2/";
const kDerivationPath2 = '$kDerivationPathWithoutIndex2$index';
dev.log('kDerivationPath2: $kDerivationPath2');

const kServiceName3 = 'main-uco-3';
const kDerivationPathWithoutIndex3 = "m/650'/$kServiceName3/";
const kDerivationPath3 = '$kDerivationPathWithoutIndex3$index';
dev.log('kDerivationPath3: $kDerivationPath3');

final originPrivateKey = apiService.getOriginKey();
dev.log('originPrivateKey: $originPrivateKey');

final blockchainTxVersion = int.parse(
(await apiService.getBlockchainVersion()).version.transaction,
);

/// Create Keychain from keyChain seed and wallet public key to encrypt secret
final keychainTransaction = apiService.newKeychainTransaction(
keychainSeed,
<String>[
uint8ListToHex(
Uint8List.fromList(walletKeyPair.publicKey!),
),
],
Uint8List.fromList(hexToUint8List(originPrivateKey)),
blockchainTxVersion,
servicesMap: {
kServiceName1: kDerivationPath1,
kServiceName2: kDerivationPath2,
kServiceName3: kDerivationPath3,
},
);
dev.log(
'keychainTransaction: ${keychainTransaction.toNodeRPC()}',
);

/// Create Keychain Access for wallet
final accessKeychainTx = apiService.newAccessKeychainTransaction(
walletSeed,
Uint8List.fromList(
hexToUint8List(keychainTransaction.address!.address!),
),
Uint8List.fromList(hexToUint8List(originPrivateKey)),
blockchainTxVersion,
);
dev.log('accessKeychainTx: ${accessKeychainTx.toNodeRPC()}');

await ArchethicTransactionSender(
apiService: apiService,
).send(
transaction: keychainTransaction,
);

await ArchethicTransactionSender(
apiService: apiService,
).send(
transaction: accessKeychainTx,
);

/// Get KeyChain Wallet
final keychain = await apiService.getKeychain(walletSeed);

expect(keychain.services.keys.elementAt(0), 'main-uco-1');
expect(keychain.services.keys.elementAt(1), 'main-uco-2');
expect(keychain.services.keys.elementAt(2), 'main-uco-3');
},
);

test('should build the transaction and the related signature', () {
final seed = Uint8List.fromList(utf8.encode('seed'));

Expand Down

0 comments on commit acd5642

Please sign in to comment.