Can someone help me successfully send ERC20 tokens using the Nethereum package in C# .NET?
I am able to successfully get account balances, but when I try to send, it just sits there....
I am using the Infura.io project api also with the below security:
eth_accounts
eth_call
eth_getBalance
eth_getTransactionReceipt
eth_sendRawTransaction
var client = new EthClient(new RpcUrl("https://mainnet.infura.io/v3/-MyProjectID-"));
Here is the code I am using:
--The call to the transfer method
/* transfer 100 tokens */
var transactionHashTask = client.transferTokens(coinOwnerAddress, coinOwnerPrivateKey, toAddress, contractAddress, 0);
var transactionHash = transactionHashTask.Result.ToString();
lblTransHash.Text = "Transaction hash: " + transactionHash;
--Code that contains the actual method
public async Task<string> transferTokens(string senderAddress, string privateKey, string receiverAddress, string contractAddress, UInt64 tokens)
{
var transactionMessage = new TransferFunction()
{
FromAddress = senderAddress,
To = receiverAddress,
AmountToSend = tokens
};
var transferHandler = web3.Eth.GetContractTransactionHandler<TransferFunction>();
Task<string> transactionHashTask = transferHandler.SendRequestAsync(contractAddress,transactionMessage);
return await transactionHashTask;
}
You are transferring something right? So maybe you have to send extra to account for the gas fees. But i'm no expert. Let me know if you solve this please.
The transfer function doesn't have AmountToSend parameter. It has TokenAmount. So change like below
var transactionMessage = new TransferFunction()
{
To = receiverAddress,
TokenAmount= tokens
};
Related
I have managed to create a c# tool to push messages to google cloud pubsub. I can't seem to find anywhere how to pubslish the message to the emulator. From what I've read the following should work by passing in the endpoint to the ClientCreationSettings. But I get a bad request response back from the emulator...
public static async Task PublishMessage()
{
var endpoint = new ServiceEndpoint("localhost", 8085);
ClientCreationSettings clientSettings = new ClientCreationSettings(1, null, null, endpoint);
string message = "hello world";
publisherClient = await PublisherClient.CreateAsync(new TopicName("project1", "topic1"), clientSettings);
await publisherClient.PublishAsync(message);
await publisherClient.ShutdownAsync(TimeSpan.FromSeconds(15));
}
Any insight appreciated
For C#, after starting the emulator with gcloud beta emulators pubsub start --project=PUBSUB_PROJECT_ID [options] and setting the environment variable for PUBSUB_EMULATOR_HOST with a handy CLI as shown here, you need to update your application code as shown in this sample:
string emulatorHostAndPort = Environment.GetEnvironmentVariable("PUBSUB_EMULATOR_HOST");
PublisherServiceApiClient client = new PublisherServiceApiClientBuilder
{
Endpoint = emulatorHostAndPort,
ChannelCredentials = ChannelCredentials.Insecure
}.Build();
// do things using client..
You need to send the PubSubMessage object instead of the string.
var message = new PubsubMessage(){ Data = "hello world" };
Your code should be like:
public static async Task PublishMessage()
{
var clientSettings = new PublisherClient.ClientCreationSettings(
null,
PublisherServiceApiSettings.GetDefault(),
ChannelCredentials.Insecure,
"localhost:8085");
var message = new PubsubMessage(){ Data = "hello world" };
publisherClient = await PublisherClient.CreateAsync(new TopicName("project1", "topic1"), clientSettings);
await publisherClient.PublishAsync(message};
await publisherClient.ShutdownAsync(TimeSpan.FromSeconds(15));
}
Source: https://googleapis.github.io/google-cloud-dotnet/docs/Google.Cloud.PubSub.V1/
I am currently using Forge Webhooks API to handle different events that might occur on a project. Everything works fine, except the payload signature check.
The reason why I want to check the payload is because the callback will end up on my API and I want to reject all requests that do not come from Forge's webhook service.
Steps I followed:
Add (register) secret key (token) on Forge. API Reference
Trigger an event that will eventually call my API for handling it.
Validating signature header. Followed this tutorial.
PROBLEM!!! My computedSignature is different from the signature received from Forge.
My C# code looks like this:
private const string SHA_HASH = "sha1hash";
var secretKeyBytes = Encoding.UTF8.GetBytes(ForgeAuthConfiguration.AntiForgeryToken);
using var hmac = new HMACSHA1(secretKeyBytes);
var computedHash = hmac.ComputeHash(request.Body.ReadAsBytes());
var computedSignature = $"{SHA_HASH}={computedHash.Aggregate("", (s, e) => s + $"{e:x2}", s => s)}";
For one example, Forge's request has this signature header: sha1hash=303c4e7d2a94ccfa559560dc2421cee8496d2d83
My C# code computes this signature: sha1hash=3bb8d41c3c1cb6c9652745f5996b4e7f832ca8d5
The same AntiForgeryToken was sent to Forge at step 1
Ok, I thought my C# code is broken, then I tried this online HMAC generator and for the given input, result is: 3bb8d41c3c1cb6c9652745f5996b4e7f832ca8d5 (same as C#)
Ok, maybe the online generator is broken, I tried their own code in node js and this is the result:
I have 3 ways of encrypting the SAME body using the SAME key and I get the SAME result every time. BUT those results are DIFFERENT from the signature provided by Forge, resulting in failing the check and rejecting a valid request...
Does anyone know what is happening with that signature?
Why is it different from my result if I follow their tutorial?
How are you validating your requests?
The code below is working at my side. Could you give it a try if it helps?
[HttpPost]
[Route("api/forge/callback/webhookbysig")]
public async Task<IActionResult> WebhookCallbackBySig()
{
try
{
var encoding = Encoding.UTF8;
byte[] rawBody = null;
using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
{
rawBody = encoding.GetBytes(reader.ReadToEnd());
}
var requestSignature = Request.Headers["x-adsk-signature"];
string myPrivateToken = Credentials.GetAppSetting("FORGE_WEBHOOK_PRIVATE_TOKEN");
var tokenBytes = encoding.GetBytes(myPrivateToken);
var hmacSha1 = new HMACSHA1(tokenBytes);
byte[] hashmessage = hmacSha1.ComputeHash(rawBody);
var calculatedSignature = "sha1hash=" + BitConverter.ToString(hashmessage).ToLower().Replace("-", "");
if (requestSignature.Equals(calculatedSignature))
{
System.Diagnostics.Debug.Write("Same!");
}
else
{
System.Diagnostics.Debug.Write("diff!");
}
}
catch(Exception ex)
{
}
// ALWAYS return ok (200)
return Ok();
}
If this does not help, please share with your webhook ID (better send email at forge.help#autodesk.com). We will ask engineer team to check it.
I'm finding very little documentation online for implementing the PayPal REST API in C#.
I have gotten past the first step of getting an access token, but I keep seeing conflicting methods for sending API calls and nothing I have tried works.
Here's my current code:
private async void cmdRefund_Click(object sender, EventArgs e)
{
//var apiContext = Configuration.GetAPIContext();
string AccessToken;
string Nonce;
string AppID;
string TokenType;
try
{
// ClientId of your Paypal app API
//This is the live ID
string APIClientId = "AZxxxx-8";
//this is the live secret Key
string APISecret = "Exxxx39";
using (var client = new HttpClient())
{
var byteArray = Encoding.UTF8.GetBytes(APIClientId + ":" + APISecret);
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
//this is the live url
var url = new Uri("https://api.paypal.com/v1/oauth2/token", UriKind.Absolute);
client.DefaultRequestHeaders.IfModifiedSince = DateTime.UtcNow;
var requestParams = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("grant_type", "client_credentials")
};
var content = new FormUrlEncodedContent(requestParams);
var webresponse = await client.PostAsync(url, content);
var resp = await webresponse.Content.ReadAsStringAsync();
MessageBox.Show(resp);
if (resp.IndexOf("access_token") == -1)
{
MessageBox.Show("PayPal Authorization Failed.");
return;
}
AccessToken = resp.Substring(resp.IndexOf("access_token") + 15);
AccessToken = AccessToken.Substring(0, AccessToken.IndexOf("\""));
Nonce = resp.Substring(resp.IndexOf("nonce") + 8);
Nonce = Nonce.Substring(0, Nonce.IndexOf("\""));
AppID = resp.Substring(resp.IndexOf("app_id") + 9);
AppID = AppID.Substring(0, AppID.IndexOf("\""));
TokenType = resp.Substring(resp.IndexOf("token_type") + 13);
TokenType = TokenType.Substring(0, TokenType.IndexOf("\""));
MessageBox.Show("Access Token: \r\n" + AccessToken + "\r\nNonce:\r\n" + Nonce + "\r\nAppID:\r\n" + AppID + "\r\nToken Type:\r\n" + TokenType);
// response will deserialized using Jsonconver
//return JsonConvert.DeserializeObject<PayPalGetTokenResponse>(resp);
}
}
catch (System.Exception ex)
{
MessageBox.Show(ex.Message);
return;
}
//Authorization has been achieved here - now I want to process a refund
var apiContext = new APIContext(AccessToken);
Amount refundAmount = new Amount();
refundAmount.total = "0.01";
refundAmount.currency = "USD";
Refund refund = new Refund();
refund.amount = refundAmount;
string saleId = "9XY489008U7836633";
//*************THIS NEXT LINE CAUSES AN ERROR
Refund refundforreal = Sale.Refund(apiContext, saleId, refund);
//*************
string refundId = refund.id;
}
The last line causes the Error: "PayPal.IdentityException: 'The remote server returned an error: (401) Unauthorized.'"
As far as I can tell, my access token is completely valid, but this does not work. I should note that I the transactions I'm trying to get information on and refund are NOT placed via the REST API, but are simply placed through the regular PayPal interface integrated on our website. I don't know if that causes a problem or not, but that is what I need to do.
I am using a Windows Forms App written in C# in Visual Studios 2017 because I'm replacing an old VB6 program that required that the user log into a PayPal session in a browser in the program and need to replace that program with something that is both usable and familiar for our employees, AND is more forward thinking by using the REST API instead of the old method of filling in fields in a WebBrowser control.
***********EDIT************ - I added this as a follow up:
I took #shamanthGowdraShankaramurthy's advice and used Postman and managed to do what I wanted, so thank you - that did help me to know that at least what I want to do is possible.
I still don't know how to do the POST in C#. I think perhaps I'll stay away from the built in "Refund" object in the SDK and instead try to POST some other way.
The url I'm using is in Postman is: https://api.paypal.com/v1/payments/sale/9XY489008U7836633/refund
I sent this as the body to do a $0.01 refund on my test transaction:
{
"amount": {
"total": "0.01",
"currency": "USD"
},
"invoice_number": "INV-1234567"
}'
I added a Bearer Token authorization to the POST with my Access Token that I had from my working code.
Finally, in Postman, I changed the body from "Text" to "JSON (application/json).
How do I incorporate all these elements (the URL, my bearer token, the body, and the information that the body is json) into a POST in a C# winforms application?
In case anyone else is looking for this, the answer turned out to be much simpler than I figured. I think I was messing myself up by not using the AccessTokens that are easily obtained by the PayPal SDK.
First, make sure that you have the App.Config file set up properly:
<!-- PayPal SDK settings -->
<paypal>
<settings>
//specify sandbox or live
<add name="mode" value="sandbox" />
<add name="clientId" value="insert_clientid_key_here" />
<add name="clientSecret" value="Insert_client_secret_key_here" />
</settings>
</paypal>
Then this is all the code I needed to make the refunds work:
private void cmdRefund_Click(object sender, EventArgs e)
{
var config = ConfigManager.Instance.GetProperties();
var accessToken = new OAuthTokenCredential(config).GetAccessToken();
var apiContext = new APIContext(accessToken);
Amount refundAmount = new Amount();
refundAmount.total = "0.01";
refundAmount.currency = "USD";
RefundRequest refund = new RefundRefundRequest();
refund.amount = refundAmount;
string saleId = "9XY489008U7836633";
Refund refundforreal = Sale.Refund(apiContext, saleId, refund);
MessageBox.Show("Refund status:" + refundforreal.state + "\r\n" + "Txn #:" + refundforreal.id);
}
I need to programmatically backup/export a SQL Database (either in Azure, or a compatible-one on-prem) to Azure Storage, and restore it to another SQL Database. I would like to use only NuGet packages for code dependencies, since I cannot guarantee that either the build or production servers will have the Azure SDK installed. I cannot find any code examples for something that I assume would be a common action. The closest I found was this:
https://blog.hompus.nl/2013/03/13/backup-your-azure-sql-database-to-blob-storage-using-code/
But, this code exports to a local bacpac file (requiring RoleEnvironment, an SDK-only object). I would think there should be a way to directly export to Blob Storage, without the intermediary file. One thought was to create a Stream, and then run:
services.ExportBacpac(stream, "dbnameToBackup")
And then write the stream to storage; however a Memory Stream wouldn't work--this could be a massive database (100-200 GB).
What would be a better way to do this?
Based on my test, the sql Microsoft Azure SQL Management Library 0.51.0-prerelease support directly export the sql database .bacpac file to the azure storage.
We could using sqlManagementClient.ImportExport.Export(resourceGroup, azureSqlServer, azureSqlDatabase,exportRequestParameters) to export the .bacpac file the azure storage.
But we couldn't find ImportExport in the lastest version of Microsoft Azure SQL Management Library SDK. So we could only use sql Microsoft Azure SQL Management Library 0.51.0-prerelease SDK.
More details about how to use sql Microsoft Azure SQL Management Library to export the sql backup to azure blob storage, you could refer to below steps and codes.
Prerequisites:
Registry an App in Azure AD and create service principle for it. More detail steps about how to registry app and get access token please refer to document.
Details codes:
Notice: Replace the clientId,tenantId,secretKey,subscriptionId with your registered azure AD information. Replace the azureSqlDatabase,resourceGroup,azureSqlServer,adminLogin,adminPassword,storageKey,storageAccount with your own sql database and storage.
static void Main(string[] args)
{
var subscriptionId = "xxxxxxxx";
var clientId = "xxxxxxxxx";
var tenantId = "xxxxxxxx";
var secretKey = "xxxxx";
var azureSqlDatabase = "data base name";
var resourceGroup = "Resource Group name";
var azureSqlServer = "xxxxxxx"; //testsqlserver
var adminLogin = "user";
var adminPassword = "password";
var storageKey = "storage key";
var storageAccount = "storage account";
var baseStorageUri = $"https://{storageAccount}.blob.core.windows.net/brandotest/";//with container name endwith "/"
var backName = azureSqlDatabase + "-" + $"{DateTime.UtcNow:yyyyMMddHHmm}" + ".bacpac"; //back up sql file name
var backupUrl = baseStorageUri + backName;
ImportExportOperationStatusResponse exportStatus = new ImportExportOperationStatusResponse();
try
{
ExportRequestParameters exportRequestParameters = new ExportRequestParameters
{
AdministratorLogin = adminLogin,
AdministratorLoginPassword = adminPassword,
StorageKey = storageKey,
StorageKeyType = "StorageAccessKey",
StorageUri = new Uri(backupUrl)
};
SqlManagementClient sqlManagementClient = new SqlManagementClient(new Microsoft.Azure.TokenCloudCredentials(subscriptionId, GetAccessToken(tenantId, clientId, secretKey)));
var export = sqlManagementClient.ImportExport.Export(resourceGroup, azureSqlServer, azureSqlDatabase,
exportRequestParameters); //do export operation
while (exportStatus.Status != Microsoft.Azure.OperationStatus.Succeeded) // until operation successed
{
Thread.Sleep(1000 * 60);
exportStatus = sqlManagementClient.ImportExport.GetImportExportOperationStatus(export.OperationStatusLink);
}
Console.WriteLine($"Export DataBase {azureSqlDatabase} to Storage {storageAccount} Succesfully");
}
catch (Exception exception)
{
//todo
}
}
private static string GetAccessToken(string tenantId, string clientId, string secretKey)
{
var authenticationContext = new AuthenticationContext($"https://login.windows.net/{tenantId}");
var credential = new ClientCredential(clientId, secretKey);
var result = authenticationContext.AcquireTokenAsync("https://management.core.windows.net/",
credential);
if (result == null)
{
throw new InvalidOperationException("Failed to obtain the JWT token");
}
var token = result.Result.AccessToken;
return token;
}
Result like this:
1.Send request to tell sql server start exporting to azure blob storage
2.Continue sending request to monitor the database exported operation status.
3.Finish exported operation.
Here's an idea:
Pass the stream to the .ExportBacPac method but hold a reference to it on a different thread where you regularly empty and reset the stream so that there's no memory overflow. I'm assuming here, that Dac does not have any means to access the stream while it is being filled.
The thing you have to take care of yourself though is thread safety - MemoryStreams are not thread safe by default. So you'd have to write your own locking mechanisms around .Position and .CopyTo. I've not tested this, but if you handle locking correctly I'd assume the .ExportBacPac method won't throw any errors while the other thread accesses the stream.
Here's a very simple example as pseudo-code just outlining my idea:
ThreadSafeStream stream = new ThreadSafeStream();
Task task = new Task(async (exitToken) => {
MemoryStream partialStream = new MemoryStream();
// Check if backup completed
if (...)
{
exitToken.Trigger();
}
stream.CopyToThreadSafe(partialStream);
stream.PositionThreadSafe = 0;
AzureService.UploadToStorage(partialStream);
await Task.Delay(500); // Play around with this - it shouldn't take too long to copy the stream
});
services.ExportBacpac(stream, "dbnameToBackup");
await TimerService.RunTaskPeriodicallyAsync(task, 500);
It's similiar to the Brando's answer but this one uses a stable package:
using Microsoft.WindowsAzure.Management.Sql;
Nuget
Using the same variables in the Brando's answer, the code will be like this:
var azureSqlServer = "xxxxxxx"+".database.windows.net";
var azureSqlServerName = "xxxxxxx";
SqlManagementClient managementClient = new SqlManagementClient(new TokenCloudCredentials(subscriptionId, GetAccessToken(tenantId, clientId, secretKey)));
var exportParams = new DacExportParameters()
{
BlobCredentials = new DacExportParameters.BlobCredentialsParameter()
{
StorageAccessKey = storageKey,
Uri = new Uri(baseStorageUri)
},
ConnectionInfo = new DacExportParameters.ConnectionInfoParameter()
{
ServerName = azureSqlServer,
DatabaseName = azureSqlDatabase,
UserName = adminLogin,
Password = adminPassword
}
};
var exportResult = managementClient.Dac.Export(azureSqlServerName, exportParams);
You can use Microsoft.Azure.Management.Fluent to export your database to a .bacpac file and store it in a blob. To do this, there are few things you need to do.
Create an AZAD (Azure Active Directory) application and Service Principal that can access resources. Follow this link for a comprehensive guide.
From the first step, you are going to need "Application (client) ID", "Client Secret", and "Tenant ID".
Install Microsoft.Azure.Management.Fluent NuGet packages, and import Microsoft.Azure.Management.Fluent, Microsoft.Azure.Management.ResourceManager.Fluent, and Microsoft.Azure.Management.ResourceManager.Fluent.Authentication namespaces.
Replace the placeholders in the code snippets below with proper values for your usecase.
Enjoy!
var principalClientID = "<Applicaiton (Client) ID>";
var principalClientSecret = "<ClientSecret>";
var principalTenantID = "<TenantID>";
var sqlServerName = "<SQL Server Name> (without '.database.windows.net'>";
var sqlServerResourceGroupName = "<SQL Server Resource Group>";
var databaseName = "<Database Name>";
var databaseLogin = "<Database Login>";
var databasePassword = "<Database Password>";
var storageResourceGroupName = "<Storage Resource Group>";
var storageName = "<Storage Account>";
var storageBlobName = "<Storage Blob Name>";
var bacpacFileName = "myBackup.bacpac";
var credentials = new AzureCredentialsFactory().FromServicePrincipal(principalClientID, principalClientSecret, principalTenantID, AzureEnvironment.AzureGlobalCloud);
var azure = await Azure.Authenticate(credentials).WithDefaultSubscriptionAsync();
var storageAccount = await azure.StorageAccounts.GetByResourceGroupAsync(storageResourceGroupName, storageName);
var sqlServer = await azure.SqlServers.GetByResourceGroupAsync(sqlServerResourceGroupName, sqlServerName);
var database = await sqlServer.Databases.GetAsync(databaseName);
await database.ExportTo(storageAccount, storageBlobName, bacpacFileName)
.WithSqlAdministratorLoginAndPassword(databaseLogin, databasePassword)
.ExecuteAsync();
So I am just trying to list the tables in the storage account to test the authorization using the Query Tables method. I tried using the SDK, but the SDK was trying to reference DLLs that aren't available in RT. Decided to try out the REST API. but am having trouble with the authentication from this spec http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx
public async Task ExecuteAsync()
{
try
{
HttpClient client = new HttpClient();
Dictionary<string, string> headers = GetHeaders("/Tables");
client.DefaultRequestHeaders.Date = DateTimeOffset.Parse(headers["Date"]);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("SharedKey", headers["Authorization"]);
const string url = "http://account-name.table.core.windows.net/Tables";
XmlReader reader = XmlReader.Create(await client.GetStreamAsync(url));
//
// Do some stuff with the reader here
//
}
catch (Exception e)
{
// handle exception
}
}
public Dictionary<string, string> GetHeaders(string resource)
{
Dictionary<string, string> headers = new Dictionary<string, string>();
headers["Date"] = DateTime.Now.ToString("R");
headers["Authorization"] = GetAuthorizationHeader(resource, headers["Date"]);
return headers;
}
public string GetAuthorizationHeader(string resource, string date)
{
const string key = PRIMARY_KEY;
const string accountName = ACCOUNT_NAME;
string signee = string.Join("\n", new List<string> { "GET", "", "", date, resource });
// make the signature
MacAlgorithmProvider hmac = MacAlgorithmProvider.OpenAlgorithm("HMAC_SHA256");
IBuffer keyMaterial = CryptographicBuffer.ConvertStringToBinary(key, BinaryStringEncoding.Utf8);
CryptographicKey hmacKey = hmac.CreateKey(keyMaterial);
IBuffer data = CryptographicBuffer.ConvertStringToBinary(signee, BinaryStringEncoding.Utf8);
IBuffer hash = CryptographicEngine.Sign(hmacKey, data);
string signature = CryptographicBuffer.EncodeToBase64String(hash);
return string.Format("{0}:{1}", accountName, signature);
}
Obviously I am missing something as I continue to get 403's. See any problems looking through this code?
A few comments:
There's a storage client library for Windows RT as well. Please take a look at my answer here: Working with Azure in Winrt with Rest API, trouble with signature.
Coming to your problem, can you try changing the following line of code:
headers["Date"] = DateTime.Now.ToString("R");
to
headers["Date"] = DateTime.UtcNow.ToString("R");
and see if that helps.
UPDATE
I also noticed that you're using CryptographicBuffer.ConvertStringToBinary to convert Base64 encoded key to bytes. Please try using CryptographicBuffer.DecodeFromBase64String (http://msdn.microsoft.com/en-us/library/windows/apps/windows.security.cryptography.cryptographicbuffer.decodefrombase64string.aspx) instead.