Elysium Scripts
React to pool and bonding trades and execute contract actions from Python.
Write Python scripts that react to trades in Market Lab pools and bonding markets on Elysium testnet. No wallet is needed to read trades. External markets and backtesting are not supported yet.
Read Trades
Create watch-market.py. Use the pool or bonding contract address, not the token address, before @trades@elysium:
script = {"name": "watch-market", "version": "2", "lookback": 100}
SOURCE = "0x59675174f1700677e608f86016f1cea764e1abfa@trades@elysium"
def on_data(ctx, history):
trade = history.source(SOURCE, 0)
market = trade["onchain"]
print(market["current_price"], market["volume"]["quote"])on_data runs when a trade arrives. lookback keeps up to 100 trades for your script.
mlab script run watch-market.pyThe market is validated on-chain when the script starts. No market refresh is needed.
Latest Trade or List
Inside on_data, choose which records to read:
latest = history.source(SOURCE, 0) # Latest trade
previous = history.source(SOURCE, 1) # One trade before the latest
earlier = history.source(SOURCE, 2) # Two trades before the latest
trades = history.source(SOURCE) # List, oldest to newestAn index returns one trade, or None if it is not available yet. No index returns the retained list, or [] when empty, not the market's entire trading history.
What a Trade Returns
Example bonding trade (sample values; block metadata and state omitted):
{
"price": 0.0001,
"size": 10,
"onchain": {
"kind": "bonding",
"market": "0x59675174f1700677e608f86016f1cea764e1abfa",
"side": "buy",
"base": {
"symbol": "gurt",
"address": "0x1171daed16376968bdd3d865318a9a4f3687f328",
"decimals": 18
},
"quote": {
"symbol": "HYPE",
"address": null,
"decimals": 18
},
"base_amount": "10",
"quote_amount": "0.001",
"current_price": 0.000100004,
"fee": {
"amount": "0.000003",
"asset": {
"symbol": "HYPE",
"address": null,
"decimals": 18
}
},
"volume": {
"base": "10",
"quote": "0.001",
"trades": 1,
"from_block": 3000000,
"through_log_index": 0
}
}
}Read these fields from trade:
| Field | Meaning |
|---|---|
price, size | Trade execution price and base-token quantity |
onchain.side | buy or sell of the base token |
onchain.base, onchain.quote | Each asset's symbol, address, and decimals; native HYPE has no token address |
onchain.base_amount, onchain.quote_amount | Exact traded amounts as decimal strings |
onchain.current_price | Price per base token at the end of the confirmed block, or None if undefined |
onchain.fee | Fee amount and asset |
onchain.volume | Observed base and quote totals and number of trades, not 24-hour volume |
onchain.state | Pool reserves or bonding market state |
onchain.kind, onchain.market | Market type and contract address |
onchain.transaction_hash, onchain.timestamp_ms | Transaction and trade time in milliseconds |
For example, trade["onchain"]["fee"]["amount"] reads the fee paid. Trades arrive after 12 block confirmations; the current market price can differ from the trade's execution price.
Trade From Your Script
mlab auth set elysiumThis creates a trading wallet and prints its address. Fund it with HYPE for gas and the assets you want to trade.
Use ctx.swap inside on_data to buy or sell, after reading that market with history.source. This example buys with 0.01 HYPE:
ctx.swap({
"exchange": "elysium",
"market": "0x59675174f1700677e608f86016f1cea764e1abfa",
"token_in": "native",
"amount": "0.01",
"key": "first-buy",
})For bonding, "native" buys with HYPE; the token's contract address sells it. For pools, use the address of the token you are paying with, such as WHYPE.
Add or Remove Liquidity
For pools only, set POOL to your pool's contract address and read its trades with history.source before calling these helpers:
ctx.deposit({
"exchange": "elysium", "market": POOL,
"amount0": "1", "amount1": "2", "key": "deposit-1",
})
ctx.withdraw({
"exchange": "elysium", "market": POOL,
"shares": "0.1", "key": "withdraw-1",
})amount0 and amount1 follow the pool's token order. shares is the number of LP tokens to redeem, not a percentage. Pass amounts as decimal strings, such as "0.01", not base-unit integers.
All three helpers accept slippage_bps (default 50, or 0.5%) and max_gas (default "0.0001" HYPE per transaction).
Follow Execution
def on_execution(ctx):
event = ctx.execution
if event["type"] == "contract.confirmed":
print(event["key"], event["data"]["result"]["receipts"])
elif event["type"] == "contract.failed":
print(event["data"]["result"]["error"])An action is complete when contract.confirmed arrives, not when the helper returns. Use a new key for each intended action; the same key and request will not trade again within that job.