Your first contract
A Solidity contract that places orders on VordCore through CoreWriter — compile it, check every call against the testnet, then deploy it.
A contract on the EVM lane can trade on VordCore through CoreWriter. The contract has its own account on the core: it trades with the USDC that account holds, and every order it places is an ordinary order on the book.
The contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface ICoreWriter {
function sendRawAction(bytes calldata data) external;
}
/// Places limit orders on VordCore for this contract's own account.
contract LimitBot {
ICoreWriter constant CORE_WRITER = ICoreWriter(0x7777777777777777777777777777777777777777);
address public immutable owner;
constructor() {
owner = msg.sender;
}
/// Move USDC this contract holds on the EVM lane to its account on the core (action 4).
function fund(uint64 usdc6) external {
require(msg.sender == owner, "not the owner");
CORE_WRITER.sendRawAction(abi.encodePacked(uint8(2), uint24(4), abi.encode(usdc6)));
}
/// Place a limit order (action 10). Price and size carry 8 decimals.
function placeLimit(uint32 pair, bool isBuy, uint64 limitPx, uint64 size, uint8 tif, uint128 cloid) external {
require(msg.sender == owner, "not the owner");
CORE_WRITER.sendRawAction(abi.encodePacked(uint8(2), uint24(10), abi.encode(pair, isBuy, limitPx, size, false, tif, cloid)));
}
/// Cancel it by your own id (action 12).
function cancel(uint32 pair, uint128 cloid) external {
require(msg.sender == owner, "not the owner");
CORE_WRITER.sendRawAction(abi.encodePacked(uint8(2), uint24(12), abi.encode(pair, cloid)));
}
}Compile it and check it against the testnet
This compiles the contract, asks the testnet what deploying it would cost, and simulates the CoreWriter call its
placeLimit makes. Nothing is sent and no funded key is needed.
# needs solc 0.8.19 or later: pip install vordium==1.4.6 requests
import subprocess, requests
from eth_abi import encode
from eth_utils import keccak
EVM = "https://rpc-testnet.vordium.com/evmrpc"
def rpc(method, params):
return requests.post(EVM, json={"jsonrpc": "2.0", "id": 1, "method": method, "params": params}, timeout=15).json()
out = subprocess.run(["solc", "--bin", "--optimize", "LimitBot.sol"], capture_output=True, text=True, check=True).stdout
bytecode = "0x" + out.strip().splitlines()[-1]
me = "0x000000000000000000000000000000000000dEaD"
print("deploy gas:", int(rpc("eth_estimateGas", [{"from": me, "data": bytecode}])["result"], 16))
# the call placeLimit(1, true, 2000 USDC, 0.01 ETH, post only, 42) makes to CoreWriter
action = b"\x02" + (10).to_bytes(3, "big") + encode(
["uint32", "bool", "uint64", "uint64", "bool", "uint8", "uint128"], [1, True, 2_000 * 10**8, 10**6, False, 1, 42])
call = {"from": me, "to": "0x7777777777777777777777777777777777777777",
"data": "0x" + keccak(b"sendRawAction(bytes)")[:4].hex() + encode(["bytes"], [action]).hex()}
print("placeLimit accepted:", "result" in rpc("eth_call", [call, "latest"]))Deploy it
Deploy it with any Ethereum tool pointed at the testnet's EVM lane, https://rpc-testnet.vordium.com/evmrpc — for
example with ethers.js, from the compiled bytecode:
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers'
const wallet = new Wallet(process.env.PRIVATE_KEY!, new JsonRpcProvider('https://rpc-testnet.vordium.com/evmrpc'))
const factory = new ContractFactory(abi, bytecode, wallet) // abi and bytecode from solc --abi --bin
const bot = await factory.deploy()
console.log('LimitBot at', await bot.getAddress())Deploying and calling need test VORD for gas on the EVM lane.
Fund it and trade
- Send the contract USDC on the EVM lane (the ERC-20 at
0x2000000000000000000000000000000000000000). - Call
fund(amount)to move it to the contract's account on the core. - Call
placeLimit(...). The order reaches the book at least three seconds later; find it withGET /orders/{contract address}on the REST API. - Call
cancel(pair, cloid)to take it off.
Network facts last checked against the network 2026-10-22 13:00:37 UTC · mainnet spec v28 · testnet spec v8