├── .gitignore ├── LICENSE ├── README.md ├── docs ├── advanced.md ├── basic.md └── index.md ├── src ├── .editorconfig ├── Configuration │ ├── ElrondNetworkConfiguration.cs │ └── Network.cs ├── Cryptography │ ├── AesCtr.cs │ └── Bech32Engine.cs ├── Domain │ ├── Abi │ │ ├── Abi.cs │ │ ├── AbiDefinition.cs │ │ └── EndpointDefinition.cs │ ├── Account.cs │ ├── Address.cs │ ├── Codec │ │ ├── AddressBinaryCodec.cs │ │ ├── BinaryCodec.cs │ │ ├── BooleanBinaryCodec.cs │ │ ├── BytesBinaryCodec.cs │ │ ├── IBinaryCodec.cs │ │ ├── MultiBinaryCodec.cs │ │ ├── NumericBinaryCodec.cs │ │ ├── OptionBinaryCodec.cs │ │ ├── StructBinaryCodec.cs │ │ └── TokenIdentifierCodec.cs │ ├── Constants.cs │ ├── ESDTTokenTransactionRequest.cs │ ├── EsdtToken.cs │ ├── EsdtTokenType.cs │ ├── Exceptions │ │ ├── AddressException.cs │ │ ├── BinaryCodecException.cs │ │ ├── GatewayException.cs │ │ ├── InsufficientFundException.cs │ │ ├── InvalidTokenAmountException.cs │ │ ├── TransactionException.cs │ │ └── WrongBinaryValueCodecException.cs │ ├── GasLimit.cs │ ├── Helper │ │ ├── BigEndianBuffer.cs │ │ ├── BytesExtensions.cs │ │ ├── Converter.cs │ │ ├── JsonSerializerWrapper.cs │ │ └── StringExtensions.cs │ ├── KeyFile.cs │ ├── NetworkConfig.cs │ ├── SmartContracts │ │ ├── CodeArtifact.cs │ │ ├── CodeMetadata.cs │ │ └── SmartContract.cs │ ├── Token.cs │ ├── TokenAmount.cs │ ├── Transaction.cs │ ├── TransactionRequest.cs │ ├── Values │ │ ├── BaseBinaryValue.cs │ │ ├── BooleanValue.cs │ │ ├── BytesValue.cs │ │ ├── FieldDefinition.cs │ │ ├── IBinaryType.cs │ │ ├── MultiValue.cs │ │ ├── NumericValue.cs │ │ ├── OptionValue.cs │ │ ├── StructField.cs │ │ ├── StructValue.cs │ │ ├── TokenIdentifierValue.cs │ │ └── TypeValue.cs │ └── Wallet.cs ├── Erdcsharp.csproj ├── Erdcsharp.sln ├── Erdcsharp.sln.DotSettings ├── Manager │ ├── ESDTTokenManager.cs │ └── IEsdtTokenManager.cs └── Provider │ ├── Dtos │ ├── AccountResponseDto.cs │ ├── ConfigResponseDto.cs │ ├── CreateTransactionResponseDto.cs │ ├── ESDTTokenResponseDto.cs │ ├── ElrondGatewayResponseDto.cs │ ├── QueryVmRequestDto.cs │ ├── QueryVmResultDto.cs │ ├── TransactionCostDto.cs │ ├── TransactionRequestDto.cs │ └── TransactionResponseDto.cs │ ├── ElrondProvider.cs │ └── IElrondProvider.cs └── tests ├── Erdcsharp.Console.NET 5.0 ├── Erdcsharp.Console.NET 5.0.csproj ├── FullAuctionData.cs ├── Program.cs ├── SmartContracts │ ├── adder │ │ ├── adder.abi.json │ │ └── adder.wasm │ └── auction │ │ ├── auction.abi.json │ │ └── auction.wasm └── Wallets │ └── erd17rnvj9shx2x9vh2ckw0nf53vvlylj6235lmrhu668rg2c9a8mxjqvjrhq5.json ├── Erdcsharp.Console.NET_Core_3.1 ├── Erdcsharp.Console.NET_Core_3.1.csproj └── Program.cs ├── Erdcsharp.Console.NET_Framework ├── App.config ├── Erdcsharp.Console.NET_Framework.csproj ├── Program.cs └── Properties │ └── AssemblyInfo.cs ├── Erdcsharp.Console ├── Elrond.SDK.Console.csproj ├── FullAuctionData.cs ├── Program.cs ├── SmartContracts │ ├── adder │ │ ├── adder.abi.json │ │ └── adder.wasm │ └── auction │ │ ├── auction.abi.json │ │ └── auction.wasm └── Wallets │ └── erd17rnvj9shx2x9vh2ckw0nf53vvlylj6235lmrhu668rg2c9a8mxjqvjrhq5.json ├── Erdcsharp.IntegrationTests ├── AccountIntegrationTests.cs ├── Erdcsharp.IntegrationTests.csproj ├── EsdtTokenIntegrationTests.cs ├── SmartContractTests.cs └── TransactionsIntegrationTests.cs └── Erdcsharp.Tests ├── Domain ├── AccountTests.cs ├── AddressTest.cs ├── Codec │ ├── BinaryCodecTests.cs │ ├── BooleanBinaryCodecTests.cs │ ├── BytesBinaryCodecTests.cs │ ├── MultiBinaryCodecTests.cs │ ├── NumericBinaryCodecTests.cs │ ├── OptionCodecTests.cs │ └── StructBinaryCodecTests.cs ├── EsdtTokenTransactionRequestTests.cs ├── GasLimitTests.cs ├── SmartContractTests.cs ├── TokenAmountTests.cs ├── TokenTests.cs └── WalletTests.cs ├── Elrond-sdk.dotnet.tests.csproj ├── Erdcsharp.UnitTests.csproj ├── FakeData ├── ElrondGatewayMockProvider.cs ├── KeyFiles │ ├── alice.json │ ├── bob.json │ └── carol.json ├── SmartContracts │ ├── adder │ │ ├── adder.abi.json │ │ └── adder.wasm │ └── auction │ │ ├── auction.abi.json │ │ └── auction.wasm └── TestWalletFactory.cs └── Manager └── EsdtTokenManagerTests.cs /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.*~ 3 | project.lock.json 4 | .DS_Store 5 | *.pyc 6 | nupkg/ 7 | 8 | # Visual Studio Code 9 | .vscode 10 | 11 | # Rider 12 | .idea 13 | 14 | # User-specific files 15 | *.suo 16 | *.user 17 | *.userosscache 18 | *.sln.docstates 19 | 20 | # Build results 21 | [Dd]ebug/ 22 | [Dd]ebugPublic/ 23 | [Rr]elease/ 24 | [Rr]eleases/ 25 | x64/ 26 | x86/ 27 | build/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Oo]ut/ 32 | msbuild.log 33 | msbuild.err 34 | msbuild.wrn 35 | 36 | # Visual Studio 2015 37 | .vs/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ## License 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) MultiversX 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mx-sdk-erdcsharp 2 | 3 | **As of January 2023, the repository is largely outdated. Updates will follow.** 4 | 5 | MultiversX C# SDK for interacting with the blockchain (in general) and smart contracts (in particular). 6 | 7 | This SDK depends on : 8 | * [BouncyCastle](https://www.nuget.org/packages/Portable.BouncyCastle/) for ed25519 and other crypto algorithms 9 | * [dotnetstandard-bip39](https://github.com/elucidsoft/dotnetstandard-bip39) for mnemonic / seed phrase. 10 | 11 | # Main Features 12 | * Transaction construction, signing, broadcasting and querying. 13 | * Smart Contracts deployment and interaction (execution and querying). 14 | * Wallet creation, derive wallet from mnemonic 15 | * Query values stored within Smart Contracts. 16 | 17 | # Documentation 18 | The documentation and guides can be found at [Read the docs](./docs/index.md). 19 | 20 | # Change Log 21 | All notable changes will be documented in this file. 22 | -------------------------------------------------------------------------------- /docs/advanced.md: -------------------------------------------------------------------------------- 1 | # [Documentation](./index.md) 2 | ## Advanced usage 3 | 4 | ### Smart contract interactions (Deploy, Call, Query) 5 | See a [full example](../tests/Erdcsharp.IntegrationTests/SmartContractTests.cs) in the integration tests sections 6 | 7 | #### Deploy a smart contract 8 | ```csharp 9 | var code = CodeArtifact.FromFilePath("FakeData/SmartContracts/adder/adder.wasm"); 10 | var codeMetadata = new CodeMetadata(false, true, false); 11 | var initialValue = NumericValue.BigUintValue(10); 12 | 13 | var deployTxRequest = TransactionRequest.CreateDeploySmartContractTransactionRequest( 14 | networkConfig, 15 | aliceAccount, 16 | code, 17 | codeMetadata, 18 | initialValue); 19 | 20 | var deployTx = await deployTxRequest.Send(_provider, alice); 21 | await deployTx.AwaitExecuted(_provider); 22 | ``` 23 | #### Compute a smart contract deployment address 24 | You can get the smart contract deployment address with the deployment transaction 25 | ```csharp 26 | var scAddress = SmartContract.ComputeAddress(deployTxRequest); 27 | ``` 28 | 29 | Or from the owner address and the nonce of the deployment. 30 | ```csharp 31 | var scAddress = SmartContract.ComputeAddress(ownerAddress, nonce); 32 | ``` 33 | 34 | #### Create a smart contract transaction 35 | This example will create a call to the 'add' method of the 'adder' smart contract and passed the BigUINT value 10. 36 | ```csharp 37 | var txRequest = TransactionRequest.CreateCallSmartContractTransactionRequest( 38 | networkConfig, 39 | account, 40 | smartContractAddress, 41 | "add", 42 | TokenAmount.Zero(), 43 | NumericValue.BigUintValue(10)); 44 | 45 | var tx = await txRequest.Send(_provider, wallet); 46 | await tx.AwaitExecuted(_provider); 47 | ``` 48 | #### Query smart contract 49 | ```csharp 50 | var outputType = TypeValue.BigUintTypeValue; 51 | var queryResult = await SmartContract.QuerySmartContract( 52 | _provider, 53 | smartContractAddress, 54 | outputType, 55 | "getSum"); 56 | ``` 57 | 58 | ### ESDT (Elrond Standard Digital Token) interraction 59 | See a [full example](../tests/Erdcsharp.IntegrationTests/EsdtTokenIntegrationTests.cs) in the integration tests sections 60 | 61 | ```csharp 62 | /// 63 | /// ESDT tokens are issued via a request to the Metachain, 64 | /// which is a transaction submitted by the Account which will manage the tokens. 65 | /// When issuing a token, one must provide a token name, a ticker, the initial supply, 66 | /// the number of decimals for display purpose and optionally additional properties 67 | /// 68 | /// 69 | /// 70 | /// Initial supply, should have an even number of characters 71 | /// The token identifier 72 | Task IssueFungibleToken(Wallet wallet, Token token, BigInteger initialSupply); 73 | 74 | /// 75 | /// One has to perform an issuance transaction in order to register a non fungible token. 76 | /// Non FungibleESDT Tokens are issued via a request to the Metachain, which is a transaction submitted by the Account which will manage the tokens. 77 | /// When issuing a token, one must provide a token name, a ticker and optionally additional properties. 78 | /// 79 | /// 80 | /// 81 | /// 82 | /// 83 | Task IssueNonFungibleToken(Wallet wallet, string tokenName, string tokenTicker); 84 | 85 | /// 86 | /// One has to perform an issuance transaction in order to register a semi fungible token. 87 | /// Semi FungibleESDT Tokens are issued via a request to the Metachain, which is a transaction submitted by the Account which will manage the tokens 88 | /// When issuing a semi fungible token, one must provide a token name, a ticker, the initial quantity and optionally additional properties 89 | /// 90 | /// 91 | /// 92 | /// 93 | /// 94 | Task IssueSemiFungibleToken(Wallet wallet, string tokenName, string tokenTicker); 95 | 96 | Task> GetSpecialRole(string tokenIdentifier); 97 | 98 | Task SetSpecialRole(Wallet wallet, string tokenIdentifier, params string[] roles); 99 | 100 | Task CreateNftToken( 101 | Wallet wallet, 102 | string tokenIdentifier, 103 | BigInteger quantity, 104 | string tokenName, 105 | ushort royalties, 106 | Dictionary attributes, 107 | Uri[] uris, 108 | byte[] hash = null); 109 | 110 | Task> GetEsdtTokens(Address address); 111 | 112 | Task GetEsdtFungibleToken(Address address, string tokenIdentifier); 113 | 114 | Task GetEsdtNonFungibleToken(Address address, string tokenIdentifier, ulong tokenId); 115 | 116 | Task TransferEsdtToken(Wallet wallet, EsdtToken token, Address receiver, BigInteger quantity); 117 | 118 | Task TransferEsdtTokenToSmartContract(Wallet wallet, EsdtToken token, Address smartContract, 119 | string functionName, BigInteger quantity, params IBinaryType[] args); 120 | ``` -------------------------------------------------------------------------------- /docs/basic.md: -------------------------------------------------------------------------------- 1 | # [Documentation](./index.md) 2 | ## Basic usage 3 | 4 | ### Load a JSON Key file and create a Wallet instance 5 | Here's a key file JSON for Alice account, do not use the key file in mainnet. 6 | ```json 7 | { 8 | "version": 4, 9 | "id": "0dc10c02-b59b-4bac-9710-6b2cfa4284ba", 10 | "address": "0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", 11 | "bech32": "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", 12 | "crypto": { 13 | "ciphertext": 14 | "4c41ef6fdfd52c39b1585a875eb3c86d30a315642d0e35bb8205b6372c1882f135441099b11ff76345a6f3a930b5665aaf9f7325a32c8ccd60081c797aa2d538", 15 | "cipherparams": { 16 | "iv": "033182afaa1ebaafcde9ccc68a5eac31" 17 | }, 18 | "cipher": "aes-128-ctr", 19 | "kdf": "scrypt", 20 | "kdfparams": { 21 | "dklen": 32, 22 | "salt": "4903bd0e7880baa04fc4f886518ac5c672cdc745a6bd13dcec2b6c12e9bffe8d", 23 | "n": 4096, 24 | "r": 8, 25 | "p": 1 26 | }, 27 | "mac": "5b4a6f14ab74ba7ca23db6847e28447f0e6a7724ba9664cf425df707a84f5a8b" 28 | } 29 | } 30 | ``` 31 | We can create a [`Wallet`](../src/Domain/Wallet.cs) instance by providing this key file and the associated password : 32 | ```csharp 33 | var filePath = "path/to/keyfile.json"; 34 | var password = "password"; 35 | var wallet = Wallet.DeriveFromKeyFile(KeyFile.FromFilePath(filePath), password); 36 | ``` 37 | 38 | For more usage please, see the [WalletTest.cs](../tests/Erdcsharp.Tests/Domain/WalletTests.cs) file. 39 | 40 | 41 | ### Create an Account, Address and TokenAmount instance 42 | An [`Account`](../src/Domain/Account.cs) instance is build from an [`Address`](../src/Domain/Address.cs) 43 | 44 | We have multiple way to build an [`Address`](../src/Domain/Address.cs) 45 | * By providing the bech32 address form 46 | ```csharp 47 | Address.FromBech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th") 48 | ``` 49 | * By providing the hex address form 50 | ```csharp 51 | Address.FromHex("0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1") 52 | ``` 53 | * By providing a valid bytes array 54 | ```csharp 55 | Address.FromBytes(new byte[] {0x00, 0x00, [...]}); 56 | ``` 57 | 58 | Full usage example below : 59 | [C# Snippet from integration tests](../tests/Erdcsharp.IntegrationTests/AccountIntegrationTests.cs) 60 | ```csharp 61 | [Test(Description = "Synchronize an account from the network")] 62 | public async Task Should_Get_Alice_Balance() 63 | { 64 | var alice = new Account(Address.FromBech32(TestData.AliceBech32)); 65 | await alice.Sync(_provider); 66 | 67 | Assert.That(alice.Balance.Token.Ticker, Is.EqualTo("EGLD")); 68 | Assert.That(alice.Nonce, Is.Not.Null); //5456 69 | Assert.That(alice.Balance.Value, Is.Not.Null); //7076251965849781128 70 | Assert.That(alice.Balance.ToCurrencyString(), Is.Not.Null); //7.076251965849781128 EGLD 71 | } 72 | ``` 73 | ## Send a transaction 74 | ### Build and sign a transaction 75 | 76 | First, we need to get a valid [`NetworkConfig`](../src/Domain/NetworkConfig.cs) instance. 77 | 78 | ```csharp 79 | var networkConfig = await NetworkConfig.GetFromNetwork(provider); 80 | ``` 81 | 82 | Then, we can build a [`TransactionRequest`](../src/Domain/TransactionRequest.cs) and send it with the provider. 83 | 84 | ```csharp 85 | // Ensure that the account in synchronize with the network to have a valid Nonce 86 | await aliceAccount.Sync(_provider); 87 | 88 | // Alice send 1 EGLD to bob 89 | var txRequest = TransactionRequest.Create(aliceAccount, networkConfig, bobAddress, TokenAmount.EGLD("1")); 90 | var tx = await txRequest.Send(_provider, aliceWallet); 91 | 92 | // Await the execution of the transaction 93 | await tx.AwaitExecuted(_provider); 94 | ``` 95 | 96 | ### Fetch transaction detail from the network 97 | 98 | We can the transaction detail from the network with the provider by calling the `GetTransactionDetail` method. 99 | ```csharp 100 | var transactionDetail = await _provider.GetTransactionDetail("ca5f97d1542307ae75086c6284ada1ed5db0dcc639e2ac2ad4fa59d3949c5e3a"); 101 | ``` -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/multiversx/mx-sdk-csharp/408d85058ca419cff59ec92fed1030faebe44c17/docs/index.md -------------------------------------------------------------------------------- /src/Configuration/ElrondNetworkConfiguration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Erdcsharp.Configuration 4 | { 5 | public class ElrondNetworkConfiguration 6 | { 7 | public ElrondNetworkConfiguration(Network network) 8 | { 9 | Network = network; 10 | switch (network) 11 | { 12 | case Network.MainNet: 13 | GatewayUri = new Uri("https://gateway.elrond.com"); 14 | ExplorerUri = new Uri("https://explorer.elrond.com/"); 15 | break; 16 | case Network.TestNet: 17 | GatewayUri = new Uri("https://testnet-gateway.elrond.com"); 18 | ExplorerUri = new Uri("https://testnet-explorer.elrond.com/"); 19 | break; 20 | case Network.DevNet: 21 | GatewayUri = new Uri("https://devnet-gateway.elrond.com"); 22 | ExplorerUri = new Uri("https://devnet-explorer.elrond.com/"); 23 | break; 24 | default: 25 | throw new ArgumentOutOfRangeException(nameof(network), network, null); 26 | } 27 | } 28 | 29 | public Network Network { get; } 30 | public Uri GatewayUri { get; } 31 | public Uri ExplorerUri { get; } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Configuration/Network.cs: -------------------------------------------------------------------------------- 1 | namespace Erdcsharp.Configuration 2 | { 3 | public enum Network 4 | { 5 | LocalNet, 6 | MainNet, 7 | TestNet, 8 | DevNet 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Cryptography/AesCtr.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Cryptography; 2 | 3 | namespace Erdcsharp.Cryptography 4 | { 5 | public sealed class AesCtr 6 | { 7 | public static byte[] Encrypt(byte[] psk, byte[] iv, byte[] inData) 8 | { 9 | var aesObj = Aes.Create(); 10 | aesObj.Mode = CipherMode.ECB; 11 | aesObj.Padding = PaddingMode.None; 12 | var zeroIv = new byte[16]; 13 | var encrypt = aesObj.CreateEncryptor(psk, zeroIv); 14 | var counter = new byte[16]; 15 | for (var i = 0; i < 16; i++) 16 | { 17 | counter[i] = iv[i]; 18 | } 19 | 20 | var ctrOut = new byte[16]; 21 | var output = new byte[inData.Length]; 22 | var pos = 0; 23 | while (true) 24 | { 25 | if (pos >= inData.Length) 26 | { 27 | break; 28 | } 29 | 30 | encrypt.TransformBlock(counter, 0, 16, ctrOut, 0); 31 | for (var i = 0; i < 16; i++) 32 | { 33 | if (pos >= inData.Length) 34 | { 35 | break; 36 | } 37 | 38 | output[pos] = (byte)(inData[pos] ^ ctrOut[i]); 39 | pos++; 40 | } 41 | 42 | // increment counter 43 | for (var i = 15; i >= 0; i--) 44 | { 45 | counter[i]++; 46 | if (counter[i] != 0) 47 | { 48 | break; 49 | } 50 | } 51 | } 52 | 53 | return output; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Domain/Abi/Abi.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Erdcsharp.Domain.Abi 4 | { 5 | public class Abi 6 | { 7 | public class Input 8 | { 9 | public string Name { get; set; } 10 | public string Type { get; set; } 11 | [JsonProperty("multi_arg")] public bool MultiArg { get; set; } 12 | } 13 | 14 | public class CustomTypes 15 | { 16 | public string Type { get; set; } 17 | public Field[] Fields { get; set; } 18 | } 19 | 20 | public class Field 21 | { 22 | public string Name { get; set; } 23 | public string Type { get; set; } 24 | } 25 | 26 | public class Endpoint 27 | { 28 | public string Name { get; set; } 29 | public Input[] Inputs { get; set; } 30 | public Output[] Outputs { get; set; } 31 | public string[] PayableInTokens { get; set; } 32 | } 33 | 34 | public class Output 35 | { 36 | public string Type { get; set; } 37 | [JsonProperty("multi_result")] public bool MultiResult { get; set; } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Domain/Abi/AbiDefinition.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Text.RegularExpressions; 7 | using Erdcsharp.Domain.Values; 8 | 9 | namespace Erdcsharp.Domain.Abi 10 | { 11 | public class AbiDefinition 12 | { 13 | public string Name { get; set; } 14 | public Abi.Endpoint[] Endpoints { get; set; } 15 | public Dictionary Types { get; set; } 16 | 17 | public EndpointDefinition GetEndpointDefinition(string endpoint) 18 | { 19 | var data = Endpoints.ToList().SingleOrDefault(s => s.Name == endpoint); 20 | if (data == null) 21 | throw new Exception("Endpoint is not define in ABI"); 22 | 23 | var inputs = data.Inputs.Select(i => new FieldDefinition(i.Name, "", GetTypeValue(i.Type))).ToList(); 24 | var outputs = data.Outputs.Select(i => new FieldDefinition("", "", GetTypeValue(i.Type))).ToList(); 25 | return new EndpointDefinition(endpoint, inputs.ToArray(), outputs.ToArray()); 26 | } 27 | 28 | private TypeValue GetTypeValue(string rustType) 29 | { 30 | var optional = new Regex("^optional<(.*)>$"); 31 | var multi = new Regex("^multi<(.*)>$"); 32 | 33 | if (optional.IsMatch(rustType)) 34 | { 35 | var innerType = optional.Match(rustType).Groups[1].Value; 36 | var innerTypeValue = GetTypeValue(innerType); 37 | return TypeValue.OptionValue(innerTypeValue); 38 | } 39 | 40 | if (multi.IsMatch(rustType)) 41 | { 42 | var innerTypes = multi.Match(rustType).Groups[1].Value.Split(',').Where(s => !string.IsNullOrEmpty(s)); 43 | var innerTypeValues = innerTypes.Select(GetTypeValue).ToArray(); 44 | return TypeValue.MultiValue(innerTypeValues); 45 | } 46 | 47 | var typeFromBaseRustType = TypeValue.FromRustType(rustType); 48 | if (typeFromBaseRustType != null) 49 | return typeFromBaseRustType; 50 | 51 | if (Types.Keys.Contains(rustType)) 52 | { 53 | var typeFromStruct = Types[rustType]; 54 | return TypeValue.StructValue( 55 | typeFromStruct.Type, 56 | typeFromStruct.Fields 57 | .ToList() 58 | .Select(c => new FieldDefinition(c.Name, "", GetTypeValue(c.Type))) 59 | .ToArray() 60 | ); 61 | } 62 | 63 | return null; 64 | } 65 | 66 | public static AbiDefinition FromJson(string json) 67 | { 68 | return Helper.JsonSerializerWrapper.Deserialize(json); 69 | } 70 | 71 | public static AbiDefinition FromFilePath(string jsonFilePath) 72 | { 73 | var fileBytes = File.ReadAllBytes(jsonFilePath); 74 | var json = Encoding.UTF8.GetString(fileBytes); 75 | return FromJson(json); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Domain/Abi/EndpointDefinition.cs: -------------------------------------------------------------------------------- 1 | using Erdcsharp.Domain.Values; 2 | 3 | namespace Erdcsharp.Domain.Abi 4 | { 5 | public class EndpointDefinition 6 | { 7 | public string Name { get; } 8 | public FieldDefinition[] Input { get; } 9 | public FieldDefinition[] Output { get; } 10 | 11 | public EndpointDefinition(string name, FieldDefinition[] input, FieldDefinition[] output) 12 | { 13 | Name = name; 14 | Input = input; 15 | Output = output; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Domain/Account.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Erdcsharp.Provider; 3 | 4 | namespace Erdcsharp.Domain 5 | { 6 | public class Account 7 | { 8 | public Address Address { get; } 9 | public TokenAmount Balance { get; private set; } 10 | public long Nonce { get; private set; } 11 | public string UserName { get; private set; } 12 | 13 | public Account(Address address) 14 | { 15 | Address = address; 16 | Nonce = 0; 17 | Balance = TokenAmount.Zero(); 18 | UserName = null; 19 | } 20 | 21 | /// 22 | /// Synchronizes account properties (such as nonce, balance) with the ones queried from the Network 23 | /// 24 | /// 25 | /// 26 | public async Task Sync(IElrondProvider provider) 27 | { 28 | var accountDto = await provider.GetAccount(Address.Bech32); 29 | 30 | Balance = TokenAmount.From(accountDto.Balance, Token.EGLD()); 31 | Nonce = accountDto.Nonce; 32 | UserName = accountDto.Username; 33 | } 34 | 35 | /// 36 | /// Increments (locally) the nonce (the account sequence number). 37 | /// 38 | public void IncrementNonce() 39 | { 40 | Nonce++; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Domain/Address.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Erdcsharp.Cryptography; 3 | using Erdcsharp.Domain.Exceptions; 4 | using Erdcsharp.Domain.Helper; 5 | using Erdcsharp.Domain.Values; 6 | 7 | namespace Erdcsharp.Domain 8 | { 9 | public class Address : BaseBinaryValue 10 | { 11 | // The human-readable-part of the bech32 addresses. 12 | private const string Hrp = Constants.Hrp; 13 | private const int PubKeyLength = 32; 14 | private const string SmartContractHexPubKeyPrefix = "0000000000000000"; 15 | 16 | private Address(string hex, string bech32) 17 | : base(TypeValue.AddressValue) 18 | { 19 | Bech32 = bech32.ToLowerInvariant(); 20 | Hex = hex.ToUpperInvariant(); 21 | } 22 | 23 | /// 24 | /// Returns the bech32 representation of the address 25 | /// 26 | public string Bech32 { get; } 27 | 28 | /// 29 | /// Returns the hex representation of the address (pubkey) 30 | /// 31 | public string Hex { get; } 32 | 33 | /// 34 | /// Creates an address object from a Buffer 35 | /// 36 | /// The buffer 37 | /// Address 38 | public static Address FromBytes(byte[] data) 39 | { 40 | var hex = Converter.ToHexString(data); 41 | var bech32 = Bech32Engine.Encode(Hrp, data); 42 | return new Address(hex, bech32); 43 | } 44 | 45 | /// 46 | /// Creates an address from a string (Hex or bech32) 47 | /// 48 | /// 49 | /// Address 50 | public static Address From(string value) 51 | { 52 | try 53 | { 54 | return IsValidHex(value) ? FromHex(value) : FromBech32(value); 55 | } 56 | catch 57 | { 58 | throw new CannotCreateAddressException(value); 59 | } 60 | } 61 | 62 | /// 63 | /// Creates an address from a hex string 64 | /// 65 | /// 66 | /// Address 67 | public static Address FromHex(string hex) 68 | { 69 | try 70 | { 71 | var bech32 = Bech32Engine.Encode(Hrp, Converter.FromHexString(hex)); 72 | return new Address(hex, bech32); 73 | } 74 | catch 75 | { 76 | throw new CannotCreateAddressException(hex); 77 | } 78 | } 79 | 80 | /// 81 | /// Creates an address from a bech32 string 82 | /// 83 | /// 84 | /// Address 85 | public static Address FromBech32(string bech32) 86 | { 87 | try 88 | { 89 | Bech32Engine.Decode(bech32, out _, out var data); 90 | var hex = Converter.ToHexString(data); 91 | return new Address(hex, bech32); 92 | } 93 | catch 94 | { 95 | throw new CannotCreateAddressException(bech32); 96 | } 97 | } 98 | 99 | /// 100 | /// Creates the Zero address (the one that should be used when deploying smart contracts) 101 | /// 102 | /// Address 103 | public static Address Zero() 104 | { 105 | const string hex = "0000000000000000000000000000000000000000000000000000000000000000"; 106 | return FromHex(hex); 107 | } 108 | 109 | public byte[] PublicKey() 110 | { 111 | return Converter.FromHexString(Hex); 112 | } 113 | 114 | public bool IsContractAddress() => Hex.StartsWith(SmartContractHexPubKeyPrefix); 115 | 116 | public override string ToString() 117 | { 118 | return Bech32; 119 | } 120 | 121 | public override bool Equals(object obj) 122 | { 123 | if (!(obj is Address item)) 124 | { 125 | return false; 126 | } 127 | 128 | return Hex.Equals(item.Hex, StringComparison.CurrentCultureIgnoreCase); 129 | } 130 | 131 | public override int GetHashCode() 132 | { 133 | return Hex.GetHashCode(); 134 | } 135 | 136 | private static bool IsValidHex(string value) 137 | { 138 | return value.FromHex().Length == PubKeyLength; 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/Domain/Codec/AddressBinaryCodec.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Erdcsharp.Domain.Exceptions; 3 | using Erdcsharp.Domain.Values; 4 | 5 | namespace Erdcsharp.Domain.Codec 6 | { 7 | public class AddressBinaryCodec : IBinaryCodec 8 | { 9 | public string Type => TypeValue.BinaryTypes.Address; 10 | 11 | public (IBinaryType Value, int BytesLength) DecodeNested(byte[] data, TypeValue type) 12 | { 13 | // We don't check the size of the buffer, we just read 32 bytes. 14 | var addressBytes = data.Take(32).ToArray(); 15 | var value = Address.FromBytes(addressBytes); 16 | return (value, addressBytes.Length); 17 | } 18 | 19 | public IBinaryType DecodeTopLevel(byte[] data, TypeValue type) 20 | { 21 | var result = DecodeNested(data, type); 22 | return result.Value; 23 | } 24 | 25 | public byte[] EncodeNested(IBinaryType value) 26 | { 27 | var address = Get(value); 28 | return address.PublicKey(); 29 | } 30 | 31 | public byte[] EncodeTopLevel(IBinaryType value) 32 | { 33 | var address = Get(value); 34 | return address.PublicKey(); 35 | } 36 | 37 | private static Address Get(IBinaryType value) 38 | { 39 | if (value is Address address) 40 | { 41 | return address; 42 | } 43 | 44 | throw new WrongBinaryValueCodecException(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Domain/Codec/BinaryCodec.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Erdcsharp.Domain.Exceptions; 4 | using Erdcsharp.Domain.Values; 5 | 6 | namespace Erdcsharp.Domain.Codec 7 | { 8 | public class BinaryCodec 9 | { 10 | private readonly List _codecs; 11 | 12 | public BinaryCodec() 13 | { 14 | _codecs = new List 15 | { 16 | new NumericBinaryCodec(), 17 | new AddressBinaryCodec(), 18 | new BooleanBinaryCodec(), 19 | new BytesBinaryCodec(), 20 | new TokenIdentifierCodec(), 21 | new StructBinaryCodec(this), 22 | new OptionBinaryCodec(this), 23 | }; 24 | } 25 | 26 | public (IBinaryType Value, int BytesLength) DecodeNested(byte[] data, TypeValue type) 27 | { 28 | CheckBufferLength(data); 29 | 30 | var codec = _codecs.SingleOrDefault(c => c.Type == type.BinaryType); 31 | if (codec == null) 32 | throw new BinaryCodecException($"No codec found for {type.BinaryType}"); 33 | 34 | var decode = codec.DecodeNested(data, type); 35 | return decode; 36 | } 37 | 38 | public IBinaryType DecodeTopLevel(byte[] data, TypeValue type) 39 | { 40 | CheckBufferLength(data); 41 | 42 | var codec = _codecs.SingleOrDefault(c => c.Type == type.BinaryType); 43 | if (codec == null) 44 | throw new BinaryCodecException($"No codec found for {type.BinaryType}"); 45 | 46 | var decode = codec.DecodeTopLevel(data, type); 47 | return decode; 48 | } 49 | 50 | public byte[] EncodeNested(IBinaryType value) 51 | { 52 | var codec = _codecs.SingleOrDefault(c => c.Type == value.Type.BinaryType); 53 | if (codec == null) 54 | throw new BinaryCodecException($"No codec found for {value.Type.BinaryType}"); 55 | 56 | var encode = codec.EncodeNested(value); 57 | return encode; 58 | } 59 | 60 | public byte[] EncodeTopLevel(IBinaryType value) 61 | { 62 | var codec = _codecs.SingleOrDefault(c => c.Type == value.Type.BinaryType); 63 | if (codec == null) 64 | throw new BinaryCodecException($"No codec found for {value.Type.BinaryType}"); 65 | 66 | var encode = codec.EncodeTopLevel(value); 67 | return encode; 68 | } 69 | 70 | private static void CheckBufferLength(byte[] buffer) 71 | { 72 | if (buffer.Length > 4096) 73 | { 74 | throw new BinaryCodecException("Buffer too large"); 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Domain/Codec/BooleanBinaryCodec.cs: -------------------------------------------------------------------------------- 1 | using Erdcsharp.Domain.Exceptions; 2 | using Erdcsharp.Domain.Values; 3 | 4 | namespace Erdcsharp.Domain.Codec 5 | { 6 | public class BooleanBinaryCodec : IBinaryCodec 7 | { 8 | public string Type => TypeValue.BinaryTypes.Boolean; 9 | 10 | private const byte True = 0x01; 11 | private const byte False = 0x00; 12 | 13 | public (IBinaryType Value, int BytesLength) DecodeNested(byte[] data, TypeValue type) 14 | { 15 | // We don't check the size of the buffer, we just read the first byte. 16 | var firstByte = data[0]; 17 | return (new BooleanValue(firstByte == True), 1); 18 | } 19 | 20 | public IBinaryType DecodeTopLevel(byte[] data, TypeValue type) 21 | { 22 | if (data.Length > 1) 23 | { 24 | throw new BinaryCodecException("should be a buffer of size <= 1"); 25 | } 26 | 27 | var firstByte = data[0]; 28 | return new BooleanValue(firstByte == True); 29 | } 30 | 31 | public byte[] EncodeNested(IBinaryType value) 32 | { 33 | var boolean = value.ValueOf(); 34 | return boolean.IsTrue() ? new[] {True} : new[] {False}; 35 | } 36 | 37 | public byte[] EncodeTopLevel(IBinaryType value) 38 | { 39 | var boolean = value.ValueOf(); 40 | return boolean.IsTrue() ? new[] {True} : new byte[0]; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Domain/Codec/BytesBinaryCodec.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Erdcsharp.Domain.Helper; 5 | using Erdcsharp.Domain.Values; 6 | 7 | namespace Erdcsharp.Domain.Codec 8 | { 9 | public class BytesBinaryCodec : IBinaryCodec 10 | { 11 | public string Type => TypeValue.BinaryTypes.Bytes; 12 | 13 | private const int BytesSizeOfU32 = 4; 14 | 15 | public (IBinaryType Value, int BytesLength) DecodeNested(byte[] data, TypeValue type) 16 | { 17 | var sizeInBytes = (int)BitConverter.ToUInt32(data.Take(BytesSizeOfU32).ToArray(), 0); 18 | if (BitConverter.IsLittleEndian) 19 | { 20 | sizeInBytes = (int)BitConverter.ToUInt32(BitConverter.GetBytes(sizeInBytes).Reverse().ToArray(), 0); 21 | } 22 | 23 | var payload = data.Slice(BytesSizeOfU32, BytesSizeOfU32 + sizeInBytes); 24 | 25 | return (new BytesValue(payload, type), sizeInBytes + payload.Length); 26 | } 27 | 28 | public IBinaryType DecodeTopLevel(byte[] data, TypeValue type) 29 | { 30 | return new BytesValue(data, type); 31 | } 32 | 33 | public byte[] EncodeNested(IBinaryType value) 34 | { 35 | var bytes = value.ValueOf(); 36 | var buffer = new List(); 37 | var lengthBytes = BitConverter.GetBytes(bytes.GetLength()); 38 | if (BitConverter.IsLittleEndian) 39 | { 40 | lengthBytes = lengthBytes.Reverse().ToArray(); 41 | } 42 | 43 | buffer.AddRange(lengthBytes); 44 | buffer.AddRange(bytes.Buffer); 45 | 46 | var data = buffer.ToArray(); 47 | 48 | return data; 49 | } 50 | 51 | public byte[] EncodeTopLevel(IBinaryType value) 52 | { 53 | var bytes = value.ValueOf(); 54 | return bytes.Buffer; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Domain/Codec/IBinaryCodec.cs: -------------------------------------------------------------------------------- 1 | using Erdcsharp.Domain.Values; 2 | 3 | namespace Erdcsharp.Domain.Codec 4 | { 5 | internal interface IBinaryCodec 6 | { 7 | /// 8 | /// constants 9 | /// 10 | string Type { get; } 11 | 12 | (IBinaryType Value, int BytesLength) DecodeNested(byte[] data, TypeValue type); 13 | 14 | IBinaryType DecodeTopLevel(byte[] data, TypeValue type); 15 | 16 | byte[] EncodeNested(IBinaryType value); 17 | 18 | byte[] EncodeTopLevel(IBinaryType value); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Domain/Codec/MultiBinaryCodec.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Erdcsharp.Domain.Values; 4 | 5 | namespace Erdcsharp.Domain.Codec 6 | { 7 | public class MultiBinaryCodec : IBinaryCodec 8 | { 9 | private readonly BinaryCodec _binaryCodec; 10 | 11 | public MultiBinaryCodec(BinaryCodec binaryCodec) 12 | { 13 | _binaryCodec = binaryCodec; 14 | } 15 | 16 | public string Type => TypeValue.BinaryTypes.Multi; 17 | 18 | public (IBinaryType Value, int BytesLength) DecodeNested(byte[] data, TypeValue type) 19 | { 20 | var result = new Dictionary(); 21 | var buffer = data.ToList(); 22 | var offset = 0; 23 | foreach (var multiType in type.MultiTypes) 24 | { 25 | var (value, bytesLength) = _binaryCodec.DecodeNested(buffer.ToArray(), multiType); 26 | result.Add(multiType, value); 27 | offset += bytesLength; 28 | buffer = buffer.Skip(bytesLength).ToList(); 29 | } 30 | 31 | var multiValue = new MultiValue(type, result); 32 | return (multiValue, offset); 33 | } 34 | 35 | public IBinaryType DecodeTopLevel(byte[] data, TypeValue type) 36 | { 37 | var decoded = DecodeNested(data, type); 38 | return decoded.Value; 39 | } 40 | 41 | public byte[] EncodeNested(IBinaryType value) 42 | { 43 | var multiValueObject = value.ValueOf(); 44 | var buffers = new List(); 45 | 46 | foreach (var multiValue in multiValueObject.Values) 47 | { 48 | var fieldBuffer = _binaryCodec.EncodeNested(multiValue.Value); 49 | buffers.Add(fieldBuffer); 50 | } 51 | 52 | var data = buffers.SelectMany(s => s); 53 | return data.ToArray(); 54 | } 55 | 56 | public byte[] EncodeTopLevel(IBinaryType value) 57 | { 58 | return EncodeNested(value); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Domain/Codec/NumericBinaryCodec.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Numerics; 5 | using Erdcsharp.Domain.Helper; 6 | using Erdcsharp.Domain.Values; 7 | 8 | namespace Erdcsharp.Domain.Codec 9 | { 10 | public class NumericBinaryCodec : IBinaryCodec 11 | { 12 | public string Type => TypeValue.BinaryTypes.Numeric; 13 | 14 | public (IBinaryType Value, int BytesLength) DecodeNested(byte[] data, TypeValue type) 15 | { 16 | if (type.HasFixedSize()) 17 | { 18 | var length = type.SizeInBytes(); 19 | var payload = data.Slice(0, length); 20 | var result = DecodeTopLevel(payload, type); 21 | return (result, length); 22 | } 23 | else 24 | { 25 | const int u32Size = 4; 26 | var sizeInBytes = (int)BitConverter.ToUInt32(data.Slice(0, u32Size), 0); 27 | if (BitConverter.IsLittleEndian) 28 | { 29 | sizeInBytes = (int)BitConverter.ToUInt32(data.Slice(0, u32Size).Reverse().ToArray(), 0); 30 | } 31 | 32 | var payload = data.Skip(u32Size).Take(sizeInBytes).ToArray(); 33 | var bigNumber = Converter.ToBigInteger(payload, !type.HasSign(), isBigEndian: true); 34 | return (new NumericValue(type, bigNumber), sizeInBytes + u32Size); 35 | } 36 | } 37 | 38 | public IBinaryType DecodeTopLevel(byte[] data, TypeValue type) 39 | { 40 | if (data.Length == 0) 41 | { 42 | return new NumericValue(type, new BigInteger(0)); 43 | } 44 | 45 | var bigNumber = Converter.ToBigInteger(data, !type.HasSign(), isBigEndian: true); 46 | return new NumericValue(type, bigNumber); 47 | } 48 | 49 | public byte[] EncodeNested(IBinaryType value) 50 | { 51 | var numericValue = value.ValueOf(); 52 | if (value.Type.HasFixedSize()) 53 | { 54 | var sizeInBytes = value.Type.SizeInBytes(); 55 | var number = numericValue.Number; 56 | var fullArray = Enumerable.Repeat((byte)0x00, sizeInBytes).ToArray(); 57 | if (number.IsZero) 58 | { 59 | return fullArray; 60 | } 61 | 62 | var payload = Converter.FromBigInteger(number, !value.Type.HasSign(), true); 63 | var payloadLength = payload.Length; 64 | 65 | var buffer = new List(); 66 | buffer.AddRange(fullArray.Slice(0, sizeInBytes - payloadLength)); 67 | buffer.AddRange(payload); 68 | var data = buffer.ToArray(); 69 | return data; 70 | } 71 | else 72 | { 73 | var payload = EncodeTopLevel(value); 74 | var sizeBytes = BitConverter.GetBytes(payload.Length).ToList(); 75 | if (BitConverter.IsLittleEndian) 76 | { 77 | sizeBytes.Reverse(); 78 | } 79 | 80 | var buffer = new List(); 81 | buffer.AddRange(sizeBytes); 82 | buffer.AddRange(payload); 83 | var data = buffer.ToArray(); 84 | return data; 85 | } 86 | } 87 | 88 | public byte[] EncodeTopLevel(IBinaryType value) 89 | { 90 | var numericValue = value.ValueOf(); 91 | if (numericValue.Number.IsZero) 92 | { 93 | return new byte[0]; 94 | } 95 | 96 | var isUnsigned = !value.Type.HasSign(); 97 | var buffer = Converter.FromBigInteger(numericValue.Number, isUnsigned, isBigEndian: true); 98 | 99 | return buffer; 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/Domain/Codec/OptionBinaryCodec.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Erdcsharp.Domain.Exceptions; 3 | using Erdcsharp.Domain.Helper; 4 | using Erdcsharp.Domain.Values; 5 | 6 | namespace Erdcsharp.Domain.Codec 7 | { 8 | public class OptionBinaryCodec : IBinaryCodec 9 | { 10 | private readonly BinaryCodec _binaryCodec; 11 | 12 | public OptionBinaryCodec(BinaryCodec binaryCodec) 13 | { 14 | _binaryCodec = binaryCodec; 15 | } 16 | 17 | public string Type => TypeValue.BinaryTypes.Option; 18 | 19 | public (IBinaryType Value, int BytesLength) DecodeNested(byte[] data, TypeValue type) 20 | { 21 | if (data[0] == 0x00) 22 | { 23 | return (OptionValue.NewMissing(), 1); 24 | } 25 | 26 | if (data[0] != 0x01) 27 | { 28 | throw new BinaryCodecException("invalid buffer for optional value"); 29 | } 30 | 31 | var (value, bytesLength) = _binaryCodec.DecodeNested(data.Slice(1), type.InnerType); 32 | return (OptionValue.NewProvided(value), bytesLength + 1); 33 | } 34 | 35 | public IBinaryType DecodeTopLevel(byte[] data, TypeValue type) 36 | { 37 | if (data.Length == 0) 38 | { 39 | return OptionValue.NewMissing(); 40 | } 41 | 42 | var decoded = _binaryCodec.DecodeTopLevel(data, type.InnerType); 43 | return OptionValue.NewProvided(decoded); 44 | } 45 | 46 | public byte[] EncodeNested(IBinaryType value) 47 | { 48 | var optionValue = value.ValueOf(); 49 | if (optionValue.IsSet()) 50 | { 51 | var encoded = _binaryCodec.EncodeNested(optionValue.Value); 52 | var payload = new List {0x01}; 53 | payload.AddRange(encoded); 54 | return payload.ToArray(); 55 | } 56 | 57 | return new byte[] {0x00}; 58 | } 59 | 60 | public byte[] EncodeTopLevel(IBinaryType value) 61 | { 62 | var optionValue = value.ValueOf(); 63 | if (optionValue.IsSet()) 64 | return EncodeNested(value); 65 | 66 | return new byte[] { }; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/Domain/Codec/StructBinaryCodec.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Erdcsharp.Domain.Values; 4 | 5 | namespace Erdcsharp.Domain.Codec 6 | { 7 | public class StructBinaryCodec : IBinaryCodec 8 | { 9 | private readonly BinaryCodec _binaryCodec; 10 | public string Type => TypeValue.BinaryTypes.Struct; 11 | 12 | public StructBinaryCodec(BinaryCodec binaryCodec) 13 | { 14 | _binaryCodec = binaryCodec; 15 | } 16 | 17 | public (IBinaryType Value, int BytesLength) DecodeNested(byte[] data, TypeValue type) 18 | { 19 | var fieldDefinitions = type.GetFieldDefinitions(); 20 | var fields = new List(); 21 | var buffer = data.ToList(); 22 | var offset = 0; 23 | foreach (var fieldDefinition in fieldDefinitions) 24 | { 25 | var (value, bytesLength) = _binaryCodec.DecodeNested(buffer.ToArray(), fieldDefinition.Type); 26 | fields.Add(new StructField(fieldDefinition.Name, value)); 27 | 28 | offset += bytesLength; 29 | buffer = buffer.Skip(bytesLength).ToList(); 30 | } 31 | 32 | var structObject = new StructValue(type, fields.ToArray()); 33 | 34 | return (structObject, offset); 35 | } 36 | 37 | public IBinaryType DecodeTopLevel(byte[] data, TypeValue type) 38 | { 39 | var decoded = DecodeNested(data, type); 40 | return decoded.Value; 41 | } 42 | 43 | public byte[] EncodeNested(IBinaryType value) 44 | { 45 | var structValue = value.ValueOf(); 46 | var buffers = new List(); 47 | var fields = structValue.Fields; 48 | 49 | foreach (var field in fields) 50 | { 51 | var fieldBuffer = _binaryCodec.EncodeNested(field.Value); 52 | buffers.Add(fieldBuffer); 53 | } 54 | 55 | var data = buffers.SelectMany(s => s); 56 | 57 | return data.ToArray(); 58 | } 59 | 60 | public byte[] EncodeTopLevel(IBinaryType value) 61 | { 62 | return EncodeNested(value); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Domain/Codec/TokenIdentifierCodec.cs: -------------------------------------------------------------------------------- 1 | using Erdcsharp.Domain.Exceptions; 2 | using Erdcsharp.Domain.Values; 3 | 4 | namespace Erdcsharp.Domain.Codec 5 | { 6 | public class TokenIdentifierCodec : IBinaryCodec 7 | { 8 | private readonly BytesBinaryCodec _bytesBinaryCodec; 9 | 10 | public TokenIdentifierCodec() 11 | { 12 | _bytesBinaryCodec = new BytesBinaryCodec(); 13 | } 14 | 15 | public string Type => TypeValue.BinaryTypes.TokenIdentifier; 16 | 17 | public (IBinaryType Value, int BytesLength) DecodeNested(byte[] data, TypeValue type) 18 | { 19 | var (value, bytesLength) = _bytesBinaryCodec.DecodeNested(data, type); 20 | return (TokenIdentifierValue.From(value.ValueOf().Buffer), bytesLength); 21 | } 22 | 23 | public IBinaryType DecodeTopLevel(byte[] data, TypeValue type) 24 | { 25 | var bytesValue = _bytesBinaryCodec.DecodeTopLevel(data, type); 26 | return TokenIdentifierValue.From(bytesValue.ValueOf().Buffer); 27 | } 28 | 29 | public byte[] EncodeNested(IBinaryType value) 30 | { 31 | var tokenIdentifierValue = Get(value); 32 | var byteValue = new BytesValue(tokenIdentifierValue.Buffer, TypeValue.TokenIdentifierValue); 33 | return _bytesBinaryCodec.EncodeNested(byteValue); 34 | } 35 | 36 | public byte[] EncodeTopLevel(IBinaryType value) 37 | { 38 | var tokenIdentifierValue = Get(value); 39 | return tokenIdentifierValue.Buffer; 40 | } 41 | 42 | private static TokenIdentifierValue Get(IBinaryType value) 43 | { 44 | if (value is TokenIdentifierValue tokenIdentifierValue) 45 | { 46 | return tokenIdentifierValue; 47 | } 48 | 49 | throw new WrongBinaryValueCodecException(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Domain/Constants.cs: -------------------------------------------------------------------------------- 1 | namespace Erdcsharp.Domain 2 | { 3 | public static class Constants 4 | { 5 | public const string ArwenVirtualMachine = "0500"; 6 | 7 | /// 8 | /// Human-Readable Part 9 | /// 10 | public const string Hrp = "erd"; 11 | 12 | /// 13 | /// eGold ticker 14 | /// 15 | public const string EGLD = "EGLD"; 16 | 17 | public static class SmartContractAddress 18 | { 19 | public const string EsdtSmartContract = "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u"; 20 | } 21 | 22 | public static class EsdtNftSpecialRoles 23 | { 24 | /// 25 | /// This role allows one to create a new NFT 26 | /// 27 | public const string EsdtRoleNftCreate = "ESDTRoleNFTCreate"; 28 | 29 | /// 30 | /// This role allows one to burn quantity of a specific NFT 31 | /// 32 | public const string EsdtRoleNftBurn = "ESDTRoleNFTBurn"; 33 | } 34 | 35 | public static class EsdtSftSpecialRoles 36 | { 37 | /// 38 | /// This role allows one to create a new SemiFungible 39 | /// 40 | public const string EsdtRoleNftCreate = "ESDTRoleNFTCreate"; 41 | 42 | /// 43 | /// This role allows one to burn quantity of a specific SemiFungible 44 | /// 45 | public const string EsdtRoleNftBurn = "ESDTRoleNFTBurn"; 46 | 47 | /// 48 | /// This role allows one to add quantity of a specific SemiFungible 49 | /// 50 | public const string EsdtRoleNftAddQuantity = "ESDTRoleNFTAddQuantity"; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Domain/EsdtTokenType.cs: -------------------------------------------------------------------------------- 1 | namespace Erdcsharp.Domain 2 | { 3 | public enum EsdtTokenType 4 | { 5 | FungibleESDT, 6 | SemiFungibleESDT, 7 | NonFungibleESDT 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Domain/Exceptions/AddressException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Erdcsharp.Domain.Exceptions 4 | { 5 | public class CannotCreateAddressException : Exception 6 | { 7 | public CannotCreateAddressException(string input) 8 | : base($"Cannot create address from {input}") 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Domain/Exceptions/BinaryCodecException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Erdcsharp.Domain.Exceptions 4 | { 5 | public class BinaryCodecException : Exception 6 | { 7 | public BinaryCodecException(string message) 8 | : base(message) 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Domain/Exceptions/GatewayException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Erdcsharp.Domain.Exceptions 4 | { 5 | public class GatewayException : Exception 6 | { 7 | public GatewayException(string errorMessage, string code) 8 | : base($"Error when calling Gateway : {errorMessage} with smartContractCode : {code}") 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Domain/Exceptions/InsufficientFundException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Erdcsharp.Domain.Exceptions 4 | { 5 | public class InsufficientFundException : Exception 6 | { 7 | public InsufficientFundException(string tokenIdentifier) 8 | : base($"Insufficient fund for token : {tokenIdentifier}") 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Domain/Exceptions/InvalidTokenAmountException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Erdcsharp.Domain.Exceptions 4 | { 5 | public class InvalidTokenAmountException : Exception 6 | { 7 | public InvalidTokenAmountException(string value) 8 | : base($"Invalid TokenAmount {value}") 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Domain/Exceptions/TransactionException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Erdcsharp.Domain.Exceptions 4 | { 5 | public class TransactionException 6 | { 7 | public class TransactionStatusNotReachedException : Exception 8 | { 9 | public TransactionStatusNotReachedException(string transactionHash, string expectedStatus) 10 | : base($"Cannot reach {expectedStatus} status for tx : '{transactionHash}'") 11 | { 12 | } 13 | } 14 | 15 | public class InvalidTransactionException : Exception 16 | { 17 | public InvalidTransactionException(string transactionHash) 18 | : base($"Transaction is invalid for tx : '{transactionHash}'") 19 | { 20 | } 21 | } 22 | 23 | public class FailedTransactionException : Exception 24 | { 25 | public FailedTransactionException(string transactionHash) 26 | : base($"Transaction failed for tx : '{transactionHash}'") 27 | { 28 | } 29 | } 30 | 31 | public class TransactionWithSmartContractErrorException : Exception 32 | { 33 | public TransactionWithSmartContractErrorException(string transactionHash, string message) 34 | : base($"Transaction tx : '{transactionHash}' has some error : {message}") 35 | { 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Domain/Exceptions/WrongBinaryValueCodecException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Erdcsharp.Domain.Exceptions 4 | { 5 | public class WrongBinaryValueCodecException : Exception 6 | { 7 | public WrongBinaryValueCodecException() 8 | : base("Wrong binary argument") 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Domain/GasLimit.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Erdcsharp.Provider; 4 | 5 | namespace Erdcsharp.Domain 6 | { 7 | public class GasLimit 8 | { 9 | public long Value { get; } 10 | 11 | public GasLimit(long value) 12 | { 13 | Value = value; 14 | } 15 | 16 | /// 17 | /// Compute GasLimit for transaction 18 | /// 19 | /// The network config 20 | /// The transaction 21 | /// A GasLimit 22 | public static GasLimit ForTransfer(NetworkConfig networkConfig, TransactionRequest transaction) 23 | { 24 | var value = networkConfig.MinGasLimit; 25 | if (string.IsNullOrEmpty(transaction.Data)) return new GasLimit(value); 26 | var bytes = Convert.FromBase64String(transaction.Data); 27 | value += networkConfig.GasPerDataByte * bytes.Length; 28 | 29 | return new GasLimit(value); 30 | } 31 | 32 | /// 33 | /// Compute GasLimit for a smat contract call 34 | /// 35 | /// The network config 36 | /// The transaction 37 | /// A GasLimit 38 | public static GasLimit ForSmartContractCall(NetworkConfig networkConfig, TransactionRequest transaction) 39 | { 40 | var value = networkConfig.MinGasLimit + 6000000; 41 | if (string.IsNullOrEmpty(transaction.Data)) 42 | return new GasLimit(value); 43 | 44 | var bytes = Convert.FromBase64String(transaction.Data); 45 | value += networkConfig.GasPerDataByte * bytes.Length; 46 | 47 | return new GasLimit(value); 48 | } 49 | 50 | public static async Task ForTransaction(TransactionRequest transactionRequest, IElrondProvider provider) 51 | { 52 | var cost = await provider.GetTransactionCost(transactionRequest.GetTransactionRequest()); 53 | if (cost.TxGasUnits == 0) 54 | throw new Exception($"Unable to get cost of transaction : {cost.ReturnMessage}"); 55 | 56 | return new GasLimit(cost.TxGasUnits); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Domain/Helper/BigEndianBuffer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Erdcsharp.Domain.Helper 5 | { 6 | public class BigEndianBuffer 7 | { 8 | private readonly List _bytes = new List(); 9 | 10 | public void WriteUInt(uint i) 11 | { 12 | _bytes.Add((byte)((i >> 0x18) & 0xff)); 13 | _bytes.Add((byte)((i >> 0x10) & 0xff)); 14 | _bytes.Add((byte)((i >> 8) & 0xff)); 15 | _bytes.Add((byte)(i & 0xff)); 16 | } 17 | 18 | public void Write(byte[] bytes) 19 | { 20 | Write(bytes, 0, bytes.Length); 21 | } 22 | 23 | private void Write(byte[] bytes, int offset, int count) 24 | { 25 | var newBytes = new byte[count]; 26 | Array.Copy(bytes, offset, newBytes, 0, count); 27 | 28 | _bytes.AddRange(newBytes); 29 | } 30 | 31 | public byte[] ToArray() 32 | { 33 | return _bytes.ToArray(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Domain/Helper/BytesExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace Erdcsharp.Domain.Helper 2 | { 3 | public static class BytesExtensions 4 | { 5 | public static byte[] Slice(this byte[] source, int start, int? optEnd = null) 6 | { 7 | var end = optEnd.GetValueOrDefault(source.Length); 8 | var len = end - start; 9 | 10 | // Return new array. 11 | var res = new byte[len]; 12 | for (var i = 0; i < len; i++) res[i] = source[i + start]; 13 | return res; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Domain/Helper/Converter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Numerics; 4 | using System.Text; 5 | 6 | namespace Erdcsharp.Domain.Helper 7 | { 8 | public static class Converter 9 | { 10 | private const byte UnsignedByte = 0x00; 11 | 12 | public static BigInteger ToBigInteger(byte[] bytes, bool isUnsigned = false, bool isBigEndian = false) 13 | { 14 | if (isUnsigned) 15 | { 16 | if (bytes.FirstOrDefault() != UnsignedByte) 17 | { 18 | var data = new[] {UnsignedByte}.ToList(); 19 | data.AddRange(bytes); 20 | bytes = data.ToArray(); 21 | } 22 | } 23 | 24 | if (isBigEndian) 25 | { 26 | bytes = bytes.Reverse().ToArray(); 27 | } 28 | 29 | return new BigInteger(bytes); 30 | } 31 | 32 | public static byte[] FromBigInteger(BigInteger bigInteger, bool isUnsigned = false, bool isBigEndian = false) 33 | { 34 | var bytes = bigInteger.ToByteArray(); 35 | if (isBigEndian) 36 | { 37 | bytes = bytes.Reverse().ToArray(); 38 | } 39 | 40 | if (!isUnsigned) 41 | return bytes; 42 | 43 | if (bytes.FirstOrDefault() == UnsignedByte) 44 | { 45 | bytes = bytes.Slice(1); 46 | } 47 | 48 | return bytes; 49 | } 50 | 51 | public static string ToHexString(byte[] bytes) 52 | { 53 | var hex = BitConverter 54 | .ToString(bytes) 55 | .Replace("-", ""); 56 | 57 | return hex; 58 | } 59 | 60 | public static byte[] FromHexString(string hex) 61 | { 62 | var bytes = new byte[hex.Length / 2]; 63 | var hexValue = new[] {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; 64 | 65 | for (int x = 0, i = 0; i < hex.Length; i += 2, x += 1) 66 | { 67 | bytes[x] = (byte)(hexValue[char.ToUpper(hex[i + 0]) - '0'] << 4 | 68 | hexValue[char.ToUpper(hex[i + 1]) - '0']); 69 | } 70 | 71 | return bytes; 72 | } 73 | 74 | public static string ToHexString(string utf8Value) 75 | { 76 | return ToHexString(Encoding.UTF8.GetBytes(utf8Value)); 77 | } 78 | 79 | public static string ToBase64String(string value) 80 | { 81 | return Convert.ToBase64String(Encoding.UTF8.GetBytes(value)); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/Domain/Helper/JsonSerializerWrapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Newtonsoft.Json; 3 | using Newtonsoft.Json.Serialization; 4 | 5 | namespace Erdcsharp.Domain.Helper 6 | { 7 | public class JsonSerializerWrapper 8 | { 9 | public static string Serialize(object value) 10 | { 11 | var serializerSettings = new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore, ContractResolver = new CamelCasePropertyNamesContractResolver()}; 12 | return JsonConvert.SerializeObject(value, serializerSettings); 13 | } 14 | 15 | public static TValue Deserialize(string json) 16 | { 17 | if (json == null) 18 | { 19 | throw new ArgumentNullException(nameof(json)); 20 | } 21 | 22 | var serializerSettings = new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore, ContractResolver = new CamelCasePropertyNamesContractResolver()}; 23 | return JsonConvert.DeserializeObject(json, serializerSettings); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Domain/Helper/StringExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace Erdcsharp.Domain.Helper 2 | { 3 | public static class StringExtensions 4 | { 5 | public static string ToHex(this byte[] bytes) 6 | { 7 | return Converter.ToHexString(bytes).ToLowerInvariant(); 8 | } 9 | 10 | public static byte[] FromHex(this string value) 11 | { 12 | return Converter.FromHexString(value); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Domain/KeyFile.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using Erdcsharp.Domain.Helper; 3 | 4 | namespace Erdcsharp.Domain 5 | { 6 | public class KeyFile 7 | { 8 | public int Version { get; set; } 9 | public string Id { get; set; } 10 | public string Address { get; set; } 11 | public string Bech32 { get; set; } 12 | public Crypto Crypto { get; set; } 13 | 14 | /// 15 | /// Load a KeyFile object from a json string 16 | /// 17 | /// JSON String 18 | /// KeyFile object 19 | public static KeyFile From(string json) 20 | { 21 | return JsonSerializerWrapper.Deserialize(json); 22 | } 23 | 24 | /// 25 | /// Load a KeyFile object from a json file path 26 | /// 27 | /// JSON String 28 | /// KeyFile object 29 | public static KeyFile FromFilePath(string filePath) 30 | { 31 | var json = File.ReadAllText(filePath); 32 | return JsonSerializerWrapper.Deserialize(json); 33 | } 34 | } 35 | 36 | public class Crypto 37 | { 38 | public string Ciphertext { get; set; } 39 | public CipherStructure Cipherparams { get; set; } 40 | public string Cipher { get; set; } 41 | public string Kdf { get; set; } 42 | public KdfSructure Kdfparams { get; set; } 43 | public string Mac { get; set; } 44 | 45 | public class CipherStructure 46 | { 47 | public string Iv { get; set; } 48 | } 49 | 50 | public class KdfSructure 51 | { 52 | public int dklen { get; set; } 53 | public string Salt { get; set; } 54 | public int N { get; set; } 55 | public int r { get; set; } 56 | public int p { get; set; } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Domain/NetworkConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Erdcsharp.Provider; 3 | 4 | namespace Erdcsharp.Domain 5 | { 6 | public class NetworkConfig 7 | { 8 | private NetworkConfig() 9 | { 10 | } 11 | 12 | public string ChainId { get; set; } 13 | public long GasPerDataByte { get; set; } 14 | public long MinGasLimit { get; set; } 15 | public long MinGasPrice { get; set; } 16 | public int MinTransactionVersion { get; set; } 17 | 18 | /// 19 | /// Synchronize the configuration with the network 20 | /// 21 | /// Elrond provider 22 | /// NetworkConfig 23 | public static async Task GetFromNetwork(IElrondProvider provider) 24 | { 25 | var constants = await provider.GetNetworkConfig(); 26 | return new NetworkConfig 27 | { 28 | ChainId = constants.Config.erd_chain_id, 29 | GasPerDataByte = constants.Config.erd_gas_per_data_byte, 30 | MinGasLimit = constants.Config.erd_min_gas_limit, 31 | MinGasPrice = constants.Config.erd_min_gas_price, 32 | MinTransactionVersion = constants.Config.erd_min_transaction_version 33 | }; 34 | } 35 | 36 | /// 37 | /// New empty NetworkConfig 38 | /// 39 | /// NetworkConfig 40 | public static NetworkConfig New() 41 | { 42 | return new NetworkConfig(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Domain/SmartContracts/CodeArtifact.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using Erdcsharp.Domain.Helper; 3 | 4 | namespace Erdcsharp.Domain.SmartContracts 5 | { 6 | public class CodeArtifact 7 | { 8 | public string Value { get; } 9 | 10 | public CodeArtifact(byte[] bytes) 11 | { 12 | Value = Converter.ToHexString(bytes); 13 | } 14 | 15 | public static CodeArtifact FromFilePath(string filePath) 16 | { 17 | var fileBytes = File.ReadAllBytes(filePath); 18 | return new CodeArtifact(fileBytes); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Domain/SmartContracts/CodeMetadata.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Erdcsharp.Domain.Helper; 3 | 4 | namespace Erdcsharp.Domain.SmartContracts 5 | { 6 | public class CodeMetadata 7 | { 8 | private readonly bool _upgradeable; 9 | private readonly bool _readable; 10 | private readonly bool _payable; 11 | public string Value { get; } 12 | 13 | public CodeMetadata(bool upgradeable, bool readable, bool payable) 14 | { 15 | _upgradeable = upgradeable; 16 | _readable = readable; 17 | _payable = payable; 18 | Value = Converter.ToHexString(ToByte()); 19 | } 20 | 21 | // Converts the metadata to the protocol-friendly representation. 22 | private byte[] ToByte() 23 | { 24 | ByteZero byteZero = 0; 25 | ByteOne byteOne = 0; 26 | 27 | if (_upgradeable) 28 | { 29 | byteZero |= ByteZero.Upgradeable; 30 | } 31 | 32 | if (_readable) 33 | { 34 | byteZero |= ByteZero.Readable; 35 | } 36 | 37 | if (_payable) 38 | { 39 | byteOne |= ByteOne.Payable; 40 | } 41 | 42 | var bytes = new[] {(byte)byteZero, (byte)byteOne}; 43 | 44 | return bytes; 45 | } 46 | 47 | 48 | [Flags] 49 | private enum ByteZero : byte 50 | { 51 | Upgradeable = 1, 52 | Reserved2 = 2, 53 | Readable = 4 54 | } 55 | 56 | [Flags] 57 | private enum ByteOne : byte 58 | { 59 | Reserved1 = 1, 60 | Payable = 2 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Domain/Token.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Numerics; 3 | using System.Text.RegularExpressions; 4 | 5 | namespace Erdcsharp.Domain 6 | { 7 | public class Token 8 | { 9 | private readonly Regex _nameValidation = new Regex("^[a-zA-Z0-9]{3,20}$"); 10 | private readonly Regex _tickerValidation = new Regex("^[A-Z0-9]{3,10}$"); 11 | public string Name { get; } 12 | public string Ticker { get; } 13 | public int DecimalPrecision { get; } 14 | 15 | public Token(string name, string ticker, int decimalPrecision) 16 | { 17 | if (!_nameValidation.IsMatch(name)) 18 | throw new ArgumentException( 19 | "Length should be between 3 and 20 characters, alphanumeric characters only", nameof(name)); 20 | 21 | if (!_tickerValidation.IsMatch(ticker)) 22 | throw new ArgumentException( 23 | "Length should be between 3 and 10 characters, alphanumeric UPPERCASE characters only", 24 | nameof(ticker)); 25 | 26 | if (decimalPrecision < 0 || decimalPrecision > 18) 27 | throw new ArgumentException("Should be between 0 and 18", nameof(decimalPrecision)); 28 | 29 | Name = name; 30 | Ticker = ticker; 31 | DecimalPrecision = decimalPrecision; 32 | } 33 | 34 | /// 35 | /// Elrond eGold token (EGLD) 36 | /// 37 | /// 38 | public static Token EGLD() 39 | { 40 | return new Token("ElrondeGold", Constants.EGLD, 18); 41 | } 42 | 43 | /// 44 | /// Create an ESDT (Elrond Standard Digital Token) 45 | /// 46 | /// The name of the token 47 | /// The token ticker 48 | /// Decimal precision of the token (max 18) 49 | /// 50 | public static Token ESDT(string name, string ticker, int decimalPrecision) 51 | { 52 | return new Token(name, ticker, decimalPrecision); 53 | } 54 | 55 | /// 56 | /// Create an ESDT (Elrond Standard Digital Token) NFT 57 | /// 58 | /// The name of the token 59 | /// The token ticker 60 | /// 61 | public static Token ESDT_NFT(string name, string ticker) 62 | { 63 | return new Token(name, ticker, 0); 64 | } 65 | 66 | /// 67 | /// The value One 68 | /// 69 | /// 70 | public BigInteger One() 71 | { 72 | var value = "1".PadRight(DecimalPrecision + 1, '0'); 73 | return BigInteger.Parse(value); 74 | } 75 | 76 | /// 77 | /// The value Zero 78 | /// 79 | /// 80 | public BigInteger Zero() 81 | { 82 | return new BigInteger(0); 83 | } 84 | 85 | public override string ToString() 86 | { 87 | return Name; 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/Domain/TokenAmount.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Numerics; 3 | using Erdcsharp.Domain.Exceptions; 4 | 5 | namespace Erdcsharp.Domain 6 | { 7 | public class TokenAmount 8 | { 9 | public Token Token { get; } 10 | public BigInteger Value { get; } 11 | 12 | private TokenAmount(long value, Token token) 13 | { 14 | Token = token; 15 | Value = new BigInteger(value); 16 | } 17 | 18 | private TokenAmount(string value, Token token) 19 | { 20 | Token = token; 21 | Value = BigInteger.Parse(value); 22 | if (Value.Sign == -1) 23 | throw new InvalidTokenAmountException(value); 24 | } 25 | 26 | /// 27 | /// Returns the string representation of the value as Token currency. 28 | /// 29 | /// 30 | public string ToCurrencyString() 31 | { 32 | var denominated = ToDenominated(); 33 | return $"{denominated} {Token.Ticker}"; 34 | } 35 | 36 | /// 37 | /// String representation of the denominated value 38 | /// 39 | /// 40 | public string ToDenominated() 41 | { 42 | var padded = Value.ToString().PadLeft(Token.DecimalPrecision, '0'); 43 | 44 | var start = (padded.Length - Token.DecimalPrecision); 45 | start = start < 0 ? 0 : start; 46 | 47 | var decimals = padded.Substring(start, Token.DecimalPrecision); 48 | var integer = start == 0 ? "0" : padded.Substring(0, start); 49 | 50 | return $"{integer}.{decimals}"; 51 | } 52 | 53 | /// 54 | /// Creates a token amount object from an eGLD value (denomination will be applied). 55 | /// 56 | /// 57 | /// 58 | // ReSharper disable once InconsistentNaming 59 | public static TokenAmount EGLD(string value) 60 | { 61 | var egld = Token.EGLD(); 62 | var split = value.Split('.'); 63 | var integerPart = split.FirstOrDefault() ?? "0"; 64 | var decimalPart = split.Length == 2 ? split[1] : string.Empty; 65 | var full = $"{integerPart}{decimalPart.PadRight(egld.DecimalPrecision, '0')}"; 66 | return new TokenAmount(full, Token.EGLD()); 67 | } 68 | 69 | /// 70 | /// Create a token amount object from a value (denomination will be applied) 71 | /// 72 | /// Amount 73 | /// Token, default is EGLD 74 | /// 75 | public static TokenAmount ESDT(string value, Token token) 76 | { 77 | var split = value.Split('.'); 78 | var integerPart = split.FirstOrDefault() ?? "0"; 79 | var decimalPart = split.Length == 2 ? split[1] : string.Empty; 80 | var full = $"{integerPart}{decimalPart.PadRight(token.DecimalPrecision, '0')}"; 81 | return new TokenAmount(full, token); 82 | } 83 | 84 | public static TokenAmount From(string value, Token token = null) 85 | { 86 | if (token == null) 87 | token = Token.EGLD(); 88 | return new TokenAmount(value, token); 89 | } 90 | 91 | /// 92 | /// Value zero 93 | /// 94 | /// Token, default is EGLD 95 | /// 96 | public static TokenAmount Zero(Token token = null) 97 | { 98 | if (token == null) 99 | token = Token.EGLD(); 100 | 101 | return new TokenAmount(0, token); 102 | } 103 | 104 | public override string ToString() 105 | { 106 | return Value.ToString(); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/Domain/Transaction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Erdcsharp.Domain.Abi; 6 | using Erdcsharp.Domain.Codec; 7 | using Erdcsharp.Domain.Exceptions; 8 | using Erdcsharp.Domain.Helper; 9 | using Erdcsharp.Domain.Values; 10 | using Erdcsharp.Provider; 11 | using Erdcsharp.Provider.Dtos; 12 | 13 | namespace Erdcsharp.Domain 14 | { 15 | public class Transaction 16 | { 17 | public string Status { get; private set; } 18 | public string TxHash { get; } 19 | 20 | private IEnumerable _smartContractResult; 21 | private string _hyperBlockHash; 22 | 23 | public Transaction(string hash) 24 | { 25 | TxHash = hash; 26 | } 27 | 28 | public static Transaction From(CreateTransactionResponseDataDto createTransactionResponse) 29 | { 30 | return new Transaction(createTransactionResponse.TxHash); 31 | } 32 | 33 | public T GetSmartContractResult(TypeValue type, int smartContractIndex = 0, int parameterIndex = 0) 34 | where T : IBinaryType 35 | { 36 | if (!_smartContractResult.Any()) 37 | throw new Exception("Empty smart contract results"); 38 | 39 | var scResult = _smartContractResult.ElementAt(smartContractIndex).Data; 40 | 41 | var fields = scResult.Split('@').Where(s => !string.IsNullOrEmpty(s)).ToArray(); 42 | var result = fields.ElementAt(parameterIndex); 43 | var responseBytes = Converter.FromHexString(result); 44 | var binaryCodec = new BinaryCodec(); 45 | var decodedResponse = binaryCodec.DecodeTopLevel(responseBytes, type); 46 | return (T)decodedResponse; 47 | } 48 | 49 | /// 50 | /// Returns whether the transaction is pending (e.g. in mempool). 51 | /// 52 | /// 53 | public bool IsPending() 54 | { 55 | return Status == "received" || Status == "pending" || Status == "partially-executed"; 56 | } 57 | 58 | /// 59 | /// Returns whether the transaction has been executed (not necessarily with success) 60 | /// 61 | /// 62 | public bool IsExecuted() 63 | { 64 | return IsSuccessful() || IsInvalid(); 65 | } 66 | 67 | /// 68 | /// Returns whether the transaction has been executed successfully. 69 | /// 70 | /// 71 | public bool IsSuccessful() 72 | { 73 | return Status == "executed" || Status == "success" || Status == "successful"; 74 | } 75 | 76 | /// 77 | /// Returns whether the transaction has been executed, but with a failure. 78 | /// 79 | /// 80 | public bool IsFailed() 81 | { 82 | return Status == "fail" || Status == "failed" || Status == "unsuccessful" || IsInvalid(); 83 | } 84 | 85 | /// 86 | /// Returns whether the transaction has been executed, but marked as invalid (e.g. due to "insufficient funds") 87 | /// 88 | /// 89 | public bool IsInvalid() 90 | { 91 | return Status == "invalid"; 92 | } 93 | 94 | public async Task Sync(IElrondProvider provider) 95 | { 96 | var transaction = await provider.GetTransactionDetail(TxHash); 97 | if (transaction.SmartContractResults != null) 98 | { 99 | _smartContractResult = transaction.SmartContractResults.OrderByDescending(s => s.Nonce).ToList(); 100 | } 101 | 102 | _hyperBlockHash = transaction.HyperblockHash; 103 | Status = transaction.Status; 104 | } 105 | 106 | public void EnsureTransactionSuccess() 107 | { 108 | if (!IsSuccessful()) 109 | throw new TransactionException.InvalidTransactionException(TxHash); 110 | } 111 | 112 | /// 113 | /// Wait for the execution of the transaction 114 | /// 115 | /// 116 | /// 117 | /// 118 | public async Task AwaitExecuted(IElrondProvider provider, TimeSpan? timeout = null) 119 | { 120 | if (!timeout.HasValue) 121 | timeout = TimeSpan.FromSeconds(60); 122 | 123 | var currentIteration = 0; 124 | do 125 | { 126 | await Task.Delay(1000); // 1 second 127 | await Sync(provider); 128 | currentIteration++; 129 | } while (!IsExecuted() && currentIteration < timeout.Value.TotalSeconds); 130 | 131 | if (!IsExecuted()) 132 | throw new TransactionException.TransactionStatusNotReachedException(TxHash, "Executed"); 133 | 134 | if (_smartContractResult != null && _smartContractResult.Any(s => !string.IsNullOrEmpty(s.ReturnMessage))) 135 | { 136 | var returnMessages = _smartContractResult.Select(x => x.ReturnMessage).ToArray(); 137 | var aggregateMessage = string.Join(Environment.NewLine, returnMessages); 138 | throw new TransactionException.TransactionWithSmartContractErrorException(TxHash, aggregateMessage); 139 | } 140 | 141 | if (IsFailed()) 142 | throw new TransactionException.FailedTransactionException(TxHash); 143 | 144 | if (IsInvalid()) 145 | throw new TransactionException.InvalidTransactionException(TxHash); 146 | } 147 | 148 | /// 149 | /// Wait for the transaction to be notarized 150 | /// 151 | /// 152 | /// 153 | /// 154 | public async Task AwaitNotarized(IElrondProvider provider, TimeSpan? timeout = null) 155 | { 156 | if (!timeout.HasValue) 157 | timeout = TimeSpan.FromSeconds(60); 158 | 159 | var currentIteration = 0; 160 | do 161 | { 162 | await Task.Delay(1000); // 1 second 163 | await Sync(provider); 164 | currentIteration++; 165 | } while (string.IsNullOrEmpty(_hyperBlockHash) && currentIteration < timeout.Value.TotalSeconds); 166 | 167 | if (currentIteration >= timeout.Value.TotalSeconds) 168 | throw new TransactionException.TransactionStatusNotReachedException(TxHash, "Notarized"); 169 | } 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /src/Domain/TransactionRequest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | using Erdcsharp.Domain.Codec; 6 | using Erdcsharp.Domain.Helper; 7 | using Erdcsharp.Domain.SmartContracts; 8 | using Erdcsharp.Domain.Values; 9 | using Erdcsharp.Provider; 10 | using Erdcsharp.Provider.Dtos; 11 | 12 | namespace Erdcsharp.Domain 13 | { 14 | public class TransactionRequest 15 | { 16 | private static readonly BinaryCodec BinaryCoder = new BinaryCodec(); 17 | private readonly string _chainId; 18 | private const int TransactionVersion = 4; 19 | 20 | public Account Account { get; } 21 | public Address Sender { get; } 22 | public long Nonce { get; } 23 | public long GasPrice { get; } 24 | public TokenAmount Value { get; private set; } 25 | public Address Receiver { get; private set; } 26 | public GasLimit GasLimit { get; private set; } 27 | public string Data { get; private set; } 28 | 29 | private TransactionRequest(Account account, NetworkConfig networkConfig) 30 | { 31 | _chainId = networkConfig.ChainId; 32 | Account = account; 33 | Sender = account.Address; 34 | Receiver = Address.Zero(); 35 | Value = TokenAmount.Zero(); 36 | Nonce = account.Nonce; 37 | GasLimit = new GasLimit(networkConfig.MinGasLimit); 38 | GasPrice = networkConfig.MinGasPrice; 39 | } 40 | 41 | public static TransactionRequest Create(Account account, NetworkConfig networkConfig) 42 | { 43 | return new TransactionRequest(account, networkConfig); 44 | } 45 | 46 | public static TransactionRequest Create(Account account, NetworkConfig networkConfig, Address receiver, 47 | TokenAmount value) 48 | { 49 | return new TransactionRequest(account, networkConfig) {Receiver = receiver, Value = value}; 50 | } 51 | 52 | public static TransactionRequest CreateDeploySmartContractTransactionRequest( 53 | NetworkConfig networkConfig, 54 | Account account, 55 | CodeArtifact codeArtifact, 56 | CodeMetadata codeMetadata, 57 | params IBinaryType[] args) 58 | { 59 | var transaction = Create(account, networkConfig); 60 | var data = $"{codeArtifact.Value}@{Constants.ArwenVirtualMachine}@{codeMetadata.Value}"; 61 | if (args.Any()) 62 | { 63 | data = args.Aggregate(data, 64 | (c, arg) => c + $"@{Converter.ToHexString(BinaryCoder.EncodeTopLevel(arg))}"); 65 | } 66 | 67 | transaction.SetData(data); 68 | transaction.SetGasLimit(GasLimit.ForSmartContractCall(networkConfig, transaction)); 69 | return transaction; 70 | } 71 | 72 | public static TransactionRequest CreateCallSmartContractTransactionRequest( 73 | NetworkConfig networkConfig, 74 | Account account, 75 | Address address, 76 | string functionName, 77 | TokenAmount value, 78 | params IBinaryType[] args) 79 | { 80 | var transaction = Create(account, networkConfig, address, value); 81 | var data = $"{functionName}"; 82 | if (args.Any()) 83 | { 84 | data = args.Aggregate(data, 85 | (c, arg) => c + $"@{Converter.ToHexString(BinaryCoder.EncodeTopLevel(arg))}"); 86 | } 87 | 88 | transaction.SetData(data); 89 | transaction.SetGasLimit(GasLimit.ForSmartContractCall(networkConfig, transaction)); 90 | return transaction; 91 | } 92 | 93 | public void SetGasLimit(GasLimit gasLimit) 94 | { 95 | GasLimit = gasLimit; 96 | } 97 | 98 | public void SetData(string data) 99 | { 100 | var dataBytes = Encoding.UTF8.GetBytes(data); 101 | Data = Convert.ToBase64String(dataBytes); 102 | } 103 | 104 | public string GetDecodedData() 105 | { 106 | return Encoding.UTF8.GetString(Convert.FromBase64String(Data)); 107 | } 108 | 109 | public TransactionRequestDto GetTransactionRequest() 110 | { 111 | var transactionRequestDto = new TransactionRequestDto 112 | { 113 | ChainID = _chainId, 114 | Data = Data, 115 | GasLimit = GasLimit.Value, 116 | Receiver = Receiver.Bech32, 117 | Sender = Sender.Bech32, 118 | Value = Value.ToString(), 119 | Version = TransactionVersion, 120 | Nonce = Nonce, 121 | GasPrice = GasPrice, 122 | Signature = null 123 | }; 124 | 125 | return transactionRequestDto; 126 | } 127 | 128 | public async Task Send(IElrondProvider provider, Wallet wallet) 129 | { 130 | var transactionRequestDto = GetTransactionRequest(); 131 | var account = wallet.GetAccount(); 132 | await account.Sync(provider); 133 | 134 | if (Value.Value > account.Balance.Value) 135 | throw new Exception($"Insufficient funds, required : {Value} and got {account.Balance}"); 136 | 137 | if (Nonce != account.Nonce) 138 | throw new Exception($"Incorrect nonce, account nonce is {account.Nonce}, not {Nonce}"); 139 | 140 | 141 | var json = JsonSerializerWrapper.Serialize(transactionRequestDto); 142 | var message = Encoding.UTF8.GetBytes(json); 143 | 144 | transactionRequestDto.Signature = wallet.Sign(message); 145 | 146 | var result = await provider.SendTransaction(transactionRequestDto); 147 | Account.IncrementNonce(); 148 | return Transaction.From(result); 149 | } 150 | 151 | public void AddArgument(IBinaryType[] args) 152 | { 153 | if (!args.Any()) 154 | return; 155 | 156 | var binaryCodec = new BinaryCodec(); 157 | var decodedData = GetDecodedData(); 158 | var data = args.Aggregate(decodedData, 159 | (c, arg) => c + $"@{Converter.ToHexString(binaryCodec.EncodeTopLevel(arg))}"); 160 | SetData(data); 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /src/Domain/Values/BaseBinaryValue.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Erdcsharp.Domain.Helper; 3 | 4 | namespace Erdcsharp.Domain.Values 5 | { 6 | public class BaseBinaryValue : IBinaryType 7 | { 8 | public TypeValue Type { get; } 9 | 10 | public BaseBinaryValue(TypeValue type) 11 | { 12 | Type = type; 13 | } 14 | 15 | public T ValueOf() where T : IBinaryType 16 | { 17 | return (T)(IBinaryType)this; 18 | } 19 | 20 | public virtual T ToObject() 21 | { 22 | return JsonSerializerWrapper.Deserialize(ToJson()); 23 | } 24 | 25 | public virtual string ToJson() 26 | { 27 | if (string.IsNullOrEmpty(Type.Name)) 28 | { 29 | var kv = new KeyValuePair(Type.Name ?? "", ToString()); 30 | var json = JsonSerializerWrapper.Serialize(kv); 31 | return json; 32 | } 33 | else 34 | { 35 | var kv = new Dictionary {{Type.Name, ToString()}}; 36 | var json = JsonSerializerWrapper.Serialize(kv); 37 | return json; 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Domain/Values/BooleanValue.cs: -------------------------------------------------------------------------------- 1 | namespace Erdcsharp.Domain.Values 2 | { 3 | public class BooleanValue : BaseBinaryValue 4 | { 5 | private readonly bool _value; 6 | 7 | public BooleanValue(bool value) 8 | : base(TypeValue.BooleanValue) 9 | { 10 | _value = value; 11 | } 12 | 13 | public static BooleanValue From(bool value) 14 | { 15 | return new BooleanValue(value); 16 | } 17 | 18 | public bool IsTrue() 19 | { 20 | return _value; 21 | } 22 | 23 | public bool IsFalse() 24 | { 25 | return _value == false; 26 | } 27 | 28 | public override string ToString() 29 | { 30 | return _value.ToString(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Domain/Values/BytesValue.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using Erdcsharp.Domain.Helper; 4 | 5 | namespace Erdcsharp.Domain.Values 6 | { 7 | public class BytesValue : BaseBinaryValue 8 | { 9 | public BytesValue(byte[] data, TypeValue type) 10 | : base(type) 11 | { 12 | Buffer = data; 13 | } 14 | 15 | public int GetLength() 16 | { 17 | return Buffer.Length; 18 | } 19 | 20 | public static BytesValue FromUtf8(string utf8String) 21 | { 22 | return new BytesValue(Encoding.UTF8.GetBytes(utf8String), TypeValue.BytesValue); 23 | } 24 | 25 | public static BytesValue FromHex(string hexString) 26 | { 27 | return new BytesValue(Converter.FromHexString(hexString), TypeValue.BytesValue); 28 | } 29 | 30 | public static BytesValue FromBuffer(byte[] data) 31 | { 32 | return new BytesValue(data, TypeValue.BytesValue); 33 | } 34 | 35 | public byte[] Buffer { get; } 36 | 37 | public override string ToString() 38 | { 39 | return Converter.ToHexString(Buffer); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Domain/Values/FieldDefinition.cs: -------------------------------------------------------------------------------- 1 | namespace Erdcsharp.Domain.Values 2 | { 3 | public class FieldDefinition 4 | { 5 | public string Name { get; } 6 | public string Description { get; } 7 | public TypeValue Type { get; } 8 | 9 | public FieldDefinition(string name, string description, TypeValue type) 10 | { 11 | Name = name; 12 | Description = description; 13 | Type = type; 14 | Type.SetName(name); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Domain/Values/IBinaryType.cs: -------------------------------------------------------------------------------- 1 | namespace Erdcsharp.Domain.Values 2 | { 3 | public interface IBinaryType 4 | { 5 | TypeValue Type { get; } 6 | 7 | T ValueOf() where T : IBinaryType; 8 | 9 | T ToObject(); 10 | 11 | string ToJson(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Domain/Values/MultiValue.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Text; 4 | using Erdcsharp.Domain.Helper; 5 | 6 | namespace Erdcsharp.Domain.Values 7 | { 8 | public class MultiValue : BaseBinaryValue 9 | { 10 | public Dictionary Values { get; } 11 | 12 | public MultiValue(TypeValue type, Dictionary values) : base(type) 13 | { 14 | Values = values; 15 | } 16 | 17 | public static MultiValue From(params IBinaryType[] values) 18 | { 19 | var t = values.Select(s => s.Type).ToArray(); 20 | return new MultiValue(TypeValue.MultiValue(t), values.ToDictionary(s => s.Type, d => d)); 21 | } 22 | 23 | public override string ToString() 24 | { 25 | var builder = new StringBuilder(); 26 | builder.AppendLine(Type.Name); 27 | foreach (var value in Values) 28 | { 29 | builder.AppendLine($"{value.Key}:{value}"); 30 | } 31 | 32 | return builder.ToString(); 33 | } 34 | 35 | public override T ToObject() 36 | { 37 | return JsonSerializerWrapper.Deserialize(ToJson()); 38 | } 39 | 40 | public override string ToJson() 41 | { 42 | var dic = new Dictionary(); 43 | for (var i = 0; i < Values.Count; i++) 44 | { 45 | var value = Values.ToArray()[i]; 46 | if (value.Value.Type.BinaryType == TypeValue.BinaryTypes.Struct) 47 | { 48 | var json = value.Value.ToJson(); 49 | var jsonObject = JsonSerializerWrapper.Deserialize(json); 50 | dic.Add($"Multi_{i}", jsonObject); 51 | } 52 | else 53 | { 54 | dic.Add($"Multi_{i}", value.Value.ToString()); 55 | } 56 | } 57 | 58 | return JsonSerializerWrapper.Serialize(dic); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Domain/Values/NumericValue.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using Erdcsharp.Domain.Exceptions; 3 | 4 | namespace Erdcsharp.Domain.Values 5 | { 6 | public class NumericValue : BaseBinaryValue 7 | { 8 | public NumericValue(TypeValue type, BigInteger number) : base(type) 9 | { 10 | Number = number; 11 | if (number.Sign == -1 && !type.HasSign()) 12 | throw new BinaryCodecException("negative, but binaryType is unsigned"); 13 | } 14 | 15 | public BigInteger Number { get; } 16 | 17 | public static NumericValue U8Value(byte value) => 18 | new NumericValue(TypeValue.U8TypeValue, new BigInteger(value)); 19 | 20 | public static NumericValue I8Value(sbyte value) => 21 | new NumericValue(TypeValue.I8TypeValue, new BigInteger(value)); 22 | 23 | public static NumericValue U16Value(ushort value) => 24 | new NumericValue(TypeValue.U16TypeValue, new BigInteger(value)); 25 | 26 | public static NumericValue I16Value(short value) => 27 | new NumericValue(TypeValue.I16TypeValue, new BigInteger(value)); 28 | 29 | public static NumericValue U32Value(uint value) => 30 | new NumericValue(TypeValue.U32TypeValue, new BigInteger(value)); 31 | 32 | public static NumericValue I32Value(int value) => 33 | new NumericValue(TypeValue.I32TypeValue, new BigInteger(value)); 34 | 35 | public static NumericValue U64Value(ulong value) => 36 | new NumericValue(TypeValue.U64TypeValue, new BigInteger(value)); 37 | 38 | public static NumericValue I64Value(long value) => 39 | new NumericValue(TypeValue.I64TypeValue, new BigInteger(value)); 40 | 41 | public static NumericValue BigUintValue(BigInteger value) => 42 | new NumericValue(TypeValue.BigUintTypeValue, value); 43 | 44 | public static NumericValue BigIntValue(BigInteger value) => new NumericValue(TypeValue.BigIntTypeValue, value); 45 | public static NumericValue TokenAmount(TokenAmount value) => new NumericValue(TypeValue.BigUintTypeValue, value.Value); 46 | 47 | public override string ToString() 48 | { 49 | return Number.ToString(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Domain/Values/OptionValue.cs: -------------------------------------------------------------------------------- 1 | using Erdcsharp.Domain.Helper; 2 | 3 | namespace Erdcsharp.Domain.Values 4 | { 5 | public class OptionValue : BaseBinaryValue 6 | { 7 | public TypeValue InnerType { get; } 8 | public IBinaryType Value { get; } 9 | 10 | private OptionValue(TypeValue type, TypeValue innerType = null, IBinaryType value = null) : base(type) 11 | { 12 | InnerType = innerType; 13 | Value = value; 14 | } 15 | 16 | public static OptionValue NewMissing() 17 | { 18 | return new OptionValue(TypeValue.OptionValue()); 19 | } 20 | 21 | public static OptionValue NewProvided(IBinaryType value) 22 | { 23 | return new OptionValue(TypeValue.OptionValue(value.Type), value.Type, value); 24 | } 25 | 26 | public bool IsSet() 27 | { 28 | return Value != null; 29 | } 30 | 31 | public override string ToString() 32 | { 33 | return IsSet() ? Value.ToString() : ""; 34 | } 35 | 36 | public override T ToObject() 37 | { 38 | return JsonSerializerWrapper.Deserialize(ToJson()); 39 | } 40 | 41 | public override string ToJson() 42 | { 43 | return IsSet() ? Value.ToJson() : "{}"; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Domain/Values/StructField.cs: -------------------------------------------------------------------------------- 1 | namespace Erdcsharp.Domain.Values 2 | { 3 | public class StructField 4 | { 5 | public IBinaryType Value { get; } 6 | public string Name { get; } 7 | 8 | public StructField(string name, IBinaryType value) 9 | { 10 | Value = value; 11 | Name = name; 12 | } 13 | 14 | public override string ToString() 15 | { 16 | return Value.ToString(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Domain/Values/StructValue.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Text; 4 | using Erdcsharp.Domain.Exceptions; 5 | using Erdcsharp.Domain.Helper; 6 | 7 | namespace Erdcsharp.Domain.Values 8 | { 9 | public class StructValue : BaseBinaryValue 10 | { 11 | public StructField[] Fields { get; } 12 | 13 | public StructValue(TypeValue structType, StructField[] fields) : base(structType) 14 | { 15 | Fields = fields; 16 | CheckTyping(); 17 | } 18 | 19 | public StructField GetStructField(string name) 20 | { 21 | var field = Fields.SingleOrDefault(f => f.Name == name); 22 | return field; 23 | } 24 | 25 | private void CheckTyping() 26 | { 27 | var definitions = Type.GetFieldDefinitions(); 28 | if (Fields.Length != definitions.Length) 29 | { 30 | throw new BinaryCodecException("fields length vs. field definitions length"); 31 | } 32 | 33 | for (var i = 0; i < Fields.Length; i++) 34 | { 35 | var field = Fields[i]; 36 | var definition = definitions[i]; 37 | var fieldType = field.Value.Type; 38 | 39 | if (fieldType.RustType != definition.Type.RustType) 40 | throw new BinaryCodecException("field rustType vs. field definitions rustType"); 41 | } 42 | } 43 | 44 | public override string ToString() 45 | { 46 | var builder = new StringBuilder(); 47 | builder.AppendLine(Type.Name); 48 | foreach (var structField in Fields) 49 | { 50 | builder.AppendLine($"{structField.Name}:{structField.Value}"); 51 | } 52 | 53 | return builder.ToString(); 54 | } 55 | 56 | public override T ToObject() 57 | { 58 | return JsonSerializerWrapper.Deserialize(ToJson()); 59 | } 60 | 61 | public override string ToJson() 62 | { 63 | var dic = new Dictionary(); 64 | foreach (var field in Fields) 65 | { 66 | if (field.Value.Type.BinaryType == TypeValue.BinaryTypes.Struct) 67 | { 68 | var json = field.Value.ToJson(); 69 | var jsonObject = JsonSerializerWrapper.Deserialize(json); 70 | dic.Add(field.Name, jsonObject); 71 | } 72 | else 73 | { 74 | dic.Add(field.Name, field.ToString()); 75 | } 76 | } 77 | 78 | return JsonSerializerWrapper.Serialize(dic); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/Domain/Values/TokenIdentifierValue.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace Erdcsharp.Domain.Values 4 | { 5 | public class TokenIdentifierValue : BaseBinaryValue 6 | { 7 | public TokenIdentifierValue(byte[] data, TypeValue type) : base(type) 8 | { 9 | Buffer = data; 10 | Value = Encoding.UTF8.GetString(data); 11 | } 12 | 13 | public string Value { get; } 14 | 15 | public byte[] Buffer { get; } 16 | 17 | public static TokenIdentifierValue From(byte[] data) 18 | { 19 | return new TokenIdentifierValue(data, TypeValue.TokenIdentifierValue); 20 | } 21 | 22 | // ReSharper disable once InconsistentNaming 23 | public static TokenIdentifierValue EGLD() 24 | { 25 | return new TokenIdentifierValue(new byte[0], TypeValue.TokenIdentifierValue); 26 | } 27 | 28 | public static TokenIdentifierValue From(string data) 29 | { 30 | var bytes = Encoding.UTF8.GetBytes(data); 31 | return new TokenIdentifierValue(bytes, TypeValue.TokenIdentifierValue); 32 | } 33 | 34 | public bool IsEGLD() 35 | { 36 | if (Buffer.Length == 0) 37 | return true; 38 | 39 | if (Value == Constants.EGLD) 40 | return true; 41 | 42 | return false; 43 | } 44 | 45 | public override string ToString() 46 | { 47 | return Value; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Erdcsharp.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Elrond C# SDK for interacting with the Elrond Network (in general) and Smart Contracts (in particular). 4 | netstandard2.0;net5.0;net461;net47; 5 | true 6 | elrond-sdk-erdsharp 7 | 8 | 9 | elrond 10 | 11 | https://github.com/ElrondNetwork/elrond-sdk-erdcsharp 12 | https://github.com/ElrondNetwork/elrond-sdk-erdcsharp 13 | Github 14 | 15 | 1.0.0 16 | true 17 | LICENSE.txt 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | True 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/Erdcsharp.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31025.194 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Erdcsharp", "Erdcsharp.csproj", "{27131229-2F55-4FCE-8CA9-515FEB9A790D}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{CAD5A9A8-7F27-45FC-875C-4566C53233E3}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{4C11B2A7-FE67-440D-9627-4C5E1FFA6909}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{89BE6A83-2144-4EB2-A314-B9FCA2CFFD90}" 13 | ProjectSection(SolutionItems) = preProject 14 | .editorconfig = .editorconfig 15 | ..\LICENSE.txt = ..\LICENSE.txt 16 | ..\README.md = ..\README.md 17 | EndProjectSection 18 | EndProject 19 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Erdcsharp.UnitTests", "..\tests\Erdcsharp.Tests\Erdcsharp.UnitTests.csproj", "{648AC8DF-BCCB-4410-8EE2-5678F294E707}" 20 | EndProject 21 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".NET 5.0", ".NET 5.0", "{032642F4-BFB4-4F72-9981-3F9CD04A4FA6}" 22 | EndProject 23 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".NET Framework 4.6.1", ".NET Framework 4.6.1", "{43B33CE4-8A5D-44A0-B053-F50ECFC9E273}" 24 | EndProject 25 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Erdcsharp.Console.NET_Framework", "..\tests\Erdcsharp.Console.NET_Framework\Erdcsharp.Console.NET_Framework.csproj", "{76BCB232-AECF-49E1-A364-2BD9EDF4634F}" 26 | EndProject 27 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".NET Core 3.1", ".NET Core 3.1", "{6027F23C-1462-4647-8F3D-E0269D3CA289}" 28 | EndProject 29 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Erdcsharp.Console.NET_Core_3.1", "..\tests\Erdcsharp.Console.NET_Core_3.1\Erdcsharp.Console.NET_Core_3.1.csproj", "{BE880803-1138-4D10-8B2C-B723D8734A4D}" 30 | EndProject 31 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Erdcsharp.Console.NET 5.0", "..\tests\Erdcsharp.Console.NET 5.0\Erdcsharp.Console.NET 5.0.csproj", "{931A7D06-10B9-473B-9E8B-6A94DE05C1B5}" 32 | EndProject 33 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{7A07DF88-D06A-479A-8E54-FB7FADE26C81}" 34 | EndProject 35 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Erdcsharp.IntegrationTests", "..\tests\Erdcsharp.IntegrationTests\Erdcsharp.IntegrationTests.csproj", "{E48A4A6E-37D7-4878-82F2-A6CB7E9EC06F}" 36 | EndProject 37 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{AFD4B8FF-CD82-4B93-9070-DABAB3F7774A}" 38 | ProjectSection(SolutionItems) = preProject 39 | ..\docs\advanced.md = ..\docs\advanced.md 40 | ..\docs\basic.md = ..\docs\basic.md 41 | ..\docs\index.md = ..\docs\index.md 42 | EndProjectSection 43 | EndProject 44 | Global 45 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 46 | Debug|Any CPU = Debug|Any CPU 47 | Release|Any CPU = Release|Any CPU 48 | EndGlobalSection 49 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 50 | {27131229-2F55-4FCE-8CA9-515FEB9A790D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 51 | {27131229-2F55-4FCE-8CA9-515FEB9A790D}.Debug|Any CPU.Build.0 = Debug|Any CPU 52 | {27131229-2F55-4FCE-8CA9-515FEB9A790D}.Release|Any CPU.ActiveCfg = Release|Any CPU 53 | {27131229-2F55-4FCE-8CA9-515FEB9A790D}.Release|Any CPU.Build.0 = Release|Any CPU 54 | {648AC8DF-BCCB-4410-8EE2-5678F294E707}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 55 | {648AC8DF-BCCB-4410-8EE2-5678F294E707}.Debug|Any CPU.Build.0 = Debug|Any CPU 56 | {648AC8DF-BCCB-4410-8EE2-5678F294E707}.Release|Any CPU.ActiveCfg = Release|Any CPU 57 | {648AC8DF-BCCB-4410-8EE2-5678F294E707}.Release|Any CPU.Build.0 = Release|Any CPU 58 | {76BCB232-AECF-49E1-A364-2BD9EDF4634F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 59 | {76BCB232-AECF-49E1-A364-2BD9EDF4634F}.Debug|Any CPU.Build.0 = Debug|Any CPU 60 | {76BCB232-AECF-49E1-A364-2BD9EDF4634F}.Release|Any CPU.ActiveCfg = Release|Any CPU 61 | {76BCB232-AECF-49E1-A364-2BD9EDF4634F}.Release|Any CPU.Build.0 = Release|Any CPU 62 | {BE880803-1138-4D10-8B2C-B723D8734A4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 63 | {BE880803-1138-4D10-8B2C-B723D8734A4D}.Debug|Any CPU.Build.0 = Debug|Any CPU 64 | {BE880803-1138-4D10-8B2C-B723D8734A4D}.Release|Any CPU.ActiveCfg = Release|Any CPU 65 | {BE880803-1138-4D10-8B2C-B723D8734A4D}.Release|Any CPU.Build.0 = Release|Any CPU 66 | {931A7D06-10B9-473B-9E8B-6A94DE05C1B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 67 | {931A7D06-10B9-473B-9E8B-6A94DE05C1B5}.Debug|Any CPU.Build.0 = Debug|Any CPU 68 | {931A7D06-10B9-473B-9E8B-6A94DE05C1B5}.Release|Any CPU.ActiveCfg = Release|Any CPU 69 | {931A7D06-10B9-473B-9E8B-6A94DE05C1B5}.Release|Any CPU.Build.0 = Release|Any CPU 70 | {E48A4A6E-37D7-4878-82F2-A6CB7E9EC06F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 71 | {E48A4A6E-37D7-4878-82F2-A6CB7E9EC06F}.Debug|Any CPU.Build.0 = Debug|Any CPU 72 | {E48A4A6E-37D7-4878-82F2-A6CB7E9EC06F}.Release|Any CPU.ActiveCfg = Release|Any CPU 73 | {E48A4A6E-37D7-4878-82F2-A6CB7E9EC06F}.Release|Any CPU.Build.0 = Release|Any CPU 74 | EndGlobalSection 75 | GlobalSection(SolutionProperties) = preSolution 76 | HideSolutionNode = FALSE 77 | EndGlobalSection 78 | GlobalSection(NestedProjects) = preSolution 79 | {27131229-2F55-4FCE-8CA9-515FEB9A790D} = {CAD5A9A8-7F27-45FC-875C-4566C53233E3} 80 | {648AC8DF-BCCB-4410-8EE2-5678F294E707} = {4C11B2A7-FE67-440D-9627-4C5E1FFA6909} 81 | {032642F4-BFB4-4F72-9981-3F9CD04A4FA6} = {7A07DF88-D06A-479A-8E54-FB7FADE26C81} 82 | {43B33CE4-8A5D-44A0-B053-F50ECFC9E273} = {7A07DF88-D06A-479A-8E54-FB7FADE26C81} 83 | {76BCB232-AECF-49E1-A364-2BD9EDF4634F} = {43B33CE4-8A5D-44A0-B053-F50ECFC9E273} 84 | {6027F23C-1462-4647-8F3D-E0269D3CA289} = {7A07DF88-D06A-479A-8E54-FB7FADE26C81} 85 | {BE880803-1138-4D10-8B2C-B723D8734A4D} = {6027F23C-1462-4647-8F3D-E0269D3CA289} 86 | {931A7D06-10B9-473B-9E8B-6A94DE05C1B5} = {032642F4-BFB4-4F72-9981-3F9CD04A4FA6} 87 | {7A07DF88-D06A-479A-8E54-FB7FADE26C81} = {4C11B2A7-FE67-440D-9627-4C5E1FFA6909} 88 | {E48A4A6E-37D7-4878-82F2-A6CB7E9EC06F} = {4C11B2A7-FE67-440D-9627-4C5E1FFA6909} 89 | EndGlobalSection 90 | GlobalSection(ExtensibilityGlobals) = postSolution 91 | SolutionGuid = {00A01422-F2F4-4A42-B110-DC3E89A50C6A} 92 | EndGlobalSection 93 | EndGlobal 94 | -------------------------------------------------------------------------------- /src/Manager/IEsdtTokenManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Numerics; 4 | using System.Threading.Tasks; 5 | using Erdcsharp.Domain; 6 | using Erdcsharp.Domain.Values; 7 | 8 | namespace Erdcsharp.Manager 9 | { 10 | public interface IEsdtTokenManager 11 | { 12 | /// 13 | /// ESDT tokens are issued via a request to the Metachain, 14 | /// which is a transaction submitted by the Account which will manage the tokens. 15 | /// When issuing a token, one must provide a token name, a ticker, the initial supply, 16 | /// the number of decimals for display purpose and optionally additional properties 17 | /// 18 | /// 19 | /// 20 | /// Initial supply, should have an even number of characters 21 | /// The token identifier 22 | Task IssueFungibleToken(Wallet wallet, Token token, BigInteger initialSupply); 23 | 24 | /// 25 | /// One has to perform an issuance transaction in order to register a non fungible token. 26 | /// Non FungibleESDT Tokens are issued via a request to the Metachain, which is a transaction submitted by the Account which will manage the tokens. 27 | /// When issuing a token, one must provide a token name, a ticker and optionally additional properties. 28 | /// 29 | /// 30 | /// 31 | /// 32 | /// 33 | Task IssueNonFungibleToken(Wallet wallet, string tokenName, string tokenTicker); 34 | 35 | /// 36 | /// One has to perform an issuance transaction in order to register a semi fungible token. 37 | /// Semi FungibleESDT Tokens are issued via a request to the Metachain, which is a transaction submitted by the Account which will manage the tokens 38 | /// When issuing a semi fungible token, one must provide a token name, a ticker, the initial quantity and optionally additional properties 39 | /// 40 | /// 41 | /// 42 | /// 43 | /// 44 | Task IssueSemiFungibleToken(Wallet wallet, string tokenName, string tokenTicker); 45 | 46 | Task> GetSpecialRole(string tokenIdentifier); 47 | 48 | Task SetSpecialRole(Wallet wallet, string tokenIdentifier, params string[] roles); 49 | 50 | Task CreateNftToken( 51 | Wallet wallet, 52 | string tokenIdentifier, 53 | BigInteger quantity, 54 | string tokenName, 55 | ushort royalties, 56 | Dictionary attributes, 57 | Uri[] uris, 58 | byte[] hash = null); 59 | 60 | Task> GetEsdtTokens(Address address); 61 | 62 | Task GetEsdtFungibleToken(Address address, string tokenIdentifier); 63 | 64 | Task GetEsdtNonFungibleToken(Address address, string tokenIdentifier, ulong tokenId); 65 | 66 | Task TransferEsdtToken(Wallet wallet, EsdtToken token, Address receiver, BigInteger quantity); 67 | 68 | Task TransferEsdtTokenToSmartContract(Wallet wallet, EsdtToken token, Address smartContract, 69 | string functionName, BigInteger quantity, params IBinaryType[] args); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Provider/Dtos/AccountResponseDto.cs: -------------------------------------------------------------------------------- 1 | namespace Erdcsharp.Provider.Dtos 2 | { 3 | public class AccountDataDto 4 | { 5 | public AccountDto Account { get; set; } 6 | } 7 | 8 | public class AccountDto 9 | { 10 | public string Address { get; set; } 11 | public long Nonce { get; set; } 12 | public string Balance { get; set; } 13 | public string Username { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Provider/Dtos/ConfigResponseDto.cs: -------------------------------------------------------------------------------- 1 | namespace Erdcsharp.Provider.Dtos 2 | { 3 | public class ConfigDataDto 4 | { 5 | public ConfigDto Config { get; set; } 6 | } 7 | 8 | public class ConfigDto 9 | { 10 | public string erd_chain_id { get; set; } 11 | public int erd_denomination { get; set; } 12 | public int erd_gas_per_data_byte { get; set; } 13 | public string erd_gas_price_modifier { get; set; } 14 | public string erd_latest_tag_software_version { get; set; } 15 | public int erd_meta_consensus_group_size { get; set; } 16 | public int erd_min_gas_limit { get; set; } 17 | public int erd_min_gas_price { get; set; } 18 | public int erd_min_transaction_version { get; set; } 19 | public int erd_num_metachain_nodes { get; set; } 20 | public int erd_num_nodes_in_shard { get; set; } 21 | public int erd_num_shards_without_meta { get; set; } 22 | public string erd_rewards_top_up_gradient_point { get; set; } 23 | public int erd_round_duration { get; set; } 24 | public int erd_rounds_per_epoch { get; set; } 25 | public int erd_shard_consensus_group_size { get; set; } 26 | public int erd_start_time { get; set; } 27 | public string erd_top_up_factor { get; set; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Provider/Dtos/CreateTransactionResponseDto.cs: -------------------------------------------------------------------------------- 1 | namespace Erdcsharp.Provider.Dtos 2 | { 3 | public class CreateTransactionResponseDataDto 4 | { 5 | public string TxHash { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Provider/Dtos/ESDTTokenResponseDto.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Erdcsharp.Provider.Dtos 4 | { 5 | public class EsdtTokenDataDto 6 | { 7 | public Dictionary Esdts { get; set; } 8 | } 9 | 10 | public class EsdtTokenData 11 | { 12 | public EsdtItemDto TokenData { get; set; } 13 | } 14 | 15 | public class EsdtItemDto 16 | { 17 | public string Balance { get; set; } 18 | public string Creator { get; set; } 19 | public string Name { get; set; } 20 | public ulong Nonce { get; set; } 21 | public string Hash { get; set; } 22 | public string Royalties { get; set; } 23 | public string TokenIdentifier { get; set; } 24 | public string[] Uris { get; set; } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Provider/Dtos/ElrondGatewayResponseDto.cs: -------------------------------------------------------------------------------- 1 | using Erdcsharp.Domain.Exceptions; 2 | 3 | namespace Erdcsharp.Provider.Dtos 4 | { 5 | /// 6 | /// In case of a success, the data field is populated, the error field is empty, while the code field is set to **successful**. 7 | /// 8 | /// 9 | public class ElrondGatewayResponseDto 10 | { 11 | /// 12 | /// 13 | /// 14 | public T Data { get; set; } 15 | 16 | /// 17 | /// Human-readable description of the issue 18 | /// 19 | public string Error { get; set; } 20 | 21 | /// 22 | /// 'successful' in case of success 23 | /// 24 | public string Code { get; set; } 25 | 26 | public void EnsureSuccessStatusCode() 27 | { 28 | if (string.IsNullOrEmpty(Error) && Code == "successful") 29 | return; 30 | 31 | throw new GatewayException(Error, Code); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Provider/Dtos/QueryVmRequestDto.cs: -------------------------------------------------------------------------------- 1 | namespace Erdcsharp.Provider.Dtos 2 | { 3 | public class QueryVmRequestDto 4 | { 5 | /// 6 | /// The Address (bech32) of the Smart Contract. 7 | /// 8 | public string ScAddress { get; set; } 9 | 10 | /// 11 | /// The rustType of the Pure Function to execute. 12 | /// 13 | public string FuncName { get; set; } 14 | 15 | /// 16 | /// The arguments of the Pure Function, as hex-encoded strings. The array can be empty. 17 | /// 18 | public string[] Args { get; set; } 19 | 20 | /// 21 | /// The Address (bech32) of the caller. 22 | /// 23 | public string Caller { get; set; } 24 | 25 | /// 26 | /// The Value to transfer (can be zero). 27 | /// 28 | public string value { get; set; } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Provider/Dtos/QueryVmResultDto.cs: -------------------------------------------------------------------------------- 1 | namespace Erdcsharp.Provider.Dtos 2 | { 3 | public class QueryVmResultDataDto 4 | { 5 | public QueryVmResultInnerDataDto Data { get; set; } 6 | } 7 | 8 | public class QueryVmResultInnerDataDto 9 | { 10 | public string[] ReturnData { get; set; } 11 | public string ReturnCode { get; set; } 12 | public string ReturnMessage { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Provider/Dtos/TransactionCostDto.cs: -------------------------------------------------------------------------------- 1 | namespace Erdcsharp.Provider.Dtos 2 | { 3 | public class TransactionCostDataDto 4 | { 5 | public long TxGasUnits { get; set; } 6 | public string ReturnMessage { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Provider/Dtos/TransactionRequestDto.cs: -------------------------------------------------------------------------------- 1 | namespace Erdcsharp.Provider.Dtos 2 | { 3 | public class TransactionRequestDto 4 | { 5 | public long Nonce { get; set; } 6 | public string Value { get; set; } 7 | public string Receiver { get; set; } 8 | public string Sender { get; set; } 9 | public long GasPrice { get; set; } 10 | public long GasLimit { get; set; } 11 | public string Data { get; set; } 12 | public string ChainID { get; set; } 13 | public int Version { get; set; } 14 | public string Signature { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Provider/Dtos/TransactionResponseDto.cs: -------------------------------------------------------------------------------- 1 | namespace Erdcsharp.Provider.Dtos 2 | { 3 | /// 4 | /// Gateway transaction response 5 | /// 6 | public class TransactionResponseData 7 | { 8 | public TransactionDto Transaction { get; set; } 9 | } 10 | 11 | /// 12 | /// Transaction detail 13 | /// 14 | public class TransactionDto 15 | { 16 | public string Type { get; set; } 17 | public long Nonce { get; set; } 18 | public long Round { get; set; } 19 | public long Epoch { get; set; } 20 | public string Value { get; set; } 21 | public string Receiver { get; set; } 22 | public string Sender { get; set; } 23 | public long GasPrice { get; set; } 24 | public long GasLimit { get; set; } 25 | public string Data { get; set; } 26 | public string Signature { get; set; } 27 | public long SourceShard { get; set; } 28 | public long DestinationShard { get; set; } 29 | public long BlockNonce { get; set; } 30 | public string BlockHash { get; set; } 31 | public long NotarizedAtSourceInMetaNonce { get; set; } 32 | public string NotarizedAtSourceInMetaHash { get; set; } 33 | public long NotarizedAtDestinationInMetaNonce { get; set; } 34 | public string NotarizedAtDestinationInMetaHash { get; set; } 35 | public string MiniblockType { get; set; } 36 | public string MiniblockHash { get; set; } 37 | public string Status { get; set; } 38 | public long HyperblockNonce { get; set; } 39 | public string HyperblockHash { get; set; } 40 | public SmartContractResultDto[] SmartContractResults { get; set; } 41 | } 42 | 43 | public class SmartContractResultDto 44 | { 45 | public string Hash { get; set; } 46 | public long Nonce { get; set; } 47 | public long Value { get; set; } 48 | public string Receiver { get; set; } 49 | public string Sender { get; set; } 50 | public string Data { get; set; } 51 | public string ReturnMessage { get; set; } 52 | public string PrevTxHash { get; set; } 53 | public string OriginalTxHash { get; set; } 54 | public long GasLimit { get; set; } 55 | public long GasPrice { get; set; } 56 | public long CallType { get; set; } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Provider/ElrondProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Http; 2 | using System.Text; 3 | using System.Threading.Tasks; 4 | using Erdcsharp.Configuration; 5 | using Erdcsharp.Domain.Helper; 6 | using Erdcsharp.Provider.Dtos; 7 | 8 | namespace Erdcsharp.Provider 9 | { 10 | public class ElrondProvider : IElrondProvider 11 | { 12 | private readonly HttpClient _httpClient; 13 | 14 | public ElrondProvider(HttpClient httpClient, ElrondNetworkConfiguration configuration = null) 15 | { 16 | _httpClient = httpClient; 17 | if (configuration != null) 18 | { 19 | _httpClient.BaseAddress = configuration.GatewayUri; 20 | } 21 | } 22 | 23 | public async Task GetNetworkConfig() 24 | { 25 | var response = await _httpClient.GetAsync("network/config"); 26 | 27 | var content = await response.Content.ReadAsStringAsync(); 28 | var result = JsonSerializerWrapper.Deserialize>(content); 29 | result.EnsureSuccessStatusCode(); 30 | return result.Data; 31 | } 32 | 33 | public async Task GetAccount(string address) 34 | { 35 | var response = await _httpClient.GetAsync($"address/{address}"); 36 | 37 | var content = await response.Content.ReadAsStringAsync(); 38 | var result = JsonSerializerWrapper.Deserialize>(content); 39 | result.EnsureSuccessStatusCode(); 40 | return result.Data.Account; 41 | } 42 | 43 | public async Task GetEsdtTokens(string address) 44 | { 45 | var response = await _httpClient.GetAsync($"address/{address}/esdt"); 46 | 47 | var content = await response.Content.ReadAsStringAsync(); 48 | var result = JsonSerializerWrapper.Deserialize>(content); 49 | result.EnsureSuccessStatusCode(); 50 | return result.Data; 51 | } 52 | 53 | public async Task GetEsdtNftToken(string address, string tokenIdentifier, ulong tokenId) 54 | { 55 | var response = await _httpClient.GetAsync($"address/{address}/nft/{tokenIdentifier}/nonce/{tokenId}"); 56 | 57 | var content = await response.Content.ReadAsStringAsync(); 58 | var result = JsonSerializerWrapper.Deserialize>(content); 59 | result.EnsureSuccessStatusCode(); 60 | return result.Data; 61 | } 62 | 63 | public async Task GetEsdtToken(string address, string tokenIdentifier) 64 | { 65 | var response = await _httpClient.GetAsync($"address/{address}/esdt/{tokenIdentifier}"); 66 | 67 | var content = await response.Content.ReadAsStringAsync(); 68 | var result = JsonSerializerWrapper.Deserialize>(content); 69 | result.EnsureSuccessStatusCode(); 70 | return result.Data; 71 | } 72 | 73 | public async Task SendTransaction(TransactionRequestDto transactionRequestDto) 74 | { 75 | var raw = JsonSerializerWrapper.Serialize(transactionRequestDto); 76 | var payload = new StringContent(raw, Encoding.UTF8, "application/json"); 77 | var response = await _httpClient.PostAsync("transaction/send", payload); 78 | 79 | var content = await response.Content.ReadAsStringAsync(); 80 | var result = 81 | JsonSerializerWrapper.Deserialize>(content); 82 | result.EnsureSuccessStatusCode(); 83 | return result.Data; 84 | } 85 | 86 | public async Task GetTransactionCost(TransactionRequestDto transactionRequestDto) 87 | { 88 | var raw = JsonSerializerWrapper.Serialize(transactionRequestDto); 89 | var payload = new StringContent(raw, Encoding.UTF8, "application/json"); 90 | var response = await _httpClient.PostAsync("transaction/cost", payload); 91 | 92 | var content = await response.Content.ReadAsStringAsync(); 93 | var result = JsonSerializerWrapper.Deserialize>(content); 94 | result.EnsureSuccessStatusCode(); 95 | return result.Data; 96 | } 97 | 98 | public async Task QueryVm(QueryVmRequestDto queryVmRequestDto) 99 | { 100 | var raw = JsonSerializerWrapper.Serialize(queryVmRequestDto); 101 | var payload = new StringContent(raw, Encoding.UTF8, "application/json"); 102 | var response = await _httpClient.PostAsync("vm-values/query", payload); 103 | 104 | var content = await response.Content.ReadAsStringAsync(); 105 | var result = JsonSerializerWrapper.Deserialize>(content); 106 | result.EnsureSuccessStatusCode(); 107 | return result.Data; 108 | } 109 | 110 | public async Task GetTransactionDetail(string txHash) 111 | { 112 | var response = await _httpClient.GetAsync($"transaction/{txHash}?withResults=true"); 113 | 114 | var content = await response.Content.ReadAsStringAsync(); 115 | var result = JsonSerializerWrapper.Deserialize>(content); 116 | result.EnsureSuccessStatusCode(); 117 | return result.Data.Transaction; 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/Provider/IElrondProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Erdcsharp.Provider.Dtos; 3 | 4 | namespace Erdcsharp.Provider 5 | { 6 | public interface IElrondProvider 7 | { 8 | /// 9 | /// This endpoint allows one to query basic details about the configuration of the Network. 10 | /// 11 | /// 12 | Task GetNetworkConfig(); 13 | 14 | /// 15 | /// This endpoint allows one to retrieve basic information about an Address (Account). 16 | /// 17 | /// The address 18 | /// 19 | Task GetAccount(string address); 20 | 21 | /// 22 | /// Returns an array of FungibleESDT Tokens that the specified address has interacted with (issued, sent or received). 23 | /// 24 | /// The Address to query in bech32 format. 25 | /// 26 | Task GetEsdtTokens(string address); 27 | 28 | /// 29 | /// Returns the balance of an address for specific FungibleESDT Tokens. 30 | /// 31 | /// The Address to query in bech32 format. 32 | /// The token identifier. 33 | /// The nonce after the NFT creation.. 34 | /// 35 | Task GetEsdtNftToken(string address, string tokenIdentifier, ulong tokenId); 36 | 37 | /// 38 | /// Returns the balance of an address for specific ESDT Tokens. 39 | /// 40 | /// The Address to query in bech32 format. 41 | /// The token identifier. 42 | /// 43 | Task GetEsdtToken(string address, string tokenIdentifier); 44 | 45 | /// 46 | /// This endpoint allows one to send a signed Transaction to the Blockchain. 47 | /// 48 | /// The transaction payload 49 | /// 50 | Task SendTransaction(TransactionRequestDto transactionRequestDto); 51 | 52 | /// 53 | /// This endpoint allows one to query the details of a Transaction. 54 | /// 55 | /// The transaction hash 56 | /// 57 | Task GetTransactionDetail(string txHash); 58 | 59 | /// 60 | /// This endpoint allows one to estimate the cost of a transaction. 61 | /// 62 | /// The transaction payload 63 | /// 64 | Task GetTransactionCost(TransactionRequestDto transactionRequestDto); 65 | 66 | /// 67 | /// This endpoint allows one to execute - with no side-effects - a pure function of a Smart Contract and retrieve the execution results (the Virtual Machine Output). 68 | /// 69 | /// 70 | /// 71 | Task QueryVm(QueryVmRequestDto queryVmRequestDto); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /tests/Erdcsharp.Console.NET 5.0/Erdcsharp.Console.NET 5.0.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net5.0 6 | Erdcsharp.Console.NET 5.0 7 | Erdcsharp.Console.NET 5.0 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Always 17 | 18 | 19 | Always 20 | 21 | 22 | Always 23 | 24 | 25 | Always 26 | 27 | 28 | Always 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /tests/Erdcsharp.Console.NET 5.0/FullAuctionData.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Elrond.SDK.Console 4 | { 5 | public class FullAuctionData 6 | { 7 | [JsonProperty("payment_token")] public PaymentToken PaymentToken { get; set; } 8 | [JsonProperty("min_bid")] public string MinBid { get; set; } 9 | [JsonProperty("max_bid")] public string MaxBid { get; set; } 10 | [JsonProperty("deadline")] public string Deadline { get; set; } 11 | [JsonProperty("original_owner")] public string OriginalOwner { get; set; } 12 | [JsonProperty("current_bid")] public string CurrentBid { get; set; } 13 | [JsonProperty("current_winner")] public string CurrentWinner { get; set; } 14 | 15 | [JsonProperty("marketplace_cut_percentage")] 16 | public string MarketplaceCutPercentage { get; set; } 17 | 18 | [JsonProperty("creator_royalties_percentage")] 19 | public string CreatorRoyaltiesPercentage { get; set; } 20 | } 21 | 22 | public class PaymentToken 23 | { 24 | [JsonProperty("token_type")] public string TokenType { get; set; } 25 | [JsonProperty("nonce")] public string Nonce { get; set; } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/Erdcsharp.Console.NET 5.0/SmartContracts/adder/adder.abi.json: -------------------------------------------------------------------------------- 1 | { 2 | "docs": [ 3 | "One of the simplest smart contracts possible,", 4 | "it holds a single variable in storage, which anyone can increment." 5 | ], 6 | "name": "Adder", 7 | "endpoints": [ 8 | { 9 | "name": "getSum", 10 | "inputs": [], 11 | "outputs": [ 12 | { 13 | "type": "BigInt" 14 | } 15 | ] 16 | }, 17 | { 18 | "name": "init", 19 | "inputs": [ 20 | { 21 | "name": "initial_value", 22 | "type": "BigInt" 23 | } 24 | ], 25 | "outputs": [] 26 | }, 27 | { 28 | "docs": [ 29 | "Add desired amount to the storage variable." 30 | ], 31 | "name": "add", 32 | "inputs": [ 33 | { 34 | "name": "value", 35 | "type": "BigInt" 36 | } 37 | ], 38 | "outputs": [] 39 | } 40 | ], 41 | "types": {} 42 | } -------------------------------------------------------------------------------- /tests/Erdcsharp.Console.NET 5.0/SmartContracts/adder/adder.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/multiversx/mx-sdk-csharp/408d85058ca419cff59ec92fed1030faebe44c17/tests/Erdcsharp.Console.NET 5.0/SmartContracts/adder/adder.wasm -------------------------------------------------------------------------------- /tests/Erdcsharp.Console.NET 5.0/SmartContracts/auction/auction.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/multiversx/mx-sdk-csharp/408d85058ca419cff59ec92fed1030faebe44c17/tests/Erdcsharp.Console.NET 5.0/SmartContracts/auction/auction.wasm -------------------------------------------------------------------------------- /tests/Erdcsharp.Console.NET 5.0/Wallets/erd17rnvj9shx2x9vh2ckw0nf53vvlylj6235lmrhu668rg2c9a8mxjqvjrhq5.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 4, 3 | "id": "3aabe829-9351-4b67-b253-442233911271", 4 | "address": "f0e6c91617328c565d58b39f34d22c67c9f96951a7f63bf35a38d0ac17a7d9a4", 5 | "bech32": "erd17rnvj9shx2x9vh2ckw0nf53vvlylj6235lmrhu668rg2c9a8mxjqvjrhq5", 6 | "crypto": { 7 | "ciphertext": 8 | "bcd5447306b6aacf31e2d2fe79e09af99185b0e986915cb8d00eb9feccecf0e18300f4b06d5bb9256bb2f7590108b7d23c8b3a024d63b32a1c4c3f98b2f80583", 9 | "cipherparams": { "iv": "6cff370564b37ab79a99000da9888725" }, 10 | "cipher": "aes-128-ctr", 11 | "kdf": "scrypt", 12 | "kdfparams": { 13 | "dklen": 32, 14 | "salt": "17d10fcbeda630fea6f3fb81d274272e69e3a3e3420c776e09852766cd7267f8", 15 | "n": 4096, 16 | "r": 8, 17 | "p": 1 18 | }, 19 | "mac": "e64f524a85fdf74567a5ccb76d79555b7499c0f0fb44bdff59d9632008aa6352" 20 | } 21 | } -------------------------------------------------------------------------------- /tests/Erdcsharp.Console.NET_Core_3.1/Erdcsharp.Console.NET_Core_3.1.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp3.1 6 | Erdcsharp.Console.NET_Core_3._1 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /tests/Erdcsharp.Console.NET_Core_3.1/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using Erdcsharp.Configuration; 5 | using Erdcsharp.Domain; 6 | using Erdcsharp.Provider; 7 | 8 | namespace Erdcsharp.Console.NET_Core_3._1 9 | { 10 | public static class Program 11 | { 12 | private const string AliceSecretHex = "413f42575f7f26fad3317a778771212fdb80245850981e48b58a4f25e344e8f9"; 13 | private const string BobBech32 = "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx"; 14 | 15 | public static async Task Main(string[] args) 16 | { 17 | var provider = new ElrondProvider(new HttpClient(), new ElrondNetworkConfiguration(Network.TestNet)); 18 | var wallet = new Wallet(AliceSecretHex); 19 | var constants = await NetworkConfig.GetFromNetwork(provider); 20 | 21 | await SynchronizingNetworkParameter(provider); 22 | await SynchronizingAnAccountObject(provider, wallet.GetAccount()); 23 | 24 | await CreatingValueTransferTransactions(provider, constants, wallet); 25 | } 26 | 27 | private static async Task SynchronizingNetworkParameter(IElrondProvider provider) 28 | { 29 | System.Console.WriteLine("SynchronizingNetworkParameter"); 30 | 31 | var constants = await NetworkConfig.GetFromNetwork(provider); 32 | 33 | System.Console.WriteLine("MinGasPrice {0}", constants.MinGasPrice); 34 | System.Console.WriteLine("ChainId {0}", constants.ChainId); 35 | System.Console.WriteLine("GasPerDataByte {0}", constants.GasPerDataByte); 36 | System.Console.WriteLine("-*-*-*-*-*" + Environment.NewLine); 37 | } 38 | 39 | private static async Task SynchronizingAnAccountObject(IElrondProvider provider, Account account) 40 | { 41 | System.Console.WriteLine("SynchronizingAnAccountObject"); 42 | 43 | await account.Sync(provider); 44 | 45 | System.Console.WriteLine("Balance {0}", account.Balance); 46 | System.Console.WriteLine("Nonce {0}", account.Nonce); 47 | 48 | System.Console.WriteLine("-*-*-*-*-*" + Environment.NewLine); 49 | } 50 | 51 | private static async Task CreatingValueTransferTransactions(IElrondProvider provider, NetworkConfig networkConfig, 52 | Wallet wallet) 53 | { 54 | System.Console.WriteLine("CreatingValueTransferTransactions"); 55 | 56 | var sender = wallet.GetAccount(); 57 | var receiver = Address.FromBech32(BobBech32); 58 | await sender.Sync(provider); 59 | 60 | var transaction = TransactionRequest.Create(sender, networkConfig, receiver, TokenAmount.EGLD("0.000000000000054715")); 61 | transaction.SetData("Hello world !"); 62 | transaction.SetGasLimit(GasLimit.ForTransfer(networkConfig, transaction)); 63 | 64 | var transactionResult = await transaction.Send(provider, wallet); 65 | await transactionResult.AwaitExecuted(provider); 66 | transactionResult.EnsureTransactionSuccess(); 67 | 68 | System.Console.WriteLine("TxHash {0}", transactionResult.TxHash); 69 | System.Console.WriteLine("-*-*-*-*-*" + Environment.NewLine); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tests/Erdcsharp.Console.NET_Framework/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /tests/Erdcsharp.Console.NET_Framework/Erdcsharp.Console.NET_Framework.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {76BCB232-AECF-49E1-A364-2BD9EDF4634F} 8 | Exe 9 | Erdcsharp.Console.NET_Framework 10 | Erdcsharp.Console.NET_Framework 11 | v4.6.1 12 | 512 13 | true 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | {27131229-2f55-4fce-8ca9-515feb9a790d} 56 | Erdcsharp 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /tests/Erdcsharp.Console.NET_Framework/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using Erdcsharp.Configuration; 5 | using Erdcsharp.Domain; 6 | using Erdcsharp.Provider; 7 | 8 | namespace Erdcsharp.Console.NET_Framework 9 | { 10 | public static class Program 11 | { 12 | private const string AliceSecretHex = "413f42575f7f26fad3317a778771212fdb80245850981e48b58a4f25e344e8f9"; 13 | private const string BobBech32 = "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx"; 14 | 15 | public static async Task Main(string[] args) 16 | { 17 | var provider = new ElrondProvider(new HttpClient(), new ElrondNetworkConfiguration(Network.TestNet)); 18 | var wallet = new Wallet(AliceSecretHex); 19 | var constants = await NetworkConfig.GetFromNetwork(provider); 20 | 21 | await SynchronizingNetworkParameter(provider); 22 | await SynchronizingAnAccountObject(provider, wallet.GetAccount()); 23 | 24 | await CreatingValueTransferTransactions(provider, constants, wallet); 25 | } 26 | 27 | private static async Task SynchronizingNetworkParameter(IElrondProvider provider) 28 | { 29 | System.Console.WriteLine("SynchronizingNetworkParameter"); 30 | 31 | var constants = await NetworkConfig.GetFromNetwork(provider); 32 | 33 | System.Console.WriteLine("MinGasPrice {0}", constants.MinGasPrice); 34 | System.Console.WriteLine("ChainId {0}", constants.ChainId); 35 | System.Console.WriteLine("GasPerDataByte {0}", constants.GasPerDataByte); 36 | System.Console.WriteLine("-*-*-*-*-*" + Environment.NewLine); 37 | } 38 | 39 | private static async Task SynchronizingAnAccountObject(IElrondProvider provider, Account account) 40 | { 41 | System.Console.WriteLine("SynchronizingAnAccountObject"); 42 | 43 | await account.Sync(provider); 44 | 45 | System.Console.WriteLine("Balance {0}", account.Balance); 46 | System.Console.WriteLine("Nonce {0}", account.Nonce); 47 | 48 | System.Console.WriteLine("-*-*-*-*-*" + Environment.NewLine); 49 | } 50 | 51 | private static async Task CreatingValueTransferTransactions(IElrondProvider provider, NetworkConfig networkConfig, Wallet wallet) 52 | { 53 | System.Console.WriteLine("CreatingValueTransferTransactions"); 54 | 55 | var sender = wallet.GetAccount(); 56 | var receiver = Address.FromBech32(BobBech32); 57 | await sender.Sync(provider); 58 | 59 | var transaction = TransactionRequest.Create(sender, networkConfig, receiver, TokenAmount.EGLD("0.000000000000054715")); 60 | transaction.SetData("Hello world !"); 61 | transaction.SetGasLimit(GasLimit.ForTransfer(networkConfig, transaction)); 62 | 63 | var transactionResult = await transaction.Send(provider, wallet); 64 | await transactionResult.AwaitExecuted(provider); 65 | transactionResult.EnsureTransactionSuccess(); 66 | 67 | System.Console.WriteLine("TxHash {0}", transactionResult.TxHash); 68 | System.Console.WriteLine("-*-*-*-*-*" + Environment.NewLine); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /tests/Erdcsharp.Console.NET_Framework/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Erdcsharp.Console.NET_Framework")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Erdcsharp.Console.NET_Framework")] 13 | [assembly: AssemblyCopyright("Copyright © 2021")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("76bcb232-aecf-49e1-a364-2bd9edf4634f")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /tests/Erdcsharp.Console/Elrond.SDK.Console.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net5.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Always 15 | 16 | 17 | Always 18 | 19 | 20 | Always 21 | 22 | 23 | Always 24 | 25 | 26 | Always 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /tests/Erdcsharp.Console/FullAuctionData.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace Elrond.SDK.Console 4 | { 5 | public class FullAuctionData 6 | { 7 | [JsonPropertyName("payment_token")] 8 | public PaymentToken PaymentToken { get; set; } 9 | [JsonPropertyName("min_bid")] 10 | public string MinBid { get; set; } 11 | [JsonPropertyName("max_bid")] 12 | public string MaxBid { get; set; } 13 | [JsonPropertyName("deadline")] 14 | public string Deadline { get; set; } 15 | [JsonPropertyName("originalOwner")] 16 | public string OriginalOwner { get; set; } 17 | [JsonPropertyName("current_bid")] 18 | public string CurrentBid { get; set; } 19 | [JsonPropertyName("current_winner")] 20 | public string CurrentWinner { get; set; } 21 | [JsonPropertyName("marketplace_cut_percentage")] 22 | public string MarketplaceCutPercentage { get; set; } 23 | [JsonPropertyName("creator_royalties_percentage")] 24 | public string CreatorRoyaltiesPercentage { get; set; } 25 | } 26 | 27 | public class PaymentToken 28 | { 29 | [JsonPropertyName("token_type")] 30 | public string TokenType { get; set; } 31 | [JsonPropertyName("nonce")] 32 | public string Nonce { get; set; } 33 | } 34 | } -------------------------------------------------------------------------------- /tests/Erdcsharp.Console/SmartContracts/adder/adder.abi.json: -------------------------------------------------------------------------------- 1 | { 2 | "docs": [ 3 | "One of the simplest smart contracts possible,", 4 | "it holds a single variable in storage, which anyone can increment." 5 | ], 6 | "name": "Adder", 7 | "endpoints": [ 8 | { 9 | "name": "getSum", 10 | "inputs": [], 11 | "outputs": [ 12 | { 13 | "type": "BigInt" 14 | } 15 | ] 16 | }, 17 | { 18 | "name": "init", 19 | "inputs": [ 20 | { 21 | "name": "initial_value", 22 | "type": "BigInt" 23 | } 24 | ], 25 | "outputs": [] 26 | }, 27 | { 28 | "docs": [ 29 | "Add desired amount to the storage variable." 30 | ], 31 | "name": "add", 32 | "inputs": [ 33 | { 34 | "name": "value", 35 | "type": "BigInt" 36 | } 37 | ], 38 | "outputs": [] 39 | } 40 | ], 41 | "types": {} 42 | } -------------------------------------------------------------------------------- /tests/Erdcsharp.Console/SmartContracts/adder/adder.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/multiversx/mx-sdk-csharp/408d85058ca419cff59ec92fed1030faebe44c17/tests/Erdcsharp.Console/SmartContracts/adder/adder.wasm -------------------------------------------------------------------------------- /tests/Erdcsharp.Console/SmartContracts/auction/auction.abi.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Auction", 3 | "constructor": { 4 | "inputs": [ 5 | { 6 | "name": "bid_cut_percentage", 7 | "type": "u64" 8 | } 9 | ], 10 | "outputs": [] 11 | }, 12 | "endpoints": [ 13 | { 14 | "name": "setCutPercentage", 15 | "inputs": [ 16 | { 17 | "name": "new_cut_percentage", 18 | "type": "u64" 19 | } 20 | ], 21 | "outputs": [] 22 | }, 23 | { 24 | "name": "auctionToken", 25 | "payableInTokens": [ 26 | "*" 27 | ], 28 | "inputs": [ 29 | { 30 | "name": "min_bid", 31 | "type": "BigUint" 32 | }, 33 | { 34 | "name": "max_bid", 35 | "type": "BigUint" 36 | }, 37 | { 38 | "name": "deadline", 39 | "type": "u64" 40 | }, 41 | { 42 | "name": "accepted_payment_token", 43 | "type": "TokenIdentifier" 44 | }, 45 | { 46 | "name": "opt_accepted_payment_token_nonce", 47 | "type": "optional", 48 | "multi_arg": true 49 | } 50 | ], 51 | "outputs": [] 52 | }, 53 | { 54 | "name": "bid", 55 | "payableInTokens": [ 56 | "*" 57 | ], 58 | "inputs": [ 59 | { 60 | "name": "nft_type", 61 | "type": "TokenIdentifier" 62 | }, 63 | { 64 | "name": "nft_nonce", 65 | "type": "u64" 66 | } 67 | ], 68 | "outputs": [] 69 | }, 70 | { 71 | "name": "endAuction", 72 | "inputs": [ 73 | { 74 | "name": "nft_type", 75 | "type": "TokenIdentifier" 76 | }, 77 | { 78 | "name": "nft_nonce", 79 | "type": "u64" 80 | } 81 | ], 82 | "outputs": [] 83 | }, 84 | { 85 | "name": "withdraw", 86 | "inputs": [ 87 | { 88 | "name": "nft_type", 89 | "type": "TokenIdentifier" 90 | }, 91 | { 92 | "name": "nft_nonce", 93 | "type": "u64" 94 | } 95 | ], 96 | "outputs": [] 97 | }, 98 | { 99 | "name": "isAlreadyUpForAuction", 100 | "inputs": [ 101 | { 102 | "name": "nft_type", 103 | "type": "TokenIdentifier" 104 | }, 105 | { 106 | "name": "nft_nonce", 107 | "type": "u64" 108 | } 109 | ], 110 | "outputs": [ 111 | { 112 | "type": "bool" 113 | } 114 | ] 115 | }, 116 | { 117 | "name": "getPaymentTokenForAuctionedNft", 118 | "inputs": [ 119 | { 120 | "name": "nft_type", 121 | "type": "TokenIdentifier" 122 | }, 123 | { 124 | "name": "nft_nonce", 125 | "type": "u64" 126 | } 127 | ], 128 | "outputs": [ 129 | { 130 | "type": "optional>", 131 | "multi_result": true 132 | } 133 | ] 134 | }, 135 | { 136 | "name": "getMinMaxBid", 137 | "inputs": [ 138 | { 139 | "name": "nft_type", 140 | "type": "TokenIdentifier" 141 | }, 142 | { 143 | "name": "nft_nonce", 144 | "type": "u64" 145 | } 146 | ], 147 | "outputs": [ 148 | { 149 | "type": "optional>", 150 | "multi_result": true 151 | } 152 | ] 153 | }, 154 | { 155 | "name": "getDeadline", 156 | "inputs": [ 157 | { 158 | "name": "nft_type", 159 | "type": "TokenIdentifier" 160 | }, 161 | { 162 | "name": "nft_nonce", 163 | "type": "u64" 164 | } 165 | ], 166 | "outputs": [ 167 | { 168 | "type": "optional", 169 | "multi_result": true 170 | } 171 | ] 172 | }, 173 | { 174 | "name": "getOriginalOwner", 175 | "inputs": [ 176 | { 177 | "name": "nft_type", 178 | "type": "TokenIdentifier" 179 | }, 180 | { 181 | "name": "nft_nonce", 182 | "type": "u64" 183 | } 184 | ], 185 | "outputs": [ 186 | { 187 | "type": "optional
", 188 | "multi_result": true 189 | } 190 | ] 191 | }, 192 | { 193 | "name": "getCurrentWinningBid", 194 | "inputs": [ 195 | { 196 | "name": "nft_type", 197 | "type": "TokenIdentifier" 198 | }, 199 | { 200 | "name": "nft_nonce", 201 | "type": "u64" 202 | } 203 | ], 204 | "outputs": [ 205 | { 206 | "type": "optional", 207 | "multi_result": true 208 | } 209 | ] 210 | }, 211 | { 212 | "name": "getCurrentWinner", 213 | "inputs": [ 214 | { 215 | "name": "nft_type", 216 | "type": "TokenIdentifier" 217 | }, 218 | { 219 | "name": "nft_nonce", 220 | "type": "u64" 221 | } 222 | ], 223 | "outputs": [ 224 | { 225 | "type": "optional
", 226 | "multi_result": true 227 | } 228 | ] 229 | }, 230 | { 231 | "name": "getFullAuctionData", 232 | "inputs": [ 233 | { 234 | "name": "nft_type", 235 | "type": "TokenIdentifier" 236 | }, 237 | { 238 | "name": "nft_nonce", 239 | "type": "u64" 240 | } 241 | ], 242 | "outputs": [ 243 | { 244 | "type": "optional", 245 | "multi_result": true 246 | } 247 | ] 248 | }, 249 | { 250 | "name": "getMarketplaceCutPercentage", 251 | "inputs": [], 252 | "outputs": [ 253 | { 254 | "type": "BigUint" 255 | } 256 | ] 257 | } 258 | ], 259 | "types": { 260 | "Auction": { 261 | "type": "struct", 262 | "fields": [ 263 | { 264 | "name": "payment_token", 265 | "type": "EsdtToken" 266 | }, 267 | { 268 | "name": "min_bid", 269 | "type": "BigUint" 270 | }, 271 | { 272 | "name": "max_bid", 273 | "type": "BigUint" 274 | }, 275 | { 276 | "name": "deadline", 277 | "type": "u64" 278 | }, 279 | { 280 | "name": "original_owner", 281 | "type": "Address" 282 | }, 283 | { 284 | "name": "current_bid", 285 | "type": "BigUint" 286 | }, 287 | { 288 | "name": "current_winner", 289 | "type": "Address" 290 | }, 291 | { 292 | "name": "marketplace_cut_percentage", 293 | "type": "BigUint" 294 | }, 295 | { 296 | "name": "creator_royalties_percentage", 297 | "type": "BigUint" 298 | } 299 | ] 300 | }, 301 | "EsdtToken": { 302 | "type": "struct", 303 | "fields": [ 304 | { 305 | "name": "token_type", 306 | "type": "TokenIdentifier" 307 | }, 308 | { 309 | "name": "nonce", 310 | "type": "u64" 311 | } 312 | ] 313 | } 314 | } 315 | } -------------------------------------------------------------------------------- /tests/Erdcsharp.Console/SmartContracts/auction/auction.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/multiversx/mx-sdk-csharp/408d85058ca419cff59ec92fed1030faebe44c17/tests/Erdcsharp.Console/SmartContracts/auction/auction.wasm -------------------------------------------------------------------------------- /tests/Erdcsharp.Console/Wallets/erd17rnvj9shx2x9vh2ckw0nf53vvlylj6235lmrhu668rg2c9a8mxjqvjrhq5.json: -------------------------------------------------------------------------------- 1 | {"version":4,"id":"3aabe829-9351-4b67-b253-442233911271","address":"f0e6c91617328c565d58b39f34d22c67c9f96951a7f63bf35a38d0ac17a7d9a4","bech32":"erd17rnvj9shx2x9vh2ckw0nf53vvlylj6235lmrhu668rg2c9a8mxjqvjrhq5","crypto":{"ciphertext":"bcd5447306b6aacf31e2d2fe79e09af99185b0e986915cb8d00eb9feccecf0e18300f4b06d5bb9256bb2f7590108b7d23c8b3a024d63b32a1c4c3f98b2f80583","cipherparams":{"iv":"6cff370564b37ab79a99000da9888725"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"17d10fcbeda630fea6f3fb81d274272e69e3a3e3420c776e09852766cd7267f8","n":4096,"r":8,"p":1},"mac":"e64f524a85fdf74567a5ccb76d79555b7499c0f0fb44bdff59d9632008aa6352"}} -------------------------------------------------------------------------------- /tests/Erdcsharp.IntegrationTests/AccountIntegrationTests.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Http; 2 | using System.Threading.Tasks; 3 | using Erdcsharp.Configuration; 4 | using Erdcsharp.Domain; 5 | using Erdcsharp.Provider; 6 | using Erdcsharp.UnitTests.FakeData; 7 | using NUnit.Framework; 8 | 9 | namespace Erdcsharp.IntegrationTests 10 | { 11 | [TestFixture(Category = "LongRunning", Description = "Transaction interaction usage")] 12 | public class AccountIntegrationTests 13 | { 14 | private IElrondProvider _provider; 15 | 16 | [SetUp] 17 | public void Setup() 18 | { 19 | _provider = new ElrondProvider(new HttpClient(), new ElrondNetworkConfiguration(Network.TestNet)); 20 | } 21 | 22 | [Test(Description = "Synchronize an account from the network")] 23 | public async Task Should_Get_Alice_Balance() 24 | { 25 | var alice = new Account(Address.FromBech32(TestData.AliceBech32)); 26 | await alice.Sync(_provider); 27 | 28 | Assert.That(alice.Balance.Token.Ticker, Is.EqualTo("EGLD")); 29 | Assert.That(alice.Nonce, Is.Not.Null); 30 | Assert.That(alice.Balance.Value, Is.Not.Null); 31 | Assert.That(alice.Balance.ToCurrencyString(), Is.Not.Null); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/Erdcsharp.IntegrationTests/Erdcsharp.IntegrationTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /tests/Erdcsharp.IntegrationTests/SmartContractTests.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Http; 2 | using System.Threading.Tasks; 3 | using Erdcsharp.Configuration; 4 | using Erdcsharp.Domain; 5 | using Erdcsharp.Domain.Abi; 6 | using Erdcsharp.Domain.SmartContracts; 7 | using Erdcsharp.Domain.Values; 8 | using Erdcsharp.Provider; 9 | using Erdcsharp.UnitTests.FakeData; 10 | using NUnit.Framework; 11 | 12 | namespace Erdcsharp.IntegrationTests 13 | { 14 | [TestFixture(Category = "LongRunning", Description = "Smart contracts interaction usage")] 15 | public class SmartContractTests 16 | { 17 | private IElrondProvider _provider; 18 | private TestWalletFactory _testWalletFactory; 19 | 20 | [SetUp] 21 | public void Setup() 22 | { 23 | _provider = new ElrondProvider(new HttpClient(), new ElrondNetworkConfiguration(Network.TestNet)); 24 | _testWalletFactory = new TestWalletFactory(); 25 | } 26 | 27 | [Test(Description = "Deploy adder smart contract from alice account with an initial value")] 28 | public async Task Should_Deploy_Adder_SmartContract_And_Set_Initial_Value() 29 | { 30 | var networkConfig = await NetworkConfig.GetFromNetwork(_provider); 31 | var alice = _testWalletFactory.Alice; 32 | var aliceAccount = alice.GetAccount(); 33 | await aliceAccount.Sync(_provider); 34 | 35 | var code = CodeArtifact.FromFilePath("FakeData/SmartContracts/adder/adder.wasm"); 36 | var codeMetadata = new CodeMetadata(false, true, false); 37 | var initialValue = NumericValue.BigUintValue(10); 38 | 39 | var deployTxRequest = TransactionRequest.CreateDeploySmartContractTransactionRequest( 40 | networkConfig, 41 | aliceAccount, 42 | code, 43 | codeMetadata, 44 | initialValue); 45 | 46 | var deployTx = await deployTxRequest.Send(_provider, alice); 47 | await deployTx.AwaitExecuted(_provider); 48 | await deployTx.AwaitNotarized(_provider); 49 | 50 | var scAddress = SmartContract.ComputeAddress(deployTxRequest); 51 | Assert.That(scAddress, Is.Not.Null); 52 | 53 | await CallSmartContract(networkConfig, scAddress); 54 | } 55 | 56 | private async Task CallSmartContract(NetworkConfig networkConfig, Address smartContractAddress) 57 | { 58 | var wallet = _testWalletFactory.Bob; 59 | var account = wallet.GetAccount(); 60 | await account.Sync(_provider); 61 | var txRequest = TransactionRequest.CreateCallSmartContractTransactionRequest( 62 | networkConfig, 63 | account, 64 | smartContractAddress, 65 | "add", 66 | TokenAmount.Zero(), 67 | NumericValue.BigUintValue(10)); 68 | 69 | var tx = await txRequest.Send(_provider, wallet); 70 | await tx.AwaitExecuted(_provider); 71 | await tx.AwaitNotarized(_provider); 72 | 73 | await QuerySmartContract(smartContractAddress); 74 | await QuerySmartContractWithAbi(smartContractAddress); 75 | } 76 | 77 | private async Task QuerySmartContract(Address smartContractAddress) 78 | { 79 | var outputType = TypeValue.BigUintTypeValue; 80 | var queryResult = await SmartContract.QuerySmartContract( 81 | _provider, 82 | smartContractAddress, 83 | outputType, 84 | "getSum"); 85 | 86 | Assert.That(queryResult.Number.ToString(), Is.EqualTo("20")); 87 | } 88 | 89 | private async Task QuerySmartContractWithAbi(Address smartContractAddress) 90 | { 91 | var abiDefinition = AbiDefinition.FromFilePath("FakeData/SmartContracts/adder/adder.abi.json"); 92 | var queryResult = await SmartContract.QuerySmartContractWithAbiDefinition( 93 | _provider, 94 | smartContractAddress, 95 | abiDefinition, 96 | "getSum"); 97 | 98 | Assert.That(queryResult.Number.ToString(), Is.EqualTo("20")); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /tests/Erdcsharp.IntegrationTests/TransactionsIntegrationTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using Erdcsharp.Configuration; 5 | using Erdcsharp.Domain; 6 | using Erdcsharp.Provider; 7 | using Erdcsharp.UnitTests.FakeData; 8 | using NUnit.Framework; 9 | 10 | namespace Erdcsharp.IntegrationTests 11 | { 12 | [TestFixture(Category = "LongRunning", Description = "Transaction interaction usage")] 13 | public class TransactionsIntegrationTests 14 | { 15 | private IElrondProvider _provider; 16 | private TestWalletFactory _testWalletFactory; 17 | 18 | [SetUp] 19 | public void Setup() 20 | { 21 | _provider = new ElrondProvider(new HttpClient(), new ElrondNetworkConfiguration(Network.TestNet)); 22 | _testWalletFactory = new TestWalletFactory(); 23 | } 24 | 25 | [Test(Description = "Send a 4 EGLD transaction from alice to bob then transfer back the money")] 26 | public async Task Should_Send_Transactions() 27 | { 28 | var networkConfig = await NetworkConfig.GetFromNetwork(_provider); 29 | var alice = _testWalletFactory.Alice.GetAccount(); 30 | var bob = _testWalletFactory.Bob.GetAccount(); 31 | 32 | await alice.Sync(_provider); 33 | await bob.Sync(_provider); 34 | var initialBalanceOfBob = bob.Balance; 35 | 36 | // Alice send 4 EGLD to Bob 37 | var txRequestOne = TransactionRequest.Create(alice, networkConfig, bob.Address, TokenAmount.EGLD("4")); 38 | var transactionOne = await txRequestOne.Send(_provider, _testWalletFactory.Alice); 39 | await transactionOne.AwaitExecuted(_provider); 40 | 41 | await alice.Sync(_provider); 42 | await bob.Sync(_provider); 43 | var initialBalanceOfAlice = alice.Balance; 44 | var newBalanceOfBob = bob.Balance; 45 | 46 | // Bob send 4 EGLD back to Bob 47 | var txRequestTwo = TransactionRequest.Create(bob, networkConfig, alice.Address, TokenAmount.EGLD("4")); 48 | var transactionTwo = await txRequestTwo.Send(_provider, _testWalletFactory.Bob); 49 | await transactionTwo.AwaitExecuted(_provider); 50 | 51 | await alice.Sync(_provider); 52 | var newBalanceOfAlice = alice.Balance; 53 | 54 | Assert.That(newBalanceOfBob.Value, Is.EqualTo(initialBalanceOfBob.Value + TokenAmount.EGLD("4").Value)); 55 | Assert.That(newBalanceOfAlice.Value, 56 | Is.EqualTo(initialBalanceOfAlice.Value + TokenAmount.EGLD("4").Value)); 57 | } 58 | 59 | [Test(Description = "Send a 1 EGLD transaction from alice to alice await await")] 60 | public async Task Should_Await_Transaction_Is_Notarized() 61 | { 62 | var networkConfig = await NetworkConfig.GetFromNetwork(_provider); 63 | var alice = _testWalletFactory.Alice.GetAccount(); 64 | 65 | await alice.Sync(_provider); 66 | 67 | // Alice send 1 EGLD to alice 68 | var txRequest = TransactionRequest.Create(alice, networkConfig, alice.Address, TokenAmount.EGLD("1")); 69 | var tx = await txRequest.Send(_provider, _testWalletFactory.Alice); 70 | await tx.AwaitNotarized(_provider); 71 | 72 | Assert.Pass(); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /tests/Erdcsharp.Tests/Domain/AccountTests.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Erdcsharp.Domain; 3 | using Erdcsharp.Provider; 4 | using Erdcsharp.Provider.Dtos; 5 | using Erdcsharp.UnitTests.FakeData; 6 | using Moq; 7 | using NUnit.Framework; 8 | 9 | namespace Erdcsharp.UnitTests.Domain 10 | { 11 | [TestFixture(Category = "UnitTests")] 12 | public class AccountTests 13 | { 14 | private Mock _mockProvider; 15 | 16 | [SetUp] 17 | public void Setup() 18 | { 19 | _mockProvider = new Mock(); 20 | } 21 | 22 | [Test] 23 | public void Account_Should_Build_With_Address() 24 | { 25 | // Arrange 26 | var aliceAddress = Address.From(TestData.AliceHex); 27 | 28 | // Act 29 | var account = new Account(aliceAddress); 30 | 31 | // Assert 32 | Assert.That(account.Address, Is.EqualTo(aliceAddress)); 33 | Assert.That(account.Nonce, Is.EqualTo(0)); 34 | } 35 | 36 | [Test] 37 | public async Task Sync_Should_Synchronize_Account_With_Network() 38 | { 39 | // Arrange 40 | var account = new Account(Address.From(TestData.AliceHex)); 41 | var address = account.Address.Bech32; 42 | _mockProvider.Setup(p => p.GetAccount(It.IsAny())).ReturnsAsync(new AccountDto 43 | { 44 | Address = address, 45 | Balance = "99882470417129999997", 46 | Nonce = 2555546, 47 | Username = "elrond" 48 | }); 49 | 50 | // Act 51 | await account.Sync(_mockProvider.Object); 52 | 53 | // Assert 54 | _mockProvider.Verify(s => s.GetAccount(address), Times.Once); 55 | Assert.That(account.Address.Bech32, Is.EqualTo(address)); 56 | Assert.That(account.Nonce, Is.EqualTo(2555546)); 57 | Assert.That(account.Balance.ToDenominated(), Is.EqualTo("99.882470417129999997")); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /tests/Erdcsharp.Tests/Domain/AddressTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Erdcsharp.Domain; 3 | using Erdcsharp.Domain.Exceptions; 4 | using Erdcsharp.UnitTests.FakeData; 5 | using NUnit.Framework; 6 | 7 | namespace Erdcsharp.UnitTests.Domain 8 | { 9 | [TestFixture(Category = "UnitTests")] 10 | public class AddressTest 11 | { 12 | [Test] 13 | public void FromBech32_Should_Create_Address() 14 | { 15 | // Act 16 | var address = Address.FromBech32(TestData.AliceBech32); 17 | 18 | // Assert 19 | Assert.That(address.Hex.Equals(TestData.AliceHex, StringComparison.CurrentCultureIgnoreCase)); 20 | Assert.That(address.Bech32.Equals(TestData.AliceBech32, StringComparison.CurrentCultureIgnoreCase)); 21 | } 22 | 23 | [Test] 24 | public void FromHex_Should_Create_Address() 25 | { 26 | // Act 27 | var address = Address.FromHex(TestData.AliceHex); 28 | 29 | // Assert 30 | Assert.That(address.Hex.Equals(TestData.AliceHex, StringComparison.CurrentCultureIgnoreCase)); 31 | Assert.That(address.Bech32.Equals(TestData.AliceBech32, StringComparison.CurrentCultureIgnoreCase)); 32 | } 33 | 34 | [Test] 35 | public void EqualTo_Should_Test_Equality() 36 | { 37 | // Arrange 38 | var aliceFoo = Address.FromHex(TestData.AliceHex); 39 | var aliceBar = Address.FromBech32(TestData.AliceBech32); 40 | var bob = Address.FromHex(TestData.BobHex); 41 | 42 | // Assert 43 | Assert.That(aliceBar, Is.EqualTo(aliceFoo)); 44 | Assert.That(aliceFoo, Is.EqualTo(aliceBar)); 45 | Assert.That(bob, Is.Not.EqualTo(null)); 46 | Assert.That(bob, Is.Not.EqualTo(aliceFoo)); 47 | Assert.That(bob, Is.Not.EqualTo(aliceBar)); 48 | } 49 | 50 | [TestCase("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", false)] 51 | [TestCase("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", true)] 52 | public void IsContractAddress_Should_Return_ExpectedResult(string address, bool expectedResult) 53 | { 54 | // Arrange 55 | var scAddress = Address.FromBech32(address); 56 | 57 | // Act 58 | var isSmartContract = scAddress.IsContractAddress(); 59 | 60 | // Assert 61 | Assert.That(isSmartContract, Is.EqualTo(expectedResult)); 62 | } 63 | 64 | [TestCase("foo")] 65 | [TestCase("aaaaaaa")] 66 | [TestCase("0D65416545")] 67 | [TestCase("erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2")] 68 | [TestCase("xerd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz")] 69 | public void From_Should_Throw_Error_When_Invalid_Input(string input) 70 | { 71 | Assert.Throws(() => Address.From(input)); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /tests/Erdcsharp.Tests/Domain/Codec/BinaryCodecTests.cs: -------------------------------------------------------------------------------- 1 | using Erdcsharp.Domain.Codec; 2 | using Erdcsharp.Domain.Values; 3 | using NUnit.Framework; 4 | 5 | namespace Erdcsharp.UnitTests.Domain.Codec 6 | { 7 | [TestFixture(Category = "UnitTests")] 8 | public class BinaryCodecTests 9 | { 10 | [Test] 11 | public void DecodeNested_False() 12 | { 13 | // Arrange 14 | var buffer = new byte[] {0x01}; 15 | var codec = new BinaryCodec(); 16 | 17 | // Act 18 | var actual = codec.DecodeNested(buffer, TypeValue.BooleanValue); 19 | 20 | BytesValue.FromBuffer(new byte[] {0x00}); 21 | // Assert 22 | Assert.AreEqual(true, (actual.Value.ValueOf()).IsTrue()); 23 | } 24 | 25 | [Test] 26 | public void DecodeNested_True() 27 | { 28 | // Arrange 29 | var buffer = new byte[] {0x01}; 30 | var codec = new BinaryCodec(); 31 | 32 | // Act 33 | var actual = codec.DecodeNested(buffer, TypeValue.BooleanValue); 34 | 35 | BytesValue.FromBuffer(new byte[] {0x00}); 36 | // Assert 37 | Assert.AreEqual(true, (actual.Value.ValueOf()).IsTrue()); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/Erdcsharp.Tests/Domain/Codec/BooleanBinaryCodecTests.cs: -------------------------------------------------------------------------------- 1 | using Erdcsharp.Domain.Codec; 2 | using Erdcsharp.Domain.Values; 3 | using NUnit.Framework; 4 | 5 | namespace Erdcsharp.UnitTests.Domain.Codec 6 | { 7 | [TestFixture(Category = "UnitTests")] 8 | public class BooleanBinaryCodecTests 9 | { 10 | private BooleanBinaryCodec _sut; 11 | 12 | [SetUp] 13 | public void Setup() 14 | { 15 | _sut = new BooleanBinaryCodec(); 16 | } 17 | 18 | [Test] 19 | public void DecodeNested_True() 20 | { 21 | // Arrange 22 | var buffer = new byte[] {0x01}; 23 | 24 | // Act 25 | var actual = _sut.DecodeNested(buffer, TypeValue.BooleanValue); 26 | 27 | // Assert 28 | Assert.IsTrue(actual.Value.ValueOf().IsTrue()); 29 | } 30 | 31 | [Test] 32 | public void DecodeNested_False() 33 | { 34 | // Arrange 35 | var buffer = new byte[] {0x00}; 36 | 37 | // Act 38 | var actual = _sut.DecodeNested(buffer, TypeValue.BooleanValue); 39 | 40 | // Assert 41 | Assert.IsTrue(actual.Value.ValueOf().IsFalse()); 42 | } 43 | 44 | 45 | [Test] 46 | public void EncodeNested_True() 47 | { 48 | // Arrange 49 | var booleanValue = BooleanValue.From(true); 50 | 51 | // Act 52 | var actual = _sut.EncodeNested(booleanValue); 53 | 54 | // Assert 55 | Assert.That(actual.Length, Is.EqualTo(1)); 56 | Assert.That(actual[0], Is.EqualTo(0x01)); 57 | } 58 | 59 | [Test] 60 | public void EncodeNested_False() 61 | { 62 | // Arrange 63 | var booleanValue = BooleanValue.From(false); 64 | 65 | // Act 66 | var actual = _sut.EncodeNested(booleanValue); 67 | 68 | // Assert 69 | Assert.That(actual.Length, Is.EqualTo(1)); 70 | Assert.That(actual[0], Is.EqualTo(0x00)); 71 | } 72 | 73 | 74 | [Test] 75 | public void DecodeTop_True() 76 | { 77 | // Arrange 78 | var buffer = new byte[] {0x01}; 79 | 80 | // Act 81 | var actual = _sut.DecodeTopLevel(buffer, TypeValue.BooleanValue); 82 | 83 | // Assert 84 | Assert.IsTrue(actual.ValueOf().IsTrue()); 85 | } 86 | 87 | [Test] 88 | public void DecodeTop_False() 89 | { 90 | // Arrange 91 | var buffer = new byte[] {0x00}; 92 | 93 | // Act 94 | var actual = _sut.DecodeTopLevel(buffer, TypeValue.BooleanValue); 95 | 96 | // Assert 97 | Assert.IsTrue(actual.ValueOf().IsFalse()); 98 | } 99 | 100 | 101 | [Test] 102 | public void Encode_True() 103 | { 104 | // Arrange 105 | var booleanValue = BooleanValue.From(true); 106 | 107 | // Act 108 | var actual = _sut.EncodeTopLevel(booleanValue); 109 | 110 | // Assert 111 | Assert.That(actual.Length, Is.EqualTo(1)); 112 | Assert.That(actual[0], Is.EqualTo(0x01)); 113 | } 114 | 115 | [Test] 116 | public void Encode_False() 117 | { 118 | // Arrange 119 | var booleanValue = BooleanValue.From(false); 120 | 121 | // Act 122 | var actual = _sut.EncodeTopLevel(booleanValue); 123 | 124 | // Assert 125 | Assert.That(actual.Length, Is.EqualTo(0)); 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /tests/Erdcsharp.Tests/Domain/Codec/BytesBinaryCodecTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Erdcsharp.Domain.Codec; 3 | using Erdcsharp.Domain.Values; 4 | using NUnit.Framework; 5 | 6 | namespace Erdcsharp.UnitTests.Domain.Codec 7 | { 8 | [TestFixture(Category = "UnitTests")] 9 | public class BytesBinaryCodecTests 10 | { 11 | private BytesBinaryCodec _sut; 12 | 13 | [SetUp] 14 | public void Setup() 15 | { 16 | _sut = new BytesBinaryCodec(); 17 | } 18 | 19 | [Test] 20 | public void BytesBinaryCodec_DecodeNested() 21 | { 22 | var buffer = Convert.FromHexString("0000000445474c44"); 23 | 24 | // Act 25 | var actual = _sut.DecodeNested(buffer, TypeValue.BytesValue); 26 | 27 | var hex = Convert.ToHexString((actual.Value.ValueOf()).Buffer); 28 | 29 | // Assert 30 | Assert.AreEqual("45474C44", hex); 31 | } 32 | 33 | [Test] 34 | public void BytesBinaryCodec_EncodeNested() 35 | { 36 | // Arrange 37 | var buffer = Convert.FromHexString("45474C44"); 38 | 39 | var value = new BytesValue(buffer, TypeValue.BytesValue); 40 | 41 | // Act 42 | var actual = _sut.EncodeNested(value); 43 | var hex = Convert.ToHexString(actual); 44 | 45 | // Assert 46 | Assert.AreEqual(buffer.Length + 4, actual.Length); 47 | Assert.AreEqual("0000000445474C44", hex); 48 | } 49 | 50 | [Test] 51 | public void BytesBinaryCodec_EncodeNested_AndDecode() 52 | { 53 | // Arrange 54 | var expected = "FDB32E9ED34CAF6009834C5A5BEF293097EA39698B3E82EFD8C71183CB731B42"; 55 | var buffer = Convert.FromHexString(expected); 56 | var value = new BytesValue(buffer, TypeValue.BytesValue); 57 | 58 | // Act 59 | var encoded = _sut.EncodeNested(value); 60 | var actual = _sut.DecodeNested(encoded, TypeValue.BytesValue); 61 | var hex = Convert.ToHexString((actual.Value.ValueOf()).Buffer); 62 | 63 | // Assert 64 | Assert.AreEqual(expected, hex); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /tests/Erdcsharp.Tests/Domain/Codec/MultiBinaryCodecTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Erdcsharp.Domain; 4 | using Erdcsharp.Domain.Codec; 5 | using Erdcsharp.Domain.Values; 6 | using NUnit.Framework; 7 | 8 | namespace Erdcsharp.UnitTests.Domain.Codec 9 | { 10 | [TestFixture(Category = "UnitTests")] 11 | public class MultiBinaryCodecTests 12 | { 13 | private MultiBinaryCodec _sut; 14 | 15 | [SetUp] 16 | public void Setup() 17 | { 18 | _sut = new MultiBinaryCodec(new BinaryCodec()); 19 | } 20 | 21 | [Test] 22 | public void EncodeTopLevel() 23 | { 24 | // Arrange 25 | var value = MultiValue.From( 26 | NumericValue.BigUintValue(TokenAmount.From("100000000000000000").Value), 27 | NumericValue.BigUintValue(TokenAmount.From("10000000000000000000").Value) 28 | ); 29 | 30 | // Act 31 | var actual = _sut.EncodeTopLevel(value); 32 | var hex = Convert.ToHexString(actual); 33 | 34 | // Assert 35 | Assert.That(hex, Is.EqualTo("00000008016345785D8A0000000000088AC7230489E80000")); 36 | } 37 | 38 | [Test] 39 | public void EncodeNested() 40 | { 41 | // Arrange 42 | var value = MultiValue.From( 43 | NumericValue.BigUintValue(TokenAmount.From("100000000000000000").Value), 44 | NumericValue.BigUintValue(TokenAmount.From("10000000000000000000").Value) 45 | ); 46 | 47 | // Act 48 | var actual = _sut.EncodeNested(value); 49 | var hex = Convert.ToHexString(actual); 50 | 51 | // Assert 52 | Assert.That(hex, Is.EqualTo("00000008016345785D8A0000000000088AC7230489E80000")); 53 | } 54 | 55 | [Test] 56 | public void DecodeTopLevel() 57 | { 58 | // Arrange 59 | var a = "00000008016345785D8A0000"; 60 | var b = "000000088AC7230489E80000"; 61 | var bytes = new List(); 62 | bytes.AddRange(Convert.FromHexString(a)); 63 | bytes.AddRange(Convert.FromHexString(b)); 64 | 65 | //// Act 66 | var actual = _sut.DecodeTopLevel(bytes.ToArray(), 67 | TypeValue.MultiValue(new[] {TypeValue.BigUintTypeValue, TypeValue.BigUintTypeValue})); 68 | 69 | var values = actual.ValueOf().Values; 70 | 71 | //// Assert 72 | //Assert.That(hex, Is.EqualTo("00")); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /tests/Erdcsharp.Tests/Domain/Codec/OptionCodecTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Erdcsharp.Domain.Codec; 3 | using Erdcsharp.Domain.Values; 4 | using NUnit.Framework; 5 | 6 | namespace Erdcsharp.UnitTests.Domain.Codec 7 | { 8 | [TestFixture(Category = "UnitTests")] 9 | public class OptionBinaryCodecTests 10 | { 11 | private OptionBinaryCodec _sut; 12 | 13 | [SetUp] 14 | public void Setup() 15 | { 16 | _sut = new OptionBinaryCodec(new BinaryCodec()); 17 | } 18 | 19 | [Test] 20 | public void EncodeTopLevel_NewMissing() 21 | { 22 | // Arrange 23 | var optionValue = OptionValue.NewMissing(); 24 | 25 | // Act 26 | var actual = _sut.EncodeTopLevel(optionValue); 27 | var hex = Convert.ToHexString(actual); 28 | 29 | // Assert 30 | Assert.That(hex, Is.EqualTo("")); 31 | } 32 | 33 | [Test] 34 | public void EncodeNested_NewMissing() 35 | { 36 | // Arrange 37 | var optionValue = OptionValue.NewMissing(); 38 | 39 | // Act 40 | var actual = _sut.EncodeNested(optionValue); 41 | var hex = Convert.ToHexString(actual); 42 | 43 | // Assert 44 | Assert.That(hex, Is.EqualTo("00")); 45 | } 46 | 47 | [Test] 48 | public void EncodeTopLevel_NewProvided() 49 | { 50 | // Arrange 51 | var optionValue = OptionValue.NewProvided(NumericValue.I16Value(12)); 52 | 53 | // Act 54 | var actual = _sut.EncodeTopLevel(optionValue); 55 | var hex = Convert.ToHexString(actual); 56 | 57 | // Assert 58 | Assert.That(hex, Is.EqualTo("01000C")); 59 | } 60 | 61 | [Test] 62 | public void EncodeNested_NewProvided() 63 | { 64 | // Arrange 65 | var optionValue = OptionValue.NewProvided(NumericValue.I16Value(12)); 66 | 67 | // Act 68 | var actual = _sut.EncodeNested(optionValue); 69 | var hex = Convert.ToHexString(actual); 70 | 71 | // Assert 72 | Assert.That(hex, Is.EqualTo("01000C")); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /tests/Erdcsharp.Tests/Domain/GasLimitTests.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Erdcsharp.Domain; 3 | using Erdcsharp.Provider; 4 | using Erdcsharp.Provider.Dtos; 5 | using Moq; 6 | using NUnit.Framework; 7 | 8 | namespace Erdcsharp.UnitTests.Domain 9 | { 10 | [TestFixture(Category = "UnitTests")] 11 | public class GasLimitTests 12 | { 13 | private IElrondProvider _elrondProvider; 14 | 15 | [SetUp] 16 | public void Setup() 17 | { 18 | var mock = new Mock(); 19 | mock.Setup(s => s.GetNetworkConfig()).ReturnsAsync(new ConfigDataDto 20 | { 21 | Config = new ConfigDto 22 | { 23 | erd_min_gas_limit = 50000, 24 | erd_gas_per_data_byte = 1500, 25 | erd_min_gas_price = 1000000000 26 | } 27 | }); 28 | _elrondProvider = mock.Object; 29 | } 30 | 31 | [Test] 32 | public async Task GasLimit_Should_Compute_Gas_ForTransfer() 33 | { 34 | // Arrange 35 | var constants = await NetworkConfig.GetFromNetwork(_elrondProvider); 36 | var address = Address.FromBech32("erd1qqqqqqqqqqqqqpgq3wltgm6g8n6telq3wz2apgjqcydladdtu4cq3ch0l0"); 37 | var transactionRequest = TransactionRequest.Create(new Account(address), constants); 38 | 39 | transactionRequest.SetData("KLJHGFhjbnklmjghfdhfkjl"); 40 | 41 | // Act 42 | var gasLimit = GasLimit.ForTransfer(constants, transactionRequest); 43 | 44 | // Assert 45 | Assert.AreEqual(84500, gasLimit.Value); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tests/Erdcsharp.Tests/Domain/SmartContractTests.cs: -------------------------------------------------------------------------------- 1 | using Erdcsharp.Domain; 2 | using Erdcsharp.Domain.SmartContracts; 3 | using NUnit.Framework; 4 | 5 | namespace Erdcsharp.UnitTests.Domain 6 | { 7 | [TestFixture(Category = "UnitTests")] 8 | public class SmartContractTests 9 | { 10 | [Test] 11 | public void Should_ComputeAddress_Based_On_Account_And_Nonce() 12 | { 13 | // Arrange 14 | var accountAddress = Address.FromBech32("erd1lkeja8knfjhkqzvrf3d9hmefxzt75wtf3vlg9m7ccugc8jmnrdpqy7yjeq"); 15 | const long accountNonce = 5; 16 | 17 | // Act 18 | var smartContractAddress = SmartContract.ComputeAddress(accountAddress, accountNonce); 19 | 20 | // Assert 21 | Assert.AreEqual("erd1qqqqqqqqqqqqqpgqfflfuh2wd78r4xgcusl4xtmj354aem0nrdpqc68c4h", smartContractAddress.Bech32); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/Erdcsharp.Tests/Domain/TokenAmountTests.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using Erdcsharp.Domain; 3 | using NUnit.Framework; 4 | 5 | namespace Erdcsharp.UnitTests.Domain 6 | { 7 | [TestFixture(Category = "UnitTests")] 8 | public class TokenAmountTests 9 | { 10 | [SetUp] 11 | public void Setup() 12 | { 13 | } 14 | 15 | [Test] 16 | public void TokenAmount_Zero_Should_Return_ZeroValue() 17 | { 18 | // Act 19 | var zero = TokenAmount.Zero(); 20 | 21 | // Assert 22 | Assert.That(zero.Value.IsZero, Is.True); 23 | } 24 | 25 | [Test] 26 | public void TokenAmount_From_Should_Return_FullValue() 27 | { 28 | // Act 29 | var tokenAmount = TokenAmount.From("1000000000000000000"); 30 | 31 | // Assert 32 | Assert.That(tokenAmount.Value, Is.EqualTo(BigInteger.Parse("1000000000000000000"))); 33 | } 34 | 35 | [Test] 36 | public void TokenAmount_EGLD_Should_CreateValueFromEGLD() 37 | { 38 | // Act 39 | var oneEgld = TokenAmount.EGLD("1"); 40 | 41 | // Assert 42 | Assert.That(oneEgld.Value, Is.EqualTo(BigInteger.Parse("1000000000000000000"))); 43 | } 44 | 45 | [Test] 46 | public void TokenAmount_ToCurrencyString_Should_FormatAmount() 47 | { 48 | // Arrange 49 | var oneEgld = TokenAmount.EGLD("1"); 50 | 51 | // Act 52 | var stringValue = oneEgld.ToCurrencyString(); 53 | 54 | // Assert 55 | Assert.That(stringValue, Is.EqualTo("1.000000000000000000 EGLD")); 56 | } 57 | 58 | [Test] 59 | public void TokenAmount_EGLD_Should_GetCorrectAmount() 60 | { 61 | // Act 62 | var egld = TokenAmount.EGLD("0.01"); 63 | 64 | // Assert 65 | Assert.That(egld.ToString(), Is.EqualTo("10000000000000000")); 66 | } 67 | 68 | [Test] 69 | public void TokenAmount_EGLD_Should_GetBillionAmount() 70 | { 71 | // Act 72 | var egld = TokenAmount.EGLD("1000000000"); 73 | 74 | // Assert 75 | Assert.That(egld.ToString(), Is.EqualTo("1000000000000000000000000000")); 76 | } 77 | 78 | [Test] 79 | public void TokenAmount_ToCurrencyString_WithCustomToken_Should_FormatAmount() 80 | { 81 | // Arrange 82 | var amount = TokenAmount.ESDT("1000000000", Token.ESDT("MyToken", "MTK", 7)); 83 | 84 | // Act 85 | var stringValue = amount.ToCurrencyString(); 86 | 87 | // Assert 88 | Assert.That(stringValue, Is.EqualTo("1000000000.0000000 MTK")); 89 | } 90 | 91 | [Test] 92 | public void TokenAmount_ToCurrencyString_WithCustomToken_Should_FormatAmount_From() 93 | { 94 | // Arrange 95 | var amount = TokenAmount.From("10000000000000000", Token.ESDT("MyToken", "MTK", 7)); 96 | 97 | // Act 98 | var stringValue = amount.ToCurrencyString(); 99 | 100 | // Assert 101 | Assert.That(stringValue, Is.EqualTo("1000000000.0000000 MTK")); 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /tests/Erdcsharp.Tests/Domain/TokenTests.cs: -------------------------------------------------------------------------------- 1 | using Erdcsharp.Domain; 2 | using NUnit.Framework; 3 | 4 | namespace Erdcsharp.UnitTests.Domain 5 | { 6 | [TestFixture(Category = "UnitTests")] 7 | public class TokenTests 8 | { 9 | [SetUp] 10 | public void Setup() 11 | { 12 | } 13 | 14 | [Test] 15 | public void Token_EGLD_Should_Have_18_DecimalPrecision() 16 | { 17 | // Act 18 | var egldToken = Token.EGLD(); 19 | 20 | // Assert 21 | Assert.That(egldToken.DecimalPrecision, Is.EqualTo(18)); 22 | Assert.That(egldToken.Ticker, Is.EqualTo(Constants.EGLD)); 23 | Assert.That(egldToken.One().ToString(), Is.EqualTo("1000000000000000000")); 24 | } 25 | 26 | [Test] 27 | public void Token_ESDT_One_Should_Return_Correct_Decimal_Precision() 28 | { 29 | // Arrange 30 | var token = Token.ESDT("MyCustomToken", "MCTK", 10); 31 | 32 | // Act 33 | var one = token.One(); 34 | 35 | // Assert 36 | Assert.That(one.ToString(), Is.EqualTo("10000000000")); 37 | } 38 | 39 | [Test] 40 | public void Token_ESDT_Zero_Should_Return_0() 41 | { 42 | // Arrange 43 | var token = Token.ESDT("MyCustomToken", "MCTK", 10); 44 | 45 | // Act 46 | var zero = token.Zero(); 47 | 48 | // Assert 49 | Assert.That(zero.IsZero, Is.True); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tests/Erdcsharp.Tests/Elrond-sdk.dotnet.tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net5.0 5 | Elrond_sdk.dotnet.tests 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /tests/Erdcsharp.Tests/Erdcsharp.UnitTests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net5.0 5 | Erdcsharp.UnitTests 6 | false 7 | Erdcsharp.UnitTests 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | Always 24 | 25 | 26 | Always 27 | 28 | 29 | Always 30 | 31 | 32 | Always 33 | 34 | 35 | Always 36 | 37 | 38 | Always 39 | 40 | 41 | Always 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /tests/Erdcsharp.Tests/FakeData/ElrondGatewayMockProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Erdcsharp.Provider; 3 | using Erdcsharp.Provider.Dtos; 4 | using Moq; 5 | 6 | namespace Erdcsharp.UnitTests.FakeData 7 | { 8 | public class ElrondGatewayMockProvider 9 | { 10 | public readonly Mock MockProvider; 11 | 12 | public ElrondGatewayMockProvider() 13 | { 14 | MockProvider = new Mock(); 15 | MockProvider.Setup(p => p.GetAccount(It.IsAny())).ReturnsAsync((string address) => 16 | new AccountDto 17 | { 18 | Address = address, 19 | Balance = "99882470417129999997", 20 | Nonce = 2555546, 21 | Username = "elrond" 22 | }); 23 | } 24 | 25 | public void SetTransactionDetailResult(string finalStatus = "success", SmartContractResultDto[] scResult = null) 26 | { 27 | var callNumber = 0; 28 | var transactionResponse = new TransactionDto(); 29 | 30 | MockProvider.Setup(s => s.GetTransactionDetail(It.IsAny())).ReturnsAsync(() => 31 | { 32 | switch (callNumber) 33 | { 34 | case 0: 35 | transactionResponse.Status = "pending"; 36 | break; 37 | case 1: 38 | transactionResponse.Status = finalStatus; 39 | transactionResponse.SmartContractResults = scResult; 40 | break; 41 | case 2: 42 | transactionResponse.HyperblockHash = Guid.NewGuid().ToString(); 43 | break; 44 | } 45 | 46 | callNumber++; 47 | return transactionResponse; 48 | }); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /tests/Erdcsharp.Tests/FakeData/KeyFiles/alice.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 4, 3 | "id": "0dc10c02-b59b-4bac-9710-6b2cfa4284ba", 4 | "address": "0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", 5 | "bech32": "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", 6 | "crypto": { 7 | "ciphertext": 8 | "4c41ef6fdfd52c39b1585a875eb3c86d30a315642d0e35bb8205b6372c1882f135441099b11ff76345a6f3a930b5665aaf9f7325a32c8ccd60081c797aa2d538", 9 | "cipherparams": { 10 | "iv": "033182afaa1ebaafcde9ccc68a5eac31" 11 | }, 12 | "cipher": "aes-128-ctr", 13 | "kdf": "scrypt", 14 | "kdfparams": { 15 | "dklen": 32, 16 | "salt": "4903bd0e7880baa04fc4f886518ac5c672cdc745a6bd13dcec2b6c12e9bffe8d", 17 | "n": 4096, 18 | "r": 8, 19 | "p": 1 20 | }, 21 | "mac": "5b4a6f14ab74ba7ca23db6847e28447f0e6a7724ba9664cf425df707a84f5a8b" 22 | } 23 | } -------------------------------------------------------------------------------- /tests/Erdcsharp.Tests/FakeData/KeyFiles/bob.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 4, 3 | "id": "85fdc8a7-7119-479d-b7fb-ab4413ed038d", 4 | "address": "8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8", 5 | "bech32": "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx", 6 | "crypto": { 7 | "ciphertext": 8 | "c2664a31350aaf6a00525560db75c254d0aea65dc466441356c1dd59253cceb9e83eb05730ef3f42a11573c9a0e33dd952d488f00535b35357bb41d127b1eb82", 9 | "cipherparams": { 10 | "iv": "18378411e31f6c4e99f1435d9ab82831" 11 | }, 12 | "cipher": "aes-128-ctr", 13 | "kdf": "scrypt", 14 | "kdfparams": { 15 | "dklen": 32, 16 | "salt": "18304455ac2dbe2a2018bda162bd03ef95b81622e99d8275c34a6d5e6932a68b", 17 | "n": 4096, 18 | "r": 8, 19 | "p": 1 20 | }, 21 | "mac": "23756172195ac483fa29025dc331bc7aa2c139533922a8dc08642eb0a677541f" 22 | } 23 | } -------------------------------------------------------------------------------- /tests/Erdcsharp.Tests/FakeData/KeyFiles/carol.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 4, 3 | "id": "65894f35-d142-41d2-9335-6ad02e0ed0be", 4 | "address": "b2a11555ce521e4944e09ab17549d85b487dcd26c84b5017a39e31a3670889ba", 5 | "bech32": "erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8", 6 | "crypto": { 7 | "ciphertext": 8 | "bdfb984a1e7c7460f0a289749609730cdc99d7ce85b59305417c2c0f007b2a6aaa7203dd94dbf27315bced39b0b281769fbc70b01e6e57f89ae2f2a9e9100007", 9 | "cipherparams": { 10 | "iv": "258ed2b4dc506b4dc9d274b0449b0eb0" 11 | }, 12 | "cipher": "aes-128-ctr", 13 | "kdf": "scrypt", 14 | "kdfparams": { 15 | "dklen": 32, 16 | "salt": "4f2f5530ce28dc0210962589b908f52714f75c8fb79ff18bdd0024c43c7a220b", 17 | "n": 4096, 18 | "r": 8, 19 | "p": 1 20 | }, 21 | "mac": "f8de52e2627024eaa33f2ee5eadcd3d3815e10dd274ea966dc083d000cc8b258" 22 | } 23 | } -------------------------------------------------------------------------------- /tests/Erdcsharp.Tests/FakeData/SmartContracts/adder/adder.abi.json: -------------------------------------------------------------------------------- 1 | { 2 | "docs": [ 3 | "One of the simplest smart contracts possible,", 4 | "it holds a single variable in storage, which anyone can increment." 5 | ], 6 | "name": "Adder", 7 | "endpoints": [ 8 | { 9 | "name": "getSum", 10 | "inputs": [], 11 | "outputs": [ 12 | { 13 | "type": "BigInt" 14 | } 15 | ] 16 | }, 17 | { 18 | "name": "init", 19 | "inputs": [ 20 | { 21 | "name": "initial_value", 22 | "type": "BigInt" 23 | } 24 | ], 25 | "outputs": [] 26 | }, 27 | { 28 | "docs": [ 29 | "Add desired amount to the storage variable." 30 | ], 31 | "name": "add", 32 | "inputs": [ 33 | { 34 | "name": "value", 35 | "type": "BigInt" 36 | } 37 | ], 38 | "outputs": [] 39 | } 40 | ], 41 | "types": {} 42 | } -------------------------------------------------------------------------------- /tests/Erdcsharp.Tests/FakeData/SmartContracts/adder/adder.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/multiversx/mx-sdk-csharp/408d85058ca419cff59ec92fed1030faebe44c17/tests/Erdcsharp.Tests/FakeData/SmartContracts/adder/adder.wasm -------------------------------------------------------------------------------- /tests/Erdcsharp.Tests/FakeData/SmartContracts/auction/auction.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/multiversx/mx-sdk-csharp/408d85058ca419cff59ec92fed1030faebe44c17/tests/Erdcsharp.Tests/FakeData/SmartContracts/auction/auction.wasm -------------------------------------------------------------------------------- /tests/Erdcsharp.Tests/FakeData/TestWalletFactory.cs: -------------------------------------------------------------------------------- 1 | using Erdcsharp.Domain; 2 | 3 | namespace Erdcsharp.UnitTests.FakeData 4 | { 5 | public class TestWalletFactory 6 | { 7 | public string Mnemonic { get; } 8 | public string Password { get; } 9 | 10 | public TestWalletFactory() 11 | { 12 | Mnemonic = "moral volcano peasant pass circle pen over picture flat shop clap goat never lyrics gather prepare woman film husband gravity behind test tiger improve"; 13 | Password = "password"; 14 | Alice = Wallet.DeriveFromMnemonic(Mnemonic, 0); 15 | Bob = Wallet.DeriveFromMnemonic(Mnemonic, 1); 16 | Carol = Wallet.DeriveFromMnemonic(Mnemonic, 2); 17 | } 18 | 19 | public Wallet Bob { get; set; } 20 | 21 | public Wallet Carol { get; set; } 22 | 23 | public Wallet Alice { get; set; } 24 | } 25 | 26 | public static class TestData 27 | { 28 | public const string AliceBech32 = "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"; 29 | public const string AliceHex = "0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1"; 30 | 31 | public const string BobBech32 = "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx"; 32 | public const string BobHex = "8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8"; 33 | 34 | public const string CarolBech32 = "erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8"; 35 | public const string CarolHex = "b2a11555ce521e4944e09ab17549d85b487dcd26c84b5017a39e31a3670889ba"; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/Erdcsharp.Tests/Manager/EsdtTokenManagerTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Numerics; 4 | using System.Threading.Tasks; 5 | using Erdcsharp.Domain; 6 | using Erdcsharp.Domain.Helper; 7 | using Erdcsharp.Manager; 8 | using Erdcsharp.Provider.Dtos; 9 | using Erdcsharp.UnitTests.FakeData; 10 | using Moq; 11 | using NUnit.Framework; 12 | 13 | namespace Erdcsharp.UnitTests.Manager 14 | { 15 | [TestFixture(Category = "UnitTests")] 16 | public class EsdtTokenManagerTests 17 | { 18 | private ElrondGatewayMockProvider _elrondGatewayMockProvider; 19 | private IEsdtTokenManager _sut; 20 | private TestWalletFactory _testWalletFactory; 21 | private string _txHash; 22 | 23 | [SetUp] 24 | public void Setup() 25 | { 26 | _elrondGatewayMockProvider = new ElrondGatewayMockProvider(); 27 | _testWalletFactory = new TestWalletFactory(); 28 | _txHash = Guid.NewGuid().ToString(); 29 | _elrondGatewayMockProvider.MockProvider.Setup(s => s.SendTransaction(It.IsAny())) 30 | .ReturnsAsync( 31 | new CreateTransactionResponseDataDto() 32 | { 33 | TxHash = _txHash 34 | }); 35 | _sut = new EsdtTokenManager(_elrondGatewayMockProvider.MockProvider.Object, NetworkConfig.New()); 36 | } 37 | 38 | [Test] 39 | public async Task IssueFungibleToken_Should_Return_TokenIdentifier() 40 | { 41 | // Arrange 42 | var alice = _testWalletFactory.Alice; 43 | var token = Token.ESDT("TOKEN", "TKN", 18); 44 | 45 | _elrondGatewayMockProvider.SetTransactionDetailResult(scResult: new[] 46 | { 47 | new SmartContractResultDto 48 | { 49 | Nonce = 0, 50 | Data = $"ESDTTransfer@{Converter.ToHexString("TK-651452")}@d3c21bcecceda1000000" 51 | }, 52 | new SmartContractResultDto 53 | { 54 | Nonce = 150, 55 | Data = "@ok" 56 | } 57 | }); 58 | 59 | // Act 60 | var tokenIdentifier = await _sut.IssueFungibleToken(alice, token, 1000000000); 61 | 62 | // Assert 63 | Assert.That(tokenIdentifier, Is.EqualTo("TK-651452")); 64 | } 65 | 66 | [Test] 67 | public async Task SetSpecialRole_Should_Passed() 68 | { 69 | // Arrange 70 | var alice = _testWalletFactory.Alice; 71 | const string tokenIdentifier = "TK-651452"; 72 | 73 | _elrondGatewayMockProvider.SetTransactionDetailResult(); 74 | 75 | // Act 76 | await _sut.SetSpecialRole(alice, tokenIdentifier, Constants.EsdtNftSpecialRoles.EsdtRoleNftCreate); 77 | 78 | // Assert 79 | var expectedData = 80 | $"setSpecialRole@{Converter.ToHexString(tokenIdentifier)}@{alice.GetAccount().Address.Hex}@{Converter.ToHexString(Constants.EsdtNftSpecialRoles.EsdtRoleNftCreate)}"; 81 | var expectedEncodedData = Converter.ToBase64String(expectedData); 82 | 83 | _elrondGatewayMockProvider.MockProvider.Verify( 84 | s => s.SendTransaction(It.Is(t => 85 | t.Data == expectedEncodedData && 86 | t.Receiver == Constants.SmartContractAddress.EsdtSmartContract && 87 | t.Value == "0" 88 | )), Times.Once); 89 | 90 | Assert.Pass(); 91 | } 92 | 93 | [Test] 94 | public async Task CreateNftToken_Should_Return_TokenNonce() 95 | { 96 | // Arrange 97 | var alice = _testWalletFactory.Alice; 98 | const string tokenIdentifier = "TK-651452"; 99 | 100 | _elrondGatewayMockProvider.SetTransactionDetailResult(scResult: new[] 101 | { 102 | new SmartContractResultDto 103 | { 104 | Nonce = 0, 105 | Data = "@ok@01" 106 | } 107 | }); 108 | 109 | // Act 110 | var tokenId = await _sut.CreateNftToken( 111 | alice, 112 | tokenIdentifier, 113 | BigInteger.One, 114 | "My token name", 115 | 550, 116 | new Dictionary(), 117 | new[] {new Uri("https://foo.bar")} 118 | ); 119 | 120 | // Assert 121 | var expectedData = 122 | $"ESDTNFTCreate@544B2D363531343532@01@4D7920746F6B656E206E616D65@0226@@@68747470733A2F2F666F6F2E6261722F"; 123 | var expectedEncodedData = Converter.ToBase64String(expectedData); 124 | _elrondGatewayMockProvider.MockProvider.Verify( 125 | s => s.SendTransaction(It.Is(t => 126 | t.Data == expectedEncodedData && 127 | t.Receiver == alice.GetAccount().Address.Bech32 && 128 | t.Value == "0" 129 | )), Times.Once); 130 | 131 | // Assert 132 | Assert.That(tokenId, Is.EqualTo(1)); 133 | } 134 | } 135 | } 136 | --------------------------------------------------------------------------------