diff --git a/neurons/miner.py b/neurons/miner.py index 64b3a05..c8c81aa 100644 --- a/neurons/miner.py +++ b/neurons/miner.py @@ -21,6 +21,8 @@ import typing import asyncio import bittensor as bt +import logging +logging.getLogger("bittensor").propagate = False # Bittensor Miner tensorusd: import tensorusd diff --git a/refund.py b/refund.py new file mode 100644 index 0000000..31d7915 --- /dev/null +++ b/refund.py @@ -0,0 +1,114 @@ +""" +Check whether bids for a given auction ID have been refunded. + +COLDKEY_PASSWORD is read from .env automatically. + +Usage: + uv run refund.py \ + --netuid 421 \ + --subtensor.network test \ + --wallet.name test \ + --wallet.hotkey default \ + --logging.info +""" + +import asyncio +import argparse +import os + +import bittensor as bt +from dotenv import load_dotenv +import logging +logging.getLogger("bittensor").propagate = False + +from tensorusd.auction.types import AuctionEvent, AuctionEventType +from tensorusd.auction.contract import TensorUSDAuctionContract, create_substrate_interface +from tensorusd.miner.auction_manager import MinerAuctionManager + +load_dotenv() + +# Hardcode the auction ID to check +AUCTION_ID = 9 + + +def build_config() -> bt.Config: + parser = argparse.ArgumentParser(description="Check auction bid refund status") + bt.Wallet.add_args(parser) + bt.Subtensor.add_args(parser) + bt.logging.add_args(parser) + + parser.add_argument( + "--auction_contract.address", + type=str, + default=os.getenv("AUCTION_CONTRACT_ADDRESS"), + required=os.getenv("AUCTION_CONTRACT_ADDRESS") is None, + help="TensorUSD Auction contract address (SS58).", + ) + + return bt.Config(parser) + + +async def main(): + config = build_config() + bt.logging(config=config) + + # Unlock wallet — coldkey is the bidder, hotkey is the signing keypair + coldkey_password = os.getenv("COLDKEY_PASSWORD") + if not coldkey_password: + bt.logging.error("COLDKEY_PASSWORD not set in .env. Exiting.") + return + wallet = bt.Wallet(config=config) + wallet.coldkey_file.save_password_to_env(coldkey_password) + wallet.unlock_coldkey() + bt.logging.info(f"Wallet ready — coldkey: {wallet.coldkey.ss58_address}") + + # Connect to chain + subtensor = bt.Subtensor(config=config) + substrate = create_substrate_interface(subtensor.chain_endpoint) + + auction_contract = TensorUSDAuctionContract( + substrate=substrate, + contract_address=config.auction_contract.address, + metadata_path="tensorusd/abis/tusdt_auction.json", + wallet=wallet, + ) + + # Pre-checks: auction must exist and be finalized before doing anything + bt.logging.info(f"Fetching auction {AUCTION_ID} from chain ...") + auction = auction_contract.get_auction(AUCTION_ID) + + if auction is None: + bt.logging.error(f"Auction {AUCTION_ID} not found on chain. Exiting.") + return + + if not auction.is_finalized: + bt.logging.warning( + f"Auction {AUCTION_ID} is not finalized yet. " + f"highest_bid={auction.highest_bid}, " + f"highest_bidder={auction.highest_bidder}. Exiting." + ) + return + + # vault_contract/strategy/tusdt not needed for handle_auction_finalized + manager = MinerAuctionManager( + auction_contract=auction_contract, + vault_contract=None, + strategy=None, + wallet=wallet, + ) + + # Build event using real on-chain winner data + event = AuctionEvent( + event_type=AuctionEventType.FINALIZED, + block_number=0, + auction_id=AUCTION_ID, + winner=auction.highest_bidder, + highest_bid=auction.highest_bid, + ) + + bt.logging.info(f"Checking refund status for auction_id={AUCTION_ID} ...") + await manager.handle_auction_finalized(event) + + +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file diff --git a/tensorusd/abis/tusdt_auction.json b/tensorusd/abis/tusdt_auction.json index cbb09d0..f01b194 100644 --- a/tensorusd/abis/tusdt_auction.json +++ b/tensorusd/abis/tusdt_auction.json @@ -1,6 +1,6 @@ { "source": { - "hash": "0xbc85bef428ab060dc2d806901d10400e7c59f69fc2df46a014e801614e71587e", + "hash": "0x1fc0856fb4bdf701e67c80582d75d440bc6aa99336809c79382865f70f24fc9f", "language": "ink! 5.1.1", "compiler": "rustc 1.93.0", "build_info": { @@ -34,6 +34,15 @@ "type": 0 } }, + { + "label": "admin", + "type": { + "displayName": [ + "AccountId" + ], + "type": 0 + } + }, { "label": "token_address", "type": { @@ -45,7 +54,9 @@ } ], "default": false, - "docs": [], + "docs": [ + "Initializes the auction contract with owner, admin, and token contract reference." + ], "label": "new", "payable": false, "returnType": { @@ -53,7 +64,7 @@ "ink_primitives", "ConstructorResult" ], - "type": 34 + "type": 38 }, "selector": "0x9bae9d5e" } @@ -82,13 +93,13 @@ "displayName": [ "ChainExtension" ], - "type": 56 + "type": 60 }, "hash": { "displayName": [ "Hash" ], - "type": 55 + "type": 59 }, "maxEventTopics": 4, "staticBufferSize": 16384, @@ -264,9 +275,9 @@ "label": "winner", "type": { "displayName": [ - "Option" + "AccountId" ], - "type": 8 + "type": 0 } }, { @@ -279,12 +290,34 @@ ], "type": 4 } + }, + { + "docs": [], + "indexed": false, + "label": "debt_balance", + "type": { + "displayName": [ + "Balance" + ], + "type": 4 + } + }, + { + "docs": [], + "indexed": false, + "label": "highest_bid_metadata", + "type": { + "displayName": [ + "Option" + ], + "type": 17 + } } ], "docs": [], "label": "AuctionFinalized", "module_path": "tusdt_auction::auction", - "signature_topic": "0xecb6c55d94a9aac8b4e207a8cb763f4460b8e570530c936dff17a77a009fb26e" + "signature_topic": "0x2bb1b99d11a544c4702e6bb53e1eaea4a6f257ac8d2e41b9c747027662fadd53" }, { "args": [ @@ -374,7 +407,7 @@ "ink", "LangError" ], - "type": 35 + "type": 39 }, "messages": [ { @@ -421,12 +454,14 @@ "displayName": [ "Option" ], - "type": 36 + "type": 40 } } ], "default": false, - "docs": [], + "docs": [ + " Creates a new liquidation auction for a vault with specified collateral and debt, returning the auction ID." + ], "label": "create_auction", "mutates": true, "payable": false, @@ -435,7 +470,7 @@ "ink", "MessageResult" ], - "type": 37 + "type": 41 }, "selector": "0xd6cd59d7" }, @@ -470,7 +505,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Places a bid on an auction, transferring the bid amount and updating the highest bid if applicable." + ], "label": "place_bid", "mutates": true, "payable": false, @@ -479,7 +516,7 @@ "ink", "MessageResult" ], - "type": 37 + "type": 41 }, "selector": "0x441cccf2" }, @@ -496,7 +533,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Finalizes an auction after it has ended, marking the highest bidder as winner." + ], "label": "finalize_auction", "mutates": true, "payable": false, @@ -505,7 +544,7 @@ "ink", "MessageResult" ], - "type": 40 + "type": 44 }, "selector": "0x28dd27b4" }, @@ -531,7 +570,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Withdraws refund for a losing bid after the auction is finalized." + ], "label": "withdraw_refund", "mutates": true, "payable": false, @@ -540,7 +581,7 @@ "ink", "MessageResult" ], - "type": 40 + "type": 44 }, "selector": "0xb98ba333" }, @@ -557,7 +598,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Retrieves the details of an auction by its ID." + ], "label": "get_auction", "mutates": false, "payable": false, @@ -566,7 +609,7 @@ "ink", "MessageResult" ], - "type": 42 + "type": 46 }, "selector": "0x15a41cb5" }, @@ -592,7 +635,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Returns the active auction ID for a vault, or None if no active auction exists." + ], "label": "get_active_vault_auction", "mutates": false, "payable": false, @@ -601,7 +646,7 @@ "ink", "MessageResult" ], - "type": 44 + "type": 48 }, "selector": "0x9b023efc" }, @@ -627,7 +672,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Retrieves a specific bid from an auction by auction ID and bid ID." + ], "label": "get_bid", "mutates": false, "payable": false, @@ -636,10 +683,47 @@ "ink", "MessageResult" ], - "type": 45 + "type": 49 }, "selector": "0xdc2d27f1" }, + { + "args": [ + { + "label": "auction_id", + "type": { + "displayName": [ + "u32" + ], + "type": 3 + } + }, + { + "label": "bidder", + "type": { + "displayName": [ + "AccountId" + ], + "type": 0 + } + } + ], + "default": false, + "docs": [ + " Retrieves a specific bid from an auction by auction ID and Bidder." + ], + "label": "get_auction_bid", + "mutates": false, + "payable": false, + "returnType": { + "displayName": [ + "ink", + "MessageResult" + ], + "type": 49 + }, + "selector": "0xa594e324" + }, { "args": [ { @@ -662,7 +746,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Returns a paginated list of all bids placed on an auction." + ], "label": "get_bids", "mutates": false, "payable": false, @@ -671,14 +757,16 @@ "ink", "MessageResult" ], - "type": 47 + "type": 51 }, "selector": "0x03302346" }, { "args": [], "default": false, - "docs": [], + "docs": [ + " Returns the total number of auctions created." + ], "label": "get_total_auctions_count", "mutates": false, "payable": false, @@ -687,14 +775,16 @@ "ink", "MessageResult" ], - "type": 50 + "type": 54 }, "selector": "0x2700a61f" }, { "args": [], "default": false, - "docs": [], + "docs": [ + " Returns the total number of active auctions." + ], "label": "get_active_auctions_count", "mutates": false, "payable": false, @@ -703,7 +793,7 @@ "ink", "MessageResult" ], - "type": 50 + "type": 54 }, "selector": "0x996f931c" }, @@ -720,7 +810,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Returns a paginated list of all auctions." + ], "label": "get_all_auctions", "mutates": false, "payable": false, @@ -729,7 +821,7 @@ "ink", "MessageResult" ], - "type": 51 + "type": 55 }, "selector": "0x95baa3db" }, @@ -746,7 +838,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Returns a paginated list of active auctions." + ], "label": "get_active_auctions", "mutates": false, "payable": false, @@ -755,14 +849,16 @@ "ink", "MessageResult" ], - "type": 51 + "type": 55 }, "selector": "0x038c0d69" }, { "args": [], "default": false, - "docs": [], + "docs": [ + " Returns the owner account ID." + ], "label": "owner", "mutates": false, "payable": false, @@ -771,9 +867,27 @@ "ink", "MessageResult" ], - "type": 54 + "type": 58 }, "selector": "0xfeaea4fa" + }, + { + "args": [], + "default": false, + "docs": [ + " Returns the admin account ID." + ], + "label": "admin", + "mutates": false, + "payable": false, + "returnType": { + "displayName": [ + "ink", + "MessageResult" + ], + "type": 58 + }, + "selector": "0x1aa66b39" } ] }, @@ -791,6 +905,15 @@ }, "name": "owner" }, + { + "layout": { + "leaf": { + "key": "0x00000000", + "ty": 0 + } + }, + "name": "admin" + }, { "layout": { "struct": { @@ -1093,6 +1216,21 @@ }, "name": "auction_bids" }, + { + "layout": { + "root": { + "layout": { + "leaf": { + "key": "0x68dcca1b", + "ty": 3 + } + }, + "root_key": "0x68dcca1b", + "ty": 21 + } + }, + "name": "auction_bidder_bids" + }, { "layout": { "root": { @@ -1103,7 +1241,7 @@ } }, "root_key": "0xafa18ddb", - "ty": 21 + "ty": 25 } }, "name": "active_vault_auction" @@ -1127,7 +1265,7 @@ } }, "root_key": "0xd9c4d144", - "ty": 25 + "ty": 29 } }, "name": "active_auctions" @@ -1142,7 +1280,7 @@ } }, "root_key": "0xf0e8b11f", - "ty": 28 + "ty": 32 } }, "name": "active_auction_indices" @@ -1152,7 +1290,7 @@ } }, "root_key": "0x00000000", - "ty": 31 + "ty": 35 } }, "types": [ @@ -1666,8 +1804,8 @@ "type": { "def": { "tuple": [ - 0, - 3 + 3, + 0 ] } } @@ -1723,7 +1861,7 @@ "params": [ { "name": "K", - "type": 3 + "type": 26 }, { "name": "V", @@ -1731,7 +1869,7 @@ }, { "name": "KeyType", - "type": 26 + "type": 27 } ], "path": [ @@ -1744,6 +1882,17 @@ }, { "id": 26, + "type": { + "def": { + "tuple": [ + 0, + 3 + ] + } + } + }, + { + "id": 27, "type": { "def": { "composite": {} @@ -1755,7 +1904,7 @@ }, { "name": "R", - "type": 27 + "type": 28 } ], "path": [ @@ -1766,7 +1915,7 @@ } }, { - "id": 27, + "id": 28, "type": { "def": { "composite": {} @@ -1785,7 +1934,7 @@ } }, { - "id": 28, + "id": 29, "type": { "def": { "composite": {} @@ -1801,7 +1950,7 @@ }, { "name": "KeyType", - "type": 29 + "type": 30 } ], "path": [ @@ -1813,7 +1962,7 @@ } }, { - "id": 29, + "id": 30, "type": { "def": { "composite": {} @@ -1825,7 +1974,7 @@ }, { "name": "R", - "type": 30 + "type": 31 } ], "path": [ @@ -1836,7 +1985,7 @@ } }, { - "id": 30, + "id": 31, "type": { "def": { "composite": {} @@ -1855,7 +2004,77 @@ } }, { - "id": 31, + "id": 32, + "type": { + "def": { + "composite": {} + }, + "params": [ + { + "name": "K", + "type": 3 + }, + { + "name": "V", + "type": 3 + }, + { + "name": "KeyType", + "type": 33 + } + ], + "path": [ + "ink_storage", + "lazy", + "mapping", + "Mapping" + ] + } + }, + { + "id": 33, + "type": { + "def": { + "composite": {} + }, + "params": [ + { + "name": "L", + "type": 11 + }, + { + "name": "R", + "type": 34 + } + ], + "path": [ + "ink_storage_traits", + "impls", + "ResolverKey" + ] + } + }, + { + "id": 34, + "type": { + "def": { + "composite": {} + }, + "params": [ + { + "name": "ParentKey", + "type": 13 + } + ], + "path": [ + "ink_storage_traits", + "impls", + "ManualKey" + ] + } + }, + { + "id": 35, "type": { "def": { "composite": { @@ -1865,9 +2084,14 @@ "type": 0, "typeName": ",>>::Type" }, + { + "name": "admin", + "type": 0, + "typeName": ",>>::Type" + }, { "name": "token", - "type": 32, + "type": 36, "typeName": ",>>::Type" }, { @@ -1886,8 +2110,13 @@ "typeName": " as::ink::storage::traits::\nAutoStorableHint<::ink::storage::traits::ManualKey<2050671336u32,\n()>,>>::Type" }, { - "name": "active_vault_auction", + "name": "auction_bidder_bids", "type": 21, + "typeName": " as::ink::storage::traits::\nAutoStorableHint<::ink::storage::traits::ManualKey<466279528u32, ()\n>,>>::Type" + }, + { + "name": "active_vault_auction", + "type": 25, "typeName": " as::ink::storage::traits::\nAutoStorableHint<::ink::storage::traits::ManualKey<3683492271u32,\n()>,>>::Type" }, { @@ -1897,12 +2126,12 @@ }, { "name": "active_auctions", - "type": 25, + "type": 29, "typeName": " as::ink::storage::traits::AutoStorableHint<::\nink::storage::traits::ManualKey<1154598105u32, ()>,>>::Type" }, { "name": "active_auction_indices", - "type": 28, + "type": 32, "typeName": " as::ink::storage::traits::AutoStorableHint<::\nink::storage::traits::ManualKey<531753200u32, ()>,>>::Type" } ] @@ -1916,14 +2145,14 @@ } }, { - "id": 32, + "id": 36, "type": { "def": { "composite": { "fields": [ { "name": "inner", - "type": 33, + "type": 37, "typeName": "::Type" } ] @@ -1937,7 +2166,7 @@ } }, { - "id": 33, + "id": 37, "type": { "def": { "composite": { @@ -1958,7 +2187,7 @@ } }, { - "id": 34, + "id": 38, "type": { "def": { "variant": { @@ -1975,7 +2204,7 @@ { "fields": [ { - "type": 35 + "type": 39 } ], "index": 1, @@ -1991,7 +2220,7 @@ }, { "name": "E", - "type": 35 + "type": 39 } ], "path": [ @@ -2000,7 +2229,7 @@ } }, { - "id": 35, + "id": 39, "type": { "def": { "variant": { @@ -2019,7 +2248,7 @@ } }, { - "id": 36, + "id": 40, "type": { "def": { "variant": { @@ -2052,7 +2281,7 @@ } }, { - "id": 37, + "id": 41, "type": { "def": { "variant": { @@ -2060,7 +2289,7 @@ { "fields": [ { - "type": 38 + "type": 42 } ], "index": 0, @@ -2069,7 +2298,7 @@ { "fields": [ { - "type": 35 + "type": 39 } ], "index": 1, @@ -2081,11 +2310,11 @@ "params": [ { "name": "T", - "type": 38 + "type": 42 }, { "name": "E", - "type": 35 + "type": 39 } ], "path": [ @@ -2094,7 +2323,7 @@ } }, { - "id": 38, + "id": 42, "type": { "def": { "variant": { @@ -2111,7 +2340,7 @@ { "fields": [ { - "type": 39 + "type": 43 } ], "index": 1, @@ -2127,7 +2356,7 @@ }, { "name": "E", - "type": 39 + "type": 43 } ], "path": [ @@ -2136,7 +2365,7 @@ } }, { - "id": 39, + "id": 43, "type": { "def": { "variant": { @@ -2147,58 +2376,66 @@ }, { "index": 1, - "name": "AuctionNotFound" + "name": "NotAdmin" }, { "index": 2, - "name": "BidNotFound" + "name": "AuctionNotFound" }, { "index": 3, - "name": "NotBidder" + "name": "BidNotFound" }, { "index": 4, - "name": "AuctionAlreadyExistsForVault" + "name": "NotBidder" }, { "index": 5, - "name": "BidBelowDebtBalance" + "name": "AuctionAlreadyExistsForVault" }, { "index": 6, - "name": "AuctionEnded" + "name": "BidBelowDebtBalance" }, { "index": 7, - "name": "AuctionNotEnded" + "name": "AuctionEnded" }, { "index": 8, - "name": "AuctionFinalized" + "name": "AuctionNotEnded" }, { "index": 9, - "name": "OutOfBoundPage" + "name": "AuctionFinalized" }, { "index": 10, - "name": "WinningBidLocked" + "name": "AuctionHasNoBids" }, { "index": 11, - "name": "InvalidDuration" + "name": "WinningBidLocked" }, { "index": 12, - "name": "TransferFailed" + "name": "InvalidDuration" }, { "index": 13, - "name": "NoRefundAvailable" + "name": "TransferFailed" }, { "index": 14, + "name": "NoRefundAvailable" + }, + { + "index": 15, + "name": "BidAmountNotIncreased" + }, + { + "index": 16, "name": "ArithmeticError" } ] @@ -2212,7 +2449,7 @@ } }, { - "id": 40, + "id": 44, "type": { "def": { "variant": { @@ -2220,7 +2457,7 @@ { "fields": [ { - "type": 41 + "type": 45 } ], "index": 0, @@ -2229,7 +2466,7 @@ { "fields": [ { - "type": 35 + "type": 39 } ], "index": 1, @@ -2241,11 +2478,11 @@ "params": [ { "name": "T", - "type": 41 + "type": 45 }, { "name": "E", - "type": 35 + "type": 39 } ], "path": [ @@ -2254,7 +2491,7 @@ } }, { - "id": 41, + "id": 45, "type": { "def": { "variant": { @@ -2271,7 +2508,7 @@ { "fields": [ { - "type": 39 + "type": 43 } ], "index": 1, @@ -2287,7 +2524,7 @@ }, { "name": "E", - "type": 39 + "type": 43 } ], "path": [ @@ -2296,7 +2533,7 @@ } }, { - "id": 42, + "id": 46, "type": { "def": { "variant": { @@ -2304,7 +2541,7 @@ { "fields": [ { - "type": 43 + "type": 47 } ], "index": 0, @@ -2313,7 +2550,7 @@ { "fields": [ { - "type": 35 + "type": 39 } ], "index": 1, @@ -2325,11 +2562,11 @@ "params": [ { "name": "T", - "type": 43 + "type": 47 }, { "name": "E", - "type": 35 + "type": 39 } ], "path": [ @@ -2338,7 +2575,7 @@ } }, { - "id": 43, + "id": 47, "type": { "def": { "variant": { @@ -2371,7 +2608,7 @@ } }, { - "id": 44, + "id": 48, "type": { "def": { "variant": { @@ -2388,7 +2625,7 @@ { "fields": [ { - "type": 35 + "type": 39 } ], "index": 1, @@ -2404,7 +2641,7 @@ }, { "name": "E", - "type": 35 + "type": 39 } ], "path": [ @@ -2413,7 +2650,7 @@ } }, { - "id": 45, + "id": 49, "type": { "def": { "variant": { @@ -2421,7 +2658,7 @@ { "fields": [ { - "type": 46 + "type": 50 } ], "index": 0, @@ -2430,7 +2667,7 @@ { "fields": [ { - "type": 35 + "type": 39 } ], "index": 1, @@ -2442,11 +2679,11 @@ "params": [ { "name": "T", - "type": 46 + "type": 50 }, { "name": "E", - "type": 35 + "type": 39 } ], "path": [ @@ -2455,7 +2692,7 @@ } }, { - "id": 46, + "id": 50, "type": { "def": { "variant": { @@ -2488,7 +2725,7 @@ } }, { - "id": 47, + "id": 51, "type": { "def": { "variant": { @@ -2496,7 +2733,7 @@ { "fields": [ { - "type": 48 + "type": 52 } ], "index": 0, @@ -2505,7 +2742,7 @@ { "fields": [ { - "type": 35 + "type": 39 } ], "index": 1, @@ -2517,11 +2754,11 @@ "params": [ { "name": "T", - "type": 48 + "type": 52 }, { "name": "E", - "type": 35 + "type": 39 } ], "path": [ @@ -2530,7 +2767,7 @@ } }, { - "id": 48, + "id": 52, "type": { "def": { "variant": { @@ -2538,7 +2775,7 @@ { "fields": [ { - "type": 49 + "type": 53 } ], "index": 0, @@ -2547,7 +2784,7 @@ { "fields": [ { - "type": 39 + "type": 43 } ], "index": 1, @@ -2559,11 +2796,11 @@ "params": [ { "name": "T", - "type": 49 + "type": 53 }, { "name": "E", - "type": 39 + "type": 43 } ], "path": [ @@ -2572,7 +2809,7 @@ } }, { - "id": 49, + "id": 53, "type": { "def": { "sequence": { @@ -2582,7 +2819,7 @@ } }, { - "id": 50, + "id": 54, "type": { "def": { "variant": { @@ -2599,7 +2836,7 @@ { "fields": [ { - "type": 35 + "type": 39 } ], "index": 1, @@ -2615,7 +2852,7 @@ }, { "name": "E", - "type": 35 + "type": 39 } ], "path": [ @@ -2624,7 +2861,7 @@ } }, { - "id": 51, + "id": 55, "type": { "def": { "variant": { @@ -2632,7 +2869,7 @@ { "fields": [ { - "type": 52 + "type": 56 } ], "index": 0, @@ -2641,7 +2878,7 @@ { "fields": [ { - "type": 35 + "type": 39 } ], "index": 1, @@ -2653,11 +2890,11 @@ "params": [ { "name": "T", - "type": 52 + "type": 56 }, { "name": "E", - "type": 35 + "type": 39 } ], "path": [ @@ -2666,7 +2903,7 @@ } }, { - "id": 52, + "id": 56, "type": { "def": { "variant": { @@ -2674,7 +2911,7 @@ { "fields": [ { - "type": 53 + "type": 57 } ], "index": 0, @@ -2683,7 +2920,7 @@ { "fields": [ { - "type": 39 + "type": 43 } ], "index": 1, @@ -2695,11 +2932,11 @@ "params": [ { "name": "T", - "type": 53 + "type": 57 }, { "name": "E", - "type": 39 + "type": 43 } ], "path": [ @@ -2708,7 +2945,7 @@ } }, { - "id": 53, + "id": 57, "type": { "def": { "sequence": { @@ -2718,7 +2955,7 @@ } }, { - "id": 54, + "id": 58, "type": { "def": { "variant": { @@ -2735,7 +2972,7 @@ { "fields": [ { - "type": 35 + "type": 39 } ], "index": 1, @@ -2751,7 +2988,7 @@ }, { "name": "E", - "type": 35 + "type": 39 } ], "path": [ @@ -2760,7 +2997,7 @@ } }, { - "id": 55, + "id": 59, "type": { "def": { "composite": { @@ -2780,7 +3017,7 @@ } }, { - "id": 56, + "id": 60, "type": { "def": { "variant": {} diff --git a/tensorusd/abis/tusdt_erc20.json b/tensorusd/abis/tusdt_erc20.json index d1bf793..a9a8c7a 100644 --- a/tensorusd/abis/tusdt_erc20.json +++ b/tensorusd/abis/tusdt_erc20.json @@ -1,6 +1,6 @@ { "source": { - "hash": "0xb1052e79867a05402777202989487461fbf05bd2ee5661727ca97ecd84fce37b", + "hash": "0xeead26f978b237d2ce4d3c7fa1016417651e247c87de79358080c426fe97a17a", "language": "ink! 5.1.1", "compiler": "rustc 1.93.0", "build_info": { @@ -36,7 +36,9 @@ } ], "default": false, - "docs": [], + "docs": [ + "Initializes the token contract with the specified owner account." + ], "label": "new", "payable": false, "returnType": { @@ -185,7 +187,9 @@ { "args": [], "default": false, - "docs": [], + "docs": [ + " Returns the owner account ID." + ], "label": "owner", "mutates": false, "payable": false, @@ -201,7 +205,9 @@ { "args": [], "default": false, - "docs": [], + "docs": [ + " Returns the total supply of tokens in circulation." + ], "label": "total_supply", "mutates": false, "payable": false, @@ -227,7 +233,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Returns the token balance of an account." + ], "label": "balance_of", "mutates": false, "payable": false, @@ -262,7 +270,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Returns the amount of tokens that a spender is allowed to transfer from an owner's account." + ], "label": "allowance", "mutates": false, "payable": false, @@ -297,7 +307,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Transfers tokens from the caller to a recipient account." + ], "label": "transfer", "mutates": true, "payable": false, @@ -332,7 +344,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Mints new tokens and adds them to an account's balance; only callable by owner." + ], "label": "mint", "mutates": true, "payable": false, @@ -367,7 +381,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Burns tokens from an account, reducing the total supply; only callable by owner." + ], "label": "burn", "mutates": true, "payable": false, @@ -402,7 +418,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Approves a spender to transfer up to a specified amount of tokens on behalf of the caller." + ], "label": "approve", "mutates": true, "payable": false, @@ -446,7 +464,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Transfers tokens on behalf of an owner account to a recipient, using the caller's allowance." + ], "label": "transfer_from", "mutates": true, "payable": false, diff --git a/tensorusd/abis/tusdt_vault.json b/tensorusd/abis/tusdt_vault.json index ef33a66..5f04e9e 100644 --- a/tensorusd/abis/tusdt_vault.json +++ b/tensorusd/abis/tusdt_vault.json @@ -1,6 +1,6 @@ { "source": { - "hash": "0xba36e326c46f9966fedd54cc4bedd8eb52ef09fbc4f5f209013f9ab33c1e08d3", + "hash": "0xf3a92706983fc3140d7172999a5ce93b37fa65c9ef71fef9022128336a1a849f", "language": "ink! 5.1.1", "compiler": "rustc 1.93.0", "build_info": { @@ -45,7 +45,9 @@ } ], "default": false, - "docs": [], + "docs": [ + "Initializes the vault contract by instantiating the token and auction contracts with the provided code hashes." + ], "label": "new", "payable": false, "returnType": { @@ -82,7 +84,7 @@ "displayName": [ "ChainExtension" ], - "type": 56 + "type": 58 }, "hash": { "displayName": [ @@ -264,9 +266,9 @@ "label": "winner", "type": { "displayName": [ - "Option" + "AccountId" ], - "type": 55 + "type": 0 } }, { @@ -279,12 +281,34 @@ ], "type": 3 } + }, + { + "docs": [], + "indexed": false, + "label": "debt_balance", + "type": { + "displayName": [ + "Balance" + ], + "type": 3 + } + }, + { + "docs": [], + "indexed": false, + "label": "highest_bid_metadata", + "type": { + "displayName": [ + "Option" + ], + "type": 55 + } } ], "docs": [], "label": "AuctionFinalized", "module_path": "tusdt_auction::auction", - "signature_topic": "0xecb6c55d94a9aac8b4e207a8cb763f4460b8e570530c936dff17a77a009fb26e" + "signature_topic": "0x2bb1b99d11a544c4702e6bb53e1eaea4a6f257ac8d2e41b9c747027662fadd53" }, { "args": [ @@ -337,7 +361,7 @@ "displayName": [ "Option" ], - "type": 55 + "type": 57 } }, { @@ -348,7 +372,7 @@ "displayName": [ "Option" ], - "type": 55 + "type": 57 } }, { @@ -616,7 +640,7 @@ "displayName": [ "Option" ], - "type": 55 + "type": 57 } }, { @@ -740,7 +764,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Updates contract parameters (collateral ratio, liquidation ratio, interest rate, etc.) with validation; only callable by owner." + ], "label": "set_contract_params", "mutates": true, "payable": false, @@ -756,7 +782,9 @@ { "args": [], "default": false, - "docs": [], + "docs": [ + " Creates a new vault for the caller with the transferred collateral and returns the vault ID." + ], "label": "create_vault", "mutates": true, "payable": true, @@ -782,7 +810,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Adds the transferred collateral amount to an existing vault." + ], "label": "add_collateral", "mutates": true, "payable": true, @@ -817,7 +847,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Borrows tokens against the vault's collateral, validating collateral ratio and accruing interest." + ], "label": "borrow_token", "mutates": true, "payable": false, @@ -852,7 +884,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Repays borrowed tokens from a vault, accruing interest and burning the repaid tokens." + ], "label": "repay_token", "mutates": true, "payable": false, @@ -887,7 +921,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Releases collateral from a vault while ensuring the remaining collateral maintains the minimum collateral ratio." + ], "label": "release_collateral", "mutates": true, "payable": false, @@ -922,7 +958,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Initiates a liquidation auction for an unsafe vault, returning the auction ID if successful." + ], "label": "trigger_liquidation_auction", "mutates": true, "payable": false, @@ -957,7 +995,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Settles a finalized liquidation auction, transferring collateral to the winner and clearing vault debt." + ], "label": "settle_liquidation_auction", "mutates": true, "payable": false, @@ -992,7 +1032,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Retrieves the vault details for a given owner and vault ID." + ], "label": "get_vault", "mutates": false, "payable": false, @@ -1008,7 +1050,9 @@ { "args": [], "default": false, - "docs": [], + "docs": [ + " Returns the account ID of the deployed ERC-20 token contract." + ], "label": "get_token_address", "mutates": false, "payable": false, @@ -1024,7 +1068,9 @@ { "args": [], "default": false, - "docs": [], + "docs": [ + " Returns the account ID of the deployed auction contract." + ], "label": "get_auction_address", "mutates": false, "payable": false, @@ -1040,7 +1086,9 @@ { "args": [], "default": false, - "docs": [], + "docs": [ + " Returns the current contract parameters (collateral ratio, liquidation ratio, interest rate, etc.) as percentages." + ], "label": "get_contract_params", "mutates": false, "payable": false, @@ -1066,7 +1114,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Sets the collateral-to-token price ratio for testing purposes; only callable by owner." + ], "label": "set_collateral_token_price_for_testing", "mutates": true, "payable": false, @@ -1082,7 +1132,9 @@ { "args": [], "default": false, - "docs": [], + "docs": [ + " Returns the current collateral-to-token price ratio used for calculations." + ], "label": "get_collateral_token_price_for_testing", "mutates": false, "payable": false, @@ -1117,7 +1169,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Returns the collateral balance for a vault, or None if the vault does not exist." + ], "label": "get_vault_collateral_balance", "mutates": false, "payable": false, @@ -1133,7 +1187,9 @@ { "args": [], "default": false, - "docs": [], + "docs": [ + " Returns the total collateral balance across all vaults." + ], "label": "get_total_collateral_balance", "mutates": false, "payable": false, @@ -1168,7 +1224,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Calculates the token value of a vault's collateral based on the current price ratio." + ], "label": "get_vault_collateral_value", "mutates": false, "payable": false, @@ -1203,7 +1261,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Returns the maximum token amount that can be borrowed against a vault's collateral." + ], "label": "get_max_borrow", "mutates": false, "payable": false, @@ -1238,7 +1298,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Returns the auction ID for an active liquidation of a vault, or None if there is no active liquidation." + ], "label": "get_liquidation_auction_id", "mutates": false, "payable": false, @@ -1254,7 +1316,9 @@ { "args": [], "default": false, - "docs": [], + "docs": [ + " Returns the total number of vaults created across all owners." + ], "label": "get_total_vaults_count", "mutates": false, "payable": false, @@ -1280,7 +1344,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Returns the number of vaults owned by a specific account." + ], "label": "get_vaults_count", "mutates": false, "payable": false, @@ -1315,7 +1381,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Returns a paginated list of vaults owned by a specific account." + ], "label": "get_vaults", "mutates": false, "payable": false, @@ -1341,7 +1409,9 @@ } ], "default": false, - "docs": [], + "docs": [ + " Returns a paginated list of all vaults across all owners." + ], "label": "get_all_vaults", "mutates": false, "payable": false, @@ -2609,58 +2679,54 @@ }, { "index": 5, - "name": "OutOfBoundPage" - }, - { - "index": 6, "name": "InvalidRatio" }, { - "index": 7, + "index": 6, "name": "InvalidAuctionDuration" }, { - "index": 8, + "index": 7, "name": "CollateralRatioExceeded" }, { - "index": 9, + "index": 8, "name": "LiquidationRatioExceeded" }, { - "index": 10, + "index": 9, "name": "RepayAmountTooHigh" }, { - "index": 11, + "index": 10, "name": "VaultInLiquidation" }, { - "index": 12, + "index": 11, "name": "NotLiquidatable" }, { - "index": 13, + "index": 12, "name": "LiquidationAuctionExists" }, { - "index": 14, + "index": 13, "name": "AuctionContractCallFailed" }, { - "index": 15, + "index": 14, "name": "AuctionNotFound" }, { - "index": 16, + "index": 15, "name": "AuctionNotFinalized" }, { - "index": 17, + "index": 16, "name": "ArithmeticError" }, { - "index": 18, + "index": 17, "name": "NotContractOwner" } ] @@ -3330,6 +3396,60 @@ }, { "id": 55, + "type": { + "def": { + "variant": { + "variants": [ + { + "index": 0, + "name": "None" + }, + { + "fields": [ + { + "type": 56 + } + ], + "index": 1, + "name": "Some" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 56 + } + ], + "path": [ + "Option" + ] + } + }, + { + "id": 56, + "type": { + "def": { + "composite": { + "fields": [ + { + "name": "hot_key", + "type": 0, + "typeName": "AccountId" + } + ] + } + }, + "path": [ + "tusdt_auction", + "auction", + "BidMetadata" + ] + } + }, + { + "id": 57, "type": { "def": { "variant": { @@ -3362,7 +3482,7 @@ } }, { - "id": 56, + "id": 58, "type": { "def": { "variant": {} diff --git a/tensorusd/auction/contract.py b/tensorusd/auction/contract.py index ffd4507..bf8f26a 100644 --- a/tensorusd/auction/contract.py +++ b/tensorusd/auction/contract.py @@ -395,6 +395,22 @@ def get_active_auctions_count(self) -> int: except Exception as e: bt.logging.error(f"Error getting active auctions count: {e}") return 0 + + def _get_bid_count(self, auction_id: int) -> int: + """Get count of bids.""" + try: + result = self.contract.read( + keypair=self.wallet.hotkey, + method="get_all_auctions", + args={"auction_id": auction_id} + ) + data = result.contract_result_data.value_object + if data and data[0] == "Ok": + return data[1]['bid_count'] + return 0 + except Exception as e: + bt.logging.error(f"Error getting bid count: {e}") + return 0 def get_current_block(self) -> int: return self.substrate.get_block_number(None) @@ -412,6 +428,124 @@ def get_current_timestamp(self) -> int: except Exception as e: bt.logging.error(f"Error getting blockchain timestamp: {e}") return 0 + + def withdraw_refund( + self, + auction_id: int, + bid_id: int + ) -> Optional[str]: + """ + Withdraw a refund for a bid on a liquidation auction. + + Args: + auction_id: Auction ID to withdraw refund from (u32) + bid_id: Bid ID to withdraw refund for (u32) + keypair: Keypair to sign the transaction + + Returns: + Transaction hash if successful, None otherwise + """ + + bt.logging.info("Refunding your latest bid from contract") + + try: + args = { + "auction_id": auction_id, + "bid_id": bid_id, + } + + gas_predict_result = self.contract.read( + keypair=self.wallet.coldkey, + method="withdraw_refund", + args=args, + ) + + bt.logging.info( + f"Submitting withdraw_refund tx: auction_id={auction_id}, bid_id={bid_id}" + ) + receipt = self.contract.exec( + keypair=self.wallet.coldkey, + method="withdraw_refund", + args=args, + gas_limit=gas_predict_result.gas_required, + ) + + if receipt.is_success: + bt.logging.info( + f"Refund withdrawn: auction={auction_id}, bid_id={bid_id}, " + f"tx={receipt.extrinsic_hash}" + ) + return receipt.extrinsic_hash + else: + bt.logging.error(f"Refund withdrawal failed: {receipt.error_message}") + return None + + except Exception as e: + bt.logging.error(f"Error withdrawing refund: {e}") + return None + + def get_auction_bid( + self, + auction_id: int, + ) -> Optional[str]: + """ + Withdraw a refund for a bid on a liquidation auction. + + Args: + auction_id: Auction ID to withdraw refund from (u32) + bid_id: Bid ID to withdraw refund for (u32) + keypair: Keypair to sign the transaction + + Returns: + Transaction hash if successful, None otherwise + """ + my_address = self.wallet.coldkey.ss58_address + bt.logging.info( + f"Fetching bid info from contract: auction_id={auction_id}, bidder={my_address}" + ) + + try: + args = { + "auction_id": auction_id, + "bidder": my_address, + } + + result = self.contract.read( + keypair=self.wallet.hotkey, + method="get_auction_bid", + args=args, + ) + + data = result.contract_result_data.value_object + + if data and data[0] == "Ok" and data[1]: + bid_id = data[1].value["id"] + amount = data[1].value["amount"] + withdrawn = data[1].value["is_withdrawn"] + + bt.logging.info( + f"Bid found: auction_id={auction_id}, bid_id={bid_id}, " + f"amount={amount}, is_withdrawn={withdrawn}" + ) + + if not withdrawn: + bt.logging.info( + f"Bid not yet refunded — initiating withdrawal: " + f"auction_id={auction_id}, bid_id={bid_id}" + ) + self.withdraw_refund(auction_id, bid_id) + else: + bt.logging.info( + f"Bid already withdrawn: auction_id={auction_id}, " + f"bid_id={bid_id}, amount={amount}" + ) + else: + bt.logging.info( + f"No bid found for auction_id={auction_id}, bidder={my_address}" + ) + + except Exception as e: + bt.logging.error(f"Error fetching auction bid: {e}") def get_active_auctions(self) -> List[ActiveAuction]: """ diff --git a/tensorusd/miner/auction_manager.py b/tensorusd/miner/auction_manager.py index d7ec36f..dee7d14 100644 --- a/tensorusd/miner/auction_manager.py +++ b/tensorusd/miner/auction_manager.py @@ -193,6 +193,7 @@ async def handle_auction_finalized(self, event: AuctionEvent): f"winner={event.winner}, " f"winning_bid={event.highest_bid}" ) + self.auction_contract.get_auction_bid(auction_id) async def _submit_bid(self, auction_id: int, bid_amount: int) -> Optional[str]: """