Skip to content

Commit e006e46

Browse files
Merge pull request #27 from RemarkableTools/wallet
Wallet
2 parents df49083 + e68b1dd commit e006e46

File tree

9 files changed

+145
-58
lines changed

9 files changed

+145
-58
lines changed

docs/advanced.md

Lines changed: 61 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,37 +20,45 @@ Get a valid [`NetworkConfig`](https://github.com/RemarkableTools/Mx.NET.SDK/blob
2020
```csharp
2121
var networkConfig = await NetworkConfig.GetFromNetwork(provider);
2222
```
23-
Create a [`Signer`](https://github.com/RemarkableTools/Mx.NET.SDK/blob/master/src/Mx.NET.SDK.Wallet/Wallet/Signer.cs) instance by providing the key file and the associated password
23+
Create a [`Signer`](https://github.com/RemarkableTools/Mx.NET.SDK/blob/master/src/Mx.NET.SDK.Wallet/Wallet/WalletSigner.cs) instance by providing the key file and the associated password
2424
```csharp
2525
var filePath = "PATH/TO/KEYFILE.json";
2626
var password = "PASSWORD";
27-
var signer = Signer.FromKeyFile(filePath, password);
27+
var signer = WalletSigner.FromKeyFile(filePath, password);
2828
```
2929
Set up my Account and Receiver Address
3030
```csharp
31-
var myAccount = Account.From(await provider.GetAccount(signer.GetAddress().Bech32));
31+
var account = Account.From(await provider.GetAccount(signer.GetAddress().Bech32));
3232
var receiverAddress = Address.FromBech32("RECEIVER_ADDRESS");
3333
```
3434
Get a token from network
3535
```csharp
36-
var token = Token.From(await provider.GetToken("OFE-29eb54"));
36+
var token = Token.From(await provider.GetToken("BUSD-632f7d"));
3737
```
3838
Create the [`Transaction Request`](https://github.com/RemarkableTools/Mx.NET.SDK/blob/master/src/Mx.NET.SDK/Domain/TransactionRequest.cs)
3939
```csharp
4040
var transactionRequest = TokenTransactionRequest.TokenTransfer(
4141
networkConfig,
4242
account,
4343
receiverAddress,
44-
token.Identifier.Value,
45-
ESDTAmount.ESDT("100", token.GetESDT()).Value);
44+
token.Identifier,
45+
ESDTAmount.ESDT("100", token.GetESDT()));
4646
```
4747
Use the [`Wallet Methods`](https://github.com/RemarkableTools/Mx.NET.SDK/blob/master/src/Mx.NET.SDK.Wallet/WalletMethods.cs) to sign the transaction
4848
```csharp
49-
var signedTransaction = transactionRequest.Sign(signer);
49+
var signedTransaction = signer.SignTransaction(transactionRequest);
5050
```
5151
POST the transaction to MultiversX API
5252
```csharp
53-
var response = await provider.SendTransaction(signedTransaction);
53+
try
54+
{
55+
var response = await provider.SendTransaction(signedTransaction);
56+
//other instructions
57+
}
58+
catch (Exception ex)
59+
{
60+
Console.WriteLine(ex.Message);
61+
}
5462
```
5563
Get the [`Transaction`](https://github.com/RemarkableTools/Mx.NET.SDK/blob/master/src/Mx.NET.SDK/Domain/Data/Transaction/Transaction.cs) from response and await for execution to finalize
5664
```csharp
@@ -65,25 +73,58 @@ Console.WriteLine($"Transaction executed with status {transaction.Status}");
6573
The example is created for the [adder](https://github.com/multiversx/mx-sdk-rs/tree/master/contracts/examples/adder) contract.
6674
#### Create a [`EGLD Transaction Request`](https://github.com/RemarkableTools/Mx.NET.SDK/blob/master/src/Mx.NET.SDK/TransactionsManager/EGLDTransactionRequest.cs) to a Smart Contract, sign it and send it to the network
6775
```csharp
68-
var transactionRequest = EGLDTransactionRequest.EGLDTransferToSmartContract(
69-
networkConfig,
70-
account,
71-
smartContractAddress,
72-
ESDTAmount.Zero(),
73-
"add",
74-
NumericValue.BigUintValue(10));
75-
var signedTransaction = transactionRequest.Sign(signer);
76-
var response = await provider.SendTransaction(signedTransaction);
77-
var transaction = Transaction.From(response.TxHash);
78-
await transaction.AwaitExecuted(provider);
79-
Console.WriteLine($"Transaction executed with status {transaction.Status}");
76+
try
77+
{
78+
var transactionRequest = EGLDTransactionRequest.EGLDTransferToSmartContract(
79+
networkConfig,
80+
account,
81+
smartContractAddress,
82+
ESDTAmount.Zero(),
83+
"add",
84+
NumericValue.BigUintValue(10));
85+
var signedTransaction = signer.SignTransaction(transactionRequest);
86+
var response = await provider.SendTransaction(signedTransaction);
87+
var transaction = Transaction.From(response.TxHash);
88+
await transaction.AwaitExecuted(provider);
89+
Console.WriteLine($"Transaction executed with status {transaction.Status}");
90+
}
91+
catch (Exception ex)
92+
{
93+
Console.WriteLine(ex.Message);
94+
}
8095
```
8196
#### Query smart contract
8297
```csharp
98+
var smartContractAddress = Address.FromBech32("CONTRACT_BECH32_ADDRESS");
8399
var outputType = TypeValue.BigUintTypeValue;
84100
var queryResult = await SmartContract.QuerySmartContract<NumericValue>(provider,
85101
smartContractAddress,
86102
outputType,
87103
"getSum");
88104
Console.WriteLine(queryResult.Number);
105+
106+
// query array from Smart Contract (random example)
107+
var queryArrayResult = await SmartContract.QueryArraySmartContract<Address>(provider,
108+
smartContractAddress,
109+
TypeValue.AddressValue,
110+
"getUsers");
111+
foreach (var user in queryArrayResult)
112+
Console.WriteLine(user.Bech32);
113+
114+
// more complex reading from Smart Contract storage (random example)
115+
uint day = 1;
116+
var dayRewards = await SmartContract.QueryArraySmartContract<StructValue>(provider,
117+
smartContractAddress,
118+
TypeValue.StructValue("EsdtTokenPayment", new FieldDefinition[3]
119+
{
120+
new FieldDefinition("token_identifier", "", TypeValue.TokenIdentifierValue),
121+
new FieldDefinition("token_nonce", "", TypeValue.U64TypeValue),
122+
new FieldDefinition("amount", "", TypeValue.BigUintTypeValue)
123+
}),
124+
"getDayRewards",
125+
null,
126+
NumericValue.U32Value(day));
127+
foreach(var esdt in dayRewards)
128+
Console.WriteLine($"{esdt.Fields[0].Value} {esdt.Fields[1].Value} {esdt.Fields[2].Value}");
129+
// You can map the StructValue from response to you custom class object for easier usage, if you need
89130
```

docs/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ var provider = new MultiversxProvider(new MultiversxNetworkConfiguration(Network
1212
```
1313
With this provider you can query the MultiversX API data like in the following examples:
1414
```csharp
15+
// You can integrate intructions in Try..Catch block
16+
1517
var networkConfig = await NetworkConfig.GetFromNetwork(provider);
1618
var account = Account.From(await provider.GetAccount("erd1sdslvlxvfnnflzj42l8czrcngq3xjjzkjp3rgul4ttk6hntr4qdsv6sets"));
1719
var transaction = Transaction.From(await provider.GetTransaction("0a94708e9653b79665ba41a6292ec865ab09e51a32be4b96b6f76ba272665f01"));

src/Mx.NET.SDK.Wallet/Mx.NET.SDK.Wallet.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<RepositoryUrl>https://github.com/RemarkableTools/Mx.NET.SDK/tree/main/src/Mx.NET.SDK.Wallet</RepositoryUrl>
1212
<RepositoryType>GitHub</RepositoryType>
1313
<Company>Remarkable Tools</Company>
14-
<Version>1.0.0</Version>
14+
<Version>1.0.1</Version>
1515
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
1616
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile>
1717
<Title>RemarkableTools.Mx.Wallet</Title>

src/Mx.NET.SDK.Wallet/Wallet/Mnemonic.cs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,48 @@ namespace Mx.NET.SDK.Wallet.Wallet
99
{
1010
public class Mnemonic
1111
{
12+
private const int MNEMONIC_STRENGTH = 256;
1213
private const string HdPrefix = "m/44'/508'/0'/0'";
1314

14-
public static byte[] DecryptSecretKey(string mnemonic, int accountIndex = 0)
15+
public string SeedPhrase { get; set; } = string.Empty;
16+
17+
private Mnemonic(string phrase)
18+
{
19+
SeedPhrase = phrase;
20+
}
21+
22+
public static Mnemonic Generate()
23+
{
24+
var bip39 = new BIP39();
25+
return new Mnemonic(bip39.GenerateMnemonic(MNEMONIC_STRENGTH, BIP39Wordlist.English));
26+
}
27+
28+
public static Mnemonic FromString(string seedPhrase)
29+
{
30+
seedPhrase = seedPhrase.Trim();
31+
32+
var bip39 = new BIP39();
33+
if (bip39.ValidateMnemonic(seedPhrase, BIP39Wordlist.English))
34+
return new Mnemonic(seedPhrase);
35+
else
36+
throw new Exception("Bad mnemonic");
37+
}
38+
39+
public string[] GetWords()
40+
{
41+
if (string.IsNullOrEmpty(SeedPhrase))
42+
throw new Exception("Seed phrase is empty");
43+
return SeedPhrase.Split(' ');
44+
}
45+
46+
public static byte[] DecryptSecretKey(string mnemonic, int addressIndex = 0)
1547
{
1648
try
1749
{
1850
var bip39 = new BIP39();
1951
var seedHex = bip39.MnemonicToSeedHex(mnemonic, "");
2052

21-
var hdPath = $"{HdPrefix}/{accountIndex}'";
53+
var hdPath = $"{HdPrefix}/{addressIndex}'";
2254
var kv = DerivePath(hdPath, seedHex);
2355
var secretKey = kv.Key;
2456
return secretKey;

src/Mx.NET.SDK.Wallet/Wallet/PemFile.cs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,29 @@ public static byte[] DecryptSecretKey(string filePath, int index = 0)
3535

3636
public static string BuildPemFile(WalletSecretKey secretKey)
3737
{
38-
throw new NotImplementedException();
39-
4038
var publicKey = secretKey.GeneratePublicKey();
4139
var address = publicKey.ToAddress().Bech32;
4240
string header = $"-----BEGIN PRIVATE KEY for {address}-----";
4341
string footer = $"-----END PRIVATE KEY for {address}-----";
4442

45-
var hex = Converter.ToHexString(secretKey.GetKey().Concat(publicKey.GetKey()).ToArray());
46-
var text = Convert.ToBase64String(Encoding.UTF8.GetBytes(hex));
47-
return text;
43+
var keys = secretKey.GetKey().Concat(publicKey.GetKey()).ToArray();
44+
var hex = Encoding.UTF8.GetBytes(Converter.ToHexString(keys));
45+
var base64Key = Convert.ToBase64String(hex);
46+
47+
var lines = SplitBy(base64Key, 64);
48+
var text = string.Join(Environment.NewLine, lines);
49+
return string.Join(Environment.NewLine, new[] { header, text, footer });
50+
}
51+
52+
private static IEnumerable<string> SplitBy(string text, int chunkSize)
53+
{
54+
var chunks = new List<string>();
55+
for (var i = 0; i < text.Length; i += chunkSize)
56+
{
57+
var chunk = text.Substring(i, Math.Min(chunkSize, text.Length - i));
58+
chunks.Add(chunk);
59+
}
60+
return chunks;
4861
}
4962
}
5063
}

src/Mx.NET.SDK.Wallet/Wallet/Wallet.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,9 @@ public Account GetAccount()
6969
/// Get the wallet signer
7070
/// </summary>
7171
/// <returns>Signer</returns>
72-
public Signer GetSigner()
72+
public WalletSigner GetSigner()
7373
{
74-
return new Signer(_secretKey);
74+
return new WalletSigner(_secretKey);
7575
}
7676

7777
/// <summary>

src/Mx.NET.SDK.Wallet/Wallet/Signer.cs renamed to src/Mx.NET.SDK.Wallet/Wallet/WalletSigner.cs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
1-
using System;
2-
using System.Text;
1+
using System.Text;
32
using Mx.NET.SDK.Core.Domain.Values;
43

54
namespace Mx.NET.SDK.Wallet.Wallet
65
{
7-
public class Signer
6+
public class WalletSigner
87
{
9-
private WalletSecretKey _secretKey;
8+
private readonly WalletSecretKey _secretKey;
109

11-
public Signer(byte[] secretKey)
10+
public WalletSigner(byte[] secretKey)
1211
{
1312
_secretKey = new WalletSecretKey(secretKey);
1413
}
1514

16-
public Signer(WalletSecretKey secretKey)
15+
public WalletSigner(WalletSecretKey secretKey)
1716
{
1817
_secretKey = secretKey;
1918
}
@@ -24,9 +23,9 @@ public Signer(WalletSecretKey secretKey)
2423
/// <param name="mnemonic">The mnemonic phrase</param>
2524
/// <param name="accountIndex">The account index, default 0</param>
2625
/// <returns></returns>
27-
public static Signer FromMnemonic(string mnemonic, int accountIndex = 0)
26+
public static WalletSigner FromMnemonic(string mnemonic, int accountIndex = 0)
2827
{
29-
return new Signer(Mnemonic.DecryptSecretKey(mnemonic, accountIndex));
28+
return new WalletSigner(Mnemonic.DecryptSecretKey(mnemonic, accountIndex));
3029
}
3130

3231
/// <summary>
@@ -35,19 +34,19 @@ public static Signer FromMnemonic(string mnemonic, int accountIndex = 0)
3534
/// <param name="filePath">The KeyFile path</param>
3635
/// <param name="password">The password</param>
3736
/// <returns></returns>
38-
public static Signer FromKeyFile(string filePath, string password)
37+
public static WalletSigner FromKeyFile(string filePath, string password)
3938
{
40-
return new Signer(KeyFile.DecryptSecretKey(filePath, password));
39+
return new WalletSigner(KeyFile.DecryptSecretKey(filePath, password));
4140
}
4241

4342
/// <summary>
4443
/// Derive a signer from PemFile
4544
/// </summary>
4645
/// <param name="filePath">The PemFile path</param>
4746
/// <returns></returns>
48-
public static Signer FromPemFile(string filePath)
47+
public static WalletSigner FromPemFile(string filePath)
4948
{
50-
return new Signer(PemFile.DecryptSecretKey(filePath));
49+
return new WalletSigner(PemFile.DecryptSecretKey(filePath));
5150
}
5251

5352
/// <summary>

src/Mx.NET.SDK.Wallet/Wallet/WalletVerifier.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace Mx.NET.SDK.Wallet.Wallet
66
{
77
public class WalletVerifier
88
{
9-
private WalletPublicKey _publicKey;
9+
private readonly WalletPublicKey _publicKey;
1010

1111
public WalletVerifier(byte[] publicKey)
1212
{

src/Mx.NET.SDK.Wallet/WalletMethods.cs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace Mx.NET.SDK.Wallet
1010
{
1111
public static class WalletMethods
1212
{
13-
public static TransactionRequestDto Sign(this TransactionRequest transactionRequest, Signer signer)
13+
public static TransactionRequestDto SignTransaction(this WalletSigner signer, TransactionRequest transactionRequest)
1414
{
1515
var transactionRequestDto = transactionRequest.GetTransactionRequest();
1616
var json = JsonWrapper.Serialize(transactionRequestDto);
@@ -20,20 +20,7 @@ public static TransactionRequestDto Sign(this TransactionRequest transactionRequ
2020
return transactionRequestDto;
2121
}
2222

23-
public static bool VerifySign(this TransactionRequest transactionRequest, string signature)
24-
{
25-
var transactionRequestDto = transactionRequest.GetTransactionRequest();
26-
var message = JsonWrapper.Serialize(transactionRequestDto);
27-
28-
var verifier = WalletVerifier.FromAddress(transactionRequest.Sender);
29-
return verifier.VerifyRaw(new SignableMessage()
30-
{
31-
Message = message,
32-
Signature = signature
33-
});
34-
}
35-
36-
public static TransactionRequestDto[] MultiSign(this TransactionRequest[] transactionsRequest, Signer signer)
23+
public static TransactionRequestDto[] SignTransactions(this WalletSigner signer, TransactionRequest[] transactionsRequest)
3724
{
3825
var transactions = new List<TransactionRequestDto>();
3926

@@ -49,5 +36,18 @@ public static TransactionRequestDto[] MultiSign(this TransactionRequest[] transa
4936

5037
return transactions.ToArray();
5138
}
39+
40+
public static bool VerifySignature(this TransactionRequest transactionRequest, string signature)
41+
{
42+
var transactionRequestDto = transactionRequest.GetTransactionRequest();
43+
var message = JsonWrapper.Serialize(transactionRequestDto);
44+
45+
var verifier = WalletVerifier.FromAddress(transactionRequest.Sender);
46+
return verifier.VerifyRaw(new SignableMessage()
47+
{
48+
Message = message,
49+
Signature = signature
50+
});
51+
}
5252
}
5353
}

0 commit comments

Comments
 (0)