public virtual void ShouldPackBool() { var soliditySha3 = new ABIEncode(); Assert.Equal("01", soliditySha3.GetABIEncodedPacked(true).ToHex()); Assert.Equal("00", soliditySha3.GetABIEncodedPacked(false).ToHex()); }
/// <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); }
/// <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); }
public virtual void ShouldPackAddress() { var soliditySha3 = new ABIEncode(); Assert.Equal("0x12890D2cce102216644c59daE5baed380d84830c", soliditySha3.GetABIEncodedPacked(new ABIValue("address", "0x12890D2cce102216644c59daE5baed380d84830c")) .ToHex(true).ConvertToEthereumChecksumAddress()); }
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()); }
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()); }
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()); }
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))); }
/// <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); }
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 }); }
public virtual void ShouldPackBigInt(int value, string type, string result) { var soliditySha3 = new ABIEncode(); Assert.Equal(result, soliditySha3.GetABIEncodedPacked(new BigInteger(value)).ToHex()); }
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 }); } }