Exemple #1
0
        /// <summary>
        /// Concats all the event metadata signatures and type names and hashes them.
        /// </summary>
        public static byte[] GetHash(List <GeneratedEventMetadata> items)
        {
            int bufferSize = 0;

            for (var i = 0; i < items.Count; i++)
            {
                bufferSize += items[i].ClrTypeFullName.Length + items[i].EventSignatureHash.Length + 2;
            }

            Span <char> inputData       = stackalloc char[bufferSize];
            Span <char> inputDataCursor = inputData;

            for (var i = 0; i < items.Count; i++)
            {
                items[i].ClrTypeFullName.AsSpan().CopyTo(inputDataCursor);
                inputDataCursor = inputDataCursor.Slice(items[i].ClrTypeFullName.Length);
                items[i].EventSignatureHash.AsSpan().CopyTo(inputDataCursor);
                inputDataCursor = inputDataCursor.Slice(items[i].EventSignatureHash.Length);
                items[i].IndexedArgsCounts.ToString("00", CultureInfo.InvariantCulture).AsSpan().CopyTo(inputDataCursor);
                inputDataCursor = inputDataCursor.Slice(2);
            }

            var hashBuffer = new byte[32];

            KeccakHash.ComputeHash(MemoryMarshal.AsBytes(inputData), hashBuffer);

            return(hashBuffer);
        }
Exemple #2
0
        /// <summary>
        /// Given a key, deletes the key-value entry from the trie.
        /// </summary>
        /// <param name="key">The key for which we'd like to remove the key-value entry.</param>
        public override void Remove(Memory <byte> key)
        {
            // Use the hash of our provided key as a key.
            Memory <byte> hash = new byte[KeccakHash.HASH_SIZE];

            KeccakHash.ComputeHash(key.Span, hash.Span);
            base.Remove(hash);
        }
Exemple #3
0
        /// <summary>
        /// Creates the 4 byte function selector from a function signature string
        /// </summary>
        /// <param name="functionSignature">Function signature, ex: "baz(uint32,bool)"</param>
        /// <param name="hexPrefix">True to prepend the hex string with "0x"</param>
        /// <returns>8 character lowercase hex string (from first 4 bytes of the sha3 hash of utf8 encoded function signature)</returns>
        public static string GetMethodIDHex(string functionSignature, bool hexPrefix = false)
        {
            var    bytes         = UTF8.GetBytes(functionSignature);
            var    hash          = KeccakHash.ComputeHash(bytes).Slice(0, 4);
            string funcSignature = HexUtil.GetHexFromBytes(hash, hexPrefix: hexPrefix);

            return(funcSignature);
        }
Exemple #4
0
        public static string GetSignatureHash(this Abi abi, bool hexPrefix = false)
        {
            string str   = GetFullSignature(abi);
            var    bytes = UTF8.GetBytes(str);
            var    hash  = KeccakHash.ComputeHash(bytes).ToHexString(hexPrefix);

            return(hash);
        }
Exemple #5
0
        public static ReadOnlyMemory <byte> GetMethodID(string functionSignature)
        {
            var bytes = UTF8.GetBytes(functionSignature);
            var mem   = new Memory <byte>(new byte[4]);

            KeccakHash.ComputeHash(bytes).Slice(0, 4).CopyTo(mem.Span);
            return(mem);
        }
Exemple #6
0
        public static Address MakeContractAddress(Address sender, BigInteger nonce)
        {
            // Create an RLP list with the address and nonce
            RLPList list = new RLPList(RLP.FromInteger(sender, ADDRESS_SIZE), RLP.FromInteger(nonce));
            var     hash = KeccakHash.ComputeHash(RLP.Encode(list)).Slice(EVMDefinitions.WORD_SIZE - ADDRESS_SIZE);

            return(new Address(hash));
        }
Exemple #7
0
        /// <summary>
        /// Given a key, sets the corresponding value in our trie.
        /// </summary>
        /// <param name="key">The key for which to set the corresponding value for.</param>
        /// <param name="value">The value to store in the trie for the provided key.</param>
        public override void Set(Memory <byte> key, byte[] value)
        {
            // Use the hash of our provided key as a key.
            Memory <byte> hash = new byte[KeccakHash.HASH_SIZE];

            KeccakHash.ComputeHash(key.Span, hash.Span);
            base.Set(hash, value);

            // Set our hash->key lookup in the database
            Database.Set(hash.ToArray(), key.ToArray());
        }
Exemple #8
0
        /// <summary>
        /// Returns a Keccak256 hash of the given message, using the prefix from eth_sign: "\u0019Ethereum Signed Message:\n{message.Length}".
        /// </summary>
        public static byte[] HashPersonalMessage(Span <byte> messageBytes)
        {
            const string PREFIX          = "\u0019Ethereum Signed Message:\n";
            string       prefixedMessage = PREFIX + messageBytes.Length.ToString(CultureInfo.InvariantCulture);

            byte[] buffer = new byte[StringUtil.UTF8.GetByteCount(prefixedMessage) + messageBytes.Length];
            StringUtil.UTF8.GetBytes(prefixedMessage, 0, prefixedMessage.Length, buffer, 0);
            messageBytes.CopyTo(buffer.AsSpan(prefixedMessage.Length));
            var resultBuffer = new byte[KeccakHash.HASH_SIZE];

            KeccakHash.ComputeHash(buffer, resultBuffer);
            return(resultBuffer);
        }
Exemple #9
0
        private void AssertHash512(string expectedHash, byte[] data, bool matches = true)
        {
            byte[] hash = new byte[64];
            KeccakHash.ComputeHash(data, hash);
            string hashString = hash.ToHexString();

            if (matches)
            {
                Assert.Equal(expectedHash, hashString, true);
            }
            else
            {
                Assert.NotEqual <string>(expectedHash, hashString, StringComparer.InvariantCultureIgnoreCase);
            }
        }
Exemple #10
0
        /// <summary>
        /// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md
        /// </summary>
        public string ToStringWithChecksum()
        {
            Span <uint> buffer = stackalloc uint[10];

            buffer[0] = _p1;
            buffer[1] = _p2;
            buffer[2] = _p3;
            buffer[3] = _p4;
            buffer[4] = _p5;

            Span <byte> addrBytes            = MemoryMarshal.AsBytes(buffer);
            Span <char> addrHexBytesPrefixed = stackalloc char[42];

            addrHexBytesPrefixed[0] = '0';
            addrHexBytesPrefixed[1] = 'x';

            Span <char> addrHexChars = addrHexBytesPrefixed.Slice(2);

            HexUtil.WriteBytesIntoHexString(addrBytes.Slice(0, 20), addrHexChars);

            for (var i = 0; i < 40; i++)
            {
                addrBytes[i] = (byte)addrHexChars[i];
            }

            KeccakHash.ComputeHash(addrBytes.Slice(0, 40), addrBytes.Slice(0, 32));

            for (var i = 0; i < 40; i++)
            {
                char inspectChar = addrHexChars[i];

                // skip check if character is a number
                if (inspectChar > 64)
                {
                    // get character casing flag
                    var  c         = i % 2 == 0 ? addrBytes[i / 2] >> 4 : addrBytes[i / 2] & 0x0F;
                    bool upperFlag = c >= 8;
                    if (upperFlag)
                    {
                        addrHexChars[i] = (char)(inspectChar - 32);
                    }
                }
            }

            return(addrHexBytesPrefixed.ToString());
        }
Exemple #11
0
 private static void Keccak512(Span <byte> message, Span <byte> output)
 {
     KeccakHash.ComputeHash(message, output);
 }
Exemple #12
0
        /// <summary>
        /// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md
        /// </summary>
        public static bool ValidChecksum(string addressHexStr)
        {
            bool foundUpper = false, foundLower = false;

            foreach (var c in addressHexStr)
            {
                foundUpper |= c > 64 && c < 71;
                foundLower |= c > 96 && c < 103;
                if (foundUpper && foundLower)
                {
                    break;
                }
            }

            if (!(foundUpper && foundLower))
            {
                return(true);
            }

            // get lowercase utf16 buffer
            Span <byte> addr = stackalloc byte[80];

            var addrSpan = addressHexStr.AsSpan();

            if (addrSpan[0] == '0' && addrSpan[1] == 'x')
            {
                addrSpan = addrSpan.Slice(2);
            }

            if (addrSpan.Length != 40)
            {
                throw new ArgumentException("Address hex string should be 40 chars long, or 42 with a 0x prefix, was given " + addressHexStr.Length, nameof(addressHexStr));
            }

            addrSpan.ToLowerInvariant(MemoryMarshal.Cast <byte, char>(addr));

            // inline buffer conversion from utf16 to ascii
            for (var i = 0; i < 40; i++)
            {
                addr[i] = addr[i * 2];
            }

            // get hash of ascii hex
            KeccakHash.ComputeHash(addr.Slice(0, 40), addr.Slice(0, 32));

            for (var i = 0; i < 40; i++)
            {
                char inspectChar = addrSpan[i];

                // skip check if character is a number
                if (inspectChar > 64)
                {
                    // get character casing flag
                    var  c         = i % 2 == 0 ? addr[i / 2] >> 4 : addr[i / 2] & 0x0F;
                    bool upperFlag = c >= 8;

                    // verify character is uppercase, otherwise bad checksum
                    if (upperFlag && inspectChar > 96)
                    {
                        return(false);
                    }

                    // verify character is lowercase
                    else if (!upperFlag && inspectChar < 97)
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
Exemple #13
0
 private static Span <byte> Keccak256(Span <byte> message)
 {
     return(KeccakHash.ComputeHash(message));
 }
Exemple #14
0
 private static Span <byte> Keccak512(Span <byte> message)
 {
     byte[] output = new byte[0x40];
     KeccakHash.ComputeHash(message, output);
     return(output);
 }
Exemple #15
0
        protected override string GenerateClassDef()
        {
            List <string> eventTypes = new List <string>();

            foreach (var item in _contract.Abi)
            {
                if (item.Type == AbiType.Event)
                {
                    eventTypes.Add($"typeof({_namespace}.{_contractName}.{item.Name})");
                }
            }

            string eventTypesString = string.Empty;

            if (eventTypes.Any())
            {
                eventTypesString = ", " + string.Join(", ", eventTypes);
            }

            string bytecodeHash         = KeccakHash.ComputeHash(_contract.Evm.Bytecode.ObjectBytes).ToHexString();
            string bytecodeDeployedHash = KeccakHash.ComputeHash(_contract.Evm.DeployedBytecode.ObjectBytes).ToHexString();
            string devDocJson           = JsonConvert.SerializeObject(_contract.Devdoc).Replace("\"", "\"\"", StringComparison.Ordinal);
            string userDocJson          = JsonConvert.SerializeObject(_contract.Userdoc).Replace("\"", "\"\"", StringComparison.Ordinal);

            string extraSummaryDoc = GetContractSummaryXmlDoc();

            return($@"
                /// <summary>{extraSummaryDoc}</summary>
                [{typeof(SolidityContractAttribute).FullName}(typeof({_contractName}), CONTRACT_SOL_FILE, CONTRACT_NAME, CONTRACT_BYTECODE_HASH, CONTRACT_BYTECODE_DEPLOYED_HASH)]
                public class {_contractName} : {typeof(BaseContract).FullName}
                {{

                    public static Lazy<byte[]> BYTECODE_BYTES = new Lazy<byte[]>(() => {typeof(HexUtil).FullName}.HexToBytes(GeneratedSolcData<{_contractName}>.Default.GetSolcBytecodeInfo(CONTRACT_SOL_FILE, CONTRACT_NAME).Bytecode));

                    public const string CONTRACT_SOL_FILE = ""{_contractSolFileName}"";
                    public const string CONTRACT_NAME = ""{_contractName}"";
                    public const string CONTRACT_BYTECODE_HASH = ""{bytecodeHash}"";
                    public const string CONTRACT_BYTECODE_DEPLOYED_HASH = ""{bytecodeDeployedHash}"";

                    protected override string ContractSolFilePath => CONTRACT_SOL_FILE;
                    protected override string ContractName => CONTRACT_NAME;
                    protected override string ContractBytecodeHash => CONTRACT_BYTECODE_HASH;
                    protected override string ContractBytecodeDeployedHash => CONTRACT_BYTECODE_DEPLOYED_HASH;

                    private {_contractName}({JsonRpcClientType} rpcClient, {typeof(Address).FullName} address, {typeof(Address).FullName} defaultFromAccount)
                        : base(rpcClient, address, defaultFromAccount)
                    {{ 
                        {typeof(EventLogUtil).FullName}.{nameof(EventLogUtil.RegisterDeployedContractEventTypes)}(
                            address.GetHexString(hexPrefix: true)
                            {eventTypesString}
                        );

                    }}

                    public static async Task<{_contractName}> At({JsonRpcClientType} rpcClient, {typeof(Address).FullName} address, {typeof(Address).FullName}? defaultFromAccount = null)
                    {{
                        defaultFromAccount = defaultFromAccount ?? (await rpcClient.Accounts())[0];
                        return new {_contractName}(rpcClient, address, defaultFromAccount.Value);
                    }}

                    {GenerateClassMembers()}
                }}
            ");
        }
Exemple #16
0
        public void SigningTest()
        {
            using (var secp256k1 = new Secp256k1())
            {
                Span <byte> signature   = new byte[Secp256k1.UNSERIALIZED_SIGNATURE_SIZE];
                Span <byte> messageHash = new byte[] { 0xc9, 0xf1, 0xc7, 0x66, 0x85, 0x84, 0x5e, 0xa8, 0x1c, 0xac, 0x99, 0x25, 0xa7, 0x56, 0x58, 0x87, 0xb7, 0x77, 0x1b, 0x34, 0xb3, 0x5e, 0x64, 0x1c, 0xca, 0x85, 0xdb, 0x9f, 0xef, 0xd0, 0xe7, 0x1f };
                Span <byte> secretKey   = "e815acba8fcf085a0b4141060c13b8017a08da37f2eb1d6a5416adbb621560ef".HexToBytes();

                bool result = secp256k1.SignRecoverable(signature, messageHash, secretKey);
                Assert.True(result);

                // Recover the public key
                Span <byte> publicKeyOutput = new byte[Secp256k1.PUBKEY_LENGTH];
                result = secp256k1.Recover(publicKeyOutput, signature, messageHash);
                Assert.True(result);

                // Serialize the public key
                Span <byte> serializedKey = new byte[Secp256k1.SERIALIZED_UNCOMPRESSED_PUBKEY_LENGTH];
                result = secp256k1.PublicKeySerialize(serializedKey, publicKeyOutput);
                Assert.True(result);

                // Slice off any prefix.
                serializedKey = serializedKey.Slice(serializedKey.Length - Secp256k1.PUBKEY_LENGTH);

                Assert.Equal("0x3a2361270fb1bdd220a2fa0f187cc6f85079043a56fb6a968dfad7d7032b07b01213e80ecd4fb41f1500f94698b1117bc9f3335bde5efbb1330271afc6e85e92", serializedKey.ToHexString(true), true);

                // Verify we could obtain the correct sender from the signature.
                Span <byte> senderAddress = KeccakHash.ComputeHash(serializedKey).Slice(KeccakHash.HASH_SIZE - Address.ADDRESS_SIZE);
                Assert.Equal("0x75c8aa4b12bc52c1f1860bc4e8af981d6542cccd", senderAddress.ToArray().ToHexString(true), true);

                // Verify it works with variables generated from our managed code.
                BigInteger ecdsa_r    = BigInteger.Parse("68932463183462156574914988273446447389145511361487771160486080715355143414637", CultureInfo.InvariantCulture);
                BigInteger ecdsa_s    = BigInteger.Parse("47416572686988136438359045243120473513988610648720291068939984598262749281683", CultureInfo.InvariantCulture);
                byte       recoveryId = 1;

                byte[] ecdsa_r_bytes = BigIntegerConverter.GetBytes(ecdsa_r);
                byte[] ecdsa_s_bytes = BigIntegerConverter.GetBytes(ecdsa_s);
                signature = ecdsa_r_bytes.Concat(ecdsa_s_bytes);

                // Allocate memory for the signature and create a serialized-format signature to deserialize into our native format (platform dependent, hence why we do this).
                Span <byte> serializedSignature = ecdsa_r_bytes.Concat(ecdsa_s_bytes);
                signature = new byte[Secp256k1.UNSERIALIZED_SIGNATURE_SIZE];
                result    = secp256k1.RecoverableSignatureParseCompact(signature, serializedSignature, recoveryId);
                if (!result)
                {
                    throw new Exception("Unmanaged EC library failed to parse serialized signature.");
                }

                // Recover the public key
                publicKeyOutput = new byte[Secp256k1.PUBKEY_LENGTH];
                result          = secp256k1.Recover(publicKeyOutput, signature, messageHash);
                Assert.True(result);


                // Serialize the public key
                serializedKey = new byte[Secp256k1.SERIALIZED_UNCOMPRESSED_PUBKEY_LENGTH];
                result        = secp256k1.PublicKeySerialize(serializedKey, publicKeyOutput);
                Assert.True(result);

                // Slice off any prefix.
                serializedKey = serializedKey.Slice(serializedKey.Length - Secp256k1.PUBKEY_LENGTH);

                // Assert our key
                Assert.Equal("0x3a2361270fb1bdd220a2fa0f187cc6f85079043a56fb6a968dfad7d7032b07b01213e80ecd4fb41f1500f94698b1117bc9f3335bde5efbb1330271afc6e85e92", serializedKey.ToHexString(true), true);

                //senderAddress = EthereumEcdsa.Recover(messageHash.ToArray(), recoveryId, ecdsa_r, ecdsa_s).GetPublicKeyHash();
                //senderAddress = senderAddress.Slice(KeccakHash.HASH_SIZE - Address.ADDRESS_SIZE);
                //Assert.Equal("0x75c8aa4b12bc52c1f1860bc4e8af981d6542cccd", senderAddress.ToArray().ToHexString(true), true);
            }
        }
Exemple #17
0
 private static void Keccak256(Span <byte> message, Span <byte> output)
 {
     KeccakHash.ComputeHash(message, output, 0x20);
 }
Exemple #18
0
        public static void GetMethodID(Span <byte> buffer, string functionSignature)
        {
            var bytes = UTF8.GetBytes(functionSignature);

            KeccakHash.ComputeHash(bytes).Slice(0, 4).CopyTo(buffer);
        }
        static void KeccakHashString(string str, Span <byte> output)
        {
            var strBytes = StringUtil.UTF8.GetBytes(str);

            KeccakHash.ComputeHash(strBytes, output);
        }
Exemple #20
0
        /// <summary>
        /// Performs the NIST SP 800-56 Concatenation Key Derivation Function ("KDF") to derive a key of the specified desired length from a base key of arbitrary length.
        /// </summary>
        /// <param name="key">The base key to derive another key from.</param>
        /// <param name="desiredKeyLength">The desired key length of the resulting derived key.</param>
        /// <param name="hashType">The type of hash algorithm to use in the key derivation process.</param>
        /// <returns>Returns the key derived from the provided base key and hash algorithm.</returns>
        private static byte[] DeriveKeyKDF(byte[] key, int desiredKeyLength, KDFHashAlgorithm hashType = KDFHashAlgorithm.SHA256)
        {
            // References:
            // https://csrc.nist.gov/CSRC/media/Publications/sp/800-56a/archive/2006-05-03/documents/sp800-56-draft-jul2005.pdf

            // Define our block size and hash size
            int hashSize;

            if (hashType == KDFHashAlgorithm.SHA256)
            {
                hashSize = 32;
            }
            else if (hashType == KDFHashAlgorithm.Keccak256)
            {
                hashSize = KeccakHash.HASH_SIZE;
            }
            else
            {
                throw new NotImplementedException();
            }

            // Determine the amount of hashes required to generate a key of the desired length (ceiling by adding one less bit than needed to round up 1)
            int hashRounds = (desiredKeyLength + (hashSize - 1)) / hashSize;

            // Create a memory space to store all hashes for each round. The final key will slice from the start of this for all bytes it needs.
            byte[]      aggregateHashData   = new byte[hashRounds * hashSize];
            Span <byte> aggregateHashMemory = aggregateHashData;
            int         aggregateHashOffset = 0;

            // Loop for each hash round to compute.
            for (int i = 0; i <= hashRounds; i++)
            {
                // Get the iteration count (starting from 1)
                byte[] counterData = BitConverter.GetBytes(i + 1);
                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(counterData);
                }

                // Get the data to hash in a single buffer
                byte[] dataToHash = counterData.Concat(key);

                // Determine what provider to use to hash the buffer.
                if (hashType == KDFHashAlgorithm.SHA256)
                {
                    // Calculate the SHA256 hash for this round.
                    byte[] hashResult = _sha256.ComputeHash(dataToHash);

                    // Copy it into our all hashes buffer.
                    hashResult.CopyTo(aggregateHashMemory.Slice(aggregateHashOffset, hashSize));
                }
                else if (hashType == KDFHashAlgorithm.Keccak256)
                {
                    // Calculate the Keccak256 hash for this round.
                    KeccakHash.ComputeHash(dataToHash, aggregateHashMemory.Slice(aggregateHashOffset, hashSize));
                }
                else
                {
                    throw new NotImplementedException();
                }

                // Advance our offset
                aggregateHashOffset += hashSize;

                // If our offset is passed our required key length, we can stop early
                if (aggregateHashOffset >= desiredKeyLength)
                {
                    break;
                }
            }

            // Slice off only the desired data
            return(aggregateHashMemory.Slice(0, desiredKeyLength).ToArray());
        }
        public ResxWriter GenerateResx()
        {
            var resxWriter = new ResxWriter();

            resxWriter.AddEntry("SolidityCompilerVersion", _solidityCompilerVersion);

            // Make paths relative
            var solSourceContent = _solSourceContent.ToDictionary(d => Util.GetRelativeFilePath(_solSourceDir, d.Key), d => d.Value);

            // Scan ast json for absolute paths and make them relative
            foreach (var absPathToken in _solcOutput.JObject["sources"].SelectTokens("$..absolutePath").OfType <JValue>())
            {
                var absPath = Util.GetRelativeFilePath(_solSourceDir, absPathToken.Value <string>());
                absPathToken.Value = absPath;
            }

            var solcSourceInfos = new List <SolcSourceInfo>();

            foreach (JProperty item in _solcOutput.JObject["sources"])
            {
                var fileName      = Util.GetRelativeFilePath(_solSourceDir, item.Name);
                var id            = item.Value.Value <int>("id");
                var astObj        = (JObject)item.Value["ast"];
                var sourceContent = solSourceContent[fileName];
                var sourceInfo    = new SolcSourceInfo
                {
                    AstJson    = astObj,
                    FileName   = fileName,
                    ID         = id,
                    SourceCode = sourceContent
                };
                solcSourceInfos.Add(sourceInfo);
            }

            var solcSourceInfosJson = JsonConvert.SerializeObject(solcSourceInfos, Formatting.Indented);

            resxWriter.AddEntry("SourcesList", solcSourceInfosJson);

            var solcBytecodeInfos = new List <SolcBytecodeInfo>();

            foreach (JProperty solFile in _solcOutput.JObject["contracts"])
            {
                foreach (JProperty solContract in solFile.Value)
                {
                    var fileName     = Util.GetRelativeFilePath(_solSourceDir, solFile.Name);
                    var contractName = solContract.Name;

                    var bytecodeObj         = solContract.Value["evm"]["bytecode"];
                    var deployedBytecodeObj = solContract.Value["evm"]["deployedBytecode"];

                    var sourceMap         = bytecodeObj.Value <string>("sourceMap");
                    var sourceMapDeployed = deployedBytecodeObj.Value <string>("sourceMap");

                    var opcodes         = bytecodeObj.Value <string>("opcodes");
                    var opcodesDeployed = deployedBytecodeObj.Value <string>("opcodes");

                    var bytecode         = bytecodeObj.Value <string>("object");
                    var bytecodeDeployed = deployedBytecodeObj.Value <string>("object");

                    var bytecodeHash         = KeccakHash.ComputeHash(HexUtil.HexToBytes(bytecode)).ToHexString();
                    var bytecodeDeployedHash = KeccakHash.ComputeHash(HexUtil.HexToBytes(bytecodeDeployed)).ToHexString();

                    solcBytecodeInfos.Add(new SolcBytecodeInfo
                    {
                        FilePath             = fileName,
                        ContractName         = contractName,
                        SourceMap            = sourceMap,
                        Opcodes              = opcodes,
                        SourceMapDeployed    = sourceMapDeployed,
                        OpcodesDeployed      = opcodesDeployed,
                        Bytecode             = bytecode,
                        BytecodeDeployed     = bytecodeDeployed,
                        BytecodeHash         = bytecodeHash,
                        BytecodeDeployedHash = bytecodeDeployedHash
                    });
                }
            }

            var solcBytecodeInfosJson = JsonConvert.SerializeObject(solcBytecodeInfos, Formatting.Indented);

            resxWriter.AddEntry("ByteCodeData", solcBytecodeInfosJson);

            var contractAbis     = _solcOutput.ContractsFlattened.ToDictionary(c => c.SolFile + "/" + c.ContractName, c => c.Contract.Abi);
            var contractAbisJson = JsonConvert.SerializeObject(contractAbis, Formatting.Indented);

            resxWriter.AddEntry("ContractAbiJson", contractAbisJson);

            return(resxWriter);
        }