Skip to content

Commit

Permalink
Merge pull request #2 from 0xxCodemonkey/CosmWasm_v1__secretjs_v1.4
Browse files Browse the repository at this point in the history
CosmWasm v1  secretjs v1.4
  • Loading branch information
0xxCodemonkey authored Sep 25, 2022
2 parents dad1d7b + d70003e commit f22eafa
Show file tree
Hide file tree
Showing 85 changed files with 2,958 additions and 3,263 deletions.
7 changes: 4 additions & 3 deletions NuGet_README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Secret.NET Core Library
Secret.NET (port of the [secret.js](https://github.com/scrtlabs/secret.js) Client) is an .NET SDK for writing applications that interact with the [Secret Network blockchain](https://scrt.network/).
Secret.NET (port of the [secret.js](https://github.com/scrtlabs/secret.js) Client) is a .NET Client to interact with the [Secret Network blockchain](https://scrt.network/) (L1 / Cosmos based), the first privacy smart contract blockchain that processes and stores data on-chain in encrypted form (SGX).
This allows [unique use cases](https://docs.scrt.network/secret-network-documentation/secret-network-overview/use-cases) like Secret NFTs where you can store public and private data e.g., Encryption Keys, passwords or other secrets.

# Key Features
- Written in .NET 6 including MAUI Support.
Expand All @@ -11,16 +12,16 @@ Secret.NET (port of the [secret.js](https://github.com/scrtlabs/secret.js) Clien
- The SDK has a wallet built in and does not currently require / support external wallets.
- Custom APIs / clients for specific smart contracts can be easily created (see packages for tokens / SNIP20 or NFT / SNIP721).

All information and documentation is available in the [**GitHub repository**](https://github.com/0xxCodemonkey/SecretNET).

:information_source: This library is still in beta (as [secret.js](https://github.com/scrtlabs/secret.js)), APIs may break. Beta testers are welcome!

## Additional packages
In addition to the Secret.NET Core Library, the following complementary packages are available:
- [**Full SNIP-20 (Token) client**](https://github.com/0xxCodemonkey/SecretNET.SNIP20), which exposes all methods of the [SNIP-20 reference implementation](https://github.com/scrtlabs/snip20-reference-impl).
- [**Full SNIP-721 / SNIP-722 (NFT) client**](https://github.com/0xxCodemonkey/SecretNET.SNIP721), which exposes all methods of the [SNIP-721 reference implementation](https://github.com/baedrik/snip721-reference-impl).


## Links

- [GitHub](https://github.com/0xxCodemonkey/SecretNET)
- [Secret Network - Secret Network is the first blockchain with customizable privacy.](https://scrt.network/)
- [Secret Network - Documentation](https://docs.scrt.network/secret-network-documentation/)
590 changes: 555 additions & 35 deletions README.md

Large diffs are not rendered by default.

293 changes: 293 additions & 0 deletions examples/SecretNET.Examples/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,293 @@
global using Newtonsoft.Json;

// SecretNET
global using SecretNET;
global using SecretNET.Tx;
global using SecretNET.Common;
global using SecretNET.Common.Storage;
using System.Reflection.Metadata;


// See https://aka.ms/new-console-template for more information

#region *** Helper functions / Objects ***

Action<string> writeHeadline = (text) =>
{
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine($"\r\n**************** {text} ****************\r\n");
Console.ForegroundColor = ConsoleColor.White;
};

Action<string, SecretTx> logSecretTx = (name, tx) =>
{
Console.WriteLine($"{name} Txhash: {tx?.Txhash}");
Console.ForegroundColor = ConsoleColor.Gray;
Console.WriteLine($"(Gas used: {tx.GasUsed} - Gas wanted {tx.GasWanted})");
Console.ForegroundColor = ConsoleColor.White;
//Console.WriteLine($"\r\nCodeId: {JsonConvert.SerializeObject(tx.GetResponseJson(), Formatting.Indented)}");
if (tx is SingleSecretTx<Secret.Compute.V1Beta1.MsgStoreCodeResponse>)
{
Console.WriteLine($"\r\nCodeId: {((SingleSecretTx<Secret.Compute.V1Beta1.MsgStoreCodeResponse>)tx).Response.CodeId}");
}
if (tx is SingleSecretTx<Secret.Compute.V1Beta1.MsgInstantiateContractResponse>)
{
Console.WriteLine($"\r\nContractAddress: {((SingleSecretTx<Secret.Compute.V1Beta1.MsgInstantiateContractResponse>)tx)?.Response?.Address}");
}
if (tx != null && (tx.Code > 0 || (tx.Exceptions?.Any()).GetValueOrDefault()))
{
Console.ForegroundColor = ConsoleColor.Red;
if (tx.Code > 0 && !string.IsNullOrWhiteSpace(tx.Codespace))
{
Console.WriteLine($"\r\n!!!!!!!!!!!! Something went wrong => Code: {tx.Code}; Codespace: {tx.Codespace} !!!!!!!!!!!!");
}
if ((tx.Exceptions?.Any()).GetValueOrDefault())
{
foreach (var ex in tx.Exceptions)
{
Console.WriteLine($"\r\n!!!!!!!!!!!! Exception: {ex.Message} !!!!!!!!!!!!");
}
}
Console.WriteLine($"\r\n{tx.RawLog}");
Console.ForegroundColor = ConsoleColor.White;
Console.ReadLine();
}
};

// TxOptions
var txOptions = new TxOptions()
{
GasLimit = 60_000,
GasPriceInFeeDenom = 0.26F
};

var txOptionsExecute = new TxOptions()
{
GasLimit = 300_000,
GasPriceInFeeDenom = 0.26F
};

var txOptionsUpload = new TxOptions()
{
GasLimit = 12_000_000,
GasPriceInFeeDenom = 0.26F
};

#endregion

writeHeadline("Setup SecretNetworkClient / Wallet");

//var storageProvider = new InMemoryOnlyStorage(); // Temporary and most likely only for DEV
var storageProvider = new AesEncryptedFileStorage("","SuperSecurePassword");
var createWalletOptions = new CreateWalletOptions(storageProvider);

Wallet wallet = null;
if (await storageProvider.HasPrivateKey())
{
var storedMnemonic = await storageProvider.GetFirstMnemonic();
wallet = await Wallet.Create(storedMnemonic, options: createWalletOptions);
}
else
{
wallet = await Wallet.Create(options: createWalletOptions);

Console.WriteLine("Please first fund the wallet with some SCRT via https://faucet.pulsar.scrttestnet.com/ ");
Console.ReadLine();
}

var gprcUrl = "https://grpc.testnet.secretsaturn.net"; // get from https://github.com/scrtlabs/api-registry
var chainId = "pulsar-2";

var createClientOptions = new CreateClientOptions(gprcUrl, chainId, wallet);
var secretClient = new SecretNetworkClient(createClientOptions);

Console.WriteLine("wallet.Address: " + wallet.Address);


#region *** Get Balance ***

// *** Get Balance (1000000 uscrt == 1 SCRT) ***

writeHeadline("Get Balance");

var response = await secretClient.Query.Bank.Balance(wallet.Address);
Console.WriteLine($"Balance: {(float.Parse(response.Amount) / 1000000f)} SCRT");

//Console.ReadLine();

#endregion

#region *** Get Subacccount and Send $SCRT ***

// Send SCRT
var subaccountWallet = await wallet.GetSubaccount(1);
Console.WriteLine($"\r\nSubaccount.Address: {subaccountWallet.Address}");

var sendResponse = await secretClient.Tx.Bank.Send(toAddress: subaccountWallet.Address, amount: 1000000, denom: null);
Console.WriteLine($"BroadcastResponse: {(sendResponse.Code == 0 ? "Success" : "Error (see log)")}");

var r1 = await secretClient.Query.Bank.Balance(subaccountWallet.Address);
Console.WriteLine($"Subaccount Balance: {(float.Parse(r1.Amount) / 1000000f)} SCRT\r\n");

//Console.ReadLine();

#endregion

#region *** Simulate and broadcast a complex transaction ***

var sendToAlice = new Cosmos.Bank.V1Beta1.MsgSend()
{
FromAddress = wallet.Address,
ToAddress = subaccountWallet.Address
};
sendToAlice.Amount.Add(new Cosmos.Base.V1Beta1.Coin() { Amount = "1", Denom = "uscrt" });

var sendToEve = new Cosmos.Bank.V1Beta1.MsgSend()
{
FromAddress = wallet.Address,
ToAddress = subaccountWallet.Address // use the same address for simplicity
};
sendToEve.Amount.Add(new Cosmos.Base.V1Beta1.Coin() { Amount = "1", Denom = "uscrt" });

var messages = new[] { sendToAlice, sendToEve };

var simulate = await secretClient.Tx.Simulate(messages);

Console.WriteLine($"Simulate => GasUsed {simulate.GasInfo.GasUsed} uscrt");

var tx = await secretClient.Tx.Broadcast(messages, new TxOptions
{
// Adjust gasLimit up by 10% to account for gas estimation error
GasLimit = (int)Math.Ceiling(simulate.GasInfo.GasUsed * 1.1),
});

logSecretTx("Broadcast result", tx);

//Console.ReadLine();

#endregion

#region *** Auth ***

// *** Get Account ***

writeHeadline("Get Account");

var accountResponse = await secretClient.Query.Auth.Account(wallet.Address);
Console.WriteLine("AccountResponse:\r\n" + JsonConvert.SerializeObject(accountResponse, Formatting.Indented) + "\r\n");

//Console.ReadLine();

#endregion

#region *** Codes ***

// *** Get Codes with source ***

writeHeadline("Get my Codes with source");

var codesResponse = await secretClient.Query.Compute.Codes();
var withSource = codesResponse.Where(c => !string.IsNullOrWhiteSpace(c.Source) && c.CreatorAddress == wallet.Address).ToList();
Console.WriteLine($"My Codes with source (Count: {withSource.Count} ):\r\n" + JsonConvert.SerializeObject(withSource, Formatting.Indented) + "\r\n");

//Console.ReadLine();

#endregion

#region *** Smart Contract (Upload, Init, Query, Execute) ***

// *** Smart Contract (Upload, Init, Query, Execute) ***

writeHeadline("Upload Contract (mysimplecounter.wasm.gz)");

// *** Upload Contract ***
// https://secretjs.scrt.network/#secretjstxcomputestorecode

byte[] wasmByteCode = File.ReadAllBytes(@"..\..\..\..\..\Resources\mysimplecounter.wasm.gz");

// MsgStoreCode
var msgStoreCodeCounter = new MsgStoreCode(wasmByteCode,
source: "https://github.com/scrtlabs/secret-template", // Source is a valid absolute HTTPS URI to the contract's source code, optional
builder: "enigmampc/secret-contract-optimizer:latest" // Builder is a valid docker image name with tag, optional
);

var storeCodeResponse = await secretClient.Tx.Compute.StoreCode(msgStoreCodeCounter, txOptions: txOptionsUpload);
logSecretTx("StoreCodeResponse", storeCodeResponse);

// *** Init Contract ***
writeHeadline("Init Contract with CodeId " + storeCodeResponse.Response.CodeId);

string? contractAddress = null;
string contractCodeHash = null;
if (storeCodeResponse.Response.CodeId > 0)
{
var codeId = storeCodeResponse.Response.CodeId;
contractCodeHash = await secretClient.Query.Compute.GetCodeHashByCodeId(codeId);

var msgInitContract = new MsgInstantiateContract(
codeId: codeId,
label: $"MySimpleCouter {codeId}",
initMsg: new { count = 100 },
codeHash: contractCodeHash); // optional but way faster

var initContractResponse = await secretClient.Tx.Compute.InstantiateContract(msgInitContract, txOptions: txOptionsUpload);
logSecretTx("InstantiateContract", initContractResponse);

contractAddress = initContractResponse?.Response?.Address;

Console.WriteLine("Contract CodeHash: " + contractCodeHash);
Console.WriteLine("Contract Address: " + contractAddress);

}

//Console.ReadLine();

#region *** Query Contract ***

//string contractAddress = "Set manual if needed";
//string contractCodeHash = "Set manual if needed";

// *** Query Contract ***

writeHeadline("Query Contract with address " + contractAddress);

var queryMsg = new { get_count = new { } };

Console.WriteLine("Query : " + JsonConvert.SerializeObject(queryMsg, Formatting.Indented) + "\r\n");

var queryContractResult = await secretClient.Query.Compute.QueryContract<object>(contractAddress, queryMsg, contractCodeHash);
Console.WriteLine("QueryContractResult:\r\n " + queryContractResult.Response);

//Console.ReadLine();

#endregion

#region *** Execute Contract ***

// *** Execute Contract ***

writeHeadline("Execute Contract with address " + contractAddress);

var executeMsg = new { increment = new { } };

Console.WriteLine("Execute : " + JsonConvert.SerializeObject(executeMsg, Formatting.Indented) + "\r\n");

var msgExecuteContract = new MsgExecuteContract(contractAddress: contractAddress, msg: executeMsg, codeHash: contractCodeHash, sender: null, sentFunds: null);

var executeContractResponse = await secretClient.Tx.Compute.ExecuteContract(msgExecuteContract, txOptionsExecute);
logSecretTx("ExecuteContract", executeContractResponse);

Thread.Sleep(1000); // give some time to let it settle

var queryContractResult2 = await secretClient.Query.Compute.QueryContract<object>(contractAddress, queryMsg, contractCodeHash);
Console.WriteLine("\r\nQueryContractResult (again) :\r\n " + queryContractResult2.Response);

Console.ReadLine();

#endregion

#endregion
14 changes: 14 additions & 0 deletions examples/SecretNET.Examples/SecretNET.Examples.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\SecretNET.csproj" />
</ItemGroup>

</Project>
Binary file added resources/mysimplecounter.wasm.gz
Binary file not shown.
Binary file added resources/snip20_reference_impl.wasm.gz
Binary file not shown.
Binary file added resources/snip721_722_reference_impl.wasm.gz
Binary file not shown.
6 changes: 4 additions & 2 deletions src/Api/ComputeMsgToNonce.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
namespace SecretNET.Api;
using System.Collections.Concurrent;

namespace SecretNET.Api;

/// <summary>
/// Dictionary which assigns messages index to nonce.
/// </summary>
public class ComputeMsgToNonce : Dictionary<int, byte[]>
public class ComputeMsgToNonce : ConcurrentDictionary<int, byte[]>
{

}
14 changes: 8 additions & 6 deletions src/Api/CosmosSdkException.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace SecretNET.Api;
using Cosmos.Base.Abci.V1Beta1;

namespace SecretNET.Api;

/// <summary>
/// Class CosmosSdkException.
Expand All @@ -23,7 +25,7 @@ public class CosmosSdkException : Exception
/// Gets the get tx response.
/// </summary>
/// <value>The get tx response.</value>
public GetTxResponse GetTxResponse { get; private set; }
public TxResponse TxResponse { get; private set; }

/// <summary>
/// Gets the raw log.
Expand All @@ -36,9 +38,9 @@ public string RawLog
{
return BroadcastTxResponse?.TxResponse?.RawLog;
}
if (GetTxResponse?.TxResponse?.RawLog != null)
if (TxResponse?.RawLog != null)
{
return GetTxResponse?.TxResponse?.RawLog;
return TxResponse?.RawLog;
}
return null;
}
Expand All @@ -60,10 +62,10 @@ public CosmosSdkException(CosmosSdkErrorEnum cosmosSdkErrorEnum, BroadcastTxResp
/// </summary>
/// <param name="cosmosSdkErrorEnum">The cosmos SDK error enum.</param>
/// <param name="response">The response.</param>
public CosmosSdkException(CosmosSdkErrorEnum cosmosSdkErrorEnum, GetTxResponse response) : base(SetErrorMessage(cosmosSdkErrorEnum))
public CosmosSdkException(CosmosSdkErrorEnum cosmosSdkErrorEnum, TxResponse response) : base(SetErrorMessage(cosmosSdkErrorEnum))
{
CosmosSdkErrorEnum = cosmosSdkErrorEnum;
GetTxResponse = response;
TxResponse = response;
}

// https://github.com/cosmos/cosmos-sdk/blob/main/types/errors/errors.go
Expand Down
Loading

0 comments on commit f22eafa

Please sign in to comment.