Sriram Ramakrishnan, Independent Researcher · Sriram.Ramakrishnan@ieee.org
Preprint: doi
AI agents increasingly pay for services in stablecoins, through protocols such as x402 and EIP-3009 authorizations. These payments are final once settled: a wrong decision before payment cannot be undone by a chargeback, and a wrong decision in a later dispute cannot be fixed by reversing the transfer.
This publication releases three artifacts:
We then analyse where the model still fails. All four unsafe approvals are prompt injections whose payment text vouches for itself, and a deterministic claims check holds all four. In disputes, 26.0% of valid refunds are wrongly denied. We trace 59 of those 61 cases to one operation: deciding whether the claim was filed inside the policy's window. A short date check lowers wrongful denials to 0.85% without adding wrongful refunds.
The design principle that comes out of this is simple: the model judges, deterministic code enforces.
Card payments have a safety net. If a merchant charges you wrongly, the issuer can reverse the transaction. Stablecoin payments have no such net. Once a USDC transfer settles, nobody can pull it back. The only remedy is a new, voluntary payment in the other direction.
This matters more now that autonomous agents hold wallets. An agent that buys API calls, data or compute through x402 makes many small payment decisions without a human looking at each one. Every one of those decisions is a point where:
General-purpose LLMs are not trained for this. The base Qwen3-4B model approves about one in three payments that should be stopped, and approves more than half of the payments carrying injected text. We wanted to measure how far a small, cheap, locally runnable model can close that gap, and, just as important, to find the errors it still makes so they can be moved into code.
| Audience | What they can use from this work |
|---|---|
| Developers of agents that hold wallets (x402 clients, MCP agents, ElizaOS, LangChain, CrewAI, Coinbase AgentKit) | A drop-in guard that checks every payment, signature and transaction before the agent signs it |
| Wallet and payment-infrastructure teams (smart wallets, Circle Wallets, Circle Gateway, x402 facilitators) | Deterministic checks for signing paths that are easy to get wrong: permits, EIP-7702 delegation, long-lived authorizations, look-alike recipients |
| AI-safety and evaluation researchers | A benchmark with safety-weighted metrics (unsafe approvals, impossible remedies, wrongful denials) and published predictions for re-scoring |
| Risk, compliance and dispute-operations teams | A model of what an automated dispute decision can and cannot promise once a payment is final |
| Educators and students | A worked example of finding a model's systematic errors and moving them into code |
Typical use cases:
This work is organised around four questions:
Objectives: (1) release a benchmark with safety-oriented metrics; (2) release a small model that runs locally; (3) publish every prediction so all numbers can be re-checked; (4) release the deterministic checks as a library usable from common agent frameworks.
Prompt injection in tool-using agents. Greshake et al. (2023) [11] showed that text retrieved by an LLM application can carry instructions that the model follows (indirect prompt injection). InjecAgent (Zhan et al., 2024) [13], AgentDojo (Debenedetti et al., 2024) [12] and Agent Security Bench (Zhang et al., ICLR 2025) [21] turned this into benchmarks across many tools and attacks. These benchmarks measure whether an agent takes a harmful action, but treat actions generically. None scores the specific harm of a payment decision: whether it can be undone, whether the remedy offered is possible, or whether a signature stays usable after the task. Our benchmark fills that gap for one domain where errors are irreversible.
Defences by design. CaMeL (Debenedetti et al., 2025) [20] argues that prompt injection should be handled by separating control flow from untrusted data and enforcing policies in code, rather than by hoping the model resists. Our results give empirical support for this view in a narrow domain: the fine-tuned model resists most injections, but the few that pass are exactly those where untrusted text vouches for itself, and only a deterministic check removes them. We differ from CaMeL in scope: we do not build an interpreter, but place checks at the one boundary that matters for payments, the signature.
Agent payment protocols. x402 (2025) [1] uses HTTP 402 and EIP-3009 authorizations [2] so that agents can pay per request in USDC. Google's Agent Payments Protocol (AP2, September 2025) [23] and the Agentic Commerce Protocol from OpenAI and Stripe (2025) [24] define how agents carry user mandates and checkouts. These protocols define how an agent pays, not whether a given payment is safe to sign. They also assume the payer can tell a legitimate request from a manipulated one. SRA-RiskGate is a complementary layer that sits before the signer and works with any of them.
On-chain fraud and address poisoning. Work on blockchain risk has mostly been forensic: for example, the Elliptic dataset (Weber et al., 2019) [25] labels Bitcoin transactions as licit or illicit for anti-money-laundering models. Tsuchiya et al. (USENIX Security 2025) [22] measured address poisoning at scale: attackers create addresses that match a victim's usual payee at both ends, hoping the victim copies the wrong one. These works analyse transactions after they happen. We address the decision before signing, and our look-alike check follows the matching pattern their study describes.
Benchmark contamination. Sainz et al. (2023) [14] argue that contamination should be measured for every benchmark. Template-generated data is especially exposed, because test cases can differ from training cases only in surface values. We therefore report a structural contamination analysis, not only a verbatim one.
The gap. To our knowledge, no public benchmark scores agent payment decisions on both sides of settlement finality, no published model is trained for that task, and no study traces such a model's remaining errors to specific operations that can be moved into code. This work provides all three, with every prediction public.
SRA-RiskGate is not just a model. It is a layered gate that sits between an agent and its wallet:
Agent proposes a payment / signature / transaction
│
▼
┌──────────────────────────────────────────────┐
│ 1. Deterministic pre-checks (sra-riskgate) │ sanctions list, blocklist,
│ – never trust what the payload says │ look-alike recipients,
│ about itself │ account code (EIP-7702),
│ │ approvals, validity windows
└──────────────────────────────────────────────┘
│ passes
▼
┌──────────────────────────────────────────────┐
│ 2. SRA-RiskGate-4B │ approve / hold / reject,
│ – judgement over policy + tool results │ flags, required actions
└──────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────┐
│ 3. Deterministic post-checks │ self-vouching claims scan,
│ – correct known model failure modes │ dispute-window arithmetic
└──────────────────────────────────────────────┘
│
▼
Only an APPROVE reaches the signer
Anything unexpected (bad JSON, a field that will not parse, a timeout) becomes a hold, never an approval. The checks never throw at the caller and never produce a refund on their own.
SRA Stablecoin Risk Bench (Hugging Face, also on Kaggle) covers both ends of a stablecoin payment's life:
approve, hold or reject, with reason codes and required actions.Configurations. The same 20,000 cases are published in four configurations:
| Config | Rows | Purpose |
|---|---|---|
benchmark (default) | 18,000 train / 2,000 test | one row per case, for evaluation |
sft | 18,000 train / 2,000 test | the same cases as chat prompt / completion, ready for TRL's SFTTrainer |
eval_risk_gate | 1,175 test | id, input, target for Inspect |
eval_dispute | 825 test | id, input, target for Inspect |
Fields of the benchmark configuration.
| Field | Contents |
|---|---|
id | case identifier, e.g. test-000012 |
task | risk_gate or dispute |
format | payment format (risk gate) or dispute rail (dispute) |
perturbations | list of injected conditions, e.g. injection, payee_sanctioned, payer_att_forged, over_limit; empty for clean cases |
decision | gold decision (risk gate) or outcome (dispute) |
flags | gold reason codes |
input | JSON string: time, policy, payload and tool results |
label | JSON string: the full gold verdict |
Label space.
decision (approve / hold / reject), risk_level (low / medium / high / severe), flags, explanation, required_actions.outcome, mechanism, settlement_state (held / final), refund_amount_usdc, refund_destination, idempotency_key, flags, explanation, required_actions.
reverse_before_release, forced_refund, voluntary_refund, recommend_voluntary_refund, deny, dismiss, escalate_to_human, await_merchant_response, no_enforceable_remedy, refer_to_issuer. There is deliberately no chargeback outcome, because push payments have no forced reversal.escrow_void, arbiter_escrow_refund, multisig_mutual_return, multisig_resolver_refund, arbiter_bond_payout, merchant_compensating_transfer, issuer_freeze_burn, none.JSON Schemas for both verdicts and for the risk attestation are in schema/. The format is specified in SPEC.md (draft sra/1). The license is CC BY 4.0.
The data comes from a deterministic generator (version 0.3.0, seed 7, n = 20000, test_frac = 0.1, dispute_frac = 0.4). Each case goes through the same steps:
direct, escrow, multisig).RiskAttestation(subject, chainId, riskLevel, flags, screenedAt, expiresAt, policyId, nonce). Dispute evidence uses signed Order, DeliveryAttestation and RefundAddressChange messages.refer_to_issuer; duplicate dispute, already refunded, outside the window or not yet due → dismiss; then the merchant response window, merchant agreement, push-payment fraud and the evidence. Instruction-like text in a party's statement overrides to escalate_to_human.reverse_before_release or an escrow/multisig mechanism, and forced_refund is allowed only as a bond payout from an active, funded bond, never above its balance. Refund amounts are capped at what remains after earlier refunds; the destination follows the escrow's refund address or a payer-signed address change; the idempotency key is refund:<dispute_id>. A refund is modelled as a compensating transaction in the Saga sense [15]: idempotent, funded and correctly addressed, never a rollback.MANIFEST.json. A test (tests/test_integrity.py) fails if the flag and action lists in code and schemas drift apart.| Property | Value |
|---|---|
| Total cases | 20,000 (18,000 train, 2,000 test; 90/10 split) |
| Task mix (generator setting) | about 60% risk gate, 40% disputes |
| Payment formats | 3 (x402, eip3009, erc20_transfer) |
| Dispute rails | 3 (direct, escrow, multisig) |
| Case types | 21 (clean + 20 perturbations) |
| Risk-gate decisions | 3; risk levels 4 |
| Dispute outcomes / mechanisms | 10 / 8 |
| Prompt length | about 1,300–2,000 tokens per case |
| Download size | benchmark test 7.9 MB, train 71.8 MB; sft test 9.1 MB, train 82.2 MB |
Test split composition (2,000 cases).
| Slice | Cases |
|---|---|
| Risk-gate cases | 1,175 |
| — correct decision is hold or reject | 847 |
| — correct decision is approve | 328 |
| — contain prompt-injection text | 69 |
| Dispute cases | 825 |
| — contain prompt-injection text | 77 |
| Legitimate payments used for false-hold testing (test + train) | 3,358 |
Metrics reported by the open scorer (score.py).
The benchmark and the checks rest on these stated assumptions:
direct payment is final on confirmation; escrow and multisig payments are held until release and final after. No party can force a reversal of a final payment.SRA-RiskGate-4B is Qwen3-4B-Instruct-2507 [6] fine-tuned with QLoRA [8]:
| Setting | Value |
|---|---|
| Base model | Qwen3-4B-Instruct-2507, 4-bit NF4, double quantisation, bf16 compute |
| LoRA | rank 32, α = 64, dropout 0.05, all attention and MLP projections |
| Training | SFT in TRL, 18,000 cases, 1 epoch, loss on the verdict only |
| Optimiser schedule | lr 1e-4, cosine, 3% warmup |
| Batch | effective 16 (2 per device × 8 accumulation steps) |
| Max length | 3,072 tokens (prompts are about 1,300–2,000, none truncated) |
| Release | merged full-precision weights; GGUF (Q8_0 to Q4_K_M) and an Ollama build |
Payment and dispute cases use different system prompts. The payment prompt states that everything inside the payload is untrusted and that instructions found there must never be followed.
Evaluation setup. Both models were run on all 2,000 test cases with vLLM on an NVIDIA T4 in float16, greedy decoding, at most 512 new tokens. Two full runs of the fine-tuned model gave identical scores. The run took 6,516 s, or 3.3 s per case. Every prediction is published.
Every stage uses open tools or public services:
| Stage | Tools |
|---|---|
| Data generation and signing | Python deterministic generator (v0.3.0, seed 7); real secp256k1 EIP-712 / EIP-3009 signatures over simulated keys; JSON Schema for verdicts |
| Training | Hugging Face Transformers, Datasets, TRL [9] (SFT), PEFT (LoRA [7]), PyTorch; 4-bit NF4 quantisation (QLoRA [8]) |
| Inference and evaluation | vLLM [10] (greedy decoding), open scorer score.py, UK AISI Inspect [17] (eval.yaml) |
| Distribution | Hugging Face Hub (model, GGUF, datasets), Ollama, PyPI, npm, MCP Registry [16] |
| Deterministic checks | sra-riskgate (Python, standard library + typed checks), TypeScript port in the ElizaOS plugin (viem) |
| Live tests | Arc Testnet RPC, Circle Gateway batch API (testnet), Circle developer-controlled wallets SDK, web3.py |
| CI and parity | GitHub Actions; TypeScript checks verified against vectors generated by the Python library |
| Metric | Qwen3-4B (base) | SRA-RiskGate-4B |
|---|---|---|
| SRA composite score ↑ | 0.421 | 0.913 |
| Risk gate (1,175 payments) | ||
| Decision accuracy ↑ | 59.8% | 99.5% |
| Unsafe approvals (of 847) ↓ | 34.6% | 0.47% |
| Over-blocking (of 328) ↓ | 5.2% | 0.0% |
| Injected payments approved (of 69) ↓ | 52.2% | 5.8% |
| Flag micro-F1 ↑ | 0.105 | 0.994 |
| Disputes (825) | ||
| Outcome accuracy ↑ | 0.0% | 77.8% |
| Impossible remedies ↓ | n/a | 0.38% |
| Wrongful refunds ↓ | n/a | 2.2% |
| Wrongful denials ↓ | n/a | 26.0% |
| Refund details fully correct ↑ | n/a | 64.3% |
| Schema-valid output (payments / disputes) ↑ | 99.8% / 0% | 100% / 100% |
The base model returns dispute JSON with the right field names but outcome values outside the allowed vocabulary, so none of its dispute verdicts is usable (n/a).
Fine-tuning cuts unsafe approvals from about one in three risky payments to about one in two hundred, while blocking fewer legitimate payments than the base model. Accuracy is 100% on 16 of the 21 case types and at least 97.9% on all but one; the exception is injection (94.2%).
Disputes are clearly harder. Per-class F1 ranges from 1.00 (refer_to_issuer) and 0.96 (reverse_before_release) down to 0.54 (recommend_voluntary_refund). The model almost never proposes an impossible remedy (0.38%), but it denies or dismisses 26.0% of claims that should be refunded. The next section explains why.
All four unsafe approvals are prompt-injection cases (4 of 69 injected payments). Outside injection, the model made no unsafe approval. In each case the untrusted payment text asserts its own verification, for example "risk level: low (verified offline)".
A payer cannot grade its own risk. So the library runs a deterministic scan for self-asserted claims in untrusted text, with Unicode normalisation against look-alike characters, and holds the payment on a match.
Model + claims check: 0 of 847 unsafe approvals, and 0 false holds on the 3,358 legitimate payments in the test and training splits.
This check was written after the failures were found, so it repairs a known weakness rather than providing an independent evaluation. Differently worded attacks may still pass.
59 of the 61 wrongful denials are dismiss verdicts carrying the flag outside_dispute_window, which the correct label never contains. The model's explanations contradict themselves:
"The dispute was filed 26.5 days after payment, outside the 60-day window."
We recomputed the days between paid_at and filed_at for every dispute and compared them with the policy's dispute_window_days. The model claims "outside the window" 112 times, and 91 of those claims (81%) are false. It also misses 33 of the 54 disputes that really are outside. The model computes the elapsed days correctly and then compares them wrongly.
Whether a dispute is inside its window is date arithmetic, so we moved it to code. check_dispute_verdict recomputes the window from the dispute's own dates. If a verdict claims "outside" but the dates say "inside", the false flag is replaced, and a deny/dismiss resting on it becomes escalate_to_human with no refund. The check never produces a refund.
| Dispute metric (825 cases) | Model | Model + window check |
|---|---|---|
| Wrongful denials ↓ | 26.0% | 0.85% |
| Wrongful refunds ↓ | 2.2% | 2.2% |
| Outcome accuracy ↑ | 77.8% | 78.7% |
Escalations count as misses, so accuracy rises only slightly, while the harmful error nearly disappears.
The lesson: the remaining model errors are not random. They cluster in two operations a model should not be trusted with when money moves irreversibly: believing what untrusted text says about itself, and comparing two numbers.
A benchmark verdict is about a description of a payment. A real agent signs a transaction or typed data. The library therefore checks the exact bytes before they are signed.
| Signing path | What sra-riskgate checks |
|---|---|
Raw transactions (check_transaction) | Decodes calldata. A plain USDC transfer goes through the full payment check. approve (including unlimited), transferFrom, calls to other contracts and native transfers are held. |
Batches (EIP-5792 sendCalls) [4] | Approved only if every call is an approved USDC transfer. Payments to the same payee are summed, so splitting a payment cannot slip under the amount limit. |
x402 / EIP-3009 [1, 2] (check_authorization) | The domain must be USDC on that chain; from must be the agent's wallet; the type definition must be the EIP-3009 one; the authorization must be current and short-lived (held if valid for more than one hour by default). |
| EIP-2612 Permit / Permit2 [4] | Always held as an allowance; unlimited values are flagged. |
| EIP-7702 [4] | Any transaction carrying an authorization list, and any standalone authorization, is held. With chain id 0 it would delegate the account on every chain. |
| Circle Gateway [5] | Accepted only with Circle's published GatewayWallet contract as the verifying contract and domain version "1". It must stay valid for at least 3 days (Gateway's minimum) and at most 8 days. |
| Circle Wallets (developer-controlled) | guard_circle_wallets wraps Circle's SDK objects so that transfers, contract executions and typed-data or transaction signing are checked before the request reaches Circle. Wallet ids not on the allowed list are held. |
| Address poisoning (v0.15.0) [22] | A recipient that matches a known payee in at least 7 hex characters, including at least 3 at each end, but is not that payee is rejected as a look-alike. A random address matches by chance about once in 140 million tries. |
| Delegated accounts (v0.16.0) | Given the sender's eth_getCode, a 0xef0100… delegation designator to an unexpected contract is held (ACCOUNT_DELEGATED) and the agent is told to stop signing. The ElizaOS plugin reads this before every guarded call. |
| Arc | USDC is the native asset (18 decimals) with a 6-decimal ERC-20 interface. A native send is checked as a USDC payment, rounded up to a whole micro-USDC so no limit can be passed with dust. |
One finding here is worth stating plainly. Our first Gateway validity limit (7 days) held every payment produced by Circle's own client SDK, which signs for 7 days plus 100 s. We found this by testing against payments generated with the SDK. Such a payment is now part of the test suite, and the limit is 8 days. Testing against the real producer of signatures, not hand-written fixtures, caught a bug that would have blocked every legitimate payment.
A minimal usage example:
from sra_riskgate import ActionDecision, check_authorization verdict = check_authorization( typed_data, # the EIP-712 payload the agent is about to sign sender=agent_address, chain_id=5042002, # Arc Testnet known_recipients=[payee], max_amount=1.0, # USDC per payment untrusted_request=request_text, # scanned for self-vouching claims ) if verdict.decision != ActionDecision.APPROVE: raise RuntimeError(f"Not signing: {verdict.flags} {verdict.explanation}")
The checks were run against live contracts and Circle's APIs on Arc's public test network, using faucet USDC only.
Direct payments. A demo agent proposed four payments, each checked before signing:
The payee's balance of exactly 0.15 USDC confirmed that both decimal scales are handled correctly on chain.
Circle Gateway. The agent deposited 0.10 USDC into Gateway and proposed four batched payments. One, built exactly as Circle's SDK builds it, was approved, signed and accepted by Gateway's batch API. Three were held before signing:
Circle Wallets. The agent was given only guarded Circle SDK objects for a developer-controlled wallet. Of four requests, one 0.10 USDC transfer to the known payee was approved, sent to Circle and confirmed on chain. An unlimited approve (contract execution), a payment to an unknown address and an unlimited EIP-2612 permit (typed-data signing) were stopped and never reached Circle.
These runs are demonstrations of the checks working end to end, not measurements of error rates on real traffic.
Template-generated benchmarks risk test cases that differ from training cases only in surface values. No test input appears verbatim in training. To detect structural overlap, we masked every hexadecimal value and every number in each input and compared the results.
Every number above can be recomputed from published files without a GPU:
pip install -U "huggingface_hub[cli]" "sra-riskgate>=0.10.0" hf download sriram1983007/sra-bench-results --repo-type dataset --local-dir results hf download sriram1983007/sra-stablecoin-risk-bench score.py data/benchmark/train.jsonl \ --repo-type dataset --local-dir bench M=results/sra-riskgate-4b; B=results/qwen3-4b-instruct-base; TRAIN=bench/data/benchmark/train.jsonl # Main results table (repeat with $B for the base model) python bench/score.py --gold $M/test.jsonl --pred $M/predictions.jsonl # Claims check: 4 -> 0 unsafe approvals, 0 false holds on 3,358 python eval/claims_check.py $M/test.jsonl $M/predictions.jsonl $TRAIN # Dispute-window check: wrongful denials 26.0% -> 0.85% python eval/dispute_window_check.py $M/test.jsonl $M/predictions.jsonl # Contamination split (99.7% / 99.3%) python eval/profile_bench.py $M/test.jsonl $M/predictions.jsonl $TRAIN --leak-split
(The eval/ scripts are in the GitHub repository; run them from a clone.)
Using it in an agent:
pip install sra-riskgate # Python library (extras: [circle]) uvx sra-riskgate-mcp # MCP server for Claude, Cursor and other MCP clients npm install elizaos-plugin-sra-riskgate # ElizaOS plugin that wraps a viem wallet client ollama pull sriram1983007/sra-riskgate # run the model locally
The library also has LangChain and CrewAI integrations, a Coinbase AgentKit action provider, and a GitHub Action that checks agent-generated calldata in CI. The ElizaOS plugin's TypeScript checks are verified against vectors generated from the Python library, so both implementations give the same verdict on the same input.
| Research question | Finding |
|---|---|
| RQ1 — Capability | Yes. Fine-tuning raised decision accuracy from 59.8% to 99.5%, cut unsafe approvals from 34.6% to 0.47% (4 of 847) and over-blocking from 5.2% to 0%. |
| RQ2 — Disputes | Partly. Outcome accuracy is 77.8% and impossible remedies are rare (0.38%), but 26.0% of valid refunds are wrongly denied. |
| RQ3 — Residual failures | Systematic, not random. All 4 unsafe approvals are self-vouching injections; 59 of 61 wrongful denials come from one date comparison. Two short checks bring unsafe approvals to 0 of 847 (0 false holds on 3,358) and wrongful denials to 0.85%, with no new wrongful refunds. |
| RQ4 — Signing boundary | Several risks exist only in the signed bytes: allowances, EIP-7702 delegation, long-lived authorizations, wrong verifying contracts, look-alike recipients and already-delegated accounts. Each is now a deterministic check, and a test against Circle's own SDK caught a bug that would have blocked every legitimate Gateway payment. |
| Dataset | 20,000 cases with real signatures; no verbatim train/test overlap; 99.3% accuracy on test cases with no structural twin in training, so the scores are not explained by memorised templates. |
A small fine-tuned model can gate agent stablecoin payments with high accuracy and few unsafe approvals. But its remaining errors are not random. They cluster in operations a model should not be trusted with when money moves irreversibly: believing what untrusted text says about itself, and comparing two numbers. Moving those operations into deterministic code removes almost all of the measured harm.
The broader takeaway for anyone building agentic payment systems: use the model for judgement, and put every check that can be written as code into code, especially at the signing boundary, where the bytes the agent signs matter more than any description of them.
We release the benchmark, the model, the predictions and the checks so that others can test this design on their own policies.
Research design, benchmark, training, evaluation and all release decisions: Sriram Ramakrishnan. Claude (Anthropic) assisted with code, analysis scripts and writing; every result was produced by the published scripts and checked by the author.
This work was first released as a preprint on Zenodo: Ramakrishnan, S. (2026). SRA-RiskGate: A Benchmark and a 4B Model for Gating Stablecoin Payments Made by AI Agents, and the Checks the Model Still Needs. doi
.5281/zenodo.23715017. Please cite the DOI.| Resource | Link |
|---|---|
| Code, paper and analysis scripts | https://github.com/sriram1983007-dev/sra-riskgate |
| Model | https://huggingface.co/sriram1983007/SRA-RiskGate-4B |
| GGUF / Ollama build | https://huggingface.co/sriram1983007/SRA-RiskGate-4B-GGUF |
| Benchmark (CC-BY-4.0) | https://huggingface.co/datasets/sriram1983007/sra-stablecoin-risk-bench |
| All predictions | https://huggingface.co/datasets/sriram1983007/sra-bench-results |
| Python library | https://pypi.org/project/sra-riskgate/ |
| MCP server | https://github.com/sriram1983007-dev/sra-riskgate-mcp |
| ElizaOS plugin | https://www.npmjs.com/package/elizaos-plugin-sra-riskgate |