Baseline: Ausgangszustand vor Modularisierung

Erster Commit des bestehenden monolithischen WinForms-Copytraders,
inklusive der Alt-Backups (*.bak), damit diese dauerhaft in der
Historie rekonstruierbar bleiben. Threema-Lib unter libs/ wurde
vendored (nested .git entfernt).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
bergm
2026-07-01 13:16:16 +02:00
co-authored by Claude Opus 4.8
commit 475d396f80
147 changed files with 25455 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
$PSWindow = (Get-Host).UI.RawUI
$NewSize = New-Object System.Management.Automation.Host.Size(4000, 3000)
$PSWindow.BufferSize = $NewSize
$PSWindow.WindowSize = New-Object System.Management.Automation.Host.Size(120, 50)
dotnet build -clp:ErrorsOnly
+14
View File
@@ -0,0 +1,14 @@
using LiteDB;
using System.Linq;
using (var db = new LiteDatabase(@"j:\Softwareprojekte\PolytraderSharp\PolyTraderSharp\bin\Debug\net8.0-windows7.0\polytrader_data.db"))
{
var accounts = db.GetCollection("accounts").FindAll().ToList();
foreach(var acc in accounts)
{
var id = acc["_id"].AsInt32;
var name = acc["Name"].AsString;
var active = acc["IsActive"].AsBoolean;
Console.WriteLine($"ID: {id}, Name: {name}, Active: {active}");
}
}
+14
View File
@@ -0,0 +1,14 @@
using LiteDB;
using System.Linq;
using (var db = new LiteDatabase(@"j:\Softwareprojekte\PolytraderSharp\PolyTraderSharp\bin\Debug\net8.0-windows7.0\data.db"))
{
var accounts = db.GetCollection("accounts").FindAll().ToList();
foreach(var acc in accounts)
{
var id = acc["_id"].AsInt32;
var name = acc["Name"].AsString;
var active = acc["IsActive"].AsBoolean;
Console.WriteLine($"ID: {id}, Name: {name}, Active: {active}");
}
}
+8
View File
@@ -0,0 +1,8 @@
import sys
def check_enc(fpath):
with open(fpath, 'rb') as f:
head = f.read(4)
print("BOM bytes:", head.hex())
check_enc(sys.argv[1])
+257
View File
@@ -0,0 +1,257 @@
from typing import Any
from dataclasses import dataclass, asdict
from json import dumps
from typing import Literal, Optional
from py_order_utils.model import (
SignedOrder,
)
from .constants import ZERO_ADDRESS
class OrderType(enumerate):
GTC = "GTC"
FOK = "FOK"
GTD = "GTD"
FAK = "FAK"
@dataclass
class ApiCreds:
api_key: str
api_secret: str
api_passphrase: str
@dataclass
class ReadonlyApiKeyResponse:
api_key: str
@dataclass
class RequestArgs:
method: str
request_path: str
body: Any = None
serialized_body: Optional[str] = None
@dataclass
class BookParams:
token_id: str
side: str = ""
@dataclass
class OrderArgs:
token_id: str
"""
TokenID of the Conditional token asset being traded
"""
price: float
"""
Price used to create the order
"""
size: float
"""
Size in terms of the ConditionalToken
"""
side: str
"""
Side of the order
"""
fee_rate_bps: int = 0
"""
Fee rate, in basis points, charged to the order maker, charged on proceeds
"""
nonce: int = 0
"""
Nonce used for onchain cancellations
"""
expiration: int = 0
"""
Timestamp after which the order is expired.
"""
taker: str = ZERO_ADDRESS
"""
Address of the order taker. The zero address is used to indicate a public order
"""
@dataclass
class MarketOrderArgs:
token_id: str
"""
TokenID of the Conditional token asset being traded
"""
amount: float
"""
BUY orders: $$$ Amount to buy
SELL orders: Shares to sell
"""
side: str
"""
Side of the order
"""
price: float = 0
"""
Price used to create the order
"""
fee_rate_bps: int = 0
"""
Fee rate, in basis points, charged to the order maker, charged on proceeds
"""
nonce: int = 0
"""
Nonce used for onchain cancellations
"""
taker: str = ZERO_ADDRESS
"""
Address of the order taker. The zero address is used to indicate a public order
"""
order_type: OrderType = OrderType.FOK
@dataclass
class TradeParams:
id: str = None
maker_address: str = None
market: str = None
asset_id: str = None
before: int = None
after: int = None
@dataclass
class OpenOrderParams:
id: str = None
market: str = None
asset_id: str = None
@dataclass
class DropNotificationParams:
ids: list[str] = None
@dataclass
class OrderSummary:
price: str = None
size: str = None
@property
def __dict__(self):
return asdict(self)
@property
def json(self):
return dumps(self.__dict__)
@dataclass
class OrderBookSummary:
market: str = None
asset_id: str = None
timestamp: str = None
bids: list[OrderSummary] = None
asks: list[OrderSummary] = None
min_order_size: str = None
neg_risk: bool = None
tick_size: str = None
last_trade_price: str = None
hash: str = None
@property
def __dict__(self):
return asdict(self)
@property
def json(self):
return dumps(self.__dict__, separators=(",", ":"))
class AssetType(enumerate):
COLLATERAL = "COLLATERAL"
CONDITIONAL = "CONDITIONAL"
@dataclass
class BalanceAllowanceParams:
asset_type: AssetType = None
token_id: str = None
signature_type: int = -1
@dataclass
class OrderScoringParams:
orderId: str
@dataclass
class OrdersScoringParams:
orderIds: list[str]
TickSize = Literal["0.1", "0.01", "0.001", "0.0001"]
@dataclass
class CreateOrderOptions:
tick_size: TickSize
neg_risk: bool
@dataclass
class PartialCreateOrderOptions:
tick_size: Optional[TickSize] = None
neg_risk: Optional[bool] = None
@dataclass
class RoundConfig:
price: float
size: float
amount: float
@dataclass
class ContractConfig:
"""
Contract Configuration
"""
exchange: str
"""
The exchange contract responsible for matching orders
"""
collateral: str
"""
The ERC20 token used as collateral for the exchange's markets
"""
conditional_tokens: str
"""
The ERC1155 conditional tokens contract
"""
@dataclass
class PostOrdersArgs:
order: SignedOrder
orderType: OrderType = OrderType.GTC
postOnly: bool = False
+11
View File
@@ -0,0 +1,11 @@
import requests
import json
url = "https://polygon-rpc.com"
payload = {
"jsonrpc": "2.0",
"method": "eth_getTransactionReceipt",
"params": ["0x884bd63c71974579e525ad9af7a081ef7f81faeed980f7f46a7fbfd8ad7534eb"],
"id": 1
}
resp = requests.post(url, json=payload).json()
print(json.dumps(resp, indent=2))
+8
View File
@@ -0,0 +1,8 @@
import sys
with open("j:/Softwareprojekte/PolytraderSharp/PolyTraderSharp/services/PolymarketApiService.cs", "r", encoding="utf-8") as f:
lines = f.readlines()
with open("j:/Softwareprojekte/PolytraderSharp/PolyTraderSharp/services/PolymarketApiService.cs", "w", encoding="utf-8") as f:
for i, line in enumerate(lines):
if 649 <= i <= 843:
continue
f.write(line)
+14
View File
@@ -0,0 +1,14 @@
from pymongo import MongoClient
from bson.objectid import ObjectId
client = MongoClient('mongodb://localhost:27017/')
db = client['PolyTraderDB']
col = db['closed_trades']
deleted = 0
for doc in col.find({}):
if isinstance(doc['_id'], ObjectId):
col.delete_one({'_id': doc['_id']})
deleted += 1
print(f"Deleted {deleted} invalid ObjectId records from closed_trades.")
+2
View File
@@ -0,0 +1,2 @@
$response = Invoke-RestMethod -Uri "https://data-api.polymarket.com/activity?user=0xC5d563A36AE78145C45a50134d48A1215220f80a"
$response | ConvertTo-Json -Depth 10 > debug_activity.json
+2
View File
@@ -0,0 +1,2 @@
$response = Invoke-RestMethod -Uri "https://gamma-api.polymarket.com/events?slug=highest-temperature-in-seattle-on-march-4-2026-54-55f"
$response | ConvertTo-Json -Depth 5 > debug_event.json
+2
View File
@@ -0,0 +1,2 @@
$response = Invoke-RestMethod -Uri "https://data-api.polymarket.com/markets?asset_id=16390480740794212860585822641698670781065007954223853906471315387406983668414"
$response | ConvertTo-Json -Depth 5 > debug_market.json
+2
View File
@@ -0,0 +1,2 @@
$response = Invoke-RestMethod -Uri "https://data-api.polymarket.com/positions?user=0xC5d563A36AE78145C45a50134d48A1215220f80a"
$response | ConvertTo-Json -Depth 10 > debug_positions.json
+161
View File
@@ -0,0 +1,161 @@
import re
import sys
def patch_file(designer_file):
with open(designer_file, 'r', encoding='utf-8') as f:
content = f.read()
grids = {
"dgv_dashboard": [
("AccountId", "Account ID", False, False),
("IsDemo", "Is Demo", False, False),
("IsActive", "Is Active", False, False),
("AccountName", "Account", True, False),
("TotalBalance", "Total USD", True, False),
("AvailableBalance", "Available", True, False),
("PositionBalance", "Positions", True, False),
("OpenTradesCount", "Open", True, False),
("ClosedTrades24h", "Closed 24h", True, False),
("Pnl24h", "Pnl 24h", True, False),
("Winrate24h", "Winrate 24h", True, False),
("ClosedTrades7d", "Closed 7d", True, False),
("Pnl7d", "Pnl 7d", True, False),
("Winrate7d", "Winrate 7d", True, False)
],
"dgv_openTrades": [
("AccountName", "Account", True, False),
("SourceTraderName", "Copied From", True, True),
("MarketQuestion", "Market", True, True),
("MarketSlug", "Market Slug", False, False),
("Outcome", "Outcome", True, False),
("Side", "Side", True, False),
("EntryPrice", "Entry Price", True, False),
("Size", "Shares", True, False),
("AmountUsd", "Amount USD", True, False)
],
"dgv_closedTrades": [
("TradeId", "ID", False, False),
("AccountId", "Account ID", False, False),
("SourceTraderId", "SourceTraderId", False, False),
("IsDemo", "Is Demo", False, False),
("TokenId", "TokenId", False, False),
("MarketSlug", "Market Slug", False, False),
("MarketQuestion", "Market", True, True),
("Outcome", "Outcome", True, False),
("Side", "Side", True, False),
("EntryPrice", "Entry Price", True, False),
("ExitPrice", "Exit Price", True, False),
("Size", "Shares", True, False),
("RealizedPnl", "P&L", True, False),
("PnlPercent", "P&L %", True, False),
("TotalFees", "Fees", True, False),
("OpenedAt", "Opened At", True, False),
("ClosedAt", "Closed At", True, False),
("ExitReason", "Reason", True, False)
],
"dgv_masterTraders": [
("Id", "Id", False, False),
("WalletAddress", "Wallet", True, False),
("DisplayName", "Name", True, False),
("Category", "Category", True, False),
("Description", "Description", True, False),
("Reasoning", "Reasoning", True, False),
("IsActive", "Is Active", True, False),
("IsHidden", "Is Hidden", True, False),
("TotalTrades", "Trades", True, False),
("WinningTrades", "Wins", True, False),
("Winrate30t", "Winrate 30t", True, False),
("TotalPnl", "Total P&L", True, False)
],
"dgv_SlaveTraders": [
("AccountId", "ID", False, False),
("Name", "Name", True, False),
("WalletAddress", "Wallet", True, False),
("IsDemo", "Is Demo", True, False),
("IsActive", "Is Active", True, False),
("CloseOnlyMode", "Close Only", True, False),
("PayoutAddress", "Payout Address", True, False),
("PayoutLimitUsd", "Payout Limit", True, False),
("PerMarketLimit", "Max %", True, False),
("MaxPriceDifference", "Max Price Diff", True, False),
("MaxBuyPrice", "Max Buy Price", True, False),
("ProfitTarget", "Profit Target", True, False),
("LimitUnder6h", "< 6h", True, False),
("LimitUnder24h", "< 24h", True, False),
("LimitUnder72h", "< 72h", True, False),
("LimitOver72h", "> 72h", True, False)
]
}
declarations = []
instantiations = []
setups = []
for dgv_name, cols in grids.items():
if f"{dgv_name}.Columns.AddRange" in content:
print(f"{dgv_name} already patched.")
continue
col_refs = []
for prop, header, visible, is_link in cols:
col_type = "DataGridViewLinkColumn" if is_link else "DataGridViewTextBoxColumn"
col_name = f"col_{dgv_name}_{prop}"
col_refs.append(f"{col_name}")
declarations.append(f"private {col_type} {col_name};")
instantiations.append(f"{col_name} = new {col_type}();")
setup = f"""//
// {col_name}
//
{col_name}.DataPropertyName = "{prop}";
{col_name}.HeaderText = "{header}";
{col_name}.Name = "{col_name}";
{col_name}.ReadOnly = true;
"""
if not visible:
setup += f"{col_name}.Visible = false;\n"
if is_link:
setup += f"{col_name}.ActiveLinkColor = Color.White;\n"
setup += f"{col_name}.LinkBehavior = LinkBehavior.SystemDefault;\n"
setup += f"{col_name}.LinkColor = Color.Blue;\n"
setup += f"{col_name}.TrackVisitedState = true;\n"
setup += f"{col_name}.VisitedLinkColor = Color.Purple;\n"
setups.append(setup)
add_range_code = f"{dgv_name}.Columns.AddRange(new DataGridViewColumn[] {{ " + ", ".join(col_refs) + " });\n"
# find `dgv_name.Name = "..."`
pattern = f'({dgv_name}\\.Name = "{dgv_name}";)'
content, n = re.subn(pattern, r'\1\n ' + add_range_code.replace('\n', '\n '), content)
if n == 0:
print(f"FAILED to find {pattern}")
if not declarations:
print("No grids to patch or already patched.")
return
# Declarations
bottom_pattern = r'(private DataGridView dgv_dashboard;)'
decl_str = "\n ".join(declarations) + "\n "
content, n = re.subn(bottom_pattern, decl_str + r'\1', content)
# Instantiations
top_pattern = r'(dgv_dashboard = new DataGridView\(\);)'
inst_str = "\n ".join(instantiations) + "\n "
content, n = re.subn(top_pattern, inst_str + r'\1', content)
# Setups
resume_pattern = r'(\(\(System\.ComponentModel\.ISupportInitialize\)dgv_dashboard\)\.EndInit\(\);)'
setup_str = "\n ".join("\n ".join(s.splitlines()) for s in setups) + "\n "
content, n = re.subn(resume_pattern, setup_str + r'\1', content)
with open(designer_file, 'w', encoding='utf-8') as f:
f.write(content)
print("Patched successfully.")
if __name__ == '__main__':
patch_file(sys.argv[1])
+6
View File
@@ -0,0 +1,6 @@
$json = Get-Content "debug_event.json" -Raw
$obj = ConvertFrom-Json $json
Write-Output "Event Closed: $($obj[0].closed)"
Write-Output "Event Active: $($obj[0].active)"
Write-Output "First Market Resolved: $($obj[0].markets[0].closed)"
Write-Output "First Market Winner: $($obj[0].markets[0].winner)"
+39
View File
@@ -0,0 +1,39 @@
import sys
import json
import logging
import os
# PolyTraderSharp - Auto-Redeem Stub
# Dieses Skript dient als Brücke zur Polymarket Relayer API, um gewonnene Tokens
# automatisiert (gasless) via On-Chain Meta-Transaktion auszulösen.
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
def redeem_tokens(token_ids, api_key, private_key, api_passphrase):
# WICHTIG: Die offizielle Automatisierung von "Redeems" ohne Gas-Gebühren
# erfordert Polymarkets py-builder-relayer-client SDK oder Relayer JWT Keys.
# Da das Gnosis Safe Proxy Wallet angesprochen werden muss, ist das klassische py_clob_client SDK dafür nicht ausgelegt.
# 1. Sammle Token IDs
tokens = [t.strip() for t in token_ids.split(",") if t.strip()]
logging.info(f"Redeem-Anforderung für Token erkannt: {tokens}")
logging.warning("HINWEIS: Ein vollautomatisierter On-Chain Redeem erfordert das 'builder-relayer-client-python' Package.")
logging.warning("Installiere es (sofern Polymarket es publiziert hat) oder nutze die Relayer REST-API direkt mit L2 Signaturen.")
logging.info("PolyTraderSharp hat die C#-seitige Accounting-Logik aktualisiert, sodass Gewinne/Verluste in deinem Interface nun sofort verbucht werden!")
# Placeholder für erfolgreiches Accounting
print(json.dumps({"status": "accounting_only", "redeemed_tokens": tokens}))
return
if __name__ == "__main__":
if len(sys.argv) < 5:
print("Usage: python redeem_markets.py <token_ids_comma_separated> <api_key> <private_key> <api_passphrase>")
sys.exit(1)
token_ids = sys.argv[1]
api_key = sys.argv[2]
private_key = sys.argv[3]
api_passphrase = sys.argv[4]
redeem_tokens(token_ids, api_key, private_key, api_passphrase)
+38
View File
@@ -0,0 +1,38 @@
import re
import sys
def revert_file(filepath):
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
# 1. Remove AddRange statements for our columns
# Example: dgv_dashboard.Columns.AddRange(new DataGridViewColumn[] { ... col_dgv_ ... });
pattern1 = r'\s*dgv_\w+\.Columns\.AddRange\(new DataGridViewColumn\[\] \{[^}]*col_dgv_[^}]*\}\);'
content = re.sub(pattern1, '', content, flags=re.MULTILINE)
# 2. Remove all lines referencing col_dgv_ (declarations, instantiations, property assignments)
# Be careful not to remove lines that just accidentally match. We'll match lines that start with whitespace and have col_dgv_
lines = content.splitlines()
new_lines = []
skip = False
for line in lines:
if "col_dgv_" in line:
continue
if line.strip() == "//" and new_lines and new_lines[-1].strip() == "//":
# Might be part of our property comment block // \n // col_name \n //
# Wait, easier to just strip empty trailing // later.
pass
new_lines.append(line)
content = "\n".join(new_lines)
# 3. Clean up empty comment blocks
content = re.sub(r'\s*// \s*\n\s*// \s*\n\s*// \s*\n', '\n', content)
with open(filepath, 'w', encoding='utf-8') as f:
f.write(content)
print("Reverted.")
if __name__ == '__main__':
revert_file(sys.argv[1])
+35
View File
@@ -0,0 +1,35 @@
import sys
import datetime
sys.path.append('J:\\Softwareprojekte\\Polytrader\\venv\\Lib\\site-packages')
from py_clob_client.signing.eip712 import get_clob_auth_domain, MSG_TO_SIGN
from py_clob_client.signing.model import ClobAuth
from eth_utils import keccak
domain = get_clob_auth_domain(137)
target_msg_hash = bytes.fromhex("68eff3a266838ca5dd9049f4dba0b95170871d2a1a16478443df0515e5c3f606")
# The timestamp of the log was 16:06:52. Let's guess unix time for 2026-03-26.
# Let's just brute force a wide range of timestamps.
# 2026-03-26 15:00:00 UTC is ~1774537200
base = 1774537200
found = False
for t in range(base - 10000, base + 10000):
clob_auth_msg = ClobAuth(
address="0x628914CF1e96A9D1Ab8F0489A9f64be5633bac41",
timestamp=str(t),
nonce=0,
message=MSG_TO_SIGN,
)
# The message hash is the keccak hash of the ABI encoded ClobAuth type struct.
# signable_bytes returns 1901 + domainHash + messageHash
signable = clob_auth_msg.signable_bytes(domain)
# the last 32 bytes is the message Hash
msg_hash = signable[34:]
if msg_hash == target_msg_hash:
print("MATCH FOUND FOR TIMESTAMP:", t)
found = True
break
if not found:
print("NO MATCH FOUND.")
+16
View File
@@ -0,0 +1,16 @@
import sys
import datetime
sys.path.append('J:\\Softwareprojekte\\Polytrader\\venv\\Lib\\site-packages')
from py_clob_client.signer import Signer
from py_clob_client.signing.eip712 import sign_clob_auth_message
signer = Signer("425454f8eef01dc6d4effeec1a9587f5969b53c18c7c9e621da73b9e80effd60", 137)
target_sig = "0x3c4f2c1cbede3e423c265a90cfc32e37c2336e95fc4aa92e82081c96bcf518295893c4e65f0c2ae6e414210815e37f40200a4b5cad0104c0f71de5551297fd5d1c"
sig = sign_clob_auth_message(signer, 1774537612, 0)
print("PYTHON SIG: " + sig)
print("CSHARP SIG: " + target_sig)
if sig == target_sig:
print("THEY ARE IDENTICAL!!")
else:
print("THE ECDSA OUTPUT DIFFERS!!")
+105
View File
@@ -0,0 +1,105 @@
// File: hash_test.csx
#r "nuget: Nethereum.Signer, 4.22.0"
#r "nuget: Nethereum.ABI, 4.22.0"
#r "nuget: Nethereum.Hex, 4.22.0"
using System;
using System.Numerics;
using Nethereum.Signer.EIP712;
using Nethereum.Signer;
using Nethereum.ABI.FunctionEncoding.Attributes;
[Struct("EIP712Domain")]
public class CtfDomain
{
[Parameter("string", "name", 1)]
public string Name { get; set; }
[Parameter("string", "version", 2)]
public string Version { get; set; }
[Parameter("uint256", "chainId", 3)]
public ulong ChainId { get; set; }
[Parameter("address", "verifyingContract", 4)]
public string VerifyingContract { get; set; }
}
[Struct("Order")]
public class CtfOrder
{
[Parameter("uint256", "salt", 1)]
public BigInteger Salt { get; set; }
[Parameter("address", "maker", 2)]
public string Maker { get; set; }
[Parameter("address", "signer", 3)]
public string Signer { get; set; }
[Parameter("address", "taker", 4)]
public string Taker { get; set; }
[Parameter("uint256", "tokenId", 5)]
public BigInteger TokenId { get; set; }
[Parameter("uint256", "makerAmount", 6)]
public BigInteger MakerAmount { get; set; }
[Parameter("uint256", "takerAmount", 7)]
public BigInteger TakerAmount { get; set; }
[Parameter("uint256", "expiration", 8)]
public BigInteger Expiration { get; set; }
[Parameter("uint256", "nonce", 9)]
public BigInteger Nonce { get; set; }
[Parameter("uint256", "feeRateBps", 10)]
public BigInteger FeeRateBps { get; set; }
[Parameter("uint8", "side", 11)]
public byte Side { get; set; }
[Parameter("uint8", "signatureType", 12)]
public byte SignatureType { get; set; }
}
var typedData = new TypedData<CtfDomain>
{
Domain = new CtfDomain
{
Name = "Polymarket CTF Exchange",
Version = "1",
ChainId = 137,
VerifyingContract = "0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E"
},
Types = Nethereum.ABI.EIP712.MemberDescriptionFactory.GetTypesMemberDescription(typeof(CtfDomain), typeof(CtfOrder)),
PrimaryType = "Order"
};
var ctfOrder = new CtfOrder
{
Salt = 17747015785747,
Maker = "0x628914cf1e96a9d1ab8f0489a9f64be5633bac41",
Signer = "0x883fe952a23bb68aab8832343d4bedde759b40ea",
Taker = "0x0000000000000000000000000000000000000000",
TokenId = BigInteger.Parse("54119275359569982132308633107899675342776540894581625713762792947175003762644"),
MakerAmount = 999180,
TakerAmount = 3660000,
Expiration = 0,
Nonce = 0,
FeeRateBps = 0,
Side = 0,
SignatureType = 0
};
string privKey = new string('1', 64);
var eip712TypedDataSigner = new Eip712TypedDataSigner();
var key = new EthECKey(privKey);
var hash = eip712TypedDataSigner.HashTypedDataV4(ctfOrder, typedData);
var sig = eip712TypedDataSigner.SignTypedDataV4(ctfOrder, typedData, key);
Console.WriteLine("CS_STRUCT_HASH|" + Nethereum.Hex.HexConvertors.Extensions.HexByteConvertorExtensions.ToHex(hash, true));
Console.WriteLine("CS_SIG|" + sig);
+39
View File
@@ -0,0 +1,39 @@
from eth_account import Account
import json
import os
import sys
sys.path.insert(0, "J:/Softwareprojekte/Polytrader/venv/Lib/site-packages")
from py_order_utils.builders.base_builder import BaseBuilder
from py_order_utils.model.order import OrderData
from py_order_utils.signer import Signer
order_json = '''{"salt":17747015785747,"maker":"0x628914cf1e96a9d1ab8f0489a9f64be5633bac41","signer":"0x883fe952a23bb68aab8832343d4bedde759b40ea","taker":"0x0000000000000000000000000000000000000000","tokenId":"54119275359569982132308633107899675342776540894581625713762792947175003762644","makerAmount":"999180","takerAmount":"3660000","expiration":"0","nonce":"0","feeRateBps":"0","side":"BUY","signatureType":0}'''
data = json.loads(order_json)
data["side"] = 0 if data["side"] == "BUY" else 1
priv_key = "0x" + "1"*64
signer = Signer(priv_key)
builder = BaseBuilder('0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E', 137, signer, lambda: 1)
from py_order_utils.model.order import Order
order = Order(
salt=int(data["salt"]),
maker=data["maker"],
signer=data["signer"],
taker=data["taker"],
tokenId=int(data["tokenId"]),
makerAmount=int(data["makerAmount"]),
takerAmount=int(data["takerAmount"]),
expiration=int(data["expiration"]),
nonce=int(data["nonce"]),
feeRateBps=int(data["feeRateBps"]),
side=int(data["side"]),
signatureType=int(data["signatureType"])
)
struct_hash = builder._create_struct_hash(order)
print("PYTHON_STRUCT_HASH|" + struct_hash)
print("PYTHON_SIG|" + signer.sign(struct_hash))