Skip to main content
The tpluspy EVM extra adds on-chain capabilities on top of the core Python SDK: reading the T+ asset registry, interacting with vault contracts, and constructing signed settlement orders. It is built on the Ape Framework and uses T+‘s own contract-defined signing scheme — not generic Ethereum tooling.

Installation

The EVM extra is not included in the default pip install tpluspy. You must install it explicitly:
pip install "tpluspy[evm]"
Without [evm] installed, any import from tplus.evm will fail immediately with ModuleNotFoundError. Do not attempt to import tplus.evm.contracts in an environment that only has the core install.
If your workflow only involves placing orders, streaming market data, or querying user state against a running tplus-core, the core install is sufficient — you do not need [evm].

Ape Console Setup

The EVM extra integrates with the ape console REPL. Start a console connected to the Sepolia testnet:
ape console --network ethereum:sepolia:alchemy
You can use any Ape-compatible provider, not just Alchemy. Point --network at any supported provider or a raw RPC URL:
ape console --network ethereum:sepolia:https://your-rpc-url
Once inside the console, tpluspy pre-loads contract instances (vault, registry) into the namespace via the Ape console extras in ape_console_extras.py. You can call contract methods directly without any further import:
In [1]: registry.getAssets()
Out[1]: [
    getAssets_return(
        assetAddress=HexBytes('0x000000000000000000000000f08a50178dfcde18524640ea6618a1f965821715'),
        chainId=11155111,
        maxDeposits=100,
    )
]

In [2]: registry.admin()
Out[2]: '0x467a95fC5359edE5d5dDc4f10A1F4B680694858E'

Registry Operations

The registry contract tracks all assets registered with T+. Import the pre-configured instance from tplus.evm.contracts:
from tplus.evm.contracts import registry

# List all registered assets
assets = registry.getAssets()
for asset in assets:
    print(f"Address:     {asset.assetAddress.hex()}")
    print(f"Chain ID:    {asset.chainId}")
    print(f"Max Deposits:{asset.maxDeposits}")

# Read the registry admin address
admin = registry.admin()
print(f"Admin: {admin}")

registry.getAssets()

Returns a list of named tuples, each containing:
FieldTypeDescription
assetAddressHexBytesThe token contract address
chainIdintThe EVM chain ID where the asset lives
maxDepositsintMaximum deposits allowed for this asset

registry.admin()

Returns the Ethereum address of the current registry admin.

Vault Operations

The vault contract manages deposit nonces and settlement state. Import the pre-configured vault instance:
from tplus.evm.contracts import vault
from ape import accounts

# Load your Ethereum account
tplus_user = accounts.load("tplus-account")

# Get the current deposit nonce for your address
nonce = vault.getDepositNonce(tplus_user)
print(f"Current nonce: {nonce}")

vault.getDepositNonce(address)

Returns the current nonce for the given Ethereum address. This nonce is required when constructing settlement Order objects — it prevents replay attacks on signed settlement messages.

Settlement Signatures

To authorise a settlement, you construct a typed Order object and sign it with your Ethereum account using T+‘s own structured-message signing scheme. The resulting signature is submitted alongside the settlement request.
Do not use generic Ethereum typed-data tooling such as eth_account.sign_typed_data for T+ settlement flows. T+ defines its own contract-level signing scheme. Using third-party EVM signing helpers will produce an invalid signature that the T+ contracts will reject.
Here is a complete example:
from ape import accounts, convert, chain
from tplus.utils.domain import Order
from tplus.evm.contracts import vault
from tplus.utils.user import UserManager

# Load your Ethereum account (stored in Ape's keyfile manager)
tplus_user = accounts.load("tplus-account")

# Load your T+ user to get the public key (used as userId in the order)
user_id = UserManager.load("my_user").public_key

# Fetch the current nonce from the vault contract
nonce = vault.getDepositNonce(tplus_user)

# Construct the settlement Order
order = Order(
    tokenOut="0x62622E77D1349Face943C6e7D5c01C61465FE1dc",
    amountOut=convert("1 ether", int),
    tokenIn="0x58372ab62269A52fA636aD7F200d93999595DCAF",
    amountIn=convert("1 ether", int),
    userId=user_id,
    nonce=nonce,
    validUntil=chain.pending_timestamp,
)

# Sign using Ape — T+'s structured-message variant
signature = tplus_user.sign_message(order).encode_rsv()
print(f"Signature: {signature.hex()}")
1

Load your Ethereum account

Use accounts.load("name") to load a keyfile stored in Ape’s account manager. This is your on-chain identity for interacting with T+ contracts.
2

Load your T+ user

UserManager.load("my_user").public_key returns your Ed25519 public key, which acts as the userId binding the settlement to your T+ account.
3

Fetch the nonce

vault.getDepositNonce(address) returns the current nonce from the contract. Always fetch it fresh — using a stale nonce will cause the settlement to be rejected.
4

Construct the Order

Build an Order from tplus.utils.domain with the token addresses, amounts (in wei), your user ID, nonce, and a validUntil timestamp.
5

Sign and encode

Call sign_message(order).encode_rsv() on your Ape account. This uses T+‘s structured-message variant — the output is an RSV-encoded byte string ready to include in your settlement request.

Supported Networks

T+ contracts are currently deployed on Ethereum Sepolia (chain ID 11155111). You can connect via any Ape-compatible provider that supports Sepolia:
# Alchemy
ape console --network ethereum:sepolia:alchemy

# Infura
ape console --network ethereum:sepolia:infura

# Direct RPC
ape console --network ethereum:sepolia:https://rpc.sepolia.example.com
Mainnet deployment details will be published when available. For now, all on-chain interactions should target Sepolia.