示例#1
0
        public virtual void ShouldPackBool()
        {
            var soliditySha3 = new ABIEncode();

            Assert.Equal("01", soliditySha3.GetABIEncodedPacked(true).ToHex());
            Assert.Equal("00", soliditySha3.GetABIEncodedPacked(false).ToHex());
        }
示例#2
0
        /// <summary>
        /// Sign a prroof that a free service provider provided free content to a Witness. Should be signed by wallet owner as Witness
        /// </summary>
        /// <param name="offchainTransaction"></param>
        /// <returns></returns>
        public SignedOffchainFreeServiceTransaction signFreeServiceProviderMbs(SignedOffchainFreeServiceTransaction offchainTransaction)
        {
            var signer  = new MessageSigner();
            var encoder = new ABIEncode();

            ABIValue[] ABIValues = new ABIValue[] {
                new ABIValue("uint", offchainTransaction.epoch),
                new ABIValue("address", offchainTransaction.freeServiceProvider),
                new ABIValue("address", offchainTransaction.validator),
                new ABIValue("uint256", offchainTransaction.freeMb)
            };

            var payloadEncoded = encoder.GetABIEncodedPacked(ABIValues);
            var proof          = Sha3Keccack.Current.CalculateHash(payloadEncoded);

            offchainTransaction.h = proof;

            var signedTx = signer.Sign(offchainTransaction.h, _wallet.PK);


            var signature = MessageSigner.ExtractEcdsaSignature(signedTx);

            offchainTransaction.v = signature.V.FirstOrDefault();
            offchainTransaction.r = signature.R;
            offchainTransaction.s = signature.S;
            if (offchainTransaction.s.Length < 32)
            {
                var tmpS = offchainTransaction.s.ToList();
                tmpS.Insert(0, 0);
                offchainTransaction.s = tmpS.ToArray();
            }

            offchainTransaction.signer = _wallet.address;
            return(offchainTransaction);
        }
示例#3
0
        /// <summary>
        /// Sign an Offchain payment as a Peer
        /// </summary>
        /// <param name="offchainTransaction">The transaction to be signed</param>
        /// <returns>The Transaction signed by wallet owner as Peer </returns>
        public SignedOffchainTransaction signOffchainPayment(SignedOffchainTransaction offchainTransaction)
        {
            var signer  = new MessageSigner();
            var encoder = new ABIEncode();

            ABIValue[] ABIValues = new ABIValue[] {
                new ABIValue("address", offchainTransaction.beneficiary),
                new ABIValue("bytes32", offchainTransaction.nonce),
                new ABIValue("uint256", offchainTransaction.amount),
                new ABIValue("uint", offchainTransaction.fee)
            };

            var payloadEncoded = encoder.GetABIEncodedPacked(ABIValues);
            var proof          = Sha3Keccack.Current.CalculateHash(payloadEncoded);

            offchainTransaction.h = proof;

            var signedTx = signer.Sign(offchainTransaction.h, _wallet.PK);


            var signature = MessageSigner.ExtractEcdsaSignature(signedTx);

            offchainTransaction.v = signature.V.FirstOrDefault();
            offchainTransaction.r = signature.R;
            offchainTransaction.s = signature.S;
            if (offchainTransaction.s.Length < 32)
            {
                var tmpS = offchainTransaction.s.ToList();
                tmpS.Insert(0, 0);
                offchainTransaction.s = tmpS.ToArray();
            }
            offchainTransaction.signer = _wallet.address;
            return(offchainTransaction);
        }
示例#4
0
        public virtual void ShouldPackAddress()
        {
            var soliditySha3 = new ABIEncode();

            Assert.Equal("0x12890D2cce102216644c59daE5baed380d84830c",
                         soliditySha3.GetABIEncodedPacked(new ABIValue("address", "0x12890D2cce102216644c59daE5baed380d84830c"))
                         .ToHex(true).ConvertToEthereumChecksumAddress());
        }
示例#5
0
        public virtual void ShouldPackFixedArrayUint8()
        {
            var list         = new List <int>(new[] { 1, 2 });
            var soliditySha3 = new ABIEncode();

            Assert.Equal(
                "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
                soliditySha3.GetABIEncodedPacked(new ABIValue("uint8[2]", list)).ToHex());
        }
示例#6
0
        public virtual void ShouldPackFixedArrayBytes16()
        {
            var list = new List <byte[]>(new[]
                                         { Encoding.UTF8.GetBytes("Hello, world!"), Encoding.UTF8.GetBytes("Hello, world!") });
            var soliditySha3 = new ABIEncode();

            Assert.Equal(
                "48656c6c6f2c20776f726c64210000000000000000000000000000000000000048656c6c6f2c20776f726c642100000000000000000000000000000000000000",
                soliditySha3.GetABIEncodedPacked(new ABIValue("bytes13[2]", list)).ToHex());
        }
示例#7
0
        public virtual void ShouldPackStaticArrayAddresses()
        {
            var list = new List <string>(new[]
                                         { "0x7Dd31bc2ffA37Ab492a8d60F9C7170B78f12E1c5", "0x0Efa8015FCEC7039Feb656a4830Aa6518BF46010" });
            var soliditySha3 = new ABIEncode();

            Assert.Equal(
                "0000000000000000000000007dd31bc2ffa37ab492a8d60f9c7170b78f12e1c50000000000000000000000000efa8015fcec7039feb656a4830aa6518bf46010",
                soliditySha3.GetABIEncodedPacked(new ABIValue("address[2]", list)).ToHex());
        }
示例#8
0
        public static byte[] EncodeMultiSend(IMultiSendInput multiSendInput)
        {
            var callData   = multiSendInput.GetCallData();
            var abiEncoder = new ABIEncode();

            return(abiEncoder.GetABIEncodedPacked(
                       new ABIValue("uint8", (int)ContractOperationType.Call),
                       new ABIValue("address", multiSendInput.Target),
                       new ABIValue("uint256", multiSendInput.Value),
                       new ABIValue("uint256", callData.Length),
                       new ABIValue("bytes", callData)));
        }
示例#9
0
        /// <summary>
        /// Sign an Offchain Payemnt as Relayer using Wallet private key
        /// </summary>
        /// <param name="offchainTransaction">The already signed by Peer Offchain Payment payload</param>
        /// <returns>The transaction signed by Wallet owner as Relayer</returns>
        public async Task <SignedOffchainTransaction> relayerSignOffchainPayment(SignedOffchainTransaction offchainTransaction)
        {
            //Check that already signed payload is valid
            var validSignature = await checkOffchainSignature(offchainTransaction);

            if (!validSignature)
            {
                throw new Exception("Invalid signature");
            }



            var signer  = new MessageSigner();
            var encoder = new ABIEncode();

            ABIValue[] ABIValues = new ABIValue[] {
                new ABIValue("bytes32", offchainTransaction.h),
                new ABIValue("uint", offchainTransaction.txUntilBlock)
            };

            var payloadEncoded = encoder.GetABIEncodedPacked(ABIValues);
            var proof          = Sha3Keccack.Current.CalculateHash(payloadEncoded);

            offchainTransaction.rh = proof;

            var signedTx = signer.Sign(offchainTransaction.rh, _wallet.PK);


            var signature = MessageSigner.ExtractEcdsaSignature(signedTx);

            offchainTransaction.rv = signature.V.FirstOrDefault();
            offchainTransaction.rr = signature.R;
            offchainTransaction.rs = signature.S;
            if (offchainTransaction.rs.Length < 32)
            {
                var tmpS = offchainTransaction.rs.ToList();
                tmpS.Insert(0, 0);
                offchainTransaction.rs = tmpS.ToArray();
            }

            offchainTransaction.relayerId = _wallet.address;
            return(offchainTransaction);
        }
示例#10
0
        private async Task ProcessJob(MySqlConnection connection, int blockchainID, OTIdentity[] identities,
                                      string address, BlockchainType blockchain, BlockchainNetwork network, Source source, uint id)
        {
            string abi = AbiHelper.GetContractAbi(ContractTypeEnum.ERC725, blockchain, network);

            string nodeUrl = await connection.ExecuteScalarAsync <string>(@"SELECT BlockchainNodeUrl FROM blockchains WHERE id = @id", new
            {
                id = blockchainID
            });

            var cl = new Web3(nodeUrl);

            var eth = new EthApiService(cl.Client);

            Int32 percentage = 0;
            int   counter    = 0;

            foreach (OTIdentity identity in identities)
            {
                counter++;
                try
                {
                    int loopPercentage = (int)Math.Round((decimal)counter * 100 / identities.Count(), MidpointRounding.AwayFromZero);
                    if (loopPercentage != percentage)
                    {
                        percentage = loopPercentage;

                        await connection.ExecuteAsync(@"UPDATE findnodesbywalletjob SET Progress = @percentage WHERE ID = @id", new
                        {
                            id = id,
                            percentage
                        });
                    }

                    var ercContract = new Contract(eth, abi, identity.Identity);

                    Function keyHasPurposeFunction = ercContract.GetFunction("keyHasPurpose");

                    var    abiEncode = new ABIEncode();
                    byte[] data      = abiEncode.GetABIEncodedPacked(address.HexToByteArray());

                    byte[] bytes = CalculateHash(data);

                    await TimeConstraint;
                    bool  hasPermission = await keyHasPurposeFunction.CallAsync <bool>(bytes, 1);

                    if (hasPermission)
                    {
                        await connection.ExecuteAsync(@"INSERT INTO findnodesbywalletresult(JobID, Identity)
VALUES(@jobID, @identity)", new
                        {
                            jobID    = id,
                            identity = identity.Identity
                        });
                    }
                }
                catch (Exception ex)
                {
                    throw;
                }
            }

            await connection.ExecuteAsync(@"UPDATE findnodesbywalletjob SET Progress = 100, EndDate = @endDate WHERE ID = @id", new
            {
                id      = id,
                endDate = DateTime.UtcNow
            });
        }
示例#11
0
        public virtual void ShouldPackBigInt(int value, string type, string result)
        {
            var soliditySha3 = new ABIEncode();

            Assert.Equal(result, soliditySha3.GetABIEncodedPacked(new BigInteger(value)).ToHex());
        }
示例#12
0
        public static async Task <BeforePayoutResult> CanTryPayout(string nodeID, string offerId, string holdingAddress,
                                                                   string holdingStorageAddress, string litigationStorageAddress, string identity, int?blockchainID,
                                                                   string selectedAddress)
        {
            if (nodeID == null || offerId == null || holdingAddress == null || holdingStorageAddress == null || litigationStorageAddress == null || identity == null || blockchainID == null || selectedAddress == null)
            {
                return(new BeforePayoutResult
                {
                    CanTryPayout = false,
                    Header = "Stop!",
                    Message = "Missing data in request."
                });
            }

            await using (var connection = new MySqlConnection(OTHubSettings.Instance.MariaDB.ConnectionString))
            {
                var holdingStorageAddressModel = await connection.QueryFirstOrDefaultAsync <ContractAddress>(ContractsSql.GetHoldingStorageAddressByAddress, new
                {
                    holdingStorageAddress = holdingStorageAddress,
                    blockchainID
                });

                holdingStorageAddress = holdingStorageAddressModel?.Address;

                if (holdingStorageAddress == null)
                {
                    return(new BeforePayoutResult
                    {
                        CanTryPayout = false,
                        Header = "Stop!",
                        Message = "OT Hub is not familiar with this holding storage smart contract address for this blockchain id " + blockchainID
                    });
                }

                var blockchainRow = await connection.QueryFirstAsync("SELECT * FROM blockchains where id = @id", new { id = blockchainID });

                string blockchainName         = blockchainRow.BlockchainName;
                string networkName            = blockchainRow.NetworkName;
                string explorerTransactionUrl = blockchainRow.TransactionUrl;

                BlockchainType    blockchainEnum  = Enum.Parse <BlockchainType>(blockchainName);
                BlockchainNetwork networkNameEnum = Enum.Parse <BlockchainNetwork>(networkName);

                string nodeUrl = await connection.ExecuteScalarAsync <string>(@"SELECT BlockchainNodeUrl FROM blockchains WHERE id = @id", new
                {
                    id = blockchainID
                });

                var cl = new Web3(nodeUrl);

                var eth = new EthApiService(cl.Client);


                var ercContract = new Contract(eth, AbiHelper.GetContractAbi(ContractTypeEnum.ERC725, blockchainEnum, networkNameEnum), identity);

                Function keyHasPurposeFunction = ercContract.GetFunction("keyHasPurpose");


                var    abiEncode = new ABIEncode();
                byte[] test      = abiEncode.GetABIEncodedPacked(selectedAddress.HexToByteArray());

                byte[] bytes = CalculateHash(test);

                bool hasPermission = await keyHasPurposeFunction.CallAsync <bool>(bytes, 1) || await keyHasPurposeFunction.CallAsync <bool>(bytes, 2);

                if (!hasPermission)
                {
                    return(new BeforePayoutResult
                    {
                        CanTryPayout = false,
                        Header = "Stop!",
                        Message = "The address you have selected in MetaMask (" + selectedAddress + ") does not have permission to payout on the identity " + identity + ". You need to pick either your management wallet or operational wallet."
                    });
                }


                var holdingStorageAbi = AbiHelper.GetContractAbi(ContractTypeEnum.HoldingStorage, blockchainEnum, networkNameEnum);

                holdingAddress = (await connection.QueryFirstOrDefaultAsync <ContractAddress>(ContractsSql.GetHoldingAddressByAddress, new
                {
                    holdingAddress = holdingAddress,
                    blockchainID
                }))?.Address;

                if (holdingAddress == null)
                {
                    return(new BeforePayoutResult
                    {
                        CanTryPayout = false,
                        Header = "Stop!",
                        Message = "OT Hub is not familiar with this holding smart contract address for this blockchain id " + blockchainID
                    });
                }

                var offerIdArray = offerId.HexToByteArray();

                var holdingStorageContract =
                    new Contract(new EthApiService(cl.Client), holdingStorageAbi,
                                 holdingStorageAddress);
                var getHolderStakedAmountFunction = holdingStorageContract.GetFunction("getHolderStakedAmount");
                var holderStakedAmount            = await getHolderStakedAmountFunction.CallAsync <BigInteger>(offerIdArray, identity);

                var getHolderPaymentTimestampFunction = holdingStorageContract.GetFunction("getHolderPaymentTimestamp");
                var holderPaymentTimestamp            = await getHolderPaymentTimestampFunction.CallAsync <BigInteger>(offerIdArray, identity);

                var getOfferHoldingTimeInMinutesFunction = holdingStorageContract.GetFunction("getOfferHoldingTimeInMinutes");
                var offerHoldingTimeInMinutes            = await getOfferHoldingTimeInMinutesFunction.CallAsync <BigInteger>(offerIdArray);

                var getHolderPaidAmountFunction = holdingStorageContract.GetFunction("getHolderPaidAmount");
                var holderPaidAmount            = await getHolderPaidAmountFunction.CallAsync <BigInteger>(offerIdArray, identity);

                if (holderStakedAmount <= 0)
                {
                    return(new BeforePayoutResult
                    {
                        CanTryPayout = false,
                        Header = "Stop!",
                        Message = "The smart contract says this identity did not hold data for this job. The transaction will likely fail if you try to send this manually."
                    });
                }


                //long holdingTime = await connection.ExecuteScalarAsync<long>(
                //    @"select HoldingTimeInMinutes from otoffer where OfferID = @offerID and blockchainID = @blockchainID",
                //    new
                //    {
                //        offerId,
                //        blockchainID
                //    });

                var latestBlockParam = BlockParameter.CreateLatest();

                var block = await cl.Eth.Blocks.GetBlockWithTransactionsByNumber.SendRequestAsync(latestBlockParam);

                DateTime blockDate = TimestampHelper.UnixTimeStampToDateTime((double)block.Timestamp.Value);

                DateTime jobStartDate = await connection.ExecuteScalarAsync <DateTime>(@"SELECT Timestamp FROM otcontract_holding_offerfinalized where OfferID = @offerID and BlockchainID = @blockchainID",
                                                                                       new
                {
                    offerID = offerId,
                    blockchainID
                });

                DateTime jobEndDate = jobStartDate.AddMinutes((int)offerHoldingTimeInMinutes);

                if (blockDate > jobEndDate)
                {
                    blockDate = jobEndDate;
                }

                BigInteger blockTimestamp = new BigInteger(TimestampHelper.DateTimeToUnixTimeStamp(blockDate));


                var amountToTransfer = holderStakedAmount;
                amountToTransfer = amountToTransfer * (blockTimestamp - holderPaymentTimestamp);
                amountToTransfer = amountToTransfer / (offerHoldingTimeInMinutes * 60);

                decimal friendlyEstimatedPayout = Web3.Convert.FromWei(amountToTransfer);



                if (holderPaidAmount == holderStakedAmount)
                {
                    var friendlyAmount = Web3.Convert.FromWei(holderPaidAmount);

                    return(new BeforePayoutResult
                    {
                        CanTryPayout = false,
                        Header = "Stop!",
                        Message = "The smart contract says you have been paid " + friendlyAmount +
                                  " TRAC for this job. The transaction will likely fail if you try to send this manually."
                    });
                }

                if (!String.IsNullOrWhiteSpace(litigationStorageAddress))
                {
                    litigationStorageAddress = (await connection.QueryFirstOrDefaultAsync <ContractAddress>(@"select Address from otcontract
where Type = 9 AND Address = @litigationStorageAddress AND blockchainID = @blockchainID", new
                    {
                        litigationStorageAddress = litigationStorageAddress,
                        blockchainID
                    }))?.Address;

                    if (litigationStorageAddress == null)
                    {
                        return(new BeforePayoutResult
                        {
                            CanTryPayout = false,
                            Header = "Stop!",
                            Message = "OT Hub is not familiar with this litigation storage smart contract address for this blockchain id " + blockchainID
                        });
                    }

                    Contract storageContract = new Contract((EthApiService)cl.Eth,
                                                            AbiHelper.GetContractAbi(ContractTypeEnum.LitigationStorage, blockchainEnum, networkNameEnum), litigationStorageAddress);
                    Function getLitigationStatusFunction = storageContract.GetFunction("getLitigationStatus");

                    Function   getLitigationTimestampFunction = storageContract.GetFunction("getLitigationTimestamp");
                    BigInteger litigationTimestampInt         =
                        await getLitigationTimestampFunction.CallAsync <BigInteger>(latestBlockParam, offerIdArray,
                                                                                    identity);

                    Function getOfferLitigationIntervalInMinutesFunction =
                        holdingStorageContract.GetFunction("getOfferLitigationIntervalInMinutes");
                    BigInteger litgationInterval =
                        await getOfferLitigationIntervalInMinutesFunction.CallAsync <BigInteger>(latestBlockParam,
                                                                                                 offerIdArray) * 60;



                    var status =
                        await getLitigationStatusFunction.CallAsync <UInt16>(latestBlockParam, offerIdArray, identity);

                    if (status == 1) //initiated
                    {
                        if (litigationTimestampInt + (litgationInterval * 2) >= block.Timestamp.Value)
                        {
                            return(new BeforePayoutResult
                            {
                                CanTryPayout = false,
                                Header = "Stop!",
                                Message =
                                    "The smart contract says 'Unanswered litigation in progress, cannot pay out'. The transaction will likely fail if you try to send this manually."
                            });
                        }
                    }
                    else if (status == 2) //answered
                    {
                        if (litigationTimestampInt + (litgationInterval) >= block.Timestamp.Value)
                        {
                            return(new BeforePayoutResult
                            {
                                CanTryPayout = false,
                                Header = "Stop!",
                                Message =
                                    "The smart contract says 'Unanswered litigation in progress, cannot pay out'. The transaction will likely fail if you try to send this manually."
                            });
                        }
                    }
                    else if (status == 0) //completed
                    {
                        //Do nothing as this is fine
                    }
                    else
                    {
                        return(new BeforePayoutResult
                        {
                            CanTryPayout = false,
                            Header = "Stop!",
                            Message =
                                "The smart contract says 'Data holder is replaced or being replaced, cannot payout!'. The transaction will likely fail if you try to send this manually."
                        });
                    }
                }

                return(new BeforePayoutResult
                {
                    CanTryPayout = true,
                    BlockchainExplorerUrlFormat = explorerTransactionUrl,
                    EstimatedPayout = friendlyEstimatedPayout
                });
            }
        }