Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 0 additions & 58 deletions Program.cs

This file was deleted.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SportX.bet C# examples
# SX.bet C# examples

This repo contains some examples for signing various order operations on sportx.bet using C#. Currently has examples for the following:

Expand Down
23 changes: 19 additions & 4 deletions SigningExampleNethereum.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,27 @@
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateProgramFile>false</GenerateProgramFile>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Jering.Javascript.NodeJS" Version="6.3.0" />
<PackageReference Include="Nethereum.Web3" Version="4.1.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<ItemGroup>
<PackageReference Include="Jering.Javascript.NodeJS" Version="6.3.0" />
<PackageReference Include="Nethereum.Web3" Version="4.14.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Xunit" Version="2.4.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.1.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>


</ItemGroup>



</Project>
43 changes: 43 additions & 0 deletions node_signatures/src/cancelAllSignature.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import ethSigUtil from "eth-sig-util";

function getCancelAllOrdersEIP712Payload(
salt: string,
timestamp: number,
chainId: number
) {
const payload = {
types: {
EIP712Domain: [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "salt", type: "bytes32" },
],
Details: [{ name: "timestamp", type: "uint256" }],
},
primaryType: "Details",
domain: {
name: "CancelAllOrdersSportX",
version: "1.0",
chainId,
salt,
},
message: { timestamp },
};
return payload;
}

export = function getCancelAllOrdersSignature(
callback: any,
salt: string,
timestamp: number,
privateKey: string,
chainId: number
) {
const payload = getCancelAllOrdersEIP712Payload(salt, timestamp, chainId);
const bufferPrivateKey = Buffer.from(privateKey.substring(2), "hex");
const signature = (ethSigUtil as any).signTypedData_v4(bufferPrivateKey, {
data: payload,
});
callback(null, signature);
};
23 changes: 19 additions & 4 deletions Order.cs → src/Order.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@
using Jering.Javascript.NodeJS;
using Newtonsoft.Json;

namespace NethereumSample
namespace SigningExampleNethereum
{
public static class GlobalVar
{
public const string JS_FILE_LOCATION = "./node_signatures/dist/main.js";
public const string CANCEL_ORDERS_V1_JS_FILE_LOCATION = "./node_signatures/dist/main.js";
public const string CANCEL_ALL_ORDERS_FILE_LOCATION = "./node_signatures/dist/cancelAllSignature.js";
}

class BigIntegerConverter : JsonConverter
Expand Down Expand Up @@ -100,8 +101,22 @@ int chainId
{
// Invoke javascript
string? result = await StaticNodeJSService.InvokeFromFileAsync<string>(
GlobalVar.JS_FILE_LOCATION,
args: new object[] { orderHashes, privateKey, 80001 }
GlobalVar.CANCEL_ORDERS_V1_JS_FILE_LOCATION,
args: new object[] { orderHashes, privateKey, chainId }
);
return result;
}

public static async Task<string?> GetCancelAllSignature(
string salt,
string timestamp,
string privateKey,
int chainId
) {
// Invoke javascript
string? result = await StaticNodeJSService.InvokeFromFileAsync<string>(
GlobalVar.CANCEL_ALL_ORDERS_FILE_LOCATION,
args: new object[] { salt, timestamp, privateKey, chainId }
);
return result;
}
Expand Down
79 changes: 79 additions & 0 deletions src/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using Nethereum.Hex.HexConvertors.Extensions;
using System.Numerics;
using Nethereum.Signer;
using Newtonsoft.Json;

namespace SigningExampleNethereum
{
class Program
{
static async Task Main(string[] args)
{
var privateKey = Environment.GetEnvironmentVariable("PRIVATE_KEY_NO_PREFIX");
if (privateKey == null)
{
throw new Exception("PRIVATE_KEY_NO_PREFIX is not defined");
}
var chainIdRaw = Environment.GetEnvironmentVariable("CHAIN_ID");
if (chainIdRaw == null) {
throw new Exception("CHAIN_ID is not defined");
}
var chainId = Int32.Parse(chainIdRaw);

EthECKey wallet = new EthECKey(privateKey);
Console.WriteLine("Wallet address: " + wallet.GetPublicAddress());


// var order = new Order
// {
// marketHash = "0x88c43af903e373ec2b2717813f6c42188aeb2d818a56eda46b6d63a08ad1e406",
// baseToken = "0x5147891461a7C81075950f8eE6384e019e39ab98",
// totalBetSize = BigInteger.Parse("100000000"),
// percentageOdds = BigInteger.Parse("50000000000000000000"),
// maker = wallet.GetPublicAddress(),
// executor = "0x3259E7Ccc0993368fCB82689F5C534669A0C06ca",
// isMakerBettingOutcomeOne = true,
// apiExpiry = DateTimeOffset.Now.AddSeconds(1000).ToUnixTimeSeconds(),
// salt = Order.Random32Bytes()
// };

// Console.WriteLine("Order hash: " + order.GetHash().ToHex(true));
// Console.WriteLine("Order signature: " + order.GetSignature(privateKey));

// var api = new SXBetApi { url = "http://localhost:8080" };
// var newOrderResult = await api.PostNewOrder(order.GetSignedOrder(privateKey));
// Console.WriteLine("New order result: " + newOrderResult);

// var deserialized = JsonConvert.DeserializeAnonymousType(
// newOrderResult,
// new { status = default(string), data = new { orders = default(string[]) } }
// );
// Console.WriteLine("Deserialized new order result: " + deserialized);

// var ordersList = new List<string>(deserialized.data.orders);

// var cancelSignature = CancelOrdersV1.GetCancelOrdersEIP712Payload(ordersList, chainId, wallet);

// Console.WriteLine("Cancel signature: " + cancelSignature);

// var cancelOrderResult = await api.CancelOrder(
// deserialized.data.orders,
// CancelOrdersV1.PROMPT,
// cancelSignature
// );
// Console.WriteLine("Cancel API call result: " + cancelOrderResult);

var salt = Utilities.Random32Bytes();

var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();

var cancelAllOrdersSignature = CancelAllOrders.GetCancelAllOrdersEIP712Payload(chainId, timestamp, wallet, salt);
var jsCancelAllOrdersSignature = await Order.GetCancelAllSignature(salt.ToHex(), timestamp.ToString(), wallet.GetPrivateKey(), chainId);
Console.WriteLine("Cancel all orders signature (c#): " + cancelAllOrdersSignature);
Console.WriteLine("Cancel all orders signature (js): " + jsCancelAllOrdersSignature);

// var cancelAllOrdersResult = await api.CancelAllOrders(cancelAllOrdersSignature, salt.ToString(), wallet.GetPublicAddress(), timestamp);
// Console.WriteLine("Cancel all API call result: " + cancelAllOrdersResult);
}
}
}
29 changes: 27 additions & 2 deletions SportXAPI.cs → src/SXBetApi.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
using Newtonsoft.Json;
using System.Text;
using System.Numerics;

namespace NethereumSample
namespace SigningExampleNethereum
{
class SportXAPI
class SXBetApi
{
static readonly HttpClient client = new HttpClient();

Expand All @@ -29,6 +30,30 @@ public async Task<string> PostNewOrder(SignedOrder order)
}
}

public async Task<string> CancelAllOrders(
string signature,
string salt,
string maker,
BigInteger timestamp
)
{
var obj = new { signature, salt, maker, timestamp };
var serialized = JsonConvert.SerializeObject(obj);
var httpContent = new StringContent(serialized, Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync(
url + "/orders/cancel/all",
httpContent
);
if (response.Content != null)
{
return await response.Content.ReadAsStringAsync();
}
else
{
throw new Exception("Content is null");
}
}

public async Task<string> CancelOrder(
string[] orderHashes,
string message,
Expand Down
50 changes: 50 additions & 0 deletions src/SignatureGeneration/CancelAllOrders.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using Nethereum.Signer.EIP712;
using Nethereum.ABI.FunctionEncoding.Attributes;
using Nethereum.Signer;
using Nethereum.ABI.EIP712;
using System.Numerics;

namespace SigningExampleNethereum
{
public static class CancelAllOrders
{

private static readonly Eip712TypedDataSigner _signer = new Eip712TypedDataSigner();

//Message types for easier input
private class Details
{
[Parameter("uint256", "timestamp", 1)]
public BigInteger Timestamp { get; set; }
}

//The generic Typed schema defintion for this message
private static TypedData<SaltDomain> getTypedDefinition(byte[] salt, BigInteger chainId)
{
return new TypedData<SaltDomain>
{
Domain = new SaltDomain
{
Name = "CancelAllOrdersSportX",
Version = "1.0",
ChainId = chainId,
Salt = salt
},
Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(SaltDomain), typeof(Details)),
PrimaryType = nameof(Details),
};
}

public static string GetCancelAllOrdersEIP712Payload(BigInteger chainId, BigInteger timestamp, EthECKey key, byte[] salt)
{
var typedData = getTypedDefinition(salt, chainId);

var details = new Details
{
Timestamp = timestamp
};

return _signer.SignTypedDataV4(details, typedData, key);
}
}
}
Loading