# AI keys (/ai/ai-keys) AI steps run on your own API key. You add keys on the **Settings** page, in the **AI keys** card. You can add one key for each provider. ## Providers and models [#providers-and-models] The **In strategies** column is the name a step uses in its `provider` field. The models are suggestions: a step can name any model that the provider offers to your key. The first model in each row is the default. A step that names no model uses it. ## Add a key [#add-a-key] ### Get a key from the provider [#get-a-key-from-the-provider] On **Settings**, find the provider in **AI keys**. Click **Add key**, then **Where to get a key** to open the provider's key page. Make a key there. ### Paste and test it [#paste-and-test-it] Paste the key into **API key**. Click **Test and save**. Spin makes one small test call with the key, to the provider's default model. This call is on your account. ### Check the result [#check-the-result] If the provider accepts the key, Spin seals it and saves it. The row shows **Saved** and "key ending" with the last 4 characters of the key. If the provider refuses the key, Spin does not save it and shows the provider's reason. A key that the provider accepts passes the test, even if the provider does not offer the default model to that key. ## Replace or remove a key [#replace-or-remove-a-key] - To change a key, click **Replace** on its row, paste the new key, and click **Test and save**. - To delete a key, click **Remove**. Steps that use that provider then give no signal, so the bot does not act on them. ## Choose the key and model for a step [#choose-the-key-and-model-for-a-step] In the workflow editor, each AI step has an **AI provider** field and a **Model** field. | Setting | What the step uses | | --- | --- | | **AI provider**: **My newest key** | Your most recently added or replaced key, with its provider's default model. | | **AI provider**: a provider | Your key for that provider. | | **Model** empty | The provider's default model. | | **Model** filled in | That model. A model needs a provider. | In JSON, these are the step's `provider` and `model` fields: ```json { "id": "research", "provider": "anthropic", "model": "claude-haiku-4-5", "prompt": "Summarise what is known about the token {{token.address}}.", "output": { "summary": "text" } } ``` A step that draws an image needs an OpenAI, xAI or Google key. If it names no provider, it uses your newest key that can draw images. See [image steps](/ai/ai-steps#image-steps). If a step names a provider that you have no key for, the strategy still saves, and the editor shows a warning. That step gives no signal until you add the key. This lets a strategy work for a later holder who has that key. ## What it costs, and who pays [#what-it-costs-and-who-pays] You pay your provider for every call that runs on your key. Spin does not pay for AI calls, and it does not resell them. A run costs more when: - the strategy has more steps (up to 3 in a run); - the prompt is longer, or it includes earlier answers; - a step reads MCP tools: each tool's description goes into the prompt, and each tool call sends data back to the model; - the model is larger or slower; - the step uses Grok's search of X or the web, which xAI bills on your key. Small, fast models usually suit AI steps, because a step can run on many tokens. You control how many runs happen with the trigger, a cheap rule before the AI, and the **AI runs an hour at most** limit. See [AI steps](/ai/ai-steps#how-often-the-ai-runs). Your key is also used when you [build a strategy with AI](/strategies/build-with-ai). ## When a key fails [#when-a-key-fails] If the provider refuses your key, limits it, or has no credit left, the step gives no signal and the bot does not act. The Spinner's page then shows the problem under **Needs your attention**, for example "Your OpenAI key was refused" or "Your OpenAI key is limited". Fix the key in **Settings**, then mark the notice as read. ## How Spin keeps your key [#how-spin-keeps-your-key] - Spin seals (encrypts) each key before it stores it. A sealed key is bound to your account and its provider. - Only Spin's servers open the key, for one call at a time. - The app never shows the key again. It shows only the last 4 characters. - Your keys belong to you, not to a Spinner. When you sell a Spinner, its bot stops using your keys at once. # AI steps (/ai/ai-steps) An AI step is one question to your own AI model. You write the prompt, and you declare the fields of the answer and what each field holds. The model must answer in that shape. Your rules then read the answer. AI steps in entries and exits need an **Epic** Spinner. A **Rare** Spinner can use AI steps only in a strategy that [launches a token](/launching). ## Where steps go [#where-steps-go] **In an entry.** The steps run after the trigger, after **Buy only if** and after any **Wait**. Then **Then buy if** (or **Then launch if**) reads the answers. The bot buys only if that rule holds. ``` When → Buy only if → Wait → AI steps → Then buy if → Buy ``` Put cheap rules in **Buy only if**. They run first, so the AI runs only on tokens that pass them. **In an exit.** Turn on **Ask the AI before selling** in an exit. Then: - **Ask the AI when** is the rule that starts a review. The bot checks it on every price change and every second. If you leave it empty, every open position can be reviewed. - **Ask at most every** sets how often the AI can review one position (in minutes; from 1 minute to 1 day, 15 minutes if you do not set it). - **Then sell if** reads the answers. The bot sells only if it holds. In the workflow editor, add a step with the **+** and choose **AI step**, or add an exit with **AI sell check**. ## The parts of a step [#the-parts-of-a-step] | In the editor | In JSON | What it is | | --- | --- | --- | | **Step name** | `id` | The step's name. Lowercase letters, digits and `_`, starting with a letter, up to 24 characters. Each step in a strategy needs its own name. | | **AI provider** | `provider` | Which of your keys runs the step. **My newest key** leaves it out. See [AI keys](/ai/ai-keys). | | **Model** | `model` | A model of that provider. Empty: the provider's default. | | **Prompt** | `prompt` | The question, up to 4,000 characters. It can include values in `{{ }}`. | | **Answer field** and **Holds** | `output` | The fields of the answer: 1 to 10 of them. | | **Tools it may read (your MCP servers)** | `tools` | Up to 3 of your [MCP servers](/ai/mcp-servers), by name. | | **Search X**, **Search the web** | `search` | Grok's own search. Only with the xAI provider. | | **Run this step only if** | `if` | A rule on earlier answers. Not on the first step. | ## Values in a prompt [#values-in-a-prompt] Write a value in double braces, and Spin fills it in before the prompt goes to the model. | You write | Spin fills in | | --- | --- | | `{{token.address}}` | The token's address. | | `{{token.price}}` | A rule value of the token. | | `{{token.buyers(60)}}` | A rule value that takes a number: here, buyers in the last 60 seconds. | | `{{research}}` | The whole answer of the earlier step `research`, as JSON. | | `{{research.summary}}` | One field of an earlier step's answer. | | `{{hook.text}}` | A field that your webhook sent (a [webhook](/ai/webhooks) strategy only). | A prompt can use every value that a rule can use at that point: - **In an entry:** token values, trigger values and bot values. A timer or a webhook has no trigger, so trigger values are unknown there. - **In an exit:** token values, position values and bot values. See [conditions](/strategies/conditions) for every value. A step can use only the steps before it. A value that is not known when the step runs reads as "unknown". ## Answer fields [#answer-fields] Each field has a name and a type. A field name is lowercase letters, digits and `_`, starting with a letter, up to 32 characters. | **Holds** in the editor | In JSON | The model answers | Rules can read it | | --- | --- | --- | --- | | **One of these words** | `["buy", "skip"]` | One of 2 to 20 words that you list | Yes | | **Yes or no** | `"boolean"` | `true` or `false` | Yes | | **A number** | `"number"` | Any number | Yes | | **A number from 0 to 1** | `{ "number": [0, 1] }` | A number in the range | Yes | | **Text (for later steps, not rules)** | `"text"` | Text, up to 4,000 characters | No | | **An image it draws** | `"image"` | Nothing: Spin draws the image, and the field is its link | No | | **A token's address, to buy (or none found)** | `"token"` | A token's address, or null if it found none | No | In JSON, a range can have other limits, for example `{ "number": [0, 100] }`. Rules read a field as `ai..`, for example `ai.decide.action`. Text fields are for later steps and for the activity: a later prompt can include them, and the **Activity** tab shows them. An answer that does not match the declared shape is not used. Spin does not guess. ### A token answer [#a-token-answer] A `token` field can name the token that the strategy buys. In **The token to buy**, choose "The token the step ... names". In JSON: ```json "target": { "token": "{{watch.token}}" } ``` The bot then looks up that token's market: a Pons or Torch token on its launchpad, any other token in its pools. Then it checks your rules with the token's own values, and buys only if they hold. If the step finds no token, or no market appears within a minute, the bot buys nothing. A token named this way cannot pin a pool. ## Chains of steps [#chains-of-steps] A strategy's AI part is a chain of 1 to 3 steps. The steps run in order, and each step can read the answers of the steps before it. **Run this step only if** (`if`) is a rule on earlier answers. If it does not hold, the chain stops there. Later steps do not run and cost nothing, and your rules see only the answers so far. Use it to make a cheap first step decide whether a costly second step runs. **Answer within** (`timeout_s`) is the time limit for the whole chain: from 5 to 120 seconds, 60 if you do not set it. An answer that comes later gives no signal. ## Example: research, then decide [#example-research-then-decide] The first step reads an MCP server. The second step runs only if the risk is not high. The bot buys only on "buy" with a confidence of at least 0.7. This is an illustration to learn from, not a strategy that is known to make money. ```json { "schema": 1, "name": "Launch check with research", "entry": { "trigger": { "on": "launch" }, "wait_s": 30, "ai": { "steps": [ { "id": "research", "tools": ["defade"], "prompt": "A token launched 30 seconds ago on Robinhood Chain: {{token.address}}. It has {{token.buyers(30)}} buyers so far. Look up its rug-pull risk, holders and deployer history. Summarise what you found.", "output": { "risk": ["low", "medium", "high"], "summary": "text" } }, { "id": "decide", "if": { "!=": [{ "f": "ai.research.risk" }, "high"] }, "prompt": "Research on a new token: {{research}}. Should a small trading bot buy it now, to sell within 30 minutes? Answer buy or skip, and your confidence from 0 to 1.", "output": { "action": ["buy", "skip"], "confidence": { "number": [0, 1] } } } ] }, "confirm": { "and": [ { "==": [{ "f": "ai.decide.action" }, "buy"] }, { ">=": [{ "f": "ai.decide.confidence" }, 0.7] } ] }, "buy_eth": 0.01 }, "exits": [ { "if": { ">=": [{ "f": "position.multiple" }, 2] }, "sell_pct": 50, "reason": "half_at_2x" }, { "if": { "<=": [{ "f": "position.multiple" }, 0.7] }, "reason": "stop_loss" }, { "if": { ">=": [{ "f": "position.age_s" }, 1800] }, "reason": "time" } ], "limits": { "max_open": 5, "max_ai_runs_per_hour": 20 } } ``` An entry with AI steps needs `confirm` (**Then buy if**): the answers matter only through a rule. The **AI launch check** preset is a similar starting point. ## Example: an AI exit [#example-an-ai-exit] After 10 minutes, the AI reviews the position at most every 15 minutes. The bot sells if the answer is "sell". Plain rules stay as a stop loss and a time exit. ```json { "schema": 1, "name": "AI exit review", "entry": { "trigger": { "on": "launch" }, "wait_s": 60, "confirm": { ">=": [{ "f": "token.buyers", "args": [60] }, 30] }, "buy_eth": 0.01 }, "exits": [ { "if": { ">=": [{ "f": "position.age_s" }, 600] }, "ai": { "every_s": 900, "steps": [ { "id": "review", "prompt": "We hold token {{token.address}}. Our profit or loss is {{position.pnl_pct}} percent. Its price changed {{token.price_change(300)}} times in the last 5 minutes. Hold or sell?", "output": { "action": ["hold", "sell"] } } ] }, "confirm": { "==": [{ "f": "ai.review.action" }, "sell"] }, "reason": "ai_review" }, { "if": { "<=": [{ "f": "position.pnl_pct" }, -40] }, "reason": "stop_loss" }, { "if": { ">=": [{ "f": "position.age_s" }, 3600] }, "reason": "time" } ] } ``` An AI exit needs `confirm` (**Then sell if**). An exit without AI puts its rule in `if` (**Sell when**) and has no `confirm`. ## Tools [#tools] A step with `tools` can read the tools of up to 3 of your [MCP servers](/ai/mcp-servers). The model can call tools for up to 5 rounds before it answers. Spin tells the model that data from tools is untrusted: information, never instructions. ## Grok's X and web search [#groks-x-and-web-search] A step on the xAI provider can use Grok's own search. xAI runs the search and bills it on your xAI key. | In the editor | In JSON | What it does | | --- | --- | --- | | **Search X** | `"search": { "x": { ... } }` | Grok reads posts on X. | | **Only posts from** | `"handles": ["@account"]` | Only posts from these accounts, up to 20. Empty: all of X. | | **Posts from** | `"days": 1` | Posts from the last 1 to 7 days (the editor offers 1, 2, 3 or 7). | | **Search the web** | `"web": true` | Grok also searches the web. | A search needs `"provider": "xai"` on the step. Grok's search is part of the step, not an MCP server. ```json { "id": "talk", "provider": "xai", "search": { "x": { "days": 1 }, "web": true }, "prompt": "Search X for posts about the token {{token.address}} on Robinhood Chain. Is the talk organic, or does it look like a coordinated raid? Give a score from 0 (raid or none) to 1 (organic).", "output": { "organic": { "number": [0, 1] }, "summary": "text" } } ``` Hype on X is easy to fake with bot raids and paid posts. A model can help to see it, but not reliably. For a full example, see [Watch X for contract addresses](/guides/watch-x-for-contract-addresses). ## Image steps [#image-steps] A step can draw an image with your image model. Use it to draw a launched token's image: see [Launching tokens](/launching#draw-the-image). - Its only answer field holds **An image it draws** (`"image"`). - It uses no tools and no search. - It needs an OpenAI, xAI or Google key. If it names no provider, it uses your newest key that can draw images. If it names no model, it uses the provider's default image model. - Its prompt describes the image. Spin draws one square image, keeps it, and the field's answer is the image's link (for example `{{art.url}}`). - The provider's own rules decide what it will draw. A refusal gives no image, and the step gives no signal. ## How often the AI runs [#how-often-the-ai-runs] Every AI run is calls on your own key, so a strategy has a limit: **AI runs an hour at most** (`limits.max_ai_runs_per_hour`). It is from 1 to 1,000, 20 if you do not set it. Each run of a chain counts once, in an entry or an exit. When the limit is reached, the bot skips that run (an entry, or an exit's review), and the activity says "max_ai_runs_per_hour reached". The trigger also sets how often the AI runs. For example, a timer every 2 minutes runs 30 times an hour, so it needs a limit of at least 30. If the same chain runs again for the same holder with the same values within 60 seconds, Spin reuses the answer and makes no new call. The **Activity** tab marks it "from the 60 s cache". One holder's answers are never reused for another holder. ## When a step fails [#when-a-step-fails] A step that fails gives no signal, and no signal never buys, sells or launches. The chain stops at the failed step. A step fails when: - you have no key for its provider, or no key at all; - the provider refuses the key, limits it, or has no credit left; - the provider does not offer the model to your key; - the answer does not have the declared shape; - the chain does not answer within its time limit; - a step names an MCP server that you have not added, or the server does not answer. The **Activity** tab shows each run's steps: the prompt as sent, with its values filled in, then the answer or why there was none, and how long it took. When a problem repeats, the Spinner's page shows it under **Needs your attention**, with what to fix. ## Who sees your prompts [#who-sees-your-prompts] Your prompts and the answers go to your own provider, on your own key. Spin does not check prompts or answers with a moderation step: your provider applies its own policies. Spin checks only a strategy's name and its exits' names when you save, because a later holder sees them. # AI and data (/ai) A strategy can ask an AI model a question before it acts. The model reads the token's values, and live data if you give it tools, and gives an answer in a fixed shape. Your rules then read the answer and decide. The AI only produces values: every buy, sell and launch still goes through your rules, your limits and the Spinner's guard. ## What AI can do in a strategy [#what-ai-can-do-in-a-strategy] | Use | What happens | Page | | --- | --- | --- | | Check before a buy | AI steps run after the trigger. **Then buy if** reads their answers. | [AI steps](/ai/ai-steps) | | Check before a sell | An exit asks the AI about an open position. **Then sell if** reads the answers. | [AI steps](/ai/ai-steps) | | Find a token to buy | A step answers with a token's address. The bot buys that token if your rules hold. | [AI steps](/ai/ai-steps) | | Read live data | A step reads tools from MCP servers that you add, or uses Grok's search of X and the web. | [MCP servers](/ai/mcp-servers) | | Launch a token | A step writes the token's name, ticker and description, and can draw its image. | [Launching tokens](/launching) | | Start from your own service | Your service sends a signed call to the Spinner's webhook. | [Webhooks](/ai/webhooks) | ## Your own key, your own costs [#your-own-key-your-own-costs] Every holder brings their own AI key. Spin has no shared key and no AI credit of its own. - Each AI step runs on your key, so your provider bills you directly. - MCP servers use your own key for each service, so that service bills you directly. - Your keys belong to you, not to a Spinner. When you sell a Spinner, its bot stops using your keys at once. The buyer's bot uses the buyer's keys. - Spin never shares the results of one holder's key with another holder. When the same AI run repeats within 60 seconds, Spin can reuse the answer, but only for the same holder. - Spin stores your keys sealed (encrypted). You never see a key again after you save it. Spin shows only its last 4 characters. Paper trading and live trading both run the AI steps, so a paper run also costs calls on your key. You set how many AI runs a strategy can make in an hour: see [AI steps](/ai/ai-steps#how-often-the-ai-runs). A model can misread data, and data from a server can be late, wrong or missing. Keep amounts small, keep your live trading limits low, and run on paper first. A strategy with an AI step cannot be backtested, because what a model would have answered on past days cannot be known. ## Tiers [#tiers] A Spinner's tier decides which AI tools its bot can use. Each tier keeps everything below it. | Tier | AI and data tools | | --- | --- | | Rare | AI steps only in a strategy that launches a token. No MCP servers. | | Epic | AI steps in entries and in exits. MCP servers in any step. | | Legendary | A webhook trigger: your own service starts the strategy. | See [Rarity and tiers](/spinners/rarity-and-tiers) for how a Spinner gets a tier, and how $SPIN unlocks a higher one. ## Start here [#start-here] # MCP servers (/ai/mcp-servers) An MCP server is a service that gives an AI model tools to look up data. With MCP servers, an AI step can read a token's rug-pull risk, what smart money buys, a contract's code, a stock's news, or posts on X. The model reads the data, and your rules decide on its answer. MCP servers in a strategy need an **Epic** Spinner. You add servers on the **Settings** page, in the **MCP servers** card. Like AI keys, servers belong to you, not to a Spinner. After a sale, the buyer's bot uses the servers that the buyer added under the same names. ## One-click servers [#one-click-servers] These servers are hosted and read-only, and each takes a key in a header. The **MCP servers** card lists the ones you have not added yet. Each one needs your own key for that service. All bots call from Spin's servers, so a server's free limit without a key would be shared by every holder, and one busy hour could stop every bot. ### Get a key [#get-a-key] On the server's row, click **Get a key**. Make a key on that service's page. ### Add the server [#add-the-server] Click **Add** and the server's name (for example **Add DeFade**). The form fills in the **Name**, the **Address** and where the key goes. Paste your key into **API key or token**. ### Connect and save [#connect-and-save] Click **Connect and save**. Spin checks the address, connects to the server with your key, and lists its tools. If it connects, Spin seals the key and saves the server. A message says how many tools your bots get. A one-click server keeps its own name (for example `defade`), because strategies and presets use that name. ## Add a custom server [#add-a-custom-server] You can add any other MCP server by its address. Click **Add another server**, then fill in the form: | Field | What to put | | --- | --- | | **Name** | The name that strategies use for this server: lowercase letters, digits, `-` and `_`, starting with a letter, up to 40 characters. | | **Address** | The server's address, for example `https://…/mcp`. | | **API key or token** | The server's key, if it needs one. | | **Send the key as** | Where the server takes its key: see below. | | **Allow tools not marked read-only** | Off unless you turn it on: see [read-only tools](#read-only-tools). | Spin refuses an address that: - does not use `https`; - has a user name or password in it; - is not public (for example `localhost` or a private network); - does not resolve. Spin also does not follow redirects. ## Where the key goes [#where-the-key-goes] A server takes its key in one of three places. Choose it in **Send the key as**. | **Send the key as** | What Spin sends | | --- | --- | | **Authorization: Bearer** | The header `Authorization: Bearer `. Most servers take this. | | **Another header** | Your key as the value of the header that you name in **Header name** (for example `x-api-key`). | | **A query parameter** | Your key in the address, as the query parameter that you name in **Query parameter name** (for example `apikey`). | Some servers take their key in the address. Do not type the key into the **Address**. Put it in **API key or token**, choose **A query parameter**, and give the parameter's name. Spin adds the key to the address only when your bots connect, so the key stays sealed and the saved address has no key in it. If the address has a parameter that looks like a key (its name has "key", "token", "secret", "auth" or "pass" in it), the form refuses it and tells you which parameter to move. ## One setup of each server [#one-setup-of-each-server] Each account can add each server once. The same address written another way counts as the same server: Spin ignores upper and lower case in the host, a default port, extra or trailing slashes, and the query. If you add a server again under a new name, Spin refuses it and names the setup you already have. Click **Replace** on that one instead. ## Change or remove a server [#change-or-remove-a-server] Each saved server shows its name, its address, the last 4 characters of its key, and a pill: **Read-only tools** or **All tools**. - **Tools** opens the list of its tools. See below. - **Replace** opens the form again. The name stays the same. Leave **API key or token** empty to keep the saved key. A new address is a new server, so you choose its tools again. - **Remove** deletes the server. Steps that name it then give no signal. ## Choose the tools [#choose-the-tools] Click **Tools** on a saved server. The list shows every tool that the server offers, with its description and about how many prompt tokens it adds. The top line shows how many tools are on and about how many prompt tokens a run costs. - Turn each tool on or off. - **Suggested** turns on the server's suggested tools (only some one-click servers suggest tools). - **All read-only** turns on every read-only tool. - **None** turns all tools off. - **Find a tool** filters a long list. - **Save tools** saves your choice. Your bots get exactly the tools that are on. Until you choose, a bot gets the server's suggested tools, or all of its read-only tools if it suggests none. Fewer tools cost less. Each tool's description goes into every run's prompt, on your AI key. For example, all of Nansen's tools add about 43,000 prompt tokens to a run, and its suggested tools about 8,000. Fewer tools also help a model choose the right one. ## Read-only tools [#read-only-tools] A server marks each tool as read-only or not. Your bots get only read-only tools unless you allow more. For X, Spin treats the tools that only read (accounts, posts, mentions, search, counts, trends and news) as read-only, because X marks none of its tools so. A tool that is not marked read-only may act on your account at that service, for example spend credit or post. To give such tools to your bots: 1. Click **Replace** on the server. 2. Turn on **Allow tools not marked read-only**. Click **Connect and save**. 3. Click **Tools**, and turn on only the tools you want. Do this only for servers that you trust. A server cannot move your Spinner's funds: every trade still goes through your rules, your limits and the Spinner's guard. ## Use a server in a step [#use-a-server-in-a-step] A step names its servers in `tools`, by their names, up to 3 a step: ```json { "id": "research", "tools": ["nansen", "defade"], "prompt": "On Robinhood Chain, who are the top holders of token {{token.address}}, and what is its rug-pull risk?", "output": { "risk": ["low", "medium", "high"], "summary": "text" } } ``` In the workflow editor, turn on each server under **Tools it may read (your MCP servers)** in the step. The Strategy tab's **Your AI keys and MCP servers** card lists your server names. If a step names a server that you have not added, the strategy still saves, and the editor shows a warning. That step gives no signal until you add the server. ## What it costs [#what-it-costs] A run with MCP tools costs: - **your AI provider:** the prompt, with the tool descriptions, the data that the tools send back, and the answer; - **the data service:** each tool call, on that service's plan. See [MCP data sources](/guides/mcp-data-sources) for examples with each one-click server. ## When a server fails [#when-a-server-fails] If a step names a server that you have not added, or a server does not answer, the step gives no signal. The Spinner's page shows "An MCP server is missing" or "An MCP server does not answer" under **Needs your attention**. Check the server's address and key in **Settings**. # Webhooks (/ai/webhooks) A webhook trigger lets your own service start a strategy. Your service watches what you want (a stream of posts, a chart alert, a Telegram group) and sends a signed call to the Spinner's webhook. The bot then runs the strategy's entry with the fields your service sent. A webhook trigger needs a **Legendary** Spinner. A call can only start an entry. It cannot move or withdraw funds. Every buy still goes through the strategy's rules, its limits and the live trading limits on the Spinner's guard. ## Set up a webhook [#set-up-a-webhook] ### Choose the trigger [#choose-the-trigger] In the workflow editor, open the **When** block. In **Start when**, choose **My own service calls its webhook (Legendary)**. ### Declare the fields [#declare-the-fields] Add the fields that your service sends, with **Answer field** and **Holds**, as for an [AI step's answer](/ai/ai-steps#answer-fields). See [fields](#fields). ### Choose what it does [#choose-what-it-does] Choose the outcome. To buy a token that your service names, set **The token to buy** to "The token your service sends". To buy one fixed token, choose it. To launch a token, see [launch from a webhook](#launch-from-a-webhook). ### Save, and make a secret [#save-and-make-a-secret] Click **Save as new version**. On the **Strategy** tab, the **Webhook** card now shows the webhook's address. Click **Make a secret**. Copy the secret and keep it in your service's settings, never in its code or a repository. The card shows it only this once. ### Sign and send calls [#sign-and-send-calls] Your service signs each call with the secret. See [signing a call](#signing-a-call). The Spinner must be activated. Calls are refused until you make a secret. ## Fields [#fields] A webhook declares 1 to 10 fields. A field name is lowercase letters, digits and `_`, starting with a letter, up to 32 characters. The types are those of an AI step's answer, but never an image. | In JSON | Your service sends | Rules read it | | --- | --- | --- | | `"number"` | A number | Yes | | `{ "number": [0, 1] }` | A number in the range | Yes | | `"boolean"` | `true` or `false` | Yes | | `["buy", "skip"]` | One of the listed words | Yes | | `"text"` | Text, up to 4,000 characters | No | | `"token"` | A token's address (`0x` and 40 hex digits), or `null` | No | The strategy uses the fields so: - **Rules** read a field as `hook.`, for example `hook.score`. - **Prompts** of AI steps, and a launch's fields, include a field as `{{hook.}}`. - **The token to buy** can be a `token` field: `"target": { "token": "{{hook.token}}" }`. A webhook has no trigger event, so trigger values are unknown in its rules. Token and bot values work as usual. ## What the bot does with a call [#what-the-bot-does-with-a-call] 1. Spin's servers check the call (see [what a call must pass](#what-a-call-must-pass)) and answer 202. 2. Within seconds, the bot starts the entry with the call's fields. 3. If the strategy buys a token that the call names, the bot looks up the token's market: a Pons or Torch token on its launchpad, any other token in its pools. If no market appears within a minute, it buys nothing. 4. The entry runs as any other: **Buy only if**, any **Wait**, any AI steps, **Then buy if**, then the buy. The strategy's limits apply, for example **Once per token**. A call that is more than 5 minutes old when the bot gets to it is dropped. A signal that late is no signal. ## Example strategy [#example-strategy] Your service sends a token and a score from 0 to 1. The bot buys only if the score is at least 0.7 and the token's market has at least 3 ETH. This is an illustration to learn from, not a strategy that is known to make money. ```json { "schema": 1, "name": "My signal service", "entry": { "trigger": { "on": "webhook", "fields": { "token": "token", "score": { "number": [0, 1] } } }, "target": { "token": "{{hook.token}}" }, "if": { "and": [ { ">=": [{ "f": "hook.score" }, 0.7] }, { ">=": [{ "f": "token.liquidity" }, 3] } ] }, "buy_eth": 0.005 }, "exits": [ { "if": { ">=": [{ "f": "position.multiple" }, 2] }, "sell_pct": 50, "reason": "take_profit" }, { "if": { "<=": [{ "f": "position.pnl_pct" }, -30] }, "reason": "stop_loss" }, { "if": { ">=": [{ "f": "position.age_s" }, 7200] }, "reason": "time" } ], "limits": { "once_per_token": true, "max_open": 3 } } ``` A webhook strategy needs `entry.target` (a token, or the one the call names) or `entry.launch`. ## Signing a call [#signing-a-call] Send a `POST` to the webhook's address, `https://spin.trading/api/hooks/`. The **Webhook** card shows the exact address. The body is a JSON object with the declared fields. Add these headers: | Header | Value | | --- | --- | | `content-type` | `application/json` | | `x-spin-timestamp` | The time of signing, in Unix seconds. | | `x-spin-signature` | `v1=` and the hex HMAC-SHA256 of `.`, with the secret as the key. | | `x-spin-event-id` | Optional. Your own id for the event: 1 to 100 letters, digits or `. _ : -`. | The signature covers the exact bytes of the body. Sign the body as you send it, and do not format it again after you sign it. If you send the same event id again, Spin takes the call once only. Without an event id, the signature names the call, so the same signed call sent twice is taken once. ```bash SECRET="whsec_..." # from the Webhook card BODY='{"token":"0x0000000000000000000000000000000000000001","score":0.9}' TS=$(date +%s) SIG="v1=$(printf '%s' "$TS.$BODY" | openssl dgst -sha256 -hmac "$SECRET" | sed 's/^.* //')" curl -X POST "https://spin.trading/api/hooks/123" \ -H "content-type: application/json" \ -H "x-spin-timestamp: $TS" \ -H "x-spin-signature: $SIG" \ -H "x-spin-event-id: post-1849" \ --data "$BODY" ``` ```js import crypto from "node:crypto"; const body = JSON.stringify({ token: "0x0000000000000000000000000000000000000001", score: 0.9 }); const ts = Math.floor(Date.now() / 1000).toString(); const sig = "v1=" + crypto.createHmac("sha256", process.env.SPIN_HOOK_SECRET).update(`${ts}.${body}`).digest("hex"); const res = await fetch("https://spin.trading/api/hooks/123", { method: "POST", headers: { "content-type": "application/json", "x-spin-timestamp": ts, "x-spin-signature": sig, "x-spin-event-id": "post-1849", }, body, }); // 202: accepted. The bot starts the entry within seconds. ``` ```python import hashlib, hmac, json, os, time, requests body = json.dumps({"token": "0x0000000000000000000000000000000000000001", "score": 0.9}, separators=(",", ":")) ts = str(int(time.time())) sig = "v1=" + hmac.new(os.environ["SPIN_HOOK_SECRET"].encode(), f"{ts}.{body}".encode(), hashlib.sha256).hexdigest() requests.post("https://spin.trading/api/hooks/123", data=body, headers={ "content-type": "application/json", "x-spin-timestamp": ts, "x-spin-signature": sig, "x-spin-event-id": "post-1849", }) ``` ## What a call must pass [#what-a-call-must-pass] Spin checks each call in this order: 1. The body is at most 8,192 bytes. 2. The Spinner is activated, and its strategy starts on a webhook. 3. The Spinner has a secret, made by the wallet that holds the Spinner now. 4. The timestamp is within 5 minutes of now. 5. The signature matches the timestamp and the exact body. 6. The body is JSON, with every declared field, of the declared type, and no other fields. 7. The event id, if you send one, has the right form. 8. The Spinner has had fewer than 30 calls in the last minute and fewer than 2,000 in the last day. | Answer | Meaning | | --- | --- | | 202 | Accepted. The body is `{"accepted": true, "duplicate": false}`. `"duplicate": true` means Spin took this event before, and takes it once only. | | 400 | The body is not JSON, a field is missing or of the wrong type, the body has a field that the strategy does not declare, or the event id has the wrong form. | | 401 | No secret yet, a timestamp more than 5 minutes from now, or a signature that does not match. | | 404 | The Spinner is not activated, or its strategy does not start on a webhook. | | 413 | The body is over 8,192 bytes. | | 429 | Over 30 calls in a minute, or over 2,000 in a day. | A refused call's body has an `error` field that says why, for example `"score" must be a number from 0 to 1`. ## The secret [#the-secret] - Spin makes the secret: `whsec_` and 32 random bytes. Spin keeps it sealed (encrypted), and shows it only once. - **Make a new secret** ends the old one at once. Use it if the secret leaks. - A sale of the Spinner ends its secret. The new holder makes their own. - The timestamp window means a captured call cannot be sent again later. ## Launch from a webhook [#launch-from-a-webhook] A webhook strategy can launch a token instead of buying one. Then your service can write the token itself: the launch fields can be webhook fields, and no AI step is needed. ```json { "schema": 1, "name": "Launch from my service", "entry": { "trigger": { "on": "webhook", "fields": { "name": "text", "symbol": "text", "description": "text", "image": "text" } }, "launch": { "launchpad": "torch", "name": "{{hook.name}}", "symbol": "{{hook.symbol}}", "description": "{{hook.description}}", "image": "{{hook.image}}" } }, "exits": [] } ``` The `image` field must be an `https://` or `ipfs://` link to the image. See [Launching tokens](/launching) for the launch fields and their terms. ## Webhooks cannot be backtested [#webhooks-cannot-be-backtested] What your service would have sent on past days cannot be known, so a webhook strategy cannot be backtested. Run it on paper first. # Getting started (/getting-started) A Spinner is an NFT on Robinhood Chain. Each Spinner is a trading bot with its own wallet. You give the bot a strategy, Spin's servers run it, and a guard contract checks every trade that the bot sends. ## What you need [#what-you-need] - **A wallet on Robinhood Chain.** You sign in to the Spin app with it. Read [Wallet and network](/getting-started/wallet-and-network). - **ETH on Robinhood Chain.** Your wallet pays gas when you mint, activate, deposit or change settings. The Spinner's own wallet needs ETH to trade live and to pay the gas of its trades. - **$SPIN.** A mint costs 10,000 $SPIN for each Spinner, and activation costs 5,000 $SPIN. If you keep more $SPIN in the same wallet as the Spinner, the bot gets more tools. Read [$SPIN](/token). - **An AI key (only for AI steps).** Strategies with AI steps use your own key from an AI provider. Read [AI keys](/ai/ai-keys). ## From zero to a running bot [#from-zero-to-a-running-bot] The [quickstart](/getting-started/quickstart) gives each step in order. This is the path: A bot follows its rules exactly. Many strategies lose money after costs, and memecoins can go to zero. Test on paper first, and only use money that you can afford to lose. Read [Risks](/safety/risks). # Quickstart (/getting-started/quickstart) This page takes you from no Spinner to a bot that trades. Each step links to a page with more detail. ### Sign in [#sign-in] 1. Open the Spin app. 2. Click **Connect wallet**. 3. Choose your wallet and sign the message. Use the wallet that will hold your Spinners. If your wallet is on a different network, the app asks it to switch to Robinhood Chain when you send a transaction. Read [Wallet and network](/getting-started/wallet-and-network). ### Get $SPIN and ETH [#get-spin-and-eth] You need $SPIN in the wallet that you signed in with: | For | $SPIN | |---|---| | One mint | 10,000 | | One activation | 5,000 | | One Spinner, minted and activated | 15,000 | You also need some ETH on Robinhood Chain for gas. If your wallet has too little $SPIN, the mint page and the activation card tell you how much more you need. When the app has a place to buy $SPIN, they also show a **Buy $SPIN** button. Read [$SPIN](/token). ### Mint a Spinner [#mint-a-spinner] 1. Open **Mint**. 2. Choose how many Spinners to mint with the **+** and **-** buttons. 3. Click **Pay ... $SPIN**. The button shows the total cost. 4. Approve the transactions in your wallet. The page shows each new Spinner and its rarity. Read [Minting](/spinners/minting). ### Activate it [#activate-it] A new Spinner is inactive. Its bot cannot trade, on paper or live, until you activate it. 1. After the mint, click **Activate Spinner #...**. You can also open the Spinner from **My Spinners**. 2. On the **Activation** card, click **Activate for 5,000 SPIN**. 3. Approve the transactions in your wallet. Read [Activation](/spinners/activation). ### Pick a preset or write a strategy [#pick-a-preset-or-write-a-strategy] 1. On the Spinner's page, open the **Strategy** tab. 2. In **Start from a preset**, choose a preset. Or build your own rules in the **Workflow** tab. 3. Change what the preset asks for, for example the token to buy or the wallets to copy. 4. Click **Save as new version**. The editor tells you which tier of tools the strategy needs, and which tier your Spinner has. A preset is a starting point, not a promise of results. Before you save, you can run a backtest on past market data. Read [Presets](/strategies/presets), [Rarity and tiers](/spinners/rarity-and-tiers) and [Backtests](/strategies/backtests). ### Paper trade [#paper-trade] An active Spinner with a saved strategy trades on paper. Paper trades use no money, but they pay the same 0.5% fee in their results as live trades. 1. Make sure that the **Bot** switch says **Running**. 2. Make sure that the **Money** control says **Paper**. 3. Watch the **Performance** and **Activity** tabs. If the bot has a problem that you can fix, a **Needs your attention** card shows it. Let the strategy run on paper long enough for you to trust its results. ### Fund the Spinner's wallet [#fund-the-spinners-wallet] 1. Open the **Wallet** tab. 2. In **Deposit**, type an amount of ETH. 3. Click **Deposit** and approve the transaction. The ETH goes to the Spinner's own wallet. The bot trades from this wallet and pays the gas of its trades from it. Read [The Spinner's wallet](/spinners/wallet). ### Go live [#go-live] 1. On the **Wallet** tab, find the **Live trading** card. You can also click **Set up live trading** at the top of the page. 2. Type your limits in **Most per trade**, **Most per day** and **For** (days). 3. Click **Allow live trading** and approve the transactions. 4. When all four steps on the card have a check mark, turn the switch from **Paper** to **Live**. The bot now trades with real ETH from the Spinner's wallet, within your limits. To stop new trades, turn the **Bot** switch to **Paused**. Read [Live trading](/spinners/live-trading). Live trading uses real money. A strategy that did well on paper or in a backtest can lose money live. Read [Risks](/safety/risks). # Wallet and network (/getting-started/wallet-and-network) ## Robinhood Chain [#robinhood-chain] Spinners live on Robinhood Chain, an Ethereum layer-2 network. All amounts in the app, trade sizes and gas are in ETH. | Setting | Value | |---|---| | Network name | Robinhood Chain | | Chain ID | 4663 | | Currency | ETH | | RPC address | `https://rpc.mainnet.chain.robinhood.com` | | Block explorer | [robinhoodchain.blockscout.com](https://robinhoodchain.blockscout.com) | You do not have to add the network by hand. When you send a transaction from the app, the app asks your wallet to switch to Robinhood Chain. ## Sign in with a wallet [#sign-in-with-a-wallet] Spin has no passwords. You sign in with an Ethereum wallet. 1. Click **Connect wallet** in the top corner of the app. 2. Choose your wallet. 3. Sign the message that the wallet shows. A signature costs no gas. After you sign in, **My Spinners** shows every Spinner that your connected wallets hold. To sign out, click the button next to your address. Your wallet signs only when you change a bot's settings or move funds: a mint, an activation, a deposit or withdrawal, or live trading limits. The bot itself never uses your wallet. It trades from the Spinner's own wallet. Read [The Spinner's wallet](/spinners/wallet). ## ETH for gas [#eth-for-gas] Two different wallets pay gas: | Wallet | Pays gas for | |---|---| | Your wallet (the one that holds the Spinner) | Mints, activations, deposits, withdrawals, live trading limits, and other settings that you sign | | The Spinner's wallet | The bot's live trades | Keep some ETH in both. If the Spinner's wallet cannot pay for a trade and its gas, the trade does not go through, and the bot page tells you to add ETH. ## The wallet that holds the Spinner matters [#the-wallet-that-holds-the-spinner-matters] Many things depend on which wallet holds the Spinner: - **Only that wallet can act.** Only the wallet that holds a Spinner can activate it, deposit into its wallet from the app, withdraw from its wallet, and set its live trading limits. If you connect a different wallet, the app shows which wallet holds the Spinner. - **Tiers count the $SPIN in that wallet.** Hold-to-unlock counts the $SPIN in the same wallet that holds the Spinner. $SPIN in another wallet, or in the Spinner's own wallet, does not count. Read [Rarity and tiers](/spinners/rarity-and-tiers). - **Live trading limits belong to that wallet.** If the Spinner moves to a different wallet, the earlier limits stop. Read [Transfers](/spinners/transfers). If you use more than one wallet, keep each Spinner in the wallet that also holds your $SPIN. Then the bot gets the tools that your $SPIN unlocks. # Guides (/guides) These guides build whole strategies, step by step, with valid JSON that you can paste into the **JSON** tab and change. Each example is a starting point to learn from, not a strategy that is known to make money. Before you start, read [AI steps](/ai/ai-steps) and [MCP servers](/ai/mcp-servers), and [the risks](/safety/risks). # MCP data sources (/guides/mcp-data-sources) An AI step can read from MCP servers: services that give a model tools to look up data. With them, a strategy can check a stock's news before it buys a tokenised stock, see what smart money buys on Robinhood Chain, wait out a rate decision, or read a contract's code before a buy. MCP tools in a strategy need an **Epic** Spinner. The model only reads. Every buy and sell still comes from your strategy's rules, its limits, and the live trading limits on the Spinner's guard. A server can make a step's answer better informed. It cannot move funds. These examples are starting points to learn from and change, not strategies that are known to make money. Data from a server can be late, wrong or missing, and a model can misread it. Keep amounts small, keep your live trading limits low, and run on paper first. AI strategies cannot be backtested: what a model would have answered on past days cannot be known. ## The servers you can add with one click [#the-servers-you-can-add-with-one-click] The **MCP servers** card on the **Settings** page lists these. Each one needs your own key from that service: **Get a key** opens its page. Spin connects to the server, lists the tools your bots get, and keeps the key sealed. After a sale, the buyer's bot uses the buyer's own servers. A step names its servers in `tools` (up to 3 a step), by the name in the **Name in strategies** column. For example: `"tools": ["nansen", "defade"]`. See [MCP servers](/ai/mcp-servers) for how to add one. **Choose the tools.** On each saved server, **Tools** lists every tool that the server offers, with its cost, and you choose the ones your bots get. A server starts with its suggested tools, or all of its read-only tools if it suggests none. **Suggested**, **All read-only** and **None** set many at once. The choice matters for cost: each tool's description goes into every run's prompt, on your AI key. All of Nansen's tools are about 43,000 prompt tokens a run, and its 9 suggested ones about 8,000. Alpha Vantage goes from about 29,000 to about 2,000. Fewer tools also help a model choose the right one, and some providers limit how many tools one request can have. **Tools that act.** A tool that the server does not mark read-only may act on your account there (for example, spend credit or post). It stays off until you turn on **Allow tools not marked read-only** for that server (with **Replace**). Then open its **Tools** and keep on only the ones you want. Allow it only for servers that you trust. **Why each needs your own key.** Every bot's calls come from Spin's servers. Without a key, all holders would share one free limit, and a busy hour would stop every bot at once. ## What it costs [#what-it-costs] A run with MCP tools costs: - **your AI provider:** the prompt (with the tool descriptions), the data that the tools send back, and the answer. A model often calls two or three tools in a run. - **the data service:** each tool call, on that service's plan. Nansen charges credits for each call. Alpha Vantage and EODHD have free keys with small daily limits, and paid plans. The strategy's trigger and **AI runs an hour at most** set how many runs there are. Start slow: a run every few hours is a few runs a day. ## Example 1: buy a tokenised stock, but not into bad news or earnings [#example-1-buy-a-tokenised-stock-but-not-into-bad-news-or-earnings] Buys a little TSLA (the tokenised stock on Robinhood Chain) every 6 hours, adding to one position. It skips a buy when the day's news is negative, or when Tesla reports earnings within 2 days. Needs: Alpha Vantage, and any AI key. ```json { "schema": 1, "name": "TSLA buys with a news check", "entry": { "trigger": { "on": "timer", "every_s": 21600 }, "target": { "token": "0x322f0929c4625ed5bad873c95208d54e1c003b2d" }, "ai": { "steps": [ { "id": "news", "tools": ["alphavantage"], "prompt": "Read the news sentiment for TSLA from the last 24 hours, and the date of Tesla's next earnings report. Is the news on balance negative? Is the report in the next 2 days?", "output": { "sentiment": ["negative", "neutral", "positive"], "earnings_soon": "boolean", "summary": "text" } } ] }, "confirm": { "and": [{ "!=": [{ "f": "ai.news.sentiment" }, "negative"] }, { "==": [{ "f": "ai.news.earnings_soon" }, false] }] }, "buy_eth": 0.005 }, "exits": [], "limits": { "once_per_token": false, "max_open": 1, "add_to_position": true, "max_ai_runs_per_hour": 2 } } ``` **Change it:** another stock (its token's address, and its ticker in the prompt); EODHD in place of Alpha Vantage (`get_company_news`, `get_sentiment_data` and `get_upcoming_earnings` give the same facts); a take-profit exit, if you want it to sell. **Cost:** 4 runs a day, each one AI request and two or three tool calls. ## Example 2: follow smart money on Robinhood Chain [#example-2-follow-smart-money-on-robinhood-chain] Every hour, asks Nansen which token smart traders and funds bought most on Robinhood Chain in the last day. If at least 3 smart wallets bought it, DeFade checks it. The bot buys only on a low rug-pull risk and at least 5 ETH of liquidity. It sells when Nansen shows smart money selling, on a 25% loss, or after a week. Needs: Nansen, DeFade, and any AI key. ```json { "schema": 1, "name": "Follow smart money on Robinhood Chain", "entry": { "trigger": { "on": "timer", "every_s": 3600 }, "target": { "token": "{{flow.token}}" }, "ai": { "steps": [ { "id": "flow", "tools": ["nansen"], "prompt": "On Robinhood Chain (chain robinhood), which token had the largest net inflow from smart traders and funds in the last 24 hours? Leave out ETH, WETH, USDG and stablecoins. Give its address, the number of smart wallets that bought it, and the net amount in dollars.", "output": { "token": "token", "wallets": "number", "net_usd": "number" } }, { "id": "check", "tools": ["defade"], "if": { ">=": [{ "f": "ai.flow.wallets" }, 3] }, "prompt": "Check token {{flow.token}} on Robinhood Chain: honeypot, sell tax, holders, snipers, deployer history. What is its rug-pull risk?", "output": { "risk": ["low", "medium", "high"] } } ] }, "confirm": { "and": [{ ">=": [{ "f": "ai.flow.wallets" }, 3] }, { "==": [{ "f": "ai.check.risk" }, "low"] }, { ">=": [{ "f": "token.liquidity" }, 5] }] }, "buy_eth": 0.01 }, "exits": [ { "ai": { "every_s": 3600, "steps": [ { "id": "out", "tools": ["nansen"], "prompt": "On Robinhood Chain, have smart traders and funds been net sellers of token {{token.address}} over the last 6 hours?", "output": { "selling": "boolean" } } ] }, "confirm": { "==": [{ "f": "ai.out.selling" }, true] }, "reason": "smart_money_out" }, { "if": { "<=": [{ "f": "position.pnl_pct" }, -25] }, "reason": "stop_loss" }, { "if": { ">=": [{ "f": "position.age_s" }, 604800] }, "reason": "time" } ], "limits": { "once_per_token": true, "max_open": 3, "max_ai_runs_per_hour": 4 } } ``` **How it works:** the first step's `token` answer is the token that the strategy buys (`"target": { "token": "{{flow.token}}" }`). The check step runs only when its `if` holds, so a quiet hour costs one step. With **Once per token** on, a token is bought at most once. **Cost:** 24 entry runs a day, plus one exit check an hour for each open position. Each Nansen call uses credits: see Nansen's pricing before you make the timer faster. ## Example 3: a stock DCA that waits out rate decisions [#example-3-a-stock-dca-that-waits-out-rate-decisions] Buys TSLA once a day, but skips the day when the Federal Reserve announces a rate decision or a US inflation report comes out, when prices often move most. Needs: EODHD, and any AI key. ```json { "schema": 1, "name": "Stock DCA that waits out rate decisions", "entry": { "trigger": { "on": "timer", "every_s": 86400 }, "target": { "token": "0x322f0929c4625ed5bad873c95208d54e1c003b2d" }, "ai": { "steps": [ { "id": "calendar", "tools": ["eodhd"], "prompt": "Read the US economic calendar for the next 24 hours. Is there a Federal Reserve rate decision, or a US CPI (inflation) report? Name it if there is.", "output": { "big_event": "boolean", "event": "text" } } ] }, "confirm": { "==": [{ "f": "ai.calendar.big_event" }, false] }, "buy_eth": 0.01 }, "exits": [], "limits": { "once_per_token": false, "max_open": 1, "add_to_position": true, "max_ai_runs_per_hour": 1 } } ``` **Change it:** the opposite (buy only on those days); other events (jobs reports, a central bank of another country); the same check as a second step in Example 1. **Cost:** one run a day, one or two tool calls. ## Example 4: read a contract's code before a buy [#example-4-read-a-contracts-code-before-a-buy] For tokens that are not from a launchpad (for example, an address posted on X: see [Watch X for contract addresses](/guides/watch-x-for-contract-addresses)), add a step that reads the contract on Blockscout. It asks if the code is verified, and if the owner can still mint, block transfers, change the tax or pause trading. Needs: Blockscout, and any AI key. Add this step after the step that finds the token (here, `watch`): ```json { "id": "code", "tools": ["blockscout"], "if": { "==": [{ "f": "ai.watch.confident" }, true] }, "prompt": "On Robinhood Chain (chain id 4663), inspect the contract of token {{watch.token}}. Is its source code verified? Can the owner mint more, block transfers, change the tax, or pause trading? Has the owner given up control?", "output": { "verified": "boolean", "owner_powers": ["none", "some", "dangerous"] } } ``` Then buy only when both answers are good: ```json "confirm": { "and": [{ "==": [{ "f": "ai.watch.confident" }, true] }, { "==": [{ "f": "ai.code.verified" }, true] }, { "==": [{ "f": "ai.code.owner_powers" }, "none"] }] } ``` Blockscout opens a session before its other tools, so this step makes one more tool call than it seems to. Exa can do a similar check from the web: ask it for news of the people behind the token, or reports of a scam, by the token's name. ## Write prompts that work with tools [#write-prompts-that-work-with-tools] - **Name the chain.** Nansen calls it `robinhood`. Blockscout uses chain id `4663`. Without it, a model may look on Ethereum. - **Ask for exact facts, in the answer's fields.** A number, a yes or no, or one of a few words is easy for a rule to check. Put the explanation in a `text` field, for the activity. - **Say what to leave out** (stablecoins, ETH), and what to answer when there is nothing. A `token` field can be null: the bot then buys nothing. - **Keep chains short.** Each tool call takes time. A chain must answer within its **Answer within** time (60 seconds unless you set it, at most 120). A late answer is no signal. - **Check before you trust.** Rules can read the token's own values too (`token.liquidity`, `token.market_cap`, `token.buy_tax`). Use them with the answers. ## When a server fails [#when-a-server-fails] If a step names a server that you have not added, or a server stops answering, the Spinner's page shows it under **Needs your attention** ("An MCP server is missing", or "An MCP server does not answer"). The Spinner's card on **My spinners** is marked too. Nothing is bought on a failed step. Check the server's key in **Settings**, then mark the notice as read when it is fixed. # Watch X for contract addresses (/guides/watch-x-for-contract-addresses) The bot watches X (accounts that you choose, or a search across all of X) for a token's contract address. It checks the token, buys a small amount, and exits on your usual rules. This guide shows three ways to build it, from the simplest to the fastest. | Way | Tier | Speed | What you need | | --- | --- | --- | --- | | A. Grok searches X on a timer | Epic | every 1 to 5 minutes, plus a few seconds | an xAI API key | | B. The X MCP server on a timer | Epic | every 1 to 5 minutes, plus a few seconds | an X API bearer token (pay-per-use), and any AI key | | C. Your own service calls the bot's webhook | Legendary | seconds after your service sees the post | a service of your own that watches X (or anything else) | Every way ends the same. The bot looks up the token's market (a Pons or Torch token on its launchpad, any other token in its pools on UP and Uniswap). It checks your rules with the token's own values, and buys only if they hold. With **Once per token** on, a token is bought at most once, however often it is posted. Posts on X are untrusted. Anyone can post a scam address in the hope that a bot buys it, and accounts are copied and hacked. Keep the buy small, add a check step (below), keep your live trading limits low, and run on paper first. AI strategies cannot be backtested: what a model would have answered on past days cannot be known. This guide shows how to build a strategy, not one that is known to make money. ## A. Grok searches X (simplest) [#a-grok-searches-x-simplest] ### Add your xAI key [#add-your-xai-key] On **Settings**, in **AI keys**, add your xAI (Grok) key. See [AI keys](/ai/ai-keys). ### Set the trigger [#set-the-trigger] On the Spinner's **Strategy** tab, open the **When** block. In **Start when**, choose **On a timer**. Set **Every** to 2 minutes. ### Add the AI step [#add-the-ai-step] Add an **AI step**: - **Step name:** `watch`. - **AI provider:** xAI (Grok). - **Search X** on. In **Only posts from**, the accounts that you trust (up to 20). In **Posts from**, **The last day**. - Answer fields: `token`, which holds **A token's address, to buy (or none found)**, and `confident`, which holds **Yes or no**. ### Set the token and the check [#set-the-token-and-the-check] - In the outcome block, set **The token to buy** to "The token the step "watch" names". - In **Then buy if**: `ai.watch.confident` is yes, and `token.liquidity` is at least 3 ETH. (The token's market has at least that much ETH. A scam posted to be bought rarely has.) - **Buy:** a small amount, in ETH or in dollars with the ETH or $ switch. ### Add exits and limits [#add-exits-and-limits] - Exits: a take profit, a stop loss and a time exit. - **Limits:** **Once per token** on. Set **AI runs an hour at most** to 30 or more: a 2-minute timer runs 30 times an hour. The same strategy in the **JSON** tab: ```json { "schema": 1, "name": "X contract watch", "entry": { "trigger": { "on": "timer", "every_s": 120 }, "target": { "token": "{{watch.token}}" }, "ai": { "steps": [ { "id": "watch", "provider": "xai", "search": { "x": { "handles": ["@account_one", "@account_two"], "days": 1 } }, "prompt": "Has any of these accounts posted a token contract address on Robinhood Chain in the last 5 minutes? Give the newest one exactly as posted, or null if none. Say whether you are confident it is the account's own call, not a reply or a quote of someone else.", "output": { "token": "token", "confident": "boolean" } } ] }, "confirm": { "and": [{ "==": [{ "f": "ai.watch.confident" }, true] }, { ">=": [{ "f": "token.liquidity" }, 3] }] }, "buy_eth": 0.005 }, "exits": [ { "if": { ">=": [{ "f": "position.multiple" }, 2] }, "reason": "take_profit", "sell_pct": 50 }, { "if": { "<=": [{ "f": "position.pnl_pct" }, -30] }, "reason": "stop_loss" }, { "if": { ">=": [{ "f": "position.age_s" }, 7200] }, "reason": "time" } ], "limits": { "once_per_token": true, "max_open": 3, "max_ai_runs_per_hour": 30 } } ``` **Cost:** each run is one Grok request with X search, on your xAI key. See xAI's pricing. A 2-minute timer is 720 runs a day. ## B. The X MCP server (exact posts from exact accounts) [#b-the-x-mcp-server-exact-posts-from-exact-accounts] Grok's search filters posts by day, and it chooses what to search. X's own MCP server returns the exact posts of the accounts that you name, with their times. ### Get a bearer token [#get-a-bearer-token] In the X developer portal, create an app on the pay-per-use plan. Copy its **bearer token** (app-only: it can read, never post). ### Add the X server [#add-the-x-server] On **Settings**, in **MCP servers**, click **Add X**. Paste the bearer token into **API key or token**, then click **Connect and save**. The bot gets X's read tools only: accounts, an account's posts and mentions, post search and counts, trends and news. It gets nothing that posts or sends. See [MCP servers](/ai/mcp-servers). ### Change the step [#change-the-step] Build the strategy as in A, but change the `watch` step: any provider, no search, and the X server as its tool. Its prompt names the accounts. ```json { "id": "watch", "tools": ["x"], "prompt": "Read the latest posts of @account_one and @account_two from the last 5 minutes. Has either posted a token contract address on Robinhood Chain? Give the newest one exactly as posted, or null if none. Say whether you are confident it is the account's own call, not a reply or a quote of someone else.", "output": { "token": "token", "confident": "boolean" } } ``` **Cost:** X bills each read on your bearer token (see X's pricing). The AI step costs the same as any other step on your key. ## Add a check step (recommended for A and B) [#add-a-check-step-recommended-for-a-and-b] Add a second step that checks the token before the bot buys it, with a rug-risk MCP server. DeFade is one click in **MCP servers**. ```json { "id": "check", "tools": ["defade"], "if": { "==": [{ "f": "ai.watch.confident" }, true] }, "prompt": "Check token {{watch.token}} on Robinhood Chain: honeypot, sell tax, holders, snipers, deployer history. Is it safe to buy a small amount?", "output": { "risk": ["low", "medium", "high"] } } ``` Then buy only on a low risk: ```json "confirm": { "and": [{ "==": [{ "f": "ai.watch.confident" }, true] }, { "==": [{ "f": "ai.check.risk" }, "low"] }, { ">=": [{ "f": "token.liquidity" }, 3] }] } ``` The check step runs only when the first step found something (its `if`), so most runs cost one request. For a token that is not from a launchpad, a step can also read its contract on Blockscout: see [MCP data sources](/guides/mcp-data-sources#example-4-read-a-contracts-code-before-a-buy). Rules can also read the token's own values once its market is known: - `token.liquidity`: the ETH in its market. It is the real ETH on a Pons curve, in a Torch pool, in a graduated Pons pool and in a v2-style pool. For other Uniswap and UP pools, it is the ETH depth near the price, which a narrow position can make look deeper than it is. - `token.buy_tax`: a Torch token's tax. - `token.market_cap`. A brand-new token's liquidity is known at once. See [conditions](/strategies/conditions) for every value. ## C. Your own service and the bot's webhook (Legendary) [#c-your-own-service-and-the-bots-webhook-legendary] For speed, run your own watcher (X's filtered stream, a Telegram listener, a chart alert) and let it call the bot the moment it sees something. ### Set up the strategy [#set-up-the-strategy] In **Start when**, choose **My own service calls its webhook (Legendary)**. Declare the fields that it sends, for example `token` (a token's address) and `score` (a number from 0 to 1). Set **The token to buy** to "The token your service sends". Add a rule such as `hook.score >= 0.7`. You can still add AI steps: their prompts can use `{{hook.token}}`. ### Make a secret [#make-a-secret] Click **Save as new version**. On the **Webhook** card, copy the address and click **Make a secret**. The card shows the secret only once. Keep it in your service's settings, never in its code. ### Sign each call [#sign-each-call] ```js // Node.js import crypto from "node:crypto"; const body = JSON.stringify({ token: "0x0000000000000000000000000000000000000001", score: 0.9 }); const ts = Math.floor(Date.now() / 1000).toString(); const sig = "v1=" + crypto.createHmac("sha256", process.env.SPIN_HOOK_SECRET).update(`${ts}.${body}`).digest("hex"); const res = await fetch("https://spin.trading/api/hooks/123", { method: "POST", headers: { "content-type": "application/json", "x-spin-timestamp": ts, "x-spin-signature": sig, "x-spin-event-id": postId }, body, }); // 202: accepted. The bot starts the entry within seconds. ``` Sign the exact bytes that you send: the signature covers the body as sent. The same strategy in JSON: ```json { "schema": 1, "name": "My X watcher", "entry": { "trigger": { "on": "webhook", "fields": { "token": "token", "score": { "number": [0, 1] } } }, "target": { "token": "{{hook.token}}" }, "if": { "and": [{ ">=": [{ "f": "hook.score" }, 0.7] }, { ">=": [{ "f": "token.liquidity" }, 3] }] }, "buy_eth": 0.005 }, "exits": [ { "if": { ">=": [{ "f": "position.multiple" }, 2] }, "reason": "take_profit", "sell_pct": 50 }, { "if": { "<=": [{ "f": "position.pnl_pct" }, -30] }, "reason": "stop_loss" }, { "if": { ">=": [{ "f": "position.age_s" }, 7200] }, "reason": "time" } ], "limits": { "once_per_token": true, "max_open": 3 } } ``` [Webhooks](/ai/webhooks) has the signing in curl and Python, every answer the webhook can give, and its limits. In short: - The webhook refuses a call with a wrong signature, a timestamp more than 5 minutes from now, fields that the strategy does not declare, a body over 8,192 bytes, or more than 30 calls a minute or 2,000 a day. - An event id sent twice is taken once. - A new secret ends the old one at once, and a sale of the Spinner ends it too. - A call can only start an entry. It cannot move or withdraw funds. Every buy still passes the strategy's rules, its limits, and the live trading limits on the Spinner's guard. - A call that is more than 5 minutes old when the bot gets to it is dropped. ## Reading the activity [#reading-the-activity] The **Activity** tab shows each run's AI answers, and why the bot did or did not buy: | The activity says | Meaning | | --- | --- | | ai: named no token | The step found no address. | | no market found for the token the AI named (or the webhook named) | No curve or pool that the bots can trade appeared within a minute. | | confirm failed | A rule said no (for example, the risk check). | | already entered | The bot bought this token before (**Once per token**). | | max_ai_runs_per_hour reached | Raise **AI runs an hour at most**, or make the timer slower. | # Welcome to Spin (/) A **Spinner** is an NFT on Robinhood Chain. Each Spinner owns its own on-chain wallet and is a trading bot. You give it a strategy: pick a preset, build rules in the workflow editor, or describe what you want in plain English. Spin's servers then run the strategy from the Spinner's wallet, all day and all night. The bot gets a key that can only trade, and the trades can only come back to the Spinner's own wallet. Whoever holds the Spinner controls its wallet, its strategy and its record, so a sale moves all of them with the NFT. Trading meme tokens is risky, and a bot follows its rules exactly, good or bad. Spin gives you building blocks, not trading advice. Read [the risks](/safety/risks) before you trade with real funds. ## How it works [#how-it-works] | Step | What happens | | --- | --- | | 1. Mint | You mint a Spinner with $SPIN. Its rarity decides which tools its bot can use. | | 2. Activate | You activate it with $SPIN, once, to switch on its bot. | | 3. Fund | You send ETH to the Spinner's own wallet. The bot trades and pays gas from it. | | 4. Strategy | You pick a preset, build a workflow, or describe a strategy to your own AI model. | | 5. Test | You replay the strategy on recent market data, and paper trade it live without funds. | | 6. Trade | You turn on live trading, with limits that a contract enforces on every trade. | ## Where to go next [#where-to-go-next] ## For AI tools [#for-ai-tools] These docs are also available as plain text for AI tools: [llms.txt](/llms.txt) lists every page, and [llms-full.txt](/llms-full.txt) has every page in full. Each page also has a **Copy Markdown** button. # Creator fees and links (/launching/creator-fees-and-links) The Spinner's wallet launches each token, so the Spinner is the token's creator. Its creator fees accrue to the Spinner's wallet, and the Spinner's account is the only one that can claim them. The fees stay with the Spinner: if you sell the Spinner, its fees and its wallet go to the buyer. ## Where creator fees come from [#where-creator-fees-come-from] | Launchpad | Creator fees | | --- | --- | | Pons | The **Creator tax** that you set at launch, on every trade of the token. | | Torch | The creator's share of the **Buy tax**, as the split that you set at launch says. Torch keeps 30% of the tax. With the split **To the Spinner's wallet**, all of the creator's 70% goes to the Spinner. | See [Launching tokens](/launching#the-launch-fields) for these terms. They are fixed for the token's life. ## Claim creator fees [#claim-creator-fees] The **Creator fees** card is on the Spinner's **Wallet** tab. It shows when the Spinner has fees from Pons or a token on Torch. - **Pons:** one line shows the fees of all the Spinner's Pons launches together. **Claim** moves them, in ETH, to the Spinner's wallet. - **Torch:** each token has its own line, with the amount to claim. **Claim** on that line moves its fees, in ETH, to the Spinner's wallet. Only the Spinner's holder can claim. Your wallet sends the claim through the Spinner's account, so you pay a little gas. Torch can sweep a token's unclaimed creator fees after 60 days without a claim or a new fee. The card warns you from day 50. Claim before day 60. If the Spinner is no longer a Torch token's creator, its line says "The Spinner is no longer its creator.", and it has no **Claim** or **Edit links**. ## Add links to a Torch token [#add-links-to-a-torch-token] A launch has no website, X or Telegram link: a strategy's launch has no fields for links. On Torch, the token's creator can set its links after the launch. The Spinner's account is the creator, so you set them through it. ### Open the links [#open-the-links] On the **Wallet** tab, in **Creator fees**, find the token. Click **Edit links**. ### Fill in the links [#fill-in-the-links] | Field | What to put | | --- | --- | | **Website** | A whole `https://` link. | | **X** | An account: `@name`, or its `x.com` link. | | **Telegram** | A group or channel: `@name`, or its `t.me` link. | Leave a field empty to remove that link. ### Save [#save] Click **Save links**. Spin writes the token's new metadata with these links. Your wallet then sends the change through the Spinner's account, for a little gas. Torch shows the links with the token. Spin can change only the links of a Torch token that the Spinner launched, while the Spinner is still its creator. ## Why Pons launches have no links [#why-pons-launches-have-no-links] Pons fixes a token's links when it launches, and nobody can change them later. A Spinner's launch has no fields for links, so a Pons launch has none, and it can never have any. If links matter for a token, launch it on Torch. # Launching tokens (/launching) A strategy can launch a new token instead of buying one. The launch is the strategy's outcome, like a buy: when the trigger fires and the rules hold, the Spinner's wallet launches a token on Pons or Torch. The Spinner is the token's creator, so the token's creator fees are its own. Every launch is written by an AI step on your own key. The step writes the token's name, ticker and description, can draw its image, and can decide that nothing is worth launching. On a [webhook](/ai/webhooks#launch-from-a-webhook), your own service can write the launch instead. ## Tiers [#tiers] | Tier | What it allows | | --- | --- | | Rare | Launches, written by AI steps without MCP servers. A step on xAI can use Grok's X search, which is not an MCP server. | | Epic | Launches whose AI steps read [MCP servers](/ai/mcp-servers). | | Legendary | Launches started by your own service through a [webhook](/ai/webhooks), and written by your service or by AI steps. | ## Set up a launch [#set-up-a-launch] ### Choose the outcome [#choose-the-outcome] In the workflow editor, open the outcome block. In **Outcome**, choose **Launch a token (Pons or Torch)**. The editor adds an AI step named `idea` that writes the token, and a **Then launch if** rule on its answer. Or start from the preset **AI launches a token, once a day**. ### Choose the trigger [#choose-the-trigger] A launch can follow any trigger. A timer is the usual one: for example, once a day the AI proposes a token, or passes. ### Write the prompt [#write-the-prompt] Edit the `idea` step's prompt: the theme, the tone, what to avoid. Keep the answer fields that the launch uses (`name`, `symbol`, `description`), and a yes or no field (`launch`) that lets the AI pass. ### Choose the launchpad and terms [#choose-the-launchpad-and-terms] In **Launch on**, choose **Pons** or **Torch**, then set its terms. See [the launch fields](#the-launch-fields). ### Set the limits [#set-the-limits] Set **Launches a day at most** and **AI runs an hour at most**. Each launch costs its dev buy and gas, and Pons charges a fee for each launch. ## The AI step writes the token [#the-ai-step-writes-the-token] The token's name, ticker, description and image must each be exactly one answer by name, for example `{{idea.name}}`. They can never be fixed text, because each launch is a new token, not the same one again. On a webhook, they can also be webhook fields, for example `{{hook.name}}`. | Field | Editor | Rules | | --- | --- | --- | | `name` | **Token name** | Needed. Cut to 32 characters. | | `symbol` | **Ticker** | Needed. Spin keeps letters and digits only, in upper case, up to 10. | | `description` | **Description** | Optional. Cut to 1,000 characters. | | `image` | **Image** | Optional. An image that a step draws, or a link to one. Empty: no image. | If the name or the ticker comes out empty, or the AI gave no answer for it, nothing is launched. The activity says "launch: the name or ticker came out empty", and the Spinner's page shows "A launch had no name or ticker". Change the prompt so that it asks for both. **Then launch if** reads the step's answers, for example `ai.idea.launch == true`. If it does not hold, nothing is launched. ## Draw the image [#draw-the-image] Turn on **Draw its image** in the outcome block. The editor adds a step named `art`: - It runs only if the `idea` step says to launch. - It draws one square image with your image model. It needs an OpenAI, xAI or Google key. - Its answer is the image's link, and the launch's **Image** becomes `{{art.url}}`. The image can also be a link that a step found, for example `{{trend.image_url}}`, or a link that your webhook sends. A link must start with `https://` or `ipfs://`. See [image steps](/ai/ai-steps#image-steps). ## The launch fields [#the-launch-fields] Both launchpads take the token's fields above and a dev buy. | Field | Editor | Values | | --- | --- | --- | | `dev_buy_eth` | **Dev buy** | The Spinner's own first buy, in ETH, from 0 to 10. 0 if you do not set it. | **Dev buy.** The Spinner's wallet buys the new token in the launch itself, so nothing can trade before it. The dev buy counts against your live trading limits on the **Wallet** tab. A Pons token starts on a bonding curve, and moves to a Uniswap pool once the curve holds 4.2 ETH. Pons charges 0.0005 ETH for each launch. | Field | Editor | Values | | --- | --- | --- | | `creator_tax_pct` | **Creator tax** | A tax on every trade, paid to the Spinner. From 0 to 10%, 2% if you do not set it. | | `buyback` | **Buyback** | Pons buys back and locks the token with part of the fees. Off if you do not set it. | A Torch token puts all of its supply (1,000,000,000 tokens) in a Uniswap pool from the first block, locked. There is no curve and no move to a pool. The pool's fee is 0.3%. Torch keeps 30% of the buy tax, and the creator's 70% goes where the split says. | Field | Editor | Values | | --- | --- | --- | | `preset` | **Starting point** | The starting market cap and the anti-snipe time. See below. `launch` if you do not set it. | | `buy_tax_pct` | **Buy tax** | A tax on buys only, fixed for the token's life. From 1 to 10%, 2% if you do not set it. Sells are not taxed. | | `split` | **Where the tax goes** | Where the creator's 70% of the tax goes, fixed for the token's life. `creator` if you do not set it. | **Starting points.** With anti-snipe, the buy tax starts at 80% and falls evenly to the token's rate over the anti-snipe time. | `preset` | Editor | Starting market cap | Anti-snipe | | --- | --- | --- | --- | | `degen` | Degen | 1 ETH | 30 seconds | | `launch` | Launch | 2.5 ETH | 15 seconds | | `steady` | Steady | 5 ETH | 15 seconds | **Splits.** | `split` | Editor | | --- | --- | | `creator` | To the Spinner's wallet | | `burn` | Buy back and burn the token | | `holders` | To the token's holders | | `creator_burn` | Half to the Spinner, half burned | | `creator_holders` | Half to the Spinner, half to holders | | `burn_holders` | Half burned, half to holders | A Spinner's Torch token gets an address that ends in `1111`. Torch marks "Launch Complete" when the price reaches 10 times its start. That is a marker in Torch's app only: nothing changes on chain. ## Example [#example] Once a day, the AI proposes a token or passes. If it says to launch, a second step draws the image, and the Spinner launches the token on Torch with no dev buy. This is an illustration to learn from, not a strategy that is known to make money. ```json { "schema": 1, "name": "AI launch", "entry": { "trigger": { "on": "timer", "every_s": 86400 }, "ai": { "steps": [ { "id": "idea", "prompt": "Propose one new meme token to launch on Robinhood Chain. Give its name (at most 32 characters), its ticker (letters and digits, at most 10) and a one-line description. Answer launch no if nothing is worth launching today.", "output": { "launch": "boolean", "name": "text", "symbol": "text", "description": "text" } }, { "id": "art", "if": { "==": [{ "f": "ai.idea.launch" }, true] }, "prompt": "A bold, simple square logo for a meme token called {{idea.name}} ({{idea.symbol}}): {{idea.description}}. No text.", "output": { "url": "image" } } ] }, "confirm": { "==": [{ "f": "ai.idea.launch" }, true] }, "launch": { "launchpad": "torch", "name": "{{idea.name}}", "symbol": "{{idea.symbol}}", "description": "{{idea.description}}", "image": "{{art.url}}", "dev_buy_eth": 0, "preset": "launch", "buy_tax_pct": 2, "split": "creator" } }, "exits": [], "limits": { "max_launches_per_day": 1, "max_ai_runs_per_hour": 2 } } ``` For Pons, replace the last three launch fields with `"creator_tax_pct": 2` and `"buyback": false`. A launching strategy gives `launch` instead of `buy_eth`, and has no `target`. ## Limits [#limits] - **Launches a day at most** (`limits.max_launches_per_day`): from 1 to 10, 1 if you do not set it. It counts the launches of the last 24 hours, and holds across a restart of Spin's servers. - **AI runs an hour at most** (`limits.max_ai_runs_per_hour`): see [AI steps](/ai/ai-steps#how-often-the-ai-runs). - Your live trading limits on the **Wallet** tab apply to the dev buy. ## A launch is not a position [#a-launch-is-not-a-position] The launched token and any dev buy stay in the Spinner's wallet. No exit sells them, so a launching strategy has no exits. The **Wallet** tab shows them, and you can **Withdraw** them to your own wallet. A launch cannot be backtested, because how a token that was never launched would have traded cannot be known. On paper, no token is launched. ## You are the creator [#you-are-the-creator] The Spinner's wallet launches the token, so the Spinner is its creator. You are responsible for the token's name, ticker, description and image. Spin does not check AI prompts or launches with a moderation step. Your AI provider applies its own policies to what its models write and draw. Creator fees go to the Spinner's wallet. See [Creator fees and links](/launching/creator-fees-and-links). # Contract addresses (/reference/contract-addresses) Spin runs on **Robinhood Chain**, an Ethereum layer 2. | Network | Value | |---|---| | Chain id | 4663 | | Gas token | ETH | | Explorer | [robinhoodchain.blockscout.com](https://robinhoodchain.blockscout.com) | The tables below come from the Spin app's own settings. Each address links to the explorer. Before you send ETH or tokens to a contract, or approve one, check its address on this page. Scam tokens and sites often copy names. Spin's app only ever uses the addresses on this page. ## Spin's contracts [#spins-contracts] ## Contracts Spin uses [#contracts-spin-uses] These contracts are not Spin's. The app and the bots use them. ## "TBC" [#tbc] "TBC" means that the contract is not deployed on Robinhood Chain yet. This page shows its address when it is deployed. Until then, the app does not use it. For example, bots trade on paper until the guard is deployed. Each Spinner's own wallet has its own address. It is not on this page. Find it on the Wallet tab of the bot's page. See [the Spinner's wallet](/spinners/wallet). # FAQ (/reference/faq) ## What is a Spinner? [#what-is-a-spinner] A Spinner is an NFT on Robinhood Chain. Each one is a trading bot with its own wallet. You give it a strategy, and Spin's servers run it. See [Spinners](/spinners). ## Do I give Spin my keys? [#do-i-give-spin-my-keys] No. The bot trades from the Spinner's own wallet, never from yours. You give the bot a trading key that works only through the guard contract. See [custody and the guard](/safety). ## Can Spin withdraw my funds? [#can-spin-withdraw-my-funds] No. Spin's servers can only send trades that the guard checks, through listed venue adapters, within your limits. Only the wallet that holds the Spinner can withdraw. See [what Spin's servers can and cannot do](/safety). ## What does it cost? [#what-does-it-cost] Minting costs 10,000 $SPIN. Activation costs 5,000 $SPIN. A live bot pays 0.5% of each trade, each way, and the Spinner's wallet pays its own gas. AI steps run on your own API key. There is no subscription. See [fees and burns](/token/fees-and-burns). ## Which chain does Spin use? [#which-chain-does-spin-use] Robinhood Chain, an Ethereum layer 2 (chain id 4663). Gas and trade amounts are in ETH. See [wallet and network](/getting-started/wallet-and-network). ## Where can a bot trade? [#where-can-a-bot-trade] On UP, Uniswap (V3 and V4), Pons and Torch. For a chosen token, the bot uses the pool with the best quote at the time of each trade. See [venues](/trading). ## What is the difference between paper and live trading? [#what-is-the-difference-between-paper-and-live-trading] A paper bot runs your strategy on the live market, but with no money: it records what it would have done. A live bot trades real ETH from the Spinner's wallet. See [live trading](/spinners/live-trading). ## Do backtests show what I will make? [#do-backtests-show-what-i-will-make] No. A backtest replays a strategy on past trades. Live results will differ. See [backtests](/strategies/backtests) and [risks](/safety/risks). ## How do I stop my bot? [#how-do-i-stop-my-bot] Pause it on its page: it makes no new trades, and open positions still exit by their rules. To stop live trading fully, switch it to paper, or revoke the bot's key and limits on the Wallet tab. See [what you control](/safety). ## Why did my bot not make a trade? [#why-did-my-bot-not-make-a-trade] Look at the bot's activity and notices. Common reasons: - The price moved past the strategy's slippage limit. - The trade was over your per-trade or per-day limit. - The Spinner's wallet did not have enough ETH for the trade, the fee and the gas. - Your limits expired. See [limits](/strategies/limits). ## What happens when I sell my Spinner? [#what-happens-when-i-sell-my-spinner] The wallet, everything in it, the strategy and the record go to the buyer. The Spinner becomes inactive, and the buyer pays the activation fee again. Withdraw your funds before you list it. See [transfers](/spinners/transfers). ## How do I get more tools without a rarer Spinner? [#how-do-i-get-more-tools-without-a-rarer-spinner] Hold $SPIN in the wallet that holds the Spinner. It unlocks the tools of higher tiers. Nothing is spent or locked. See [hold-to-unlock](/token) and [rarity and tiers](/spinners/rarity-and-tiers). ## Who gets the weekly airdrop? [#who-gets-the-weekly-airdrop] Every Spinner whose live bot is ranked on the 7-day leaderboard at the end of the week. A higher rank gets a bigger share. See [the weekly airdrop](/token/airdrop). ## Can I lose money? [#can-i-lose-money] Yes. Many strategies lose money, and meme tokens often go to zero. Only use money you can afford to lose. See [risks](/safety/risks). ## Does Spin see my AI results or share them? [#does-spin-see-my-ai-results-or-share-them] Your AI steps run on your own API key. Spin keeps cached answers per holder only. It never shares them with other holders, and another holder's key never pays for your answers. See [AI keys](/ai/ai-keys). ## Is the USDG position live? [#is-the-usdg-position-live] Not yet. It is built for Legendary Spinners, but it is not deployed on Robinhood Chain yet. See [USDG position](/trading/usdg-position). ## Where do I find the contract addresses? [#where-do-i-find-the-contract-addresses] On the [contract addresses](/reference/contract-addresses) page. Check an address there before you send anything to it. # Glossary (/reference/glossary) | Term | Meaning | |---|---| | $SPIN | Spin's token. You use it to mint and activate Spinners and to unlock higher tiers. Trading fees buy it back and burn it. See [$SPIN](/token). | | Activation | The 5,000 $SPIN fee that switches a Spinner's bot on. 70% is burned and 30% goes to the protocol. A sale or transfer resets it. See [activation](/spinners/activation). | | Adapter | A small contract that builds the calls for one trade on one venue. The guard runs trades only through adapters that it lists. Each adapter sends a trade's output back to the Spinner's wallet. | | Agent identity (ERC-8004) | The bot's on-chain identity in the ERC-8004 identity registry. The Spinner's wallet registers it at activation, so it moves with the NFT. | | AI step | A question that a strategy asks your chosen AI model, on your own API key. A chain has up to three steps. Each step declares the shape of its answer, and your rules read it. See [AI steps](/ai/ai-steps). | | Anti-snipe | A Torch launch's extra buy tax at launch. It starts at 80% and falls to the token's own rate over the first seconds. | | Backtest | A replay of a strategy on past on-chain trades, with fees and costs, to see what it would have done. See [backtests](/strategies/backtests). | | Best quote | For a chosen token, the bot checks the token's deepest pools and trades in the one that gives the most. See [venues](/trading). | | Bonding curve | A launchpad's built-in market for a new token. The price goes up as people buy and down as they sell. Pons uses one. | | Burn | To destroy tokens for good, so the supply gets smaller. | | Buy tax | A tax that a token takes on each buy. Every Torch token has one, from 1% to 10%, set at launch. | | Chosen token | A token that you pick in a strategy for the bot to buy, instead of the token that started the entry. It trades on UP or Uniswap. | | Condition | A check in a strategy that must be true before the bot acts, such as "at least 30 buyers in 60 seconds". See [conditions](/strategies/conditions). | | Creator fees | Fees that a launchpad pays to the creator of a token. $SPIN's creator fees fund the [weekly airdrop](/token/airdrop). Tokens that your bot launches pay their creator fees to the Spinner's wallet. | | DCA | Dollar-cost averaging: buying a fixed amount of a token on a schedule. | | Exit | A rule that sells all or part of a position, such as take profit, stop loss or a time limit. See [exits](/strategies/exits). | | Gas float | The small amount of ETH that a USDG position keeps to pay for its own steps. | | Graduation | When a Pons token's bonding curve fills and the token moves to its Uniswap V4 pool. Torch has no graduation: "Launch Complete" is only a display marker at 10 times the starting price. | | Guard | SpinBotGuard: the contract that checks every trade a bot sends. It allows only listed adapters, within the limits that the holder sets. See [custody and the guard](/safety). | | Holder | The wallet that holds a Spinner. Only the holder can change the bot's strategy and limits, and withdraw from its wallet. | | Hook | Code that a Uniswap V4 pool runs on each swap. It can take a fee. The bot uses a V4 pool with a hook only if the Uniswap adapter allows that hook. | | Launchpad | A platform that creates new tokens and their first market. Spin bots trade on, and launch tokens on, Pons and Torch. See [launching](/launching). | | Leaderboard | The public ranking of live bots by P/L over 1, 7 and 30 days. See [leaderboard](/token/leaderboard). | | Limits | The most ETH a bot may spend per trade and per day, and when the limits expire. The holder sets them on the guard. | | Live trading | Trading with real ETH from the Spinner's wallet, through the guard. See [live trading](/spinners/live-trading). | | MCP server | A service that gives AI models tools to read data, through the Model Context Protocol. You connect the ones your AI steps may use. See [MCP servers](/ai/mcp-servers). | | P/L | Profit and loss: ETH from sales, less ETH spent on buys, plus what selling the open positions would return now. | | Paper trading | Running a strategy on the live market with no money. The bot records what it would have done. | | Pause | Stops a bot's new trades. Open positions still exit by their rules. | | Position | What a bot holds of one token after a buy, until its exits sell it. | | Preset | A ready-made strategy that you can use as it is or change. Presets are starting points. See [presets](/strategies/presets). | | Protocol | Spin itself. The protocol gets its share of the fees in its treasury. | | Rarity | A Spinner's trait from the collection: Common, Uncommon, Rare, Epic or Legendary. It sets the tier the Spinner starts with. See [rarity and tiers](/spinners/rarity-and-tiers). | | Risk level | The choice of venue types for a USDG position: Stable, Balanced or Active. See [USDG position](/trading/usdg-position). | | Robinhood Chain | An Ethereum layer 2 network (chain id 4663) where Spinners live. Gas is paid in ETH. | | Slippage | How much less you get than the quote, because the price moved or your own trade moved it. A strategy sets the most slippage it accepts. | | Spinner | One NFT of the Spin collection. Each one is a trading bot with its own wallet. See [Spinners](/spinners). | | Strategy | The rules a bot follows: what starts an entry, what it checks, what it buys, and how it exits. See [strategies](/strategies). | | Tier | The set of tools a Spinner's bot can use. It is the higher of the Spinner's rarity and what the holder's $SPIN unlocks. | | Tokenbound account | The Spinner's own smart-contract wallet (ERC-6551). The NFT owns it, so whoever holds the Spinner controls it. | | Trading fee | 0.5% of each bot trade, each way, taken by the guard. 70% buys back and burns $SPIN, and 30% goes to the protocol. | | Trigger | The event that starts a strategy's entry: a launch, a trade, a timer, or a call to its webhook. See [triggers](/strategies/triggers). | | USDG | Robinhood's dollar token on Robinhood Chain. The USDG position holds it. | | Venue | A place where a bot trades: UP, Uniswap, Pons or Torch. See [venues](/trading). | | Version | Each time you save a strategy, Spin keeps it as a new version. You can see older versions and use one again. See [versions](/strategies/versions). | | Webhook | A signed call from your own service that starts an entry for your bot (Legendary). See [webhooks](/ai/webhooks). | | Weekly airdrop | 70% of $SPIN's creator fees, shared each week between the Spinners whose bots are ranked on the 7-day leaderboard. See [weekly airdrop](/token/airdrop). | # Custody and the guard (/safety) You never give Spin your keys. Each Spinner has its own wallet, and only the wallet that holds the Spinner controls it. Spin's servers run the bot, but they can only send trades through a contract that checks each one: the **guard** (SpinBotGuard). ## The Spinner's own wallet [#the-spinners-own-wallet] Each Spinner owns a smart-contract wallet: a Tokenbound account (ERC-6551). The NFT owns the wallet, so whoever holds the Spinner controls it. - The bot trades only from this wallet. It never touches your own wallet. - You can deposit and withdraw ETH and tokens at any time, from the Wallet tab. See [the Spinner's wallet](/spinners/wallet). - The wallet works without Spin. If Spin's servers are down, you still control the wallet on chain. ## How live trading is switched on [#how-live-trading-is-switched-on] Live trading needs four steps. The Wallet tab shows each one. See [live trading](/spinners/live-trading). 1. The Spinner is [active](/spinners/activation). 2. You give the bot its trading key. This lets the guard contract act for the Spinner's wallet. Spin gives this permission only to the guard contract, never to a plain key. 3. You set the limits: the most ETH per trade, the most ETH per day, and how long the limits last (up to 365 days). 4. The Spinner's wallet holds ETH. The guard is not deployed on Robinhood Chain yet. Until it is, bots trade on paper only. ## What the guard allows [#what-the-guard-allows] For each trade, the guard: - Accepts the trade only from Spin's servers, and only for a genuine Spinner wallet. - Checks that the Spinner is active and that your limits are set and not expired. - Runs the trade only through a venue adapter that it lists. Each adapter sends everything a trade produces back to the Spinner's wallet. See [venues](/trading). - Measures the ETH that leaves the wallet, with the fee and gas included, and checks it against your limits. - Takes the 0.5% trading fee and pays the trade's gas from the wallet. The contract caps both. ## What the guard refuses [#what-the-guard-refuses] - A trade through an adapter that it does not list. - A call to the Spinner's wallet itself or to the guard. - A buy over your per-trade limit or your per-day limit. - Any trade after your limits expire, after you take the trading key back, or after the Spinner is sold. While live trading is on, your per-trade and per-day limits never stop a sell. So the bot can always exit a position. After your limits expire or you revoke the key, the bot cannot sell either: you can then withdraw the tokens from the wallet yourself. ## What Spin's servers can and cannot do [#what-spins-servers-can-and-cannot-do] | Spin's servers can | Spin's servers cannot | |---|---| | Send trades that the guard checks, through listed adapters | Withdraw ETH or tokens to any address | | Buy within your limits | Change your limits | | Sell what the bot holds | Trade after you take the key back | | Take the 0.5% fee and the trade's gas, both capped in the contract | Use your own wallet | Spin's servers also run your strategy, your AI steps and your backtests. They follow your rules, but they cannot get past the guard. ## What you control [#what-you-control] - **Limits.** Change the per-trade limit, the per-day limit and how long they last, at any time. - **Pause.** Pause the bot on its page. A paused bot makes no new trades. Open positions still exit by their rules. - **Paper or live.** Switch the bot back to paper at any time. - **Revoke.** Press "Revoke the bot's key and limits". This takes back the trading key and clears the limits. Either one alone stops live trading. - **Withdrawals.** Withdraw ETH and tokens from the Spinner's wallet to your own wallet at any time. ## A sale moves everything with the NFT [#a-sale-moves-everything-with-the-nft] When a Spinner is sold or transferred, its wallet, everything in it, its strategy and its record move with it. - The Spinner becomes inactive. The new holder pays the activation fee again. - The trading key and the limits that the old holder set stop working. The new holder sets their own. - Until the sale completes, the seller still controls the wallet and can move its funds. So withdraw the wallet's funds before you list a Spinner. When you buy one, pay for the Spinner and its record, not for its balance. See [transfers](/spinners/transfers). ## What still needs your trust [#what-still-needs-your-trust] - **Venue adapters.** The protocol decides which adapters the guard lists, and can add new ones. Each adapter is a small contract that sends a trade's output back to the Spinner's wallet. Your ETH limits apply to every buy through any adapter. - **Bad trades within your limits.** If someone took over Spin's servers, they could make bad trades within your limits. They still could not withdraw. Keep your limits as small as your strategy needs. - **Pause for everyone.** The protocol can pause the guard for every bot. You can still withdraw from the wallet while it is paused. See [risks](/safety/risks) for the full list. # Risks (/safety/risks) A trading bot is a tool. It follows your rules exactly, and it does not stop to think. Read these risks before you switch a bot to live trading. You can lose all the money in a Spinner's wallet. Nothing on this site is financial, investment or tax advice. ## Market risk [#market-risk] Prices go down as well as up. Many strategies lose money after fees and costs. A bot can lose faster than a person, because it acts on every signal its rules allow. ## Meme tokens and rugs [#meme-tokens-and-rugs] Most new tokens lose most of their value, often in minutes. - A creator can sell their tokens and crash the price. - Liquidity can disappear, so you cannot sell at a fair price. - Some token contracts stop holders from selling, or take large taxes. Rules can check liquidity, taxes and what the creator does. No rule removes this risk. ## Slippage and taxes [#slippage-and-taxes] - A fast market can fill your trade at a worse price than the quote, up to your slippage limit. - A trade that hits its slippage limit does not happen, so the bot can miss a buy or an exit. - Torch tokens tax buys. During anti-snipe, the tax can start at 80%, and your slippage limit does not include it. See [venues](/trading). - Pools, hooks and launchpads take their own fees. ## Smart contract risk [#smart-contract-risk] The guard, the venue adapters, the Spinner's wallet, the USDG position and every venue that a bot uses are smart contracts. Any of them can have a bug. A bug can lose funds. - The guard caps each buy with your limits. Keep your limits as small as your strategy needs. - The protocol decides which venue adapters the guard lists. A faulty adapter could lose tokens that the wallet holds. ## The USDG position [#the-usdg-position] The [USDG position](/trading/usdg-position) puts USDG into lending and liquidity venues. These venues have their own contract risk. A liquidity range also moves with the price of the other token. A stablecoin can lose its peg. Projections of yield are not promises. ## AI answers can be wrong [#ai-answers-can-be-wrong] - An AI model can misread a strategy that you describe in words. Read every rule before you save it. - An AI step can give a wrong answer. A missing or invalid answer is "no signal", but a wrong answer that is in the right format is used. - An MCP server can return wrong data, or text written to mislead a model. - Hype on X is easy to fake with bots and paid posts. AI cannot reliably tell. AI only gives signals. Your rules and your limits still decide each trade. ## Keys and third-party services [#keys-and-third-party-services] - **Your wallet.** Anyone with your wallet's keys controls your Spinners and their wallets. Keep your keys safe. - **Your AI keys.** AI steps run on your own API keys. You pay your provider for each call. Set spending limits with your provider. - **MCP servers and webhooks.** A service that you connect can fail, change, or send bad data. A webhook secret that leaks lets others start entries for your bot. - **Venues and launchpads.** Launchpads, exchanges, data and AI providers can change their rules, fees or availability. - **Outages and delays.** A bot can act late or miss an event if the chain, a data source or Spin's servers are slow or down. Your wallet stays yours and usable even then. ## Paper results and backtests do not predict live results [#paper-results-and-backtests-do-not-predict-live-results] Backtests replay a strategy on past trades. Paper trading runs it live with no money. Both are useful tests, but live results will differ: - Real fills, fees, slippage and timing differ from the simulation. - Other traders react to your trades. - The market changes. What worked before can fail next. A good backtest, a good paper run or a high rank on the [leaderboard](/token/leaderboard) does not mean that a strategy will make money. ## $SPIN [#spin] Mint, activation and tier unlocks are fixed amounts of $SPIN. The price of $SPIN can fall as well as rise. The [weekly airdrop](/token/airdrop) changes with the fees that $SPIN earns, and it is not guaranteed. ## No advice [#no-advice] Spin gives you building blocks and presets. Presets are starting points only. Spin does not tell you what to trade and makes no claim that any strategy or preset will make money. Owning a Spinner gives you access to software tools. It is not a share in Spin. # Activation (/spinners/activation) A Spinner starts inactive. Its bot cannot trade until the Spinner is active: not on paper, not live, and it cannot run backtests. Activation switches the bot on. ## Cost [#cost] Activation costs **5,000 $SPIN**: | Part | $SPIN | Where it goes | |---|---|---| | 70% | 3,500 | Burned | | 30% | 1,500 | The protocol | You also pay a small amount of ETH for gas. ## Activate a Spinner [#activate-a-spinner] ### Open the Spinner [#open-the-spinner] Open **My Spinners** and choose the Spinner. Or, after a mint, click **Activate Spinner #...**. ### Check the Activation card [#check-the-activation-card] The **Activation** card is at the top of the Spinner's page. An inactive Spinner has an **Inactive** pill. - Only the wallet that holds the Spinner can activate it. If you are signed in with a different wallet, the card shows which wallet holds it. - If your wallet has less than 5,000 $SPIN, the card says how much more you need. ### Activate [#activate] Click **Activate for 5,000 SPIN**. Your wallet asks you to approve the transactions: 1. An approval of the fee in $SPIN, if your wallet has not approved enough already. 2. The activation. 3. The registration of the bot as an on-chain agent, the first time only. If your wallet supports it, they go in one batch. If a step fails, the app tells you, and nothing is spent except gas. ### Done [#done] The pill changes to **Active**, and the card says "Its bot can trade." Next, give the bot a strategy on the **Strategy** tab. Read [Presets](/strategies/presets) or [Strategies](/strategies). ## The on-chain agent identity (ERC-8004) [#the-on-chain-agent-identity-erc-8004] The first time you activate a Spinner, the app also registers its bot as an agent in the ERC-8004 identity registry. ERC-8004 is a standard for on-chain AI agents. - The identity belongs to the Spinner's own wallet, not to your wallet. - It moves with the NFT. A new holder does not register it again. - When the bot is registered, the **Activation** card says "Its bot is registered as an on-chain agent (ERC-8004), owned by the Spinner's wallet." If an active Spinner has no identity yet, the card says so and shows a **Register it** button. Click it to register the bot on its own. This costs only gas. ## A sale or transfer resets activation [#a-sale-or-transfer-resets-activation] When the Spinner goes to a new wallet, by a sale or a transfer, it becomes inactive again. The new holder pays the 5,000 $SPIN again to activate it. The wallet and its funds, the strategy and its version history, and the track record stay with the Spinner. The new holder also sets up live trading again. Read [Transfers](/spinners/transfers). Activation spends $SPIN once. Hold-to-unlock only counts the $SPIN that stays in your wallet. After you pay for activation, your wallet holds 5,000 $SPIN less, and that can change your tier. Read [Rarity and tiers](/spinners/rarity-and-tiers). # What a Spinner is (/spinners) A Spinner is one of 7,777 NFTs in the Spin collection on Robinhood Chain. Each Spinner is a pixel-art character. Each Spinner is also a trading bot. Four things belong to it. ## The NFT [#the-nft] The NFT is the Spinner. Whoever holds the NFT controls the bot: its wallet, its strategy and its settings. Each Spinner has a rarity, which decides the tools that its bot can use. Read [Rarity and tiers](/spinners/rarity-and-tiers). ## Its own wallet [#its-own-wallet] Each Spinner owns a smart-contract wallet: a token-bound account (ERC-6551). The wallet belongs to the NFT, not to you or to Spin. Whoever holds the NFT controls the wallet. The bot trades from this wallet, and only from this wallet. It never uses your own wallet. Read [The Spinner's wallet](/spinners/wallet). ## Its bot [#its-bot] You give the bot a strategy: a preset, rules that you build, or rules that AI writes from your words. Spin's servers run the strategy and send its trades. Read [Strategies](/strategies). The bot trades on paper first. To trade with real ETH, you give the bot a trading key and set limits for each trade and each day. A guard contract, SpinBotGuard, checks every live trade against your limits. The bot can trade only on approved venues, and it can never withdraw funds from the wallet. Read [Live trading](/spinners/live-trading) and [Safety](/safety). Each Spinner runs one strategy at a time. To run more strategies at the same time, hold more Spinners. ## Its on-chain agent identity [#its-on-chain-agent-identity] When you activate a Spinner, the app also registers its bot as an on-chain agent in the ERC-8004 identity registry, in the same batch of transactions that you sign. The identity belongs to the Spinner's own wallet, so it moves with the NFT when the Spinner changes hands. Read [Activation](/spinners/activation). A public reputation for each bot in the ERC-8004 reputation registry, made from its weekly leaderboard results when the weekly airdrop is calculated. ## The Spinner's page [#the-spinners-page] Open a Spinner from **My Spinners** to see its page. The top of the page has the **Activation** card and two switches: **Bot** (running or paused) and **Money** (paper or live). Below them are five tabs: | Tab | What it shows | |---|---| | **Strategy** | The strategy editor, the Spinner's tier of tools, and its saved versions | | **Wallet** | The Spinner's wallet, its tokens, creator fees from its launches, and live trading | | **USDG** | The USDG position, a Legendary tool. Read [USDG position](/trading/usdg-position) | | **Performance** | The bot's open and closed positions and its results | | **Activity** | What the bot did, and why | Each Spinner also has a **Public page** that anyone can open without signing in. It shows the bot's record: its results and its positions. It never shows the strategy. ## What travels with the NFT [#what-travels-with-the-nft] The wallet and its funds, the strategy and its version history, the track record and the agent identity all stay with the NFT. A sale or transfer resets the activation and the live trading permission. AI keys and MCP servers belong to the holder, not the NFT, so a new holder adds their own. Read [Transfers](/spinners/transfers). # Live trading (/spinners/live-trading) ## Paper and live [#paper-and-live] An active Spinner with a saved strategy trades in one of two ways: | Mode | What happens | |---|---| | **Paper** | The bot follows its strategy on the live market, but it uses no money. It records what it would have done. Paper results include the same 0.5% fee as live trades. | | **Live** | The bot trades with real ETH from the Spinner's wallet, within the limits that you set. | Every Spinner starts on paper. The **Money** control at the top of the Spinner's page shows the mode. While live trading is not set up, it shows how many of the four steps are done, and a **Set up live trading** button. Test a strategy on paper first. Watch its results on the **Performance** tab, and see each decision on the **Activity** tab. ## The four steps [#the-four-steps] The **Live trading** card on the **Wallet** tab lists four steps. Each step gets a check mark when it is done: 1. **The Spinner is active.** Read [Activation](/spinners/activation). 2. **The bot has its trading key.** 3. **Limits set for each trade and each day.** 4. **The Spinner wallet holds ETH.** Read [The Spinner's wallet](/spinners/wallet). Steps 2 and 3 happen together, when you click **Allow live trading**. ## Turn on live trading [#turn-on-live-trading] ### Set your limits [#set-your-limits] On the **Live trading** card, type: - **Most per trade**: the most ETH that one buy can spend. - **Most per day**: the most ETH that all buys together can spend in one day. It must be at least the limit per trade. - **For**: the number of days that the permission lasts, from 1 to 365. The form starts at 0.05 ETH a trade, 0.5 ETH a day, for 30 days. Change these to amounts that you are ready to lose. ### Allow live trading [#allow-live-trading] Click **Allow live trading**. Your wallet asks you to approve the transactions: 1. Set up the Spinner's wallet, if it is not set up yet. 2. Give the bot its trading key. 3. Set the bot's limits. ### Fund the wallet [#fund-the-wallet] If the Spinner's wallet has no ETH, deposit some on the **Spinner wallet** card. ### Switch to live [#switch-to-live] When all four steps have a check mark, the switch says "Ready. Switch on to trade with real ETH." Turn the switch from **Paper** to **Live**. You can use the switch on the **Live trading** card or the **Money** switch at the top of the page. To go back to paper, turn the switch from **Live** to **Paper**. ## The limits [#the-limits] The guard contract, SpinBotGuard, checks every live trade before it lets it through: - **Most per trade.** A buy that would spend more than this is refused. - **Most per day.** Buys stop when the day's total reaches this limit. The day starts at 00:00 UTC. - **For.** After the last day, the permission ends and the bot cannot trade live. Set up live trading again to continue. The limits count all the ETH that leaves the wallet for a buy: the amount, the 0.5% fee and the gas of the trade. Sells do not count against the limits. A limit never stops an exit. When a limit stops a buy, the bot page shows a notice, for example "A buy was over your limit per trade" or "Your daily limit stopped a buy". To change the limits, type new values and click **Update limits**. The guard also lets the bot trade only on approved venues, and it lets the bot send funds only back to the Spinner's wallet. The bot can never withdraw. Read [Safety](/safety). ## Revoke the bot's key [#revoke-the-bots-key] Click **Revoke the bot's key and limits** to stop live trading at once. Your wallet asks you to approve the transaction. After that, the bot cannot trade live. Switch the mode to **Paper**, or allow live trading again. Without its key, the bot cannot sell the tokens that it bought live. To exit those positions, allow live trading again, or withdraw the tokens on the **Tokens** card. The same is true when the permission ends after its last day. ## Pause the bot [#pause-the-bot] The **Bot** switch at the top of the Spinner's page turns the bot on and off: | Switch | Meaning | |---|---| | **Running** | The bot trades by its strategy. | | **Paused** | No new trades. Open positions still exit by their rules. | | **Off** | The Spinner is not active. Activate it to switch its bot on. | Pausing does not change the mode or the limits. Turn the switch back to **Running** to start again. ## Who can change these [#who-can-change-these] Only the wallet that holds the Spinner can set limits, revoke the key and switch between paper and live. A sale or transfer cancels the trading key and the limits. Read [Transfers](/spinners/transfers). # Minting (/spinners/minting) You mint Spinners on the **Mint** page of the app. Every mint is paid in $SPIN. ## Price [#price] | Mint | Price for each Spinner | |---|---| | Public mint | 10,000 $SPIN | The $SPIN that you pay to mint goes to the protocol. You also pay a small amount of ETH for gas. The **Price** on the mint page is the price for your wallet in the phase that is open now. ## Phases [#phases] The mint can have two phases. A pill at the top of the mint card shows the phase that is open: | Pill | Meaning | |---|---| | **Whitelist** | Only wallets on the whitelist can mint, each up to its own allowance. The whitelist has its own part of the supply. | | **Public** | Any wallet can mint. | | **Closed** | No mint is open now. | The progress bar shows how many of the 7,777 Spinners are minted. In the whitelist phase, a second bar shows how much of the whitelist supply is minted. If your wallet cannot mint, the page tells you why. For example: "This wallet is not on the whitelist. The public mint opens later." ## Mint a Spinner [#mint-a-spinner] ### Get $SPIN [#get-spin] The card shows **Your $SPIN**: the $SPIN in the wallet that you signed in with. If you have too little, the card says how much more you need. When a place to buy $SPIN is set, it also shows a **Buy $SPIN** button. Your balance updates on the page by itself after you buy. ### Choose how many [#choose-how-many] Use the **+** and **-** buttons to choose the number of Spinners. The card shows the most that your wallet can mint now, and the total cost. ### Pay [#pay] Click **Pay ... $SPIN** (the button shows the total). Your wallet asks you to approve the transactions: 1. An approval that lets the collection take exactly the cost in $SPIN. The app asks for it only if your wallet has not approved enough already. 2. The mint. If your wallet supports it, both go in one batch. If a step fails, the app tells you, and nothing is spent except gas. ### See what you got [#see-what-you-got] The reel spins while the mint confirms, then stops on each new Spinner and shows its rarity. The new Spinners are now in your wallet. ## After the mint [#after-the-mint] A new Spinner is inactive. Its bot cannot trade until you activate it. - Click **Activate Spinner #...** under the mint result to open the Spinner's page. - Click **View transaction** to see the mint on the block explorer. Your new Spinners also show in **My Spinners**. A new Spinner usually appears there within a minute of the mint. Next: [activate the Spinner](/spinners/activation). # Rarity and tiers (/spinners/rarity-and-tiers) ## Rarities [#rarities] Each Spinner has a rarity. The rarity shows as a lit platform under the character's feet. These are the shares of the collection: | Rarity | Share of the collection | |---|---| | Common | 50% | | Uncommon | 25% | | Rare | 15% | | Epic | 8% | | Legendary | 2% | One-of-one Spinners have the rarity **Mythic**. A Mythic Spinner has everything that a Legendary Spinner has. ## Tiers of tools [#tiers-of-tools] The rarity decides the tier of tools that the bot can use. There are five tiers. Each tier keeps everything in the tiers below it. | Tier | What the bot can use | |---|---| | **Common** | Presets exactly as they are made: a DCA of a listed token every 6 hours or once a day, at any amount; copy wallets; launch momentum | | **Uncommon** | Presets with their numbers changed, for example a DCA of any token at any interval | | **Rare** | Any strategy built from rules, without AI. AI only to launch a token (no MCP servers) | | **Epic** | AI steps in entries or exits, and MCP servers | | **Legendary** | A webhook trigger, and the USDG position | The DCA tokens that a Common Spinner can buy are listed on [Presets](/strategies/presets). To learn more about each tool, read [Strategies](/strategies), [AI steps](/ai/ai-steps), [MCP servers](/ai/mcp-servers), [Webhooks](/ai/webhooks), [Launching tokens](/launching) and [USDG position](/trading/usdg-position). ## Hold $SPIN to unlock higher tiers [#hold-spin-to-unlock-higher-tiers] You can raise a Spinner's tier without a rarer Spinner. Hold $SPIN in the same wallet that holds the Spinner. Each step up has a price: | Step | $SPIN for the step | |---|---| | Uncommon | 5,000 | | Rare | 10,000 | | Epic | 25,000 | | Legendary | 50,000 | The steps above the Spinner's own rarity add up. For example, a Common Spinner needs 5,000 + 10,000 + 25,000 + 50,000 = 90,000 $SPIN for Legendary tools. A Rare Spinner needs 25,000 + 50,000 = 75,000 $SPIN for the same tools. This table gives the $SPIN to hold for each tier, by the Spinner's own rarity: Holding is enough. The $SPIN is not spent and not locked. The tier is the higher of the Spinner's rarity and what its holder's $SPIN unlocks. The $SPIN must be in the same wallet that holds the Spinner. $SPIN in a different wallet that you own, or in the Spinner's own wallet, does not count. ## See your Spinner's tier [#see-your-spinners-tier] On the Spinner's page, open the **Strategy** tab. The **Tools** card shows: - the tier that the Spinner has now, - its rarity and the $SPIN that its holder's wallet holds, - how much more $SPIN to hold for the next tier. The strategy editor also shows the tier that your strategy needs, for example "Needs Rare tools; this Spinner has Common." If the Spinner's tier is too low, you cannot save the strategy. The editor tells you how much more $SPIN to hold. ## If the tier goes down [#if-the-tier-goes-down] The tier follows the $SPIN in the holder's wallet at all times. If you sell or move $SPIN out of that wallet, the tier can go down. If the strategy then needs a higher tier than the Spinner has: - The bot makes no new buys and no new launches, and it pauses. - Sells still go ahead, so open positions can still exit. - The bot page shows a notice that the strategy needs a higher tier. To start again, hold enough $SPIN in the wallet, or change the strategy to one that the tier allows. Then turn the **Bot** switch back to **Running**. A USDG position takes no new risk when the Spinner is no longer Legendary. After a grace period, it moves to **Stable**. You can always withdraw. Read [USDG position](/trading/usdg-position). # Transfers (/spinners/transfers) A Spinner is an NFT. You can sell it or send it to another wallet like any other NFT. The bot goes with it. ## What stays with the Spinner [#what-stays-with-the-spinner] These belong to the NFT, so they go to the new holder: - **The wallet and its funds.** All the ETH and tokens in the Spinner's wallet. - **The strategy and its version history.** Every saved version, with its results. - **The track record.** The bot's positions and results, also on its **Public page**. - **The agent identity.** The ERC-8004 identity belongs to the Spinner's wallet. - **What the wallet owns.** For example, creator fees from tokens that the bot launched, and a USDG position. ## What resets [#what-resets] | What | After a sale or transfer | |---|---| | Activation | The Spinner becomes **Inactive**. The new holder pays 5,000 $SPIN to activate it again. | | Mode | The bot goes back to **Paper**. | | Trading key and limits | They stop. They belong to the wallet that set them, so the new holder sets up live trading again. | | Webhook secret | It stops. The new holder makes a new one. Read [Webhooks](/ai/webhooks). | Some things belong to a person, not to the Spinner, so they never move with it: AI keys and MCP servers in **Settings**. A new holder adds their own before the bot's AI steps can run. Read [AI keys](/ai/ai-keys). ## Before you sell [#before-you-sell] The wallet's funds go with the NFT. Until the sale completes, you, the seller, can still move them. Withdraw the ETH and tokens that you want to keep before you list the Spinner. Read [The Spinner's wallet](/spinners/wallet). ## Before you buy [#before-you-buy] When you buy a Spinner, pay for the Spinner and its record, not for its wallet balance. The seller can move the funds out of the wallet until the sale completes. Open the Spinner's **Public page** before you buy. Anyone can open it without signing in. It shows the bot's results and its positions. It does not show the strategy. After you buy, you can see the strategy and every earlier version. ## What the new holder sees [#what-the-new-holder-sees] ### The Spinner appears [#the-spinner-appears] Sign in with the wallet that now holds the Spinner. The Spinner shows in **My Spinners**, usually within a minute of the purchase. ### Activate it [#activate-it] The **Activation** card shows **Inactive**. Click **Activate for 5,000 SPIN**. The agent identity is already registered, so activation does not register it again. Read [Activation](/spinners/activation). ### Check the strategy and its versions [#check-the-strategy-and-its-versions] The **Strategy** tab shows the strategy that the bot runs. The **Versions** card lists every saved version, newest first: - when each version ran, - who saved it: "you" or "an earlier holder", - its paper and live results. Click **View rules** to read a version. To run an earlier version again, click **Use this version again**, then **Use them now**. This saves its rules as a new version. Read [Versions](/strategies/versions). The strategy must fit the Spinner's tier. The tier counts the $SPIN in your wallet, not in the earlier holder's. Read [Rarity and tiers](/spinners/rarity-and-tiers). ### Set up live trading again [#set-up-live-trading-again] The bot starts on paper. To trade live, set your own limits and click **Allow live trading** on the **Wallet** tab. Read [Live trading](/spinners/live-trading). Tokens that the bot bought live for the earlier holder stay in the Spinner's wallet. The bot cannot sell them live until the Spinner is active and the new holder allows live trading. The new holder can also withdraw them on the **Tokens** card. # The Spinner's wallet (/spinners/wallet) Each Spinner owns a smart-contract wallet, a token-bound account (ERC-6551). The wallet belongs to the NFT. Whoever holds the NFT controls the wallet. The bot trades only from this wallet. You manage the wallet on the **Wallet** tab of the Spinner's page. ## The Spinner wallet card [#the-spinner-wallet-card] The **Spinner wallet** card shows: - **Balance**: the ETH in the Spinner's wallet. - The wallet's address. Click it to open the wallet on the block explorer. The address exists from the mint. The wallet contract itself is set up the first time that you withdraw or allow live trading. The app adds this step to your transaction for you. You can deposit before that. ## Deposit ETH [#deposit-eth] 1. In **Deposit**, type an amount of ETH. 2. Click **Deposit**. 3. Approve the transaction in your wallet. Anyone can send ETH to the Spinner's address from any wallet on Robinhood Chain. Only send on Robinhood Chain. ## Withdraw ETH [#withdraw-eth] 1. In **Withdraw to your wallet**, type an amount, or click **Max** for the full balance. 2. Click **Withdraw**. 3. Approve the transaction in your wallet. The ETH goes to the wallet that holds the Spinner. Only that wallet can withdraw. ## Tokens [#tokens] The **Tokens** card lists the tokens in the Spinner's wallet: tokens that the bot bought live, tokens that it launched, and some common tokens of Robinhood Chain. To withdraw a token: 1. Type an amount next to the token, or click **Max**. 2. Click **Withdraw**. 3. Approve the transaction in your wallet. The tokens go to the wallet that holds the Spinner. If a token that you expect is not in the list, type its contract address in **Another token** and click **Show**. If the Spinner launched tokens, a card for its creator fees also shows on this tab. Read [Creator fees and links](/launching/creator-fees-and-links). ## Gas [#gas] | Who sends it | Who pays the gas | |---|---| | You: deposits, withdrawals, live trading limits, activation | Your wallet | | The bot: its live trades | The Spinner's wallet | For each live trade, the guard pays back the gas of the trade from the Spinner's wallet. Keep some ETH in the Spinner's wallet for this, as well as the ETH to trade. If the wallet cannot pay for a trade and its gas, the trade does not go through. The bot page then shows a notice: "Too little ETH in the Spinner's wallet." Paper trades use no ETH and no gas. ## What the bot can and cannot do [#what-the-bot-can-and-cannot-do] The bot can use the wallet only through the guard contract, and only after you allow live trading. Read [Live trading](/spinners/live-trading). | Action | The bot | |---|---| | Trade on approved venues | Can, within your limits | | Launch a token on an approved launchpad (eligible tiers) | Can | | Pay the 0.5% trading fee and the gas of its trades | Can | | Send funds anywhere else | Cannot | | Withdraw from the wallet | Cannot | | Change its own limits | Cannot. Only the holder can | You can take the bot's key back at any time. Read [Safety](/safety) to learn how the guard works. The funds in the wallet go with the NFT. Withdraw them before you list the Spinner for sale. Read [Transfers](/spinners/transfers). # Backtests (/strategies/backtests) A backtest replays a strategy on recent days of the market. It uses the same engine as the bot, and the same fills as paper trading. So its decisions are the ones the bot would have made on those days. A backtest shows how a strategy would have traded in the past. Past days do not say what comes next. A good backtest does not mean that a strategy will make money. ## Who can run one [#who-can-run-one] You can run a backtest when you hold an activated Spinner, at any tier. If the Spinner is not activated, the **Backtest** section says: "Backtests are for activated Spinners: activate this one to test a strategy on the last 30 days of the market." Read [activation](/spinners/activation). ## Run a backtest [#run-a-backtest] ### Choose the period [#choose-the-period] Under the editor, in **Backtest**, choose **Over**: **The last day**, **The last 7 days**, **The last 14 days** or **The last 30 days**. ### Start it [#start-it] Select **Run the backtest**. A dialog opens. The result grows as the days replay. ### Stop or run again [#stop-or-run-again] Select **Stop** to stop the run. When it is done, select **Run again** or **Close**. Closing the dialog also stops a run. The backtest uses the strategy as it is in the editor now, saved or not. It runs in your browser. Your browser keeps the days it downloads, so a second run of the same days is faster. ## The data and the period [#the-data-and-the-period] Spin keeps the last 30 days of market history. A backtest reads what its strategy needs: - A launch or trade strategy reads every launch and trade on its launchpads (Pons, Torch, or both). - A strategy with a chosen token reads that token's price history. Spin keeps price history only for the tokens on its token list. The backtest uses the latest days that all the data it needs covers. The days are in UTC. If there is no data for the strategy, the backtest says why, for example "not enough data: no stored days cover this strategy yet". ## How it fills [#how-it-fills] The backtest fills buys and sells as paper trading does: - A Pons curve fills by the curve's own math, with its fee and tax. - A pool fills at its price less its fee, with no price impact. - The bot's own trades never move the market. - The 0.5% bot fee is taken from each trade, each way. ## What it shows [#what-it-shows] | Item | What it is | | --- | --- | | **Result** | The return in percent, with the result in ETH. It counts sales, less buys, plus what is still held. | | **Trades** | The number of trades, and how many closed. | | **Winners** | The share of closed trades that made money. | | **Worst drawdown** | The largest fall of the running result from its high, in ETH. | Under these, you see: - A chart of the running result over time. - The ETH spent, the ETH back from sales, and the value still held. A position still open at the end is valued at its last price, less the cost of selling. - "Not bought": the most common reasons the strategy did not buy, with how often. For example "confirm failed" or "max_open reached". - When the run ends: one trade over its token's price, and a table of the trades, newest first (up to 50). Select **Chart** on a trade to show it over its token's price. Each trade shows its token, when it opened (UTC), the ETH in, its result, and the exit that closed it. ## What cannot be backtested [#what-cannot-be-backtested] The editor says so when a strategy cannot be backtested, and why: - **A strategy with an AI step.** Its answers on past days cannot be known. - **A strategy that launches a token.** How a token that was never launched would have traded is unknowable. - **A webhook strategy.** What your service would have sent on past days cannot be known. - **A chosen token that is not on Spin's token list.** Spin has no price history for it. ## The limits of a backtest [#the-limits-of-a-backtest] - It covers 30 days at most. - A pool has no price impact, and the bot's own trades do not move the price. A real trade can get a worse price, mostly in a thin market. - A backtest of a few trades says little. Look at the number of trades, the share of winners, and the worst drawdown together. - Run the strategy on paper before you turn on live trading. Read [live trading](/spinners/live-trading). # Build with AI (/strategies/build-with-ai) **Build with AI** turns your words into a strategy. You describe what you want. Your own AI model writes the strategy, the engine checks it, and the editor shows it. You then check it, change it if you want, and save it yourself. It works on any tier. It uses your own AI key and model, so your AI provider bills you for each request. ## Before you start [#before-you-start] Add an AI key in **Settings**. Until you have one, the **Build with AI** box shows **Add an AI key**. Read [AI keys](/ai/ai-keys). ## Build a strategy [#build-a-strategy] ### Describe it [#describe-it] In **Describe the strategy**, write what the bot should do. Example: "Buy 0.01 ETH of TSLA every day, but skip days with bad news." ### Choose the key and model [#choose-the-key-and-model] In **Your AI key**, choose the key to use. In **Model**, type a model of that provider, or leave it empty to use the provider's default. ### Send it [#send-it] Select **Build with AI**. While your model writes, the box says "Your model is writing it…". ### Check the strategy [#check-the-strategy] The editor now shows the new strategy. Read every block. Then select **Save as new version** to save it. Nothing is saved before this. ## What it writes [#what-it-writes] The model writes a whole strategy, in the same shape as one you build by hand. It knows: - Every part of the strategy and every rule value. - The tickers and addresses of the tokens on the DCA list, so you can name a token by its ticker. - Your MCP servers, and the one-click servers you could add. - The AI providers you have keys for. - The tier of your Spinner. The engine checks what the model writes. If it finds problems, it sends them back to the model to fix, up to two more times. If the strategy still has problems, you see: "It still has problems, shown under the editor: fix them there, or ask again." ## Notes from the model [#notes-from-the-model] With each strategy, the model writes a few short notes. They say what it chose where your words left something open, what your request asked that a strategy cannot do, and which MCP servers or AI keys you must add first. The model can also ask a question when something important is unclear. It still writes its best strategy. ## Requests above your tier [#requests-above-your-tier] If your request needs a higher tier than your Spinner has, the model first says which tier it needs. It does not write the strategy yet. You see, for example: "This needs Epic tools; this Spinner has Rare, so it could not run here." You can then: - Ask for a version that fits your tier. The model's note says what such a version could do. - Select **Build it anyway**. The model writes the strategy for the higher tier. You can read and test it, but you cannot save it until the Spinner has that tier. Read [the tier a strategy needs](/strategies#the-tier-a-strategy-needs). ## Edit with AI [#edit-with-ai] When the editor already has a strategy, the box can change it instead of writing a new one. 1. Keep **Change the strategy in the editor** on. 2. In **What to change**, write the change. Example: "Take profit at 3x, and add a 20% stop loss." 3. Select **Edit with AI**. The model keeps everything you did not ask to change. It works on the strategy as it is in the editor now, with any changes you made by hand. Turn **Change the strategy in the editor** off to write a new strategy from your words instead. ## The conversation [#the-conversation] Your requests and the model's notes show as a conversation in the box. The model reads the conversation so far, so you can ask for changes step by step. The conversation stays on this page only. Select **Clear** to start again. A model can misread what you want. Read every block before you save, run a [backtest](/strategies/backtests) where you can, and run the strategy on paper first. # Buying (/strategies/buying) The **Buy** block is the outcome of an entry check. Open it to set what the bot buys, how much ETH it spends, and the slippage it accepts. In **Outcome**, choose **Buy a token** or **Launch a token (Pons or Torch)**. This page is about buying. Read [launching](/launching) for launches. ## What the bot buys [#what-the-bot-buys] A buy buys one of these: - **The token that started it.** With a launch or trade trigger, the bot buys the token that launched or was traded. This is the default. - **A chosen token.** Turn on **Buy a chosen token**, then pick it in **Token to buy**. Every buy then buys this token, whatever started the check. - **A token an AI step names.** An AI step can answer with a token's address. The bot then buys that token. - **A token your service sends.** With a webhook trigger, a token field of the call can be the token the bot buys. A timer or a webhook trigger has no token of its own. So these strategies always need a chosen token, a named token, or a launch. ### The token that started it [#the-token-that-started-it] The bot buys the token where it trades on its launchpad. A Pons token trades on its bonding curve, then in its pool once it has graduated. A Torch token trades in its own pool. If a Pons curve has sold out and the token has not reached its pool yet, the bot does not buy. ### A chosen token [#a-chosen-token] **Token to buy** lists the tokens on Spin's token list, deepest first. Search by symbol, name or address. You can also paste the whole address of a token that is not on the list. The bot then finds its pools when it trades. A backtest cannot price such a token, and the editor does not know its decimals. Then choose **Where it trades**: | Option | The bot trades in | | --- | --- | | **The best pool at trade time** | The pool with the best quote, on UP or Uniswap. | | **The best UP pool at trade time** | The UP pool with the best quote. | | **The best Uniswap pool at trade time** | The Uniswap pool with the best quote. | | **Only** a pool | One pool that you pin. The bot checks it on chain before it trades. | The bot compares the pools' quotes on every trade, buys and sells alike. A pool whose hook the bots do not support is skipped. In JSON, the chosen token is `entry.target`: ```json { "schema": 1, "name": "DCA", "entry": { "trigger": { "on": "timer", "every_s": 21600 }, "target": { "token": "0x117cc2133c37b721f49de2a7a74833232b3b4c0c" }, "buy_eth": 0.01 }, "exits": [], "limits": { "once_per_token": false, "max_open": 1, "add_to_position": true } } ``` `target.venue` is `"up"` or `"uniswap"`, to keep to one venue. `target.pool` pins one pool: a pool's address, or a Uniswap V4 pool id. A pinned pool needs its venue. When every buy buys the same token, **Once per token** must be off (`"once_per_token": false`). The editor turns it off for you. ### A token an AI step names [#a-token-an-ai-step-names] Give an AI step a field that holds **A token's address, to buy (or none found)**. Then choose it in **The token to buy**, for example "The token the step "news" names". In JSON, the target is the step's answer by name: ```json { "token": "{{news.token}}" } ``` The bot buys the token where it trades, once it is named: on its launchpad for a Pons or Torch token, else in the best pool on UP or Uniswap. If no token is named, or no market is found within a minute, nothing is bought. Rules can check the token's own values (its liquidity, its buy tax, its buyers) before it buys. With **Once per token** on, a token is bought at most once. A named token cannot pin a pool. AI steps outside a token launch need an Epic Spinner. Read [AI steps](/ai/ai-steps). ### A token your service sends [#a-token-your-service-sends] With a webhook trigger, declare a field of the token type. Then choose "The token your service sends" in **The token to buy**. In JSON, the target is `{"token": "{{hook.}}"}`. As with a named token, if no market is found within a minute, nothing is bought. Read [webhooks](/ai/webhooks). ## How much the bot buys [#how-much-the-bot-buys] Set the amount in **Buy**, in ETH. In JSON, it is `entry.buy_eth`: more than 0, and at most 100. The 0.5% bot fee is taken from each trade, each way. The live trading limits on the **Wallet** tab include the fee. Read [live trading](/spinners/live-trading). ## Slippage [#slippage] Set **Slippage** in percent. The buy reverts if it would get this much less than the quoted amount. In JSON, it is `entry.max_slippage_pct`: from 0.1 to 50, and 10 by default. Sells have their own slippage, **Exit slippage**, in the limits. Read [limits](/strategies/limits). ## Prices per whole token [#prices-per-whole-token] `token.price` in a rule is a price in wei per the token's smallest unit. For a token with 18 decimals, such as every Pons token, that is ETH per whole token. The editor shows prices in ETH per whole token when it knows the token's decimals. For a chosen token, it says so under the token: "Prices in rules are ETH per whole" and the token's symbol. For a token with other decimals, the JSON keeps wei per its smallest unit. That number is ETH per whole token times 10 to the power of (18 minus the token's decimals). For a token that is not on the list, the editor does not know its decimals, so prices in the workflow are wei per its smallest unit too. # Conditions (/strategies/conditions) A condition is a rule that is true or false. The bot checks it at a fixed place in the strategy, and goes on only when it is true. A strategy has conditions in these places: | Block | JSON | When the bot checks it | | --- | --- | --- | | **Buy only if** | `entry.if` | At once, when the trigger starts the check. No condition: every time. | | **Then buy if** or **After the wait, buy if** | `entry.confirm` | After the wait, or on the answers of the AI steps. | | **Run this step only if** | `entry.ai.steps[n].if` | Before an AI step after the first. If it is false, the chain stops there. | | **Sell when** or **Ask the AI when** | `exits[n].if` | On every price change and every second. | | **Then sell if** | `exits[n].confirm` | On the answers of an AI sell check. | ## Rows that must all hold [#rows-that-must-all-hold] In the workflow, a condition is a list of rows. All rows must hold. Each row has: 1. A value, for example `token.buyers`. 2. Its window, if the value has one, for example 60 seconds. 3. A comparison. 4. The number or word to compare with. Select **Add a condition** to add the first row, and **And also** to add more. Select the "x" on a row to remove it. A condition with no rows is "Always": the check goes on every time. The comparisons are: | In the workflow | In JSON | For | | --- | --- | --- | | **more than** | `>` | Numbers | | **at least** | `>=` | Numbers | | **less than** | `<` | Numbers | | **at most** | `<=` | Numbers | | **is** | `==` | Numbers and words | | **is not** | `!=` | Numbers and words | | **is yes** | the value alone | Yes or no values | | **is no** | `not` | Yes or no values | The yes or no values are `token.graduated`, `token.creator_sold` and `event.first_buy`, and AI answers or webhook fields of the yes or no type. All other rule values are numbers. In JSON, a value is `{"f": ""}`, with `"args"` for its window. A comparison has the value first and the number second. Rows that must all hold are an `and`: ```json { "and": [ { ">=": [{ "f": "token.buyers", "args": [60] }, 30] }, { "not": { "f": "token.creator_sold" } } ] } ``` ## Windows [#windows] Some values count what happened in a recent window, for example `token.buyers(window_s)`: the distinct wallets that bought in the last `window_s` seconds. The window is in seconds, and it is at most 3600 (one hour). The engine keeps one hour of trades and prices for each token. `token.price_change(window_s)` is the price now divided by the price `window_s` seconds ago, so 1 is flat and 1.5 is up 50%. Until the engine has watched a pool for that long, it has no value. ## Missing values [#missing-values] A value can be unknown, for example `token.age_s` for a token that launched before the engine started to watch it. A comparison with an unknown value is false. So a rule over missing data never buys and never sells. You do not need to check for missing values. ## Prices [#prices] `token.price` is a price in wei per the token's smallest unit. For a token with 18 decimals (every Pons token), that is ETH per whole token. The workflow shows and takes prices in ETH per whole token when it knows the token's decimals. The JSON keeps the stored number. For a token with fewer decimals, the stored number is larger: ETH per whole token times 10 to the power of (18 minus its decimals). Read [prices per whole token](/strategies/buying#prices-per-whole-token). ## Where each value can be used [#where-each-value-can-be-used] Values come in four groups. Not every group can be used everywhere: | Group | Entry conditions | Sell rules | | --- | --- | --- | | `token.*`: the token being considered | Yes | Yes | | `event.*`: the trade or launch that started the check | Yes, but not with a timer or a webhook trigger | No | | `position.*`: the open position | No | Yes | | `bot.*`: the bot | Yes | Yes | The editor offers only the values that fit where you are. The engine refuses a value that is used where it cannot be known. ### The token [#the-token] ### The trade or launch that started the check [#the-trade-or-launch-that-started-the-check] The workflow does not offer `event.trader`. You can use it in JSON. ### The position (sell rules only) [#the-position-sell-rules-only] ### The bot [#the-bot] ## Values from AI answers [#values-from-ai-answers] Each AI step declares the fields of its answer. A condition after the AI steps can read them as `ai..`, for example `ai.decide.action`. You can use them in **Then buy if**, in **Then sell if**, and in **Run this step only if** of a later step. A rule can read fields that are a number, yes or no, or one of a list of words. It cannot read text, images or token addresses. A word must be one of the field's own words: the engine refuses `"buyy"` for a field whose words are `buy` and `skip`. ```json { "and": [ { "==": [{ "f": "ai.decide.action" }, "buy"] }, { ">=": [{ "f": "ai.decide.confidence" }, 0.7] }, { "!=": [{ "f": "ai.decide.risk" }, "high"] } ] } ``` No answer, an answer in the wrong shape, or an answer that comes too late never buys or sells. Read [AI steps](/ai/ai-steps). ## Values from webhook fields [#values-from-webhook-fields] With a webhook trigger, entry conditions can read the fields your service sends as `hook.`. As with AI answers, a rule can read numbers, yes or no, and words, but not text or token addresses. Read [webhooks](/ai/webhooks). ## What only JSON can express [#what-only-json-can-express] The workflow rows cover most conditions. JSON can also express these. The workflow keeps such a condition exactly as it is, and you edit it in the **JSON** tab. ### Or [#or] `or` holds when at least one of its parts holds. This condition holds when 50 wallets bought in the last minute, or when more than 1 ETH net went in: ```json { "or": [ { ">=": [{ "f": "token.buyers", "args": [60] }, 50] }, { ">": [{ "f": "token.net_eth", "args": [60] }, 1] } ] } ``` ### Not around more than one value [#not-around-more-than-one-value] `not` around a single yes or no value is a row (**is no**). `not` around a larger condition needs JSON. This condition holds unless the token both has graduated and is more than an hour old: ```json { "not": { "and": [ { "f": "token.graduated" }, { ">": [{ "f": "token.age_s" }, 3600] } ] } } ``` ### Arithmetic [#arithmetic] `+`, `-`, `*` and `/` combine two values. This condition holds when the token had more than twice as many buys as sells in the last 5 minutes: ```json { ">": [{ "f": "token.buys", "args": [300] }, { "*": [{ "f": "token.sells", "args": [300] }, 2] }] } ``` A division by zero gives an unknown value, so the comparison is false. ### A value on the right [#a-value-on-the-right] The workflow rows put the value first. A comparison with a value on the right, or with a value on both sides, needs JSON. ### Limits of a condition [#limits-of-a-condition] - An `and` or an `or` has 1 to 20 parts. - A value takes at most 4 arguments. - A word or text is at most 200 characters. - There is no `null` in rules. A missing value already makes a comparison false. # Exits (/strategies/exits) Exits are the rules that sell an open position. Each exit is a **Sell** block beside the **Buy** block. A strategy can have up to 10 exits. ## Add a sell rule [#add-a-sell-rule] ### Open the menu [#open-the-menu] Select the "+" under the sell blocks (**Add an exit**). ### Choose the kind [#choose-the-kind] Choose **Sell rule** for a rule on the market, or **AI sell check** to ask your AI model. ### Set the rule [#set-the-rule] The new block opens. Set its fields, then select **Done**. Each exit has these fields: | Field | JSON | What it is | | --- | --- | --- | | **Exit name** | `reason` | A short name, 1 to 40 characters. It shows in the activity and in backtests as the reason a position sold. | | **Sell** | `sell_pct` | The percent of what is still held, from 1 to 100. The default is 100. | | **Sell when** | `if` | The condition. Read [conditions](/strategies/conditions). | A sell rule can read the token's values, the position's values and the bot's values. It cannot read the values of the trade that started the entry. The position values are: ## Sell percent [#sell-percent] **Sell** is a percent of what the position still holds, not of what it bought. Example: the launch momentum preset sells 50% at 2 times the entry price. A later exit at 100% then sells the rest. ## The order of the exits [#the-order-of-the-exits] The bot checks the exits in order, on every price change of the token and every second. Each exit sells at most once for each position. A position has one sell at a time. When one exit sells, the next exits wait for the next check. If a sell fails, the exit can sell again. The bot tries it again after 30 seconds. A Pons curve that has sold out cannot take a sell. The bot then waits until the token trades in its pool, as any holder would. Example: the exits of the launch momentum preset, in order. ```json { "schema": 1, "name": "Launch momentum", "entry": { "trigger": { "on": "launch" }, "wait_s": 60, "confirm": { ">=": [{ "f": "token.buyers", "args": [60] }, 30] }, "buy_eth": 0.02 }, "exits": [ { "if": { ">=": [{ "f": "position.multiple" }, 2] }, "sell_pct": 50, "reason": "half_at_2x" }, { "if": { "and": [ { ">=": [{ "f": "position.peak_multiple" }, 1.5] }, { ">=": [{ "f": "position.drawdown_pct" }, 30] } ] }, "reason": "trailing_stop" }, { "if": { "<=": [{ "f": "position.pnl_pct" }, -50] }, "reason": "stop_loss" }, { "if": { ">=": [{ "f": "position.age_s" }, 1800] }, "reason": "time" } ] } ``` 1. **half_at_2x** sells half when the price is 2 times the entry price. 2. **trailing_stop** sells what is still held when the price has been at least 1.5 times the entry, then falls 30% from its highest point. 3. **stop_loss** sells when the position's estimated return is -50% or less. 4. **time** sells after 30 minutes. This example leaves out two checks of the preset, to keep it short. Read [presets](/strategies/presets) for the full preset. ## Slippage on sells [#slippage-on-sells] A sell reverts if it would get much less ETH than the market state suggests. Set this in **Exit slippage** in the **Limits** block (`limits.exit_slippage_pct`, 25% by default). Read [limits](/strategies/limits). ## AI sell checks [#ai-sell-checks] An AI sell check asks your own AI model whether to sell each position. Choose **AI sell check** in the "+" menu, or turn on **Ask the AI before selling** in a sell rule. It needs an Epic Spinner. An AI sell check has: - **Ask the AI when**: a condition. The bot asks only while it holds. No condition: the bot asks all the time, within the limits below. - The AI steps: up to 3, with their prompts and answer fields. Prompts can also use position values, such as `{{position.multiple}}`. - **Answer within**: how long the steps have to answer, in seconds (5 to 120; 60 by default). - **Ask at most every**: how often the bot asks for each position, in minutes. In JSON, `ai.every_s` is in seconds, from 60 to 86400, and 900 (15 minutes) by default. - **Then sell if**: the condition on the answers. The bot sells only when it holds. A new AI sell check starts with one step, `review`, whose answer is `sell` or `hold`, and sells when the answer is `sell`: ```json { "ai": { "every_s": 900, "steps": [ { "id": "review", "prompt": "Should a small trading bot sell its position in {{token.address}} now? It is at {{position.multiple}} times its entry price.", "output": { "action": ["sell", "hold"] } } ] }, "confirm": { "==": [{ "f": "ai.review.action" }, "sell"] }, "reason": "ai_exit" } ``` The editor starts the prompt empty. Write your own prompt. Each run is calls on your own AI key, and counts toward **AI runs an hour at most**. No answer, or a late answer, never sells. Read [AI steps](/ai/ai-steps). ## Never sells [#never-sells] A strategy with no exits shows one block: **Never sells**. "No exits: it buys and holds. Add an exit to sell." The bot then only buys and holds. This is how the DCA presets work: each buy adds to one position, and the bot never sells it. The tokens stay in the Spinner's wallet. Read [the Spinner wallet](/spinners/wallet). ## Open positions keep their rules [#open-positions-keep-their-rules] A position keeps the exits and the exit slippage it was opened with. When you save a new version, open positions still sell by their old exits. Only new positions use the new exits. Read [versions](/strategies/versions). # How a strategy runs (/strategies) A strategy tells a Spinner's bot when to buy, what to buy, and when to sell. It is a short JSON document that the engine checks before you can save it. Spin's servers then run it from the Spinner's own wallet. You edit a strategy on the **Strategy** tab of your Spinner. You can edit it as a workflow of blocks or as JSON. Both tabs edit the same strategy. Read [the workflow editor](/strategies/workflow-editor) to learn how. A Spinner runs one strategy at a time: the version you saved last. Read [versions](/strategies/versions) to learn how saving works. ## The order of the parts [#the-order-of-the-parts] Each time something happens that the strategy listens for, the bot starts an entry check. The check goes through these parts in order. If one part stops the check, the bot does not buy. | Order | Block in the workflow | JSON | What it does | | --- | --- | --- | --- | | 1 | **When** | `entry.trigger` | Starts the check: a launch, a trade, a timer or a webhook call. | | 2 | **Buy only if** | `entry.if` | A condition checked at once. No condition: every check goes on. | | 3 | **Limits** | `limits` | The bot checks its limits (open positions, entries an hour, once per token). | | 4 | **Wait** (optional) | `entry.wait_s` | The check waits this many seconds (at most 3600). | | 5 | **AI** steps (optional) | `entry.ai` | Up to 3 questions to your own AI model, one after the other. | | 6 | **Then buy if** or **After the wait, buy if** | `entry.confirm` | A condition on the AI's answers, or on the market after the wait. | | 7 | **Buy** or **Launch** | `entry.buy_eth` or `entry.launch` | The bot buys a token, or launches a new one. | | 8 | **Sell** rules | `exits` | Up to 10 sell rules, checked on every price change and every second. | The **Limits** block also holds limits that apply over the whole strategy, such as how many positions can be open at the same time. Read [limits](/strategies/limits). The check in step 6 is only there when the strategy has a wait or AI steps. AI steps always need it, because their answers only matter through a rule. ## The parts in short [#the-parts-in-short] - [Triggers](/strategies/triggers): what starts an entry check. - [Conditions](/strategies/conditions): the rules in **Buy only if**, **Then buy if** and the sell rules, and every value they can read. - [Buying](/strategies/buying): what the bot buys, where, how much, and with how much slippage. - [Exits](/strategies/exits): when and how much the bot sells. - [Limits](/strategies/limits): the limits over the whole strategy, with their defaults. - [AI steps](/ai/ai-steps): questions to your own AI model before a buy or a sell. - [Launching](/launching): a strategy can launch a new token instead of buying one. ## The tier a strategy needs [#the-tier-a-strategy-needs] Each Spinner has a tier of tools. A strategy can only run when the Spinner has the tier it needs. The editor shows the tier under the strategy, for example "Needs Rare tools; this Spinner has Epic." | The strategy uses | Tier it needs | | --- | --- | | A preset exactly as made: a DCA of a listed token every 6 hours or once a day (any amount), copy wallets, or launch momentum | Common | | A preset with its numbers changed, or a DCA of any token at any interval | Uncommon | | Any other strategy built from rules, without AI | Rare | | AI steps only to write a token launch, without MCP servers | Rare | | AI steps in an entry (other than a launch) or in an exit, or MCP servers anywhere | Epic | | A webhook trigger | Legendary | The strategy's name is free to change at every tier. If a strategy needs a higher tier than the Spinner has, you cannot save it. Read [rarity and tiers](/spinners/rarity-and-tiers) to learn how a Spinner gets its tier. ## Paper and live [#paper-and-live] A bot trades on paper until you turn on live trading. On paper, the bot makes the same decisions, and Spin records the fills it would have got from the market at that moment, with the 0.5% bot fee and gas. No funds move. When you turn on live trading, the bot trades with real ETH from the Spinner's wallet, within the limits that you set on chain. Read [live trading](/spinners/live-trading). A strategy does exactly what its rules say, good or bad. Presets are starting points, and a good backtest does not mean that a strategy will make money. Keep amounts small. # Limits (/strategies/limits) Limits apply over the whole strategy. Most of them are in the **Limits** block, at the top of the workflow. A few are in the blocks they belong to. A limit you leave out takes its default. These limits are the strategy's own. The live trading limits (the most ETH a trade and a day) are a separate thing: you set them on chain, on the **Wallet** tab. Read [live trading](/spinners/live-trading). ## The Limits block [#the-limits-block] | Field | JSON | Range | Default | What it does | | --- | --- | --- | --- | --- | | **Open positions at most** | `limits.max_open` | 1 to 100 | 5 | The most positions the bot has at the same time. | | **New entries an hour at most** | `limits.max_entries_per_hour` | 1 to 1000 | No limit | The most entries the bot starts in an hour. Empty: no limit. | | **Exit slippage** | `limits.exit_slippage_pct` | 1 to 90 | 25 | A sell reverts if it would get this much less ETH (in percent) than the market state suggests. | | **AI runs an hour at most** | `limits.max_ai_runs_per_hour` | 1 to 1000 | 20 | The most AI chains the bot runs in an hour, for entries and exits together. | | **Once per token** | `limits.once_per_token` | on or off | on | The bot never buys the same token twice. | | **Launches a day at most** | `limits.max_launches_per_day` | 1 to 10 | 1 | A launching strategy launches at most this many tokens in a day. | | (JSON only) | `limits.add_to_position` | true or false | false | A buy of a token the bot holds adds to its open position there, instead of opening another. | A launching strategy shows only **Launches a day at most** and **AI runs an hour at most** in the **Limits** block. ### How the bot counts [#how-the-bot-counts] - **Open positions at most** counts open positions, and also entries that are still waiting, asking the AI, or buying. - **New entries an hour at most** and **AI runs an hour at most** count over the last hour. - **Launches a day at most** counts over the last 24 hours. - An entry starts when its check passes **Buy only if** and the limits. - When a limit stops an entry, the bot skips it, with a reason such as "max_open reached". ### Once per token [#once-per-token] With **Once per token** on, the bot enters each token at most once. This is the default, and it suits launch and trade strategies. A token counts as entered once its check passes **Buy only if** and the limits, even if a later check stops the buy. When the strategy buys a chosen token, every buy buys the same token. **Once per token** must then be off, and the editor turns it off. When the token comes from an AI step's answer, **Once per token** stays on by default, so each token the AI names is bought once. ### Add to position [#add-to-position] With `add_to_position` on, a buy of a token that the bot already holds adds to that position. The position's entry price becomes the average of its buys. The DCA presets use this, with `max_open` at 1, so all their buys build one position. ## Limits in other blocks [#limits-in-other-blocks] | Field | Block | JSON | Range | Default | | --- | --- | --- | --- | --- | | **Slippage** | **Buy** | `entry.max_slippage_pct` | 0.1 to 50 | 10 | | **Buy** | **Buy** | `entry.buy_eth` | more than 0, at most 100 ETH | none: you set it | | **Wait** | **Wait** | `entry.wait_s` | 0 to 3600 seconds | 0 (no wait) | | **Answer within** | an **AI** step | `entry.ai.timeout_s` | 5 to 120 seconds | 60 | | **Ask at most every** | an AI sell check | `exits[n].ai.every_s` | 60 to 86400 seconds | 900 | | **Answer within** | an AI sell check | `exits[n].ai.timeout_s` | 5 to 120 seconds | 60 | | **Dev buy** | **Launch** | `entry.launch.dev_buy_eth` | 0 to 10 ETH | 0 | **Answer within** is for all the steps of a chain together. An answer that comes later gives no signal, so the bot does not buy or sell on it. ## Limits of the strategy's shape [#limits-of-the-strategys-shape] - A strategy has up to 3 AI steps in its entry, and up to 3 in each AI sell check. - A strategy has up to 10 exits. - A copy wallets trigger follows up to 1,000 wallets. - A timer runs every 60 seconds at the shortest, and every 7 days at the longest. - A strategy's name is 1 to 80 characters. An exit's name is 1 to 40 characters. - A rule's window is at most 3600 seconds. # Presets (/strategies/presets) A preset is a ready-made strategy. It is a starting point to learn from and change, not a strategy that is known to make money. Test it with a [backtest](/strategies/backtests) and on paper before you trade with real funds. ## Use a preset [#use-a-preset] ### Choose the preset [#choose-the-preset] On the **Strategy** tab, open **Start from a preset** and choose one. The preset replaces the strategy in the editor. ### Check and change it [#check-and-change-it] Read its blocks in the **Workflow** tab. Change what you want. The line under the editor shows the tier the strategy needs now. ### Save it [#save-it] Select **Save as new version**. Nothing is saved before this. ## The tier of a preset [#the-tier-of-a-preset] A preset exactly as made needs Common tools. A preset with its numbers changed needs Uncommon tools. Any other change (a new rule, a removed exit, a switch turned on or off) makes it a strategy built from rules, which needs Rare tools. The strategy's name is free to change. Read [the tier a strategy needs](/strategies#the-tier-a-strategy-needs). ## The presets [#the-presets] | **Start from a preset** | What it does | Tier as made | | --- | --- | --- | | **DCA: a quarter of a day's amount every 6 hours** | Buys one token every 6 hours, and never sells. | Common | | **DCA: a day's amount once a day** | Buys one token once a day, and never sells. | Common | | **Copy wallets (add yours)** | Copies the first buy of a token by wallets you choose. | Common | | **Launch momentum (Pons)** | Buys new Pons launches that draw a crowd in their first minute. | Common | | **Launch momentum (Torch)** | The same, for Torch launches, with a check on the anti-snipe tax. | Common | | **AI launch check (Epic; needs an AI key)** | Asks your AI model about each new Pons launch after 30 seconds. | Epic | | **AI launch check on Torch (Epic; needs an AI key)** | The same, for Torch launches, after 60 seconds. | Epic | | **AI launches a token, once a day (Rare; needs an AI key)** | Once a day, your AI model proposes a token, and the Spinner launches it. | Rare | ### DCA [#dca] Both DCA presets buy one chosen token on a timer, and never sell. Each buy adds to one position (`add_to_position` on, `max_open` at 1). The amount is a day's amount: 0.04 ETH a day by default. So the 6-hour preset buys 0.01 ETH four times a day, and the daily preset buys 0.04 ETH once a day. The DCA presets start on SPY. A DCA stays Common at any amount, with any of these tokens, every 6 hours or once a day: A DCA of any other token, or at any other interval, is Uncommon. ### Copy wallets [#copy-wallets] The bot follows the wallets you paste in **Wallets to copy**. When one of them buys a Pons token for the first time, the bot waits 10 seconds, then buys 0.02 ETH of it. It sells at 3 times its entry price (**take_profit**), or after 60 minutes (**time**). It holds up to 50 positions at once. The preset starts with no wallets. Add at least one before you can save. Any wallets keep it Common. Read [copy wallets](/strategies/triggers#copy-wallets). ### Launch momentum (Pons) [#launch-momentum-pons] The bot waits 60 seconds after each Pons launch. It buys 0.02 ETH only if at least 30 wallets bought in that minute, the creator has not sold, and the token has not graduated. It holds up to 5 positions. It sells: 1. Half at 2 times its entry price (**half_at_2x**). 2. What is still held, after the price has been 1.5 times the entry and falls 30% from its peak (**trailing_stop**). 3. All when the estimated return is -50% or less (**stop_loss**). 4. All after 30 minutes (**time**). ### Launch momentum (Torch) [#launch-momentum-torch] The same as the Pons preset, for Torch launches. It also buys only if the buy tax (`token.buy_tax`) is at most 0.1 (10%). A Torch launch's anti-snipe tax is over by the 60-second wait, and the buy still checks it. ### AI launch check [#ai-launch-check] The bot waits 30 seconds after each launch (60 seconds on Torch). Then your AI model reads the token's first trading: buyers, buys and sells, net ETH, price change, creator selling and buy tax. It answers buy or skip, its confidence from 0 to 1, and the risk. The bot buys 0.01 ETH only on "buy", with a confidence of 0.7 or more, and a risk that is not "high". It sells half at 2 times its entry price, all at 0.7 times (**stop_loss**), or all after 30 minutes. It runs the AI at most 20 times an hour. This preset needs an AI key and an Epic Spinner. Read [AI keys](/ai/ai-keys) and [AI steps](/ai/ai-steps). ### AI launches a token, once a day [#ai-launches-a-token-once-a-day] Once a day, your AI model proposes one new meme token: its name, ticker and a one-line description, or "no" when nothing is worth launching. When it says launch, the Spinner's wallet launches the token on Torch, with a 2% buy tax and no dev buy. It launches at most one token a day. It has no exits: a launch is not a position. Read [launching](/launching). ## The JSON of a preset [#the-json-of-a-preset] Each preset is an ordinary strategy. This is the DCA preset every 6 hours, as made: ```json { "schema": 1, "name": "DCA", "entry": { "trigger": { "on": "timer", "every_s": 21600 }, "target": { "token": "0x117cc2133c37b721f49de2a7a74833232b3b4c0c" }, "buy_eth": 0.01 }, "exits": [], "limits": { "once_per_token": false, "max_open": 1, "add_to_position": true } } ``` Read [triggers](/strategies/triggers) for the JSON of the copy wallets and launch momentum presets. # Triggers (/strategies/triggers) The trigger is the **When** block. It decides when the bot starts an entry check. Open it and choose **Start when**: | **Start when** | JSON | Starts a check when | | --- | --- | --- | | **A token launches** | `{"on": "launch"}` | A new token launches on a launchpad. | | **Someone trades a launchpad token** | `{"on": "trade"}` | A wallet buys or sells a launchpad token. | | **On a timer** | `{"on": "timer", "every_s": 3600}` | The timer's period comes round. | | **My own service calls its webhook (Legendary)** | `{"on": "webhook", "fields": {...}}` | Your own service calls the bot's webhook. | ## Launchpads [#launchpads] A launch or trade trigger watches one or both launchpads. Choose it in **Launchpad**: **Pons**, **Torch**, or **Pons and Torch**. - **Pons**: a token starts on a bonding curve, and moves to a Uniswap pool once the curve holds 4.2 ETH. The value `token.graduated` becomes true then. - **Torch**: all of a token's supply is in its own Uniswap pool from the first block. Torch has no move to a pool. The value `token.graduated` becomes true when the price reaches 10 times its launch price. In JSON, the launchpads are `venues`: `["pons"]`, `["torch"]` or `["pons", "torch"]`. A trigger without `venues` watches Pons only. Torch tokens trade in their own Uniswap pool from the first block. With anti-snipe, a buy in its first 15 to 60 seconds pays up to 80% tax: wait it out, or check `token.buy_tax`. The value `token.buy_tax` is the tax as a fraction, so 0.8 is 80%. The Torch launch momentum preset waits 60 seconds and buys only if `token.buy_tax` is at most 0.1. ## A token launches [#a-token-launches] The check starts once for each new token on the chosen launchpads. The token that launched is the token the bot buys, unless the strategy chooses another one. Read [buying](/strategies/buying). Most launch strategies add a wait, then check how the token traded in that time. Example: the launch momentum preset waits 60 seconds, then buys only if at least 30 wallets bought. ```json { "schema": 1, "name": "Launch momentum", "entry": { "trigger": { "on": "launch" }, "wait_s": 60, "confirm": { "and": [ { ">=": [{ "f": "token.buyers", "args": [60] }, 30] }, { "not": { "f": "token.creator_sold" } }, { "not": { "f": "token.graduated" } } ] }, "buy_eth": 0.02 }, "exits": [ { "if": { ">=": [{ "f": "position.multiple" }, 2] }, "sell_pct": 50, "reason": "half_at_2x" }, { "if": { "and": [ { ">=": [{ "f": "position.peak_multiple" }, 1.5] }, { ">=": [{ "f": "position.drawdown_pct" }, 30] } ] }, "reason": "trailing_stop" }, { "if": { "<=": [{ "f": "position.pnl_pct" }, -50] }, "reason": "stop_loss" }, { "if": { ">=": [{ "f": "position.age_s" }, 1800] }, "reason": "time" } ], "limits": { "max_open": 5 } } ``` ## Someone trades a launchpad token [#someone-trades-a-launchpad-token] The check starts on each trade of a token on the chosen launchpads. Set two more fields: - **Which trades**: **Buys**, **Sells**, or **Buys and sells**. In JSON, `side` is `"buy"` or `"sell"`. Leave `side` out for both. - **By**: **Any wallet**, or **Wallets I choose**. The token that was traded is the token the bot buys, unless the strategy chooses another one. Conditions can read the trade itself: `event.eth` (its size), `event.first_buy` (the trader's first buy of the token) and `event.trader`. Read [conditions](/strategies/conditions). ### Copy wallets [#copy-wallets] Choose **Wallets I choose** to copy wallets. Paste the addresses in **Wallets to copy**: one a line, or with commas or spaces between them. The editor keeps each address once, and names any text that is not an address. A strategy can copy up to 1,000 wallets. A wallet counts only when it sends the trade itself. In JSON, the list is `wallets`: ```json { "schema": 1, "name": "Copy wallets", "entry": { "trigger": { "on": "trade", "side": "buy", "wallets": ["0x1111111111111111111111111111111111111111"] }, "if": { "f": "event.first_buy" }, "wait_s": 10, "buy_eth": 0.02 }, "exits": [ { "if": { ">=": [{ "f": "position.multiple" }, 3] }, "reason": "take_profit" }, { "if": { ">=": [{ "f": "position.age_s" }, 3600] }, "reason": "time" } ], "limits": { "max_open": 50 } } ``` This is the copy wallets preset with one example address. Replace it with the wallets you want to copy. ## On a timer [#on-a-timer] The check starts once in each period. Set the period in **Every**, in minutes. The shortest period is 1 minute, and the longest is 7 days. In JSON, `every_s` is the period in seconds (60 to 604800). A timer has no token of its own. So a timer strategy must name the token it buys (`entry.target`), or launch a token. A timer has no triggering trade either, so its conditions cannot read `event` values. Each bot runs at its own moment within the period, so bots on the same timer do not all trade at once. A timer first runs at its next moment after you save, never at once. If the bot misses a moment, it does not make it up. The DCA presets use a timer. Read [presets](/strategies/presets). ### Act when a price passes a level [#act-when-a-price-passes-a-level] A timer can check a price. Name the token in `entry.target`, and put the level in the conditions. On each tick, the bot reads the token's price and buys only if the condition holds. `token.price` is in ETH for one whole token. The rule below buys once when one token costs 0.05 ETH or less: ```json { "trigger": { "on": "timer", "every_s": 60 }, "target": { "token": "0x0000000000000000000000000000000000000001" }, "if": { "<=": [{ "f": "token.price" }, 0.05] }, "buy_eth": 0.01 } ``` Add **Once per token** in the limits, or the bot buys again on each tick while the price stays below the level. The bot sees the price only on a tick, so a short period finds the level sooner. ### Act on an AI signal [#act-on-an-ai-signal] A timer can also ask an AI step on each tick: for example, "Is the news on this stock good or bad today?" The bot buys only if the step's answer passes your rules. AI steps in an entry need an Epic Spinner. Read [AI steps](/ai/ai-steps). ## My own service calls its webhook [#my-own-service-calls-its-webhook] Your own service starts the check with a signed call to the bot's webhook. You declare the fields that your service sends. Rules read them as `hook.`, and prompts as `{{hook.}}`. A token field can be the token that the bot buys. A webhook trigger needs a Legendary Spinner. After you save, the webhook's address and secret show on the **Strategy** tab. Read [webhooks](/ai/webhooks) to set it up. # Versions (/strategies/versions) Each time you save a strategy, it becomes a new version. The newest version is the one the bot runs. Earlier versions stay, with their results. ## Save as new version [#save-as-new-version] Select **Save as new version** under the editor. The button is off while the strategy has problems, or while it needs a higher tier than the Spinner has. When you save, Spin's servers check the strategy again: - The engine's checks, the same as in the editor. - The tier the strategy needs, against the tier the Spinner has now. - The strategy's name and its exit names. Other holders can see these words later, so a word that is flagged is refused, with what to change. Then you see "Saved as version N. The bot uses it within seconds." The card's title shows the strategy's name and its version, for example "Launch momentum (version 3)". A strategy runs only while the Spinner has the tools it needs. Read [rarity and tiers](/spinners/rarity-and-tiers). ## What open positions keep [#what-open-positions-keep] Open positions keep the rules they were opened with. A position sells by the exits and the exit slippage of the version that opened it, even after you save a new version. Only new entries use the new version. ## Version history [#version-history] The **Versions** card on the **Strategy** tab lists every version that the Spinner has run, newest first. More versions load as you scroll. Each version shows: - Its number and name. The version the bot runs now has the **Active** label. - When it ran: "Since" a date for the active version, or the dates from and to for an earlier one. - Who saved it: "you", or "an earlier holder". The history stays with the Spinner after a sale. - Its results, live and paper apart: the trades it closed, the average return a trade, the share it won, and the result in ETH. It also shows how many of its positions are still open. A version with no trades shows "No trades." These results are a record of the past. They do not say how a version will do next. ## Use a version again [#use-a-version-again] ### View its rules [#view-its-rules] In the **Versions** card, select **View rules** on the version. Its rules show as JSON. You cannot change them here. ### Choose to use it [#choose-to-use-it] Select **Use this version again**. This button is not there for the active version. ### Confirm [#confirm] Read the note: "This saves version N's rules as a new version, and the Spinner trades on them at once. Open positions keep the rules they were opened with." Select **Use them now**, or **Cancel**. The rules then become a new version, for example "Version 2's rules are now version 5." The tier check still applies. # The workflow editor (/strategies/workflow-editor) The strategy editor is on the **Strategy** tab of your Spinner. It has two tabs: - **Workflow** shows the strategy as connected blocks, in the order the bot runs them. - **JSON** shows the same strategy as text, in the **Strategy** box. Both tabs edit the same strategy. A change in one tab shows in the other. The engine checks the strategy as you type, with the same checks that Spin's servers run when you save. ## The blocks [#the-blocks] The blocks come from the strategy itself. You do not drag or connect them by hand. The main column shows the entry, from top to bottom: | Block | What it is | | --- | --- | | **When** | The trigger. Read [triggers](/strategies/triggers). | | **Buy only if** | The first condition, checked at once. A strategy that launches tokens shows **Launch only if**. | | **Wait** | Shown only when the strategy waits before its next check. | | **AI: <step name>** | One block for each AI step, up to 3. Read [AI steps](/ai/ai-steps). | | **Then buy if** | The condition on the AI's answers. With a wait and no AI steps, it is **After the wait, buy if**. A launching strategy shows **Then launch if** or **After the wait, launch if**. | | **Buy** | How much ETH the bot buys, and of which token. A launching strategy shows **Launch** instead. Read [buying](/strategies/buying). | Beside the main column, you see: - **Limits**, at the top. Read [limits](/strategies/limits). - One **Sell: <exit name>** block for each sell rule, connected to the **Buy** block. Read [exits](/strategies/exits). - **Never sells**, when the strategy has no sell rules. The bot then only buys and holds. Each block shows its settings in one or two lines, for example "token.buyers(60) at least 30 and token.creator_sold is no". A strategy that launches tokens has no sell blocks. A launch is not a position: the bot does not sell the tokens it launches. ## Open a block [#open-a-block] ### Select the block [#select-the-block] Click or tap the block. A dialog opens with the block's settings. ### Change the settings [#change-the-settings] Change the fields. The workflow and the JSON change as you type. ### Close the dialog [#close-the-dialog] Select **Done**. Some blocks have a **Remove** button in their dialog: **Wait**, each **Sell** rule, and each AI step. The other blocks always stay, because every strategy has them. A launching strategy always keeps at least one AI step, because an AI step writes each launch. When you remove the wait, the check after it goes too, unless the strategy has AI steps. When you remove the last AI step, its check goes too, unless the strategy has a wait. ## Add a block with "+" [#add-a-block-with-] A "+" button shows wherever a block can go. Select it to see what it can add. When you choose an item, the editor adds the block and opens it. | Where the "+" is | What it offers | | --- | --- | | On the link after **Buy only if**, when there is no wait | **Wait**: "Then check again, e.g. to see if a launch draws a crowd." | | On the link after the wait, or after **Buy only if** when there is no wait | **AI step**: "Ask your AI model (with data tools). Later blocks can use its answer." | | On the link after each AI step | **AI step**, to add the next step there | | Under the sell rules (**Add an exit**) | **Sell rule**: "Sell when a rule holds: a profit, a loss, a time." **AI sell check**: "Ask your AI model whether to sell each position." | The **AI step** item shows only while the strategy has fewer than 3 AI steps. A new wait starts at 60 seconds. A new sell rule starts as "position.multiple at least 2". AI steps and AI sell checks need an Epic Spinner, except for the AI step that writes a token launch. Read [the tier a strategy needs](/strategies#the-tier-a-strategy-needs). ## Problems on blocks [#problems-on-blocks] When the engine finds a problem, the block it is about gets a red border and a note, for example "2 to fix". Open the block to read the problems at the top of its dialog. The editor also lists every problem under the strategy. A problem that is about the strategy as a whole shows only there. You cannot save the strategy until it has no problems. The editor also warns you when an AI step cannot run for you today: when you have no AI key, no key for the step's provider, or not the MCP server that the step reads. These are warnings, not problems. You can still save. ## Conditions that only JSON can show [#conditions-that-only-json-can-show] The condition fields in the workflow show rows that must all hold. A condition that uses more than that (`or`, a `not` around more than one value, or arithmetic) shows this note: "This condition uses more than the form shows (or, not, arithmetic). It is kept as it is: edit it in the JSON tab." The block shows "A rule only the JSON tab shows". Read [conditions](/strategies/conditions). ## When the JSON does not parse [#when-the-json-does-not-parse] If the text in the **JSON** tab is not valid JSON, or not a strategy object, the **Workflow** tab cannot show it. It says: "The JSON is not a strategy the workflow can show yet (it does not parse). Fix it in the JSON tab." ## Narrow screens [#narrow-screens] The workflow uses its full width. On a screen narrower than two columns of blocks, it uses one column: **Limits** at the top, then the entry, then the sell rules under **Buy**, set in a little. The canvas does not pan or zoom. The page scrolls over it, as over any part of the page. ## Start from a preset [#start-from-a-preset] Use **Start from a preset** above the tabs to replace the strategy in the editor with a preset. Nothing is saved until you select **Save as new version**. Read [presets](/strategies/presets). You can also describe a strategy in words and let your own AI model write it. Read [build with AI](/strategies/build-with-ai). ## Save [#save] Give the strategy a name in **Strategy name**, then select **Save as new version**. Read [versions](/strategies/versions). # Weekly airdrop (/token/airdrop) $SPIN launches on Torch. Torch pays the creator of a token a share of the tax on buys of that token. These are $SPIN's **creator fees**. Each week: - 70% of $SPIN's creator fees are airdropped to Spinner wallets, in ETH. - 30% go to the protocol. The weekly payout is not live yet. It starts after $SPIN launches. The leaderboard that decides it is built, and you can see it now. ## Who qualifies [#who-qualifies] Every Spinner whose bot makes the weekly trade minimum gets a share. Not only the top bots: every bot that makes the minimum. To qualify, a bot must: - Trade live, with real ETH. Paper bots are not ranked. - Be ranked on the 7-day [leaderboard](/token/leaderboard) when the week ends. A bot is ranked when it makes at least 5 trades (buys or sells) in the window. The week ends each Monday at 00:00 UTC. At that time, Spin's servers freeze the 7-day board. The airdrop for that week uses the frozen board. ## How shares work [#how-shares-work] Every ranked bot gets a share. The higher its place on the leaderboard, the bigger its share. The airdrop is paid in ETH. The airdrop goes to the Spinner's own wallet, not to the holder's wallet. It stays with the Spinner if the Spinner is sold. ## What to expect [#what-to-expect] The size of the airdrop depends on the creator fees that $SPIN earns that week. It changes every week. It is not guaranteed. A bot's rank depends on its trades, and many strategies lose money. See [risks](/safety/risks). # Fees and burns (/token/fees-and-burns) Spin has no subscription. You pay to mint and activate a Spinner, and the bot pays a fee on the trades it makes. A bot that does not trade pays no trading fee. ## Every fee [#every-fee] | Fee | Amount | Paid in | Where it goes | |---|---|---|---| | Mint | 10,000 $SPIN per Spinner | $SPIN | 100% to the protocol | | Activation | 5,000 $SPIN, again after each sale | $SPIN | 70% burned, 30% to the protocol | | Trading fee | 0.5% of each bot trade, each way | ETH | 70% buys back and burns $SPIN, 30% to the protocol | | USDG position fee (Legendary) | 5% of realised gains | USDG | The protocol | $SPIN's own creator fees are split too: 70% go to Spinner wallets each week and 30% go to the protocol. See [the weekly airdrop](/token/airdrop). ## Mint [#mint] A Spinner costs 10,000 $SPIN. The payment goes to the protocol. See [minting](/spinners/minting). ## Activation [#activation] A new Spinner starts inactive. Activation costs 5,000 $SPIN: - 3,500 $SPIN (70%) is burned. - 1,500 $SPIN (30%) goes to the protocol. Each sale or transfer makes the Spinner inactive again. The new holder pays the activation fee again. The Spinner's wallet, strategy and record stay with it. AI keys and MCP servers stay with the earlier holder, so the new holder adds their own. See [transfers](/spinners/transfers). ## Trading fee [#trading-fee] The guard takes 0.5% of each trade that a live bot makes: - On a buy: 0.5% of the ETH that the bot spends. - On a sell: 0.5% of the ETH that the bot gets. The guard sends the fee in ETH from the Spinner's wallet to the protocol. 70% of it is used to buy $SPIN on the market and burn it. 30% goes to the protocol. A buyback contract that buys and burns $SPIN with the 70% share. The 70/30 split applies from the first trade. Until the contract is live, the protocol keeps the 70% share apart. When the contract goes live, the whole saved balance goes into it to buy and burn $SPIN. The guard contract cannot charge more than 1% on a trade. Paper trades move no money, so nothing is paid. But paper results and backtests include the fee, so you can see its effect. ## Other costs [#other-costs] These costs are not Spin's fees, but your bot pays them: - **Gas.** The Spinner's wallet pays the gas for each of its trades. The guard contract caps the gas price and the amount for each trade. - **Venue fees and taxes.** Pools, launchpads and tokens take their own fees and taxes. See [venues](/trading). - **AI calls.** AI steps run on your own API key, so your provider bills you. See [AI keys](/ai/ai-keys). On buys, the trading fee and the gas count against your per-trade and per-day [limits](/safety). ## Burns [#burns] $SPIN is burned in two ways: 1. 70% of each activation fee, when the Spinner is activated. 2. The $SPIN that 70% of the trading fees buy back. A burn destroys the tokens, so the supply of $SPIN gets smaller. # $SPIN (/token) $SPIN is Spin's token. It runs the economy around the bots. You use it to mint Spinners, to activate them, and to unlock higher tiers of tools. $SPIN is not launched yet. Its address shows as "TBC" on the [contract addresses](/reference/contract-addresses) page until it is. ## Where it launches [#where-it-launches] $SPIN launches on [Torch](/trading), a launchpad on Robinhood Chain. A Torch token trades in a Uniswap V4 pool against ETH from its first block. ## What $SPIN is for [#what-spin-is-for] | Use | Amount | What it does | |---|---|---| | Mint | 10,000 $SPIN per Spinner | Mints one Spinner. See [minting](/spinners/minting). | | Activate | 5,000 $SPIN | Switches the Spinner's bot on. A sale resets it. See [activation](/spinners/activation). | | Hold to unlock | See the table below | Unlocks the tools of higher tiers. Nothing is spent. | ## Hold to unlock [#hold-to-unlock] A Spinner's rarity sets the tools its bot can use. Hold $SPIN in the wallet that holds the Spinner, and the Spinner gets the tools of a higher tier. - The Spinner's tier is the higher of its rarity and what your $SPIN unlocks. - Each tier keeps every tool of the tiers below it. - Holding is enough. Nothing is spent or locked. - The steps above the Spinner's own rarity add up. This table shows the $SPIN to hold, by the Spinner's rarity: If you sell or move the $SPIN, the Spinner goes back to the tier of its rarity. See [rarity and tiers](/spinners/rarity-and-tiers) for the tools of each tier. ## The flywheel [#the-flywheel] The bots feed $SPIN in three ways: 1. **Activation burns $SPIN.** 70% of each activation fee is burned. A sale resets activation, so each new holder pays it again. 2. **Trades buy back and burn $SPIN.** Each bot trade pays a 0.5% fee, each way. 70% of the fee buys back $SPIN and burns it. 3. **$SPIN's creator fees go back to the bots.** 70% of $SPIN's creator fees go to Spinner wallets each week. Every Spinner that makes the weekly trade minimum gets a share. So more bots that trade means more $SPIN bought back and burned, and more Spinners that share the weekly airdrop. The size of each part depends on what the bots and the market do. Nothing about it is guaranteed. See [fees and burns](/token/fees-and-burns) for every split, and [the weekly airdrop](/token/airdrop) for who gets a share. Mint, activation and tier unlocks are fixed amounts of $SPIN. The price of $SPIN can fall as well as rise. See [risks](/safety/risks). # Leaderboard (/token/leaderboard) The leaderboard is a public page of the Spin app. Anyone can see it, without signing in. It ranks live bots by their profit and loss (P/L). ## What it ranks [#what-it-ranks] - **Live bots only.** Paper bots are not ranked. - **The bot's own trades only.** Deposits, withdrawals, tokens you send to the wallet and the [USDG position](/trading/usdg-position) do not count. - **P/L after costs.** P/L is the ETH from sales, less the ETH spent on buys, plus what selling the open positions would return now. It is after the 0.5% trading fee and gas. Open positions are valued at what a sale would really return now, with price impact. So a push on a thin pool's price just before an update barely moves a bot's P/L. ## Windows [#windows] Choose a window: - 1 day - 7 days (the default) - 30 days A bot's P/L in a window is its P/L now, less its P/L at the start of the window. The board updates every 5 minutes. ## Rank by % or by ETH [#rank-by--or-by-eth] Use **Rank by** to choose: | Choice | What it ranks | |---|---| | Return (%) | P/L divided by the capital at work: the cost of what the bot held at the start of the window, plus its buys in the window. | | Profit (ETH) | P/L in ETH. | Each row shows the P/L in % and in ETH, with its value in dollars, and the bot's trades in the window. ## Who is ranked [#who-is-ranked] A bot is ranked in a window when it makes at least 5 trades (buys or sells) in that window. One lucky trade does not top the board. A bot with fewer trades shows without a rank. ## Find a Spinner [#find-a-spinner] ### Open the search [#open-the-search] Use **Find a Spinner or a wallet** at the top of the leaderboard. ### Enter a Spinner number or a wallet [#enter-a-spinner-number-or-a-wallet] Enter a Spinner number, such as `#123`, or a wallet address. A wallet shows every Spinner it holds. ### Read the result [#read-the-result] The result shows each Spinner's row in the window, or why it has none: - "Not ranked yet": the bot has fewer than 5 trades in this window. - "Trades on paper": only live bots are ranked. - "No live trades or open positions in this window". Select a Spinner in the list to open its public page, with its record and its open and closed positions. ## The weekly airdrop [#the-weekly-airdrop] Each Monday at 00:00 UTC, the 7-day board decides the [weekly airdrop](/token/airdrop). Every ranked bot gets a share, and a higher rank gets a bigger share. A bot at the top of the board can lose next week. The board shows what bots did, not what they will do. # Venues (/trading) A bot trades from its Spinner's own wallet, in ETH. Each trade goes through the [guard](/safety), which runs it through a venue adapter: a small contract that knows how to trade on one venue. The guard accepts only adapters that it lists. Live trading starts on Robinhood Chain when the guard and the venue adapters are deployed. Until then, every bot trades on paper. The [contract addresses](/reference/contract-addresses) page shows "TBC" for each contract that is not deployed yet. ## The venues [#the-venues] | Venue | What it is | What a bot trades there | |---|---|---| | UP | A decentralised exchange on Robinhood Chain | Its V2-style volatile pools and its concentrated-liquidity pools. Spin does not offer UP's stable pools. | | Uniswap | A decentralised exchange | V3 pools and V4 pools. A V4 pool with a hook is used only if the Uniswap adapter allows that hook. | | Pons | A launchpad with a bonding curve | ETH-paired Pons tokens on their bonding curve. After a token graduates, the bot trades it in its Uniswap V4 pool. | | Torch | A launchpad | ETH-paired Torch tokens, in each token's own Uniswap V4 pool. | ### Pons [#pons] A new Pons token trades on a bonding curve: the price goes up as people buy and down as they sell. When the curve fills, the token **graduates**: it leaves the curve for a Uniswap V4 pool. The bot follows the token to its pool. On the curve, Pons takes a 1% fee on each buy and each sell, plus the token's own creator tax. In the pool, the pool's hook takes its cut. ### Torch [#torch] A Torch launch puts the whole supply of the token into a Uniswap V4 pool against ETH from the first block. There is no bonding curve and no move to a new pool. Every Torch pool has a 0.3% pool fee and no hook. Torch has no graduation event. Torch's app shows "Launch Complete" when the price reaches 10 times the token's starting price. This is only a display marker: nothing changes on chain. In a strategy, `token.graduated` is true for a Torch token once it reaches that mark. Spin trades only Torch tokens that are paired with ETH. ## Which token the bot buys [#which-token-the-bot-buys] A strategy buys one of two kinds of token: - **The token that started the entry.** A launch or a trade on Pons or Torch starts the entry, and the bot buys that token on its launchpad. See [triggers](/strategies/triggers). - **A chosen token.** You pick a token in the strategy (for example a stock token or a token that an AI step names). The bot trades it on UP or Uniswap. See [buying](/strategies/buying). ### The best quote [#the-best-quote] For a chosen token, the bot uses the pool with the best quote at the time of each trade: 1. Spin's servers find the token's deepest pools on UP and Uniswap (V3 and V4). They use only pools against wrapped ETH, native ETH or USDG. Pools with less than about $1,000 of liquidity are not used. 2. For each trade, the servers get a quote from each of these pools. 3. The trade goes to the pool that gives the most. A trade in a USDG pool goes through a USDG pool against ETH in the same swap. You can change this in the strategy: - Keep the token to one venue (UP or Uniswap). The bot then uses the best pool on that venue. - Pin one pool. The bot then uses only that pool. Spin's servers check the pool on chain before the first trade. ## Slippage [#slippage] Slippage is how much less you get than the quote, because the price moved or your own trade moved it. Each strategy sets two limits: | Setting | Default | Range | What it does | |---|---|---|---| | Slippage (on the buy) | 10% | 0.1% to 50% | The buy reverts if it would get more than this much less of the token than quoted. | | Exit slippage (in the limits) | 25% | 1% to 90% | A sell reverts if it would get more than this much less ETH than expected. | A trade that reverts on slippage does not happen. The bot's activity says "Not done: the price moved past the strategy's slippage limit." A low limit protects the price but can miss fast markets. A high limit fills more often but can fill at a bad price. Set both in the [workflow editor](/strategies/workflow-editor) and [limits](/strategies/limits). ## Taxes on Torch [#taxes-on-torch] Every Torch token has a **buy tax**, set at launch from 1% to 10%. It never changes after launch. Sells are not taxed. A Torch launch can also have an **anti-snipe** tax. It starts at 80% and falls in a straight line to the token's own rate. On Torch's presets this takes 15 or 30 seconds after launch. The token takes its tax after the swap checks its minimum. So a buy during anti-snipe can pass the slippage check and still lose up to 80% to the tax. To avoid this, add a condition on `token.buy_tax` (for example, at most 0.1) or wait before the buy. Spin's Torch presets wait 60 seconds and check `token.buy_tax`. Other tokens can have taxes too: a Pons token's creator tax, or a fee that a Uniswap V4 hook takes. The values `token.buy_tax` and `token.liquidity` help you write rules for this. See [conditions](/strategies/conditions). ## The trading fee [#the-trading-fee] The guard takes a fee of 0.5% of each trade, each way: - On a buy, 0.5% of the ETH that the bot spends. - On a sell, 0.5% of the ETH that the bot gets. The guard takes the fee in ETH from the Spinner's wallet. 70% of the fee buys back and burns $SPIN. 30% goes to the protocol. See [fees and burns](/token/fees-and-burns). The Spinner's wallet also pays the gas for each trade. The fee and the gas count against your [limits](/safety) on buys. # USDG position (/trading/usdg-position) The USDG position is built but is not deployed on Robinhood Chain yet. In the app, its tab says "It is not live on this network yet" until then. The USDG position is a tool for [Legendary](/spinners/rarity-and-tiers) Spinners. You deposit USDG (Robinhood's dollar token) and choose a risk level. Spin's servers then keep the balance in one venue at a time and move it when another venue that your level allows is projected to pay clearly more. A Spinner that is not Legendary by rarity can get this tool by holding $SPIN. See [hold-to-unlock](/token). ## Where the position lives [#where-the-position-lives] Each Spinner has its own position contract. The Spinner's wallet owns it. So: - Only the wallet that holds the Spinner can set it up, deposit, withdraw or change its risk. - The position moves with the Spinner when it is sold. - Spin's servers can only put the USDG into a listed venue that your risk level allows, take it out, and collect its income. They cannot withdraw it. ## Set it up [#set-it-up] ### Open the USDG position tab [#open-the-usdg-position-tab] Open your bot's page and go to the USDG position tab. ### Choose a risk level [#choose-a-risk-level] Choose Stable, Balanced or Active. You can also turn on Stable LP. ### Enter the USDG to put in [#enter-the-usdg-to-put-in] The USDG comes from your wallet. ### Press "Set up and deposit" [#press-set-up-and-deposit] One request creates the position, saves your risk choice, deposits the USDG and adds the gas float. Your choice lasts one year. You can renew it. ## Risk levels [#risk-levels] Each level allows a set of venue types. Spin's servers put the whole balance into one venue at a time, from the types that your level allows. | Level | Venues it allows | |---|---| | Stable | Lending vaults only (Morpho, Spark). No exposure to ETH. | | Balanced | Uniswap ETH/USDG ranges when they are projected to beat lending, else lending. | | Active | Also UP's reward pools (ETH, tokenized stocks) when they are projected to beat both. | **Stable LP** is an option that you can add to any level. It allows UP's aUSD/USDG pool. aUSD is a new stablecoin. If it failed, up to half of what is in that pool could be lost. A liquidity range holds part of its value in the other token (ETH or a stock token), so its value also moves with that token's price. The tab shows a "Venues now" card with each venue's projection. These are projections, not promises. They change every hour. ## Rebalancing [#rebalancing] Spin's servers check the venues every few minutes. They: - Collect the venue's income (fees or rewards), about once a day. - Move the balance only when another allowed venue is projected to pay clearly more, after the cost of the move. - Re-centre a liquidity range when the price leaves it. - Leave a stablecoin pool if its price moves too far off the peg. You can change the risk level at any time. If the balance is in a venue that the new level does not allow, it leaves that venue. ## Withdrawals [#withdrawals] There is no lock-up. Spin's servers can never block a withdrawal. - Withdraw an amount, or 25%, 50% or all of the position. - The USDG goes to the Spinner's wallet. From there, withdraw it to your own wallet on the Wallet tab. - A full withdrawal also returns the gas float. If a venue's exit cannot run, the position has an escape: you request it, and after 7 days you can make any call from the position yourself. ## The fee [#the-fee] The protocol takes 5% of realised gains, never of the balance: - A gain is realised when income is collected or when the balance comes back from a venue with more than went in. - A withdrawal also pays 5% on the gain that it realises. - A loss is carried forward. Later gains first make up that loss, and pay no fee until they do. The position contract cannot charge more than 10%. ## The gas float [#the-gas-float] The position keeps a small amount of ETH to pay the gas for each step that Spin's servers take. Setup adds 0.002 ETH from your wallet. - The float is used only while the balance is in a venue. - When it runs low, the tab warns you. Spin's servers then stop collecting income and keep enough for an exit. - Top it up from the tab at any time. The float stays the position's and comes back with a full withdrawal. ## If the Spinner stops being Legendary [#if-the-spinner-stops-being-legendary] If the Spinner's tier drops below Legendary (for example, you sell some $SPIN): 1. At once, Spin's servers take no new risk. 2. After 72 hours, they move everything to Stable (lending). Hold the $SPIN again to keep your choice. Withdrawals stay open the whole time. ## When the Spinner is sold [#when-the-spinner-is-sold] A new holder must choose a risk level again before Spin's servers act on the position. The Spinner must also be active. Until then, the balance stays where it is, and the holder can withdraw it. Before you sell a Spinner, withdraw the position. See [transfers](/spinners/transfers).