Skip to content

.Net Core library to assist smooth development on VeChain for developers and hobbyists.

Notifications You must be signed in to change notification settings

vechain/thor-devkit.netcore

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 

Repository files navigation

VeChain Thor Devkit in .NetCore

.Net Core library to assist smooth development on VeChain for developers and hobbyists.

Release Notes

See ReleaseNotes.md

Usage

    using Org.VeChain.Thor.Devkit;
    using Org.VeChain.Thor.Devkit.Extension;

Acknowledgement

A Special shout out to following projects:

API

Crypto

  • Hashing
    byte[] blake2bHash = Cry.Blake2b.CalculateHash("hello world");
    Console.log(blake2bHash.ToHexString());
    // 0x256c83b297114d201b30179f3f0ef0cace9783622da5974326b436178aeef610

    byte[] keccack256Hash = Cry.Keccack256.CalculateHash("hello world");
    Console.log(keccack256Hash.ToHexString());
    // 0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad
  • HDNode
    var works = new string[12]{"mouse","brave","fun","viable","utility","veteran","luggage","area","bike","myself","target","thunder"};

    var node = new HDNode(works);
    var sonNode = node.Derive(0);
    var grandNode = sonNode.Derive(1);

    Console.log(node.privateKey.ToHexString());
    Console.log(sonNode.privateKey.ToHexString());
    Console.log(grandNode.privateKey.ToHexString());
    // 0x546498ba394789f18b5b4b62227572fe033f8f7f2597a747ada3d8ec8f20f650
    // 0x12ddf96bb7f2c031ee9b776e2b236f2fc46de6f90fb9cd48a82e0c849327d251
    // 0xa7af80364059211616e47394cf49240b40f7a87cea54ec99a6aa1815b586d74e

    var seed = "0x403d3e5f3646f517d3d6f51bd98f90493d502d259506abbfe46d5af2196960531edf6030aef3876fe3432f457c9cb9d6f312c538f19d3f30e731022d309683c2".ToBytes();
    
    var node = new HDNode(seed);
    Console.log(node.privateKey.ToHexString());
    // 0x546498ba394789f18b5b4b62227572fe033f8f7f2597a747ada3d8ec8f20f650

    var privateKey = "0x546498ba394789f18b5b4b62227572fe033f8f7f2597a747ada3d8ec8f20f650".ToBytes();
    var chainCode = "0xc86826253a925f5958a838756e20ba33e71566da60b9e274f97342492c578c10".ToBytes();
    IHDNode node = new HDNode(privateKey,chainCode);
    Console.log(node.privateKey.ToHexString());
    // 0x546498ba394789f18b5b4b62227572fe033f8f7f2597a747ada3d8ec8f20f650
  • Mnemonic & Keystore
    var works = new string[12]{"mouse","brave","fun","viable","utility","veteran","luggage","area","bike","myself","target","thunder"};
    var priKey = Mnemonic.DerivePrivateKey(works);
    Console.log(priKey.ToHexString());
    // 0x12ddf96bb7f2c031ee9b776e2b236f2fc46de6f90fb9cd48a82e0c849327d251

    var priKey = "0xdce1443bd2ef0c2631adc1c67e5c93f13dc23a41c18b536effbbdcbcdb96fb65";
    var keystore = Keystore.EncryptToJson(priKey.ToBytes(),"123456789");
    var recoveredPriKey = Keystore.DecryptFromJson(keystore,"123456789");
    Console.log(recoveredPriKey.SequenceEqual(priKey.ToBytes()));
    // True
  • Secp256K1
    var priKey = Secp256k1.GeneratePrivateKey();
    var pubKey = Secp256k1.DerivePublicKey(priKey);

    var msgHash = Keccack256.CalculateHash("hello world");
    var signature = Secp256k1.Sign(msgHash,priKey);

    var recoveredPubKey = Secp256k1.RecoverPublickey(Keccack256.CalculateHash("hello world"),signature);
    Console.log(pubKey.SequenceEqual(recoveredPubKey));
    // True
  • SimpleWallet
    var priKey = "0xdce1443bd2ef0c2631adc1c67e5c93f13dc23a41c18b536effbbdcbcdb96fb65".ToBytes();
    var vechainKey = new SimpleWallet(priKey);
    Console.log(vechainKey.address);
    Console.log(SimpleWallet.ToChecksumAddress(vechainKey.address));
    // 0x7567d83b7b8d80addcb281a71d54fc7b3364ffed
    // 0x7567D83b7b8d80ADdCb281A71d54Fc7B3364ffed

ABI

  • ABI Parames Builder
    string abiJson = "[{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"numProposals\",\"type\":\"uint8\"}]";
    IAbiParameterDefinition[] parames = (new AbiParameterBuilder()).Builder(abiJson);
    Console.log(parames.Length);
    Console.log(parames[0].Name);
    Console.log(parames[0].ABIType);
    Console.log(parames[1].Name);
    Console.log(parames[1].ABIType);
    // 2
    // to
    // address
    // numProposals
    // uint8
  • ABI Function Encode
    string abiJson = "{\"constant\": false,\"inputs\": [{\"name\": \"a1\",\"type\": \"uint256\"},{\"name\": \"a2\",\"type\": \"string\"}],\"name\": \"f1\",\"outputs\": [{\"name\": \"r1\",\"type\": \"address\"},{\"name\": \"r2\",\"type\": \"bytes\"}],\"payable\": false,\"stateMutability\": \"nonpayable\",\"type\": \"function\"}";
    AbiFuncationCoder coder = new AbiFuncationCoder(abiJson);
    var encodeData = coder.Encode(1,"foo");

    var data = "0x27fcbb2f000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000003666f6f0000000000000000000000000000000000000000000000000000000000";
    Console.log(encodeData.SequenceEqual(data.ToBytes()));
    // True
  • ABI Function Decode
    string outputData = "0x0000000000000000000000004c6f3ca686c053354a83c030e80d2ee0a000b0cf000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c073850000000000000000000000000000000000000000000000000000000005c073850000000000000000000000000000000000000000000000000000000005c073850";
    string abiJson = "{\"constant\": true,\"inputs\": [{\"name\": \"_tokenId\",\"type\": \"uint256\"}],\"name\": \"getMetadata\",\"outputs\": [{\"name\": \"\",\"type\": \"address\"},{\"name\": \"\",\"type\": \"uint8\"},{\"name\": \"\",\"type\": \"bool\"},{\"name\": \"\",\"type\": \"bool\"},{\"name\": \"\",\"type\": \"uint64\"},{\"name\": \"\",\"type\": \"uint64\"},{\"name\": \"\",\"type\": \"uint64\"}],\"payable\": false,\"stateMutability\": \"view\",\"type\": \"function\"}";
    AbiFuncationCoder coder = new AbiFuncationCoder(abiJson);
    var output = coder.Decode(outputData.ToBytes());

    Console.log((output[0].Result as string).Equals("0x4c6f3ca686c053354a83c030e80d2ee0a000b0cf"));
    Console.log(((BigInteger)output[1].Result).Equals(new BigInteger(5)));
    Console.log(((bool)output[2].Result).Equals(false));
    Console.log(((bool)output[3].Result).Equals(false));
    Console.log(((BigInteger)output[4].Result).Equals(new BigInteger(1543977040)));
    Console.log(((BigInteger)output[5].Result).Equals(new BigInteger(1543977040)));
    Console.log(((BigInteger)output[6].Result).Equals(new BigInteger(1543977040)));
    // True
  • ABI Event Encode (Due to build event filter)
    string abiJson = "{\"anonymous\": false,\"inputs\": [{\"indexed\": true,\"name\": \"_from\",\"type\": \"address\"},{\"indexed\": true,\"name\": \"_to\",\"type\": \"address\"},{\"indexed\": false,\"name\": \"_value\",\"type\": \"uint256\"}],\"name\": \"Transfer\",\"type\": \"event\"}";
    AbiEventCoder coder = new AbiEventCoder(abiJson);

    Dictionary<string,dynamic> indexed = new Dictionary<string,dynamic>();
    indexed.Add("_from","0xe4aea9f855d6960d56190fb26e32d0ec2ab40d82");
    indexed.Add("_to","0xf43a84be55e162034f4c13de65294a3875f15bc9");

    byte[][] filters = coder.EncodeFilter(indexed);

    Console.log(filters[0].SequenceEqual("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef".ToBytes()));
    Console.log(filters[1].SequenceEqual("0x000000000000000000000000e4aea9f855d6960d56190fb26e32d0ec2ab40d82".ToBytes()));
    Console.log(filters[2].SequenceEqual("0x000000000000000000000000f43a84be55e162034f4c13de65294a3875f15bc9".ToBytes()));
    // True
  • ABI Event Decode
    tring abiJson = "{\"anonymous\": false,\"inputs\": [{\"indexed\": true,\"name\": \"_from\",\"type\": \"address\"},{\"indexed\": true,\"name\": \"_to\",\"type\": \"address\"},{\"indexed\": false,\"name\": \"_value\",\"type\": \"uint256\"}],\"name\": \"Transfer\",\"type\": \"event\"}";
    AbiEventCoder coder = new AbiEventCoder(abiJson);

    List<byte[]> topics = new List<byte[]>();
    topics.Add("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef".ToBytes());
    topics.Add("0x000000000000000000000000e4aea9f855d6960d56190fb26e32d0ec2ab40d82".ToBytes());
    topics.Add("0x000000000000000000000000f43a84be55e162034f4c13de65294a3875f15bc9".ToBytes());
    byte[] data = "0x0000000000000000000000000000000000000000000000056bc75e2d63100000".ToBytes();

    AbiEventTopic[] decode = coder.DecodeTopics(topics.ToArray(),data);

    console.log(decode.Length == 3);
    console.log(decode[0].Definition.Name == "_from" && decode[0].Definition.Indexed == true && (decode[0].Result as string).Equals("0xe4aea9f855d6960d56190fb26e32d0ec2ab40d82"));
    console.log(decode[1].Definition.Name == "_to" && decode[1].Definition.Indexed == true && (decode[1].Result as string).Equals("0xf43a84be55e162034f4c13de65294a3875f15bc9"));
    console.log(decode[2].Definition.Name == "_value" && decode[2].Definition.Indexed == false && decode[2].Result.ToString().Equals("100000000000000000000"));

RLP

  • Scalar RLP Encode & Decode
    var bigInterger =  BigInteger.Parse("102030405060708090A0B0C0D0E0F2",NumberStyles.AllowHexSpecifier);

    byte[] encode = (new RlpBigIntegerKind()).EncodeToRlp(bigInterger).Encode();
    // 0x8F102030405060708090A0B0C0D0E0F2

    var decode = (new RlpBigIntegerKind()).DecodeFromRlp(new RlpItem(encode));
  • Array RLP Encode & Decode
    var array = new int[3]{1,2,3};
    byte[] encode = (new RlpArrayKind(new RlpIntKind(true)).EncodeToRlp(array).Encode());
    // 0xC3010203

    var decode = (new RlpArrayKind()).DecodeFromRlp(new RlpArray(encode));
    // {1,2,3}

Transaction

  • Transaction (MTT Multi-task transaction)
var txbody = new Body();
    txbody.ChainTag = 74;
    txbody.BlockRef = "0x005d64da8e7321bd";
    txbody.Expiration = 18;
    txbody.GasPriceCoef = 0;
    txbody.Gas = 21000;
    txbody.DependsOn = "";
    txbody.Nonce = "0xd6846cde87878603";
    txbody.Reserved = null;
    txbody.Clauses.Add(new Clause("0xa4aDAfAef9Ec07BC4Dc6De146934C7119341eE25",new BigInteger(100000),"0x2398479812734981"));
    txbody.Clauses.Add(new Clause("0xa4aDAfAef9Ec07BC4Dc6De146934C7119341eE25",new BigInteger(100000),"0x2398479812734981"));
    txbody.Clauses.Add(new Clause("0xa4aDAfAef9Ec07BC4Dc6De146934C7119341eE25",new BigInteger(100000),"0x2398479812734981"));

    var transaction = new Transaction.Transaction(txbody);
    transaction.Signature = Cry.Secp256k1.Sign(transaction.SigningHash(),"0xdce1443bd2ef0c2631adc1c67e5c93f13dc23a41c18b536effbbdcbcdb96fb65".ToBytes());
    
    var rlp = (Transaction.Transaction.UnsignedRlpDefinition() as RlpStructKind).EncodeToRlp(transaction.Body);
  • Transaction (VIP-191)
    var delegated_body = new Body();
    delegated_body.ChainTag = 74;
    delegated_body.BlockRef = "0x005d64da8e7321bd";
    delegated_body.Expiration = 18;
    delegated_body.GasPriceCoef = 0;
    delegated_body.Gas = 21000;
    delegated_body.DependsOn = "";
    delegated_body.Nonce = "0xd6846cde87878603";
    delegated_body.Reserved = new Reserved();
    delegated_body.Reserved.Features = 1;
    delegated_body.Clauses.Add(new Clause("0xa4aDAfAef9Ec07BC4Dc6De146934C7119341eE25",new BigInteger(100000),"0x2398479812734981"));
    delegated_body.Clauses.Add(new Clause("0xa4aDAfAef9Ec07BC4Dc6De146934C7119341eE25",new BigInteger(100000),"0x2398479812734981"));
    delegated_body.Clauses.Add(new Clause("0xa4aDAfAef9Ec07BC4Dc6De146934C7119341eE25",new BigInteger(100000),"0x2398479812734981"));

    var transaction = new Transaction.Transaction(delegated_body);
    Assert.True(transaction.IsDelegated);

    var senderPrikey = "0xdce1443bd2ef0c2631adc1c67e5c93f13dc23a41c18b536effbbdcbcdb96fb65";
    var senderAddr = "0x7567d83b7b8d80addcb281a71d54fc7b3364ffed";

    var gasPayerPrikey = "0x321d6443bc6177273b5abf54210fe806d451d6b7973bccc2384ef78bbcd0bf51";
    var geaPayerAddr = "0xd3ae78222beadb038203be21ed5ce7c9b1bff602";

    var senderSigningHash = transaction.SigningHash();
    var gasPayerSigningHash = transaction.SigningHash(senderAddr);

    var senderSignature = Cry.Secp256k1.Sign(senderSigningHash,senderPrikey.ToBytes());
    var gasPayerSignature = Cry.Secp256k1.Sign(gasPayerSigningHash,gasPayerPrikey.ToBytes());

    transaction.AddVIP191Signature(senderSignature,gasPayerSignature);

Certificate

  • Certificate
    Certificate.Certificate info = new Certificate.Certificate();
    info.Purpose = "identification";
    info.Payload = new CertificatePayload();
    info.Payload.Type = "text";
    info.Payload.Content = "fyi";
    info.Domain = "localhost";
    info.Timestamp = 1545035330;
    info.Signer = "0x7567d83b7b8d80addcb281a71d54fc7b3364ffed";

    byte[] msgHash = CertificateCoder.SigningHash(info);

    var signature = Cry.Secp256k1.Sign(msgHash,"0xdce1443bd2ef0c2631adc1c67e5c93f13dc23a41c18b536effbbdcbcdb96fb65".ToBytes());
    info.Signature = signature;

    CertificateCoder.Verify(info);
    // True

Testing

    dotnet test ./Org.VeChain.Thor/Org.VeChain.Thor.Devkit.UnitTest

About

.Net Core library to assist smooth development on VeChain for developers and hobbyists.

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages