
    %iH                        U d Z ddlZddlZddlZddlmZmZmZmZm	Z	 da
dadadZ ej        d          ZdefdZd Zdd	Zd
edededefdZdedededededefdZdee         dz  fdZd
edefdZd
ededeeef         dz  fdZd
ededz  fdZg a ee         e!d<   da"ee!d<   ddee         dz  dee         fdZ#dS ) u*  
Turbo Relayer — submits transactions to Turbo.sol on Monad.

Handles:
  - createMarket() every 5 minutes
  - executeTrade() when orders match
  - resolve() after market expiry with Pyth VAA data
  - getPosition() to query on-chain balances

The relayer wallet pays all gas. Users never pay gas.
    N)TURBO_CONTRACT_ADDRESSMONAD_RPC_URLMONAD_CHAIN_IDTURBO_RELAYER_KEYPYTH_BTC_FEEDz3https://hermes.pyth.network/v2/updates/price/latesta  [
  {
    "inputs": [
      {"name": "marketId", "type": "bytes32"},
      {"name": "strikePrice", "type": "uint256"},
      {"name": "startTime", "type": "uint256"},
      {"name": "endTime", "type": "uint256"}
    ],
    "name": "createMarket",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "components": [
          {"name": "marketId", "type": "bytes32"},
          {"name": "maker", "type": "address"},
          {"name": "side", "type": "uint8"},
          {"name": "outcome", "type": "uint8"},
          {"name": "price", "type": "uint256"},
          {"name": "size", "type": "uint256"},
          {"name": "nonce", "type": "uint256"},
          {"name": "expiration", "type": "uint256"}
        ],
        "name": "buyOrder",
        "type": "tuple"
      },
      {"name": "buySig", "type": "bytes"},
      {
        "components": [
          {"name": "marketId", "type": "bytes32"},
          {"name": "maker", "type": "address"},
          {"name": "side", "type": "uint8"},
          {"name": "outcome", "type": "uint8"},
          {"name": "price", "type": "uint256"},
          {"name": "size", "type": "uint256"},
          {"name": "nonce", "type": "uint256"},
          {"name": "expiration", "type": "uint256"}
        ],
        "name": "sellOrder",
        "type": "tuple"
      },
      {"name": "sellSig", "type": "bytes"},
      {"name": "fillSize", "type": "uint256"}
    ],
    "name": "executeTrade",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {"name": "marketId", "type": "bytes32"},
      {"name": "priceUpdate", "type": "bytes[]"}
    ],
    "name": "resolve",
    "outputs": [],
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "inputs": [
      {"name": "user", "type": "address"},
      {"name": "value", "type": "uint256"},
      {"name": "deadline", "type": "uint256"},
      {"name": "v", "type": "uint8"},
      {"name": "r", "type": "bytes32"},
      {"name": "s", "type": "bytes32"}
    ],
    "name": "approveUsdcWithPermit",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [{"name": "marketId", "type": "bytes32"}],
    "name": "redeem",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [{"name": "marketId", "type": "bytes32"}],
    "name": "isMarketActive",
    "outputs": [{"name": "", "type": "bool"}],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {"name": "marketId", "type": "bytes32"},
      {"name": "user", "type": "address"}
    ],
    "name": "getPosition",
    "outputs": [
      {"name": "yes", "type": "uint256"},
      {"name": "no", "type": "uint256"}
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {"name": "marketId", "type": "bytes32"}
    ],
    "name": "getMarket",
    "outputs": [
      {"name": "strikePrice", "type": "uint256"},
      {"name": "startTime", "type": "uint256"},
      {"name": "endTime", "type": "uint256"},
      {"name": "resolved", "type": "bool"},
      {"name": "outcome", "type": "uint8"}
    ],
    "stateMutability": "view",
    "type": "function"
  }
]returnc                  8    t          t          ot                    S N)boolr   r        &/var/www/html/turbo/backend/relayer.pyis_liver      s    &<+<===r   c                     t           d S t                      st          dd           d S 	 ddlm}   | |                     t                              a t           j        j        	                    t                    at           j                            |                     t                    t                    at           j                            t          j                  }t          dt          j         d           t          dt                               |d	          d
dd           d S # t(          $ r!}t          d| d           d a Y d }~d S d }~ww xY w)NuE   [RELAYER] No contract address or relayer key — running in mock modeTflushr   Web3addressabiu*   [RELAYER] Connected to Monad — relayer: z[RELAYER] Balance: etherz.4fz MONz[RELAYER] Failed to init web3: )_w3r   printweb3r   HTTPProviderr   ethaccountfrom_keyr   _accountcontractto_checksum_addressr   	TURBO_ABI	_contractget_balancer   from_wei	Exception)r   balancees      r   _initr*      sl   
99 U]abbbbd4$$]33447?++,=>>G$$,,-CDD % 
 
	 '%%h&677M8;KMMUYZZZZLCLL'$B$BLLLLTXYYYYYY   3334@@@@s   DD4 4
E>EEc           	         t                       t          t          d S 	 |                     t          j        t          j                            t          j                  dt          j        j        |t          d          }t          	                    |          }t          j        
                    |j                  }t          j                            |d          }|j        dk    rdnd}t          d| d	|                                 d
           |S # t           $ r}t          d| d
           Y d }~d S d }~ww xY w)Ni@B )fromnoncegasgasPricevaluechainId   )timeout   OKFAILEDz[RELAYER] TX : Tr   z[RELAYER] TX error: )r*   r   r    build_transactionr   r   get_transaction_count	gas_pricer   sign_transactionsend_raw_transactionraw_transactionwait_for_transaction_receiptstatusr   hexr'   )tx_funcr0   txsignedtx_hashreceiptr?   r)   s           r   _send_txrF      s@   	GGG
{h&t&&$W2283CDD)%(
 (
   **2..'..v/EFF'66w6KK 1,,(7f7777tDDDD   (Q((5555ttttts   C9D 
E$D>>Emarket_id_hexstrike_price_6d
start_timeend_timec                 B   t                       t          t          d|  d           d S t                              |                     dd                              dd                    }t          j                            ||||          }t          |           d S )Nz[RELAYER] Mock createMarket: Tr   0x @   0)
r*   r$   r   bytesfromhexreplaceljust	functionscreateMarketrF   )rG   rH   rI   rJ   market_id_bytesrA   s         r   create_market_onchainrW      s    	GGG=m==TJJJJmmM$9$9$$C$C$I$I"c$R$RSSO!..*h G Wr   	buy_orderbuy_sig
sell_ordersell_sig	fill_sizec                    t                       t          t          d| d           dS d }|r.t                              |                    dd                    nd}|r.t                              |                    dd                    nd}fd	}d
dlm t          dd           t          d| d         dd          d| d          d| d          d| d          d| d          
d           t          d|d         dd          d|d          d|d          d|d          d|d          
d           t          d| d            || |d          }	 |||d          }
|	r|
st          dd           dS t          |          dk    st          |          dk    rt          dd           dS t          j	        
                     ||           | ||          ||          }t          |          }|duo
|j        d k    S )!z5Execute trade on-chain. Returns True if TX succeeded.Nz"[RELAYER] Mock executeTrade: size=Tr   c           	      b   | d                              d          r| d         n
d| d         z   }|                    dd          }t                              |dd                    t                              | d                   | d         | d         | d	         | d
         | d         | d         fS )NmarketIdrL   B   rO      makersideoutcomepricesizer-   
expiration)
startswithrS   rP   rQ   r   r"   )omids     r   to_tuplez'execute_trade_onchain.<locals>.to_tuple   s     }77==Wa
mm4!J-CWiiC  MM#abb'""##AgJ//fIq|QwZ6AgJ,
 	
r   rL   rM   sA                                                                    c                    	 | d                              d          r| d         n
d| d         z   }|                    dd          }t                              |dd                    }ddlm}                     d	          }                    d
	          }                    d	          }                     |g d|||t          t          g                    }	                    d	          }
                     |g d|
|| d         | d         | d         | d         | d         | d         | d         g	                    }                    d|	z   |z             }t          
                    |d d         d          }t          
                    |dd         d          }|d         }t          j        j                            ||||f          }|                                | d                                         k    }t!          d| d|d d          d| d         d d          d|rd nd! d"#           |S # t"          $ r"}t!          d| d$| d"#           Y d }~d%S d }~ww xY w)&Nr_   rL   r`   rO   ra   r   )encodezREIP712Domain(string name,string version,uint256 chainId,address verifyingContract))textTurbo1)bytes32rq   rq   uint256r   zzOrder(bytes32 marketId,address maker,uint8 side,uint8 outcome,uint256 price,uint256 size,uint256 nonce,uint256 expiration))	rq   rq   r   uint8rs   rr   rr   rr   rr   rb   rc   rd   re   rf   r-   rg   s       bigrN   )vrsz  z: recovered=
   z
 expected= r5   z	MISMATCH!Tr   z: verify error: F)rh   rS   rP   rQ   eth_abirm   keccakr   r   int
from_bytesr   r   r   _recover_hashlowerr   r'   )order	sig_byteslabelrj   	mid_bytes
abi_encodeds_typehash	name_hashversion_hash
domain_sepotstruct_hashdigestrsv	recoveredmatchr)   r   s                      r   
verify_sigz)execute_trade_onchain.<locals>.verify_sig   s   	',Z'8'C'CD'I'Ig%
##tV[\fVgOgC))B$$Cc!""g..I444444++++  A  AK11I;;C;00LZZCCCi~G]^& &  J
   #_  `  `B++jjgggYgfuY?OQVW^Q_afgmanpuv}p~  AF  GS  AT  U' '  K [[z!9K!GHHFy"~u55AyB/77A"A55f1a)5LLIOO%%w)=)=)?)??Ezuzz)CRC.zzE'NSVTVSVDWzzbgZxZ^Z^mxzz  CG  H  H  H  HL 	 	 	1u11a11>>>>55555	s   II 
I2I--I2r   r   z[RELAYER] executeTrade debug:z  buy:  maker=rb   rw   z side=rc   z price=re   z size=rf   z nonce=r-   z  sell: maker=z  fill_size=rY   r[   zE[RELAYER] Signature verification failed locally, skipping on-chain TXFA   z([RELAYER] Bad signature length, skippingr4   )r*   r$   r   rP   rQ   rR   r   r   lenrT   executeTraderF   r?   )rX   rY   rZ   r[   r\   rk   buy_sig_bytessell_sig_bytesr   buy_oksell_okrA   rE   r   s                @r   execute_trade_onchainr      s5    
GGG>9>>dKKKKt
 
 
 AHYEMM'//$";";<<<\MBJ\U]]8#3#3D"#=#=>>>P\N         D 	
*$7777	  ]9W-crc2  ]  ])F:K  ]  ]T]^eTf  ]  ]nwx~n  ]  ]  IR  SZ  I[  ]  ]  ei  j  j  j  j	  b:g.ss3  b  b:f;M  b  bV`ahVi  b  bq{  }C  rD  b  b  MW  X_  M`  b  b  jn  o  o  o  o	
$
$
$D1111Z	=)<<Fj^Z@@G  V^bccccu
=R3~#6#6"#<#<9FFFFu!.. G wG$67>Q#66r   c            	         	 t          j        dd          } t          j        t          | ddd          }|                                 |                                }|                    di                               dg           }|st          d	d
           dS d |D             }t          dt          |           dt          |d                    dd
           |S # t          $ r}t          d| d
           Y d}~dS d}~ww xY w)z
    Fetch the latest Pyth price update VAA (Verified Action Approval)
    for BTC/USD. This is the signed binary data that Turbo.resolve()
    passes to pyth.updatePriceFeeds() for on-chain verification.
    rL   rM   r@   )zids[]encodingrw   )paramsr3   binarydataz#[RELAYER] No Pyth VAA data returnedTr   Nc                 B    g | ]}t                               |          S r   )rP   rQ   ).0vaas     r   
<listcomp>z"fetch_pyth_vaa.<locals>.<listcomp>K  s$    ???CU]]3''???r   z[RELAYER] Fetched Pyth VAA: z update(s), r   z bytesz [RELAYER] Pyth VAA fetch error: )
r   rR   httpxgetPYTH_HERMES_VAA_URLraise_for_statusjsonr   r   r'   )feed_idrespr   binary_data	vaa_bytesr)   s         r   fetch_pyth_vaar   5  sC   'b11y$%88
 
 

 	yy{{ hhx,,00<< 	7tDDDD4??;???	bS^^bbYWX\IZIZbbbjnoooo   444DAAAAttttts   BC# AC# #
D-DDc                 ,   t                       t          t          d|  d           dS t                      }|st          d|  dd           dS t                              |                     dd	                              d
d                    }	 ddlm	} d}t          j        d          }t          j                            |                    |          |          }|j                            |                                          }t          d| dd           n.# t&          $ r!}t          d| dd           d}Y d}~nd}~ww xY wt          j                            ||          }	t+          |	|          }
|
duo
|
j        dk    S )u   
    Resolve a market on-chain:
    1. Fetch Pyth VAA (signed price update)
    2. Call Turbo.resolve(marketId, priceUpdate) — pays Pyth fee in MON
    3. Contract verifies Pyth signature, reads BTC price, sets outcome
    Nz[RELAYER] Mock resolve: Tr   Fz[RELAYER] Cannot resolve u    — no Pyth datarL   rM   rN   rO   r   r   *0x2880aB155794e7179c9eE2e38200202908C17B43z[{"inputs":[{"name":"updateData","type":"bytes[]"}],"name":"getUpdateFee","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]r   z[RELAYER] Pyth update fee: z weiz[RELAYER] Fee query error: z, using 1 weir4   )r0   )r*   r$   r   r   rP   rQ   rR   rS   r   r   r   loadsr   r   r!   r"   rT   getUpdateFeecallr'   resolverF   r?   )rG   r   rV   r   pyth_addresspyth_abipyth_contract
update_feer)   rA   rE   s              r   resolve_market_onchainr   T  s    
GGG888EEEEu   I J-JJJRVWWWWummM$9$9$$C$C$I$I"c$R$RSSOC:  @  A  A((,,\:: ) 
 
 #,99)DDIIKK
<J<<<DIIIII   <A<<<DIIII





 !))/9EEGwj111G$67>Q#66s   BD( (
E2EEuser_addressc                    t                       t          dS 	 ddlm} t                              |                     dd                              dd                    }t          j        	                    ||
                    |                                                    }|d         |d         fS # t          $ r}t          d	| d
           Y d}~dS d}~ww xY w)z1Query Turbo.getPosition(marketId, user) on-chain.Nr   r   rL   rM   rN   rO   r4   z[RELAYER] getPosition error: Tr   )r*   r$   r   r   rP   rQ   rR   rS   rT   getPositionr"   r   r'   r   )rG   r   r   rV   resultr)   s         r   get_onchain_positionr   }  s    	GGGt
--(=(=dB(G(G(M(MbRU(V(VWW$00$$\22
 
 $&& 	 q	6!9%%   1a11>>>>ttttts   BB6 6
C CCc                    t                       t          dS 	 t                              |                     dd                              dd                    }t          j                            |                                          }|d         |d         |d         |d	         |d
         dS # t          $ r}t          d| d           Y d}~dS d}~ww xY w)z)Query Turbo.getMarket(marketId) on-chain.NrL   rM   rN   rO   r   r4   ra         )strikePrice	startTimeendTimeresolvedrd   z[RELAYER] getMarket error: Tr   )r*   r$   rP   rQ   rR   rS   rT   	getMarketr   r'   r   )rG   rV   r   r)   s       r   get_onchain_marketr     s    	GGGt--(=(=dB(G(G(M(MbRU(V(VWW$..??DDFF!!9ayq	ay
 
 	
    /A//t<<<<ttttts   BB2 2
C<CC_trade_cache_last_scanned_block
market_idsc                 6   t                       t          t          S 	 ddlm} d}t
          j        j        }t          dk    r|at          |k    rt          S t          j
        d          }t
          j                            |                    t                    |          }i }| rd | D             }d|i|d	<   t          d
z   }d}	g }
t          ||d
z   |	          D ]D}t          ||	z   d
z
  |          }	 |j        j                            ||          }|D ]}t
          j                            |d                   }|
                    d|d         d                                         z   |d         d         |d         d         |d         d         |d         d         |d         d         |d         d         |d         |d         |d                                         d
           Ր# t,          $ r%}t/          d| d| d| d           Y d}~ nd}~ww xY w|
r<t                              |
           t/          dt3          |
           dd           |at          S # t,          $ r%}t/          d | d           t          cY d}~S d}~ww xY w)!u   
    Read Trade events from Turbo.sol filtered by market IDs.
    Uses indexed marketId topic for efficient on-chain queries.
    Caches results — only fetches new blocks since last call.
    Nr   r   iPa  [{
            "anonymous": false,
            "inputs": [
                {"indexed": true, "name": "marketId", "type": "bytes32"},
                {"indexed": true, "name": "buyer", "type": "address"},
                {"indexed": true, "name": "seller", "type": "address"},
                {"indexed": false, "name": "outcome", "type": "uint8"},
                {"indexed": false, "name": "price", "type": "uint256"},
                {"indexed": false, "name": "size", "type": "uint256"},
                {"indexed": false, "name": "fee", "type": "uint256"}
            ],
            "name": "Trade",
            "type": "event"
        }]r   c                     g | ]D}t                               |                    d d                              dd                    ES )rL   rM   rN   rO   )rP   rQ   rR   rS   )r   rj   s     r   r   z&get_onchain_trades.<locals>.<listcomp>  sB    ```cemmCKKb$9$9$?$?C$H$HII```r   r_   argument_filtersr4   i  )
from_blockto_blockblockNumberrL   argsbuyersellerrd   re   rf   fee	timestamptransactionHash)
r_   r   r   rd   re   rf   r   r   r   txHashz[RELAYER] Trade scan chunk -r7   Tr   z[RELAYER] Found z new on-chain tradesz$[RELAYER] get_onchain_trades error: )r*   r$   r   r   r   r   r   block_numberr   r   r   r!   r"   r   rangemineventsTradeget_logs	get_blockappendr@   r'   r   extendr   )r   r   DEPLOY_BLOCKlatesttrade_event_abicontract_with_eventstopic_filterpaddedr   
chunk_size
new_tradesstartendlogslogblockr)   s                    r   get_onchain_tradesr     s7    
GGGM%!##". &((* &    #w//,,-CDD  0  
  
  	D``U_```F0:F/CL+, )1,


:vz:>> 	 	Eej(1,f55C+28AA$s B      CG--c-.@AAE%%$(3v;z+B+F+F+H+H$H!$VW!5"%f+h"7#&v;y#9!$VW!5 #FF 3"6{51%*;%7'*='9"%&7"8"<"<">">' '        FEFFCFF1FFdSSSS  	X
+++JS__JJJRVWWWW$   8Q88EEEEsP   7I) BI) 6C8G0.I) 0
H:HI) HA	I) )
J3JJJ)r   r
   )$__doc__r   timer   configr   r   r   r   r   r   r    r$   r   r   r#   r   r   r*   rF   strr{   rW   dictr   listrP   r   r   tupler   r   r   __annotations__r   r   r   r   r   <module>r      s{  
 
 
                
 	K  DJ v v v	r> > > > >  2   6 s &)58    Q7T Q7C Q7&*Q769Q7FIQ7NRQ7 Q7 Q7 Q7lUd*    >$7# $7$ $7 $7 $7 $7R 3 5c?UYCY    &c dTk    * d4j    S   X X49t#3 XtDz X X X X X Xr   