Hushxima
Marketplace

External farming

Hand us wallets you already hold and we give them a life. Daily on-chain activity under a persona, for as long as you ask, with the keys returned or forgotten at the end.

Everything else on this site is about wallets the platform produced. External farming is the other direction: wallets you already hold, whose keys you hand over, and which the platform then trades on your behalf so they build the same kind of history the catalog sells. A wallet you bought here can be enrolled too, to keep its activity going after the sale.

Nothing is funded for you here. The wallets farm with what they hold, or with the slice of it you let them have: see How much it trades with.

What is on offer

GET /aging/external/presets lists what an enrolment can ask for: the chains farming runs on, the personas available with the chains each is calibrated for, the timezone profiles (an IANA zone and a waking window), the tiers, and the limits on a request.

GET
/aging/external/presets

Authorization

bearerAuth
AuthorizationBearer <token>

JWT from /auth/login (users) or an org API key (mk_...) for integrations.

In: header

Response Body

application/json

curl -X GET "https://example.com/aging/external/presets"
{  "chains": [    "string"  ],  "limits": {    "max_duration_days": 0,    "max_tx_per_day": 0,    "max_wallets_per_request": 0  },  "personas": [    {      "chains": [        "string"      ],      "description": "string",      "id": "string",      "name": "string"    }  ],  "tiers": [    "string"  ],  "timezone_profiles": [    {      "iana": "string",      "id": "string",      "name": "string",      "wake_end": "string",      "wake_start": "string"    }  ]}

Enrolling

POST /aging/external/enroll takes a batch of private keys and a farming profile shared by the batch.

{
  "wallets": [
    { "secret_key": "0x…", "buyer_ref": "customer-42" },
    { "secret_key": "5Kd…", "chains": ["solana"], "label": "treasury-2" }
  ],
  "chains": ["ethereum", "base"],
  "persona": "memecoin_degen",
  "timezone_profile": "europe_day",
  "tier": "tier2",
  "tx_per_day_min": 2,
  "tx_per_day_max": 6,
  "duration_days": 30,
  "budget_min_native": "500000000000000000",
  "budget_max_native": "1000000000000000000",
  "budget_compound": true,
  "token_mints": ["0x…", "0x…"],
  "token_inherit_default": true
}

A key is accepted as hex for an EVM wallet, with or without the 0x, and as base58, hex or a JSON byte array for a Solana keypair. It is encrypted on arrival like every other key the platform holds, and never written down in clear. See Security.

Each key farms only the chains of its own network. A Solana key farms solana; an EVM key farms every EVM chain you list, since it is the same address on all of them, and the first one listed is its home chain. A per-wallet chains overrides the request's list for that wallet.

persona and timezone_profile take an id or a name from the presets. tier defaults to tier1 and only shapes how positions are handled. Every wallet draws its own daily rate from [tx_per_day_min, tx_per_day_max], so a batch does not move in lockstep, and the farm runs duration_days from now.

The last five fields bound what the farm may do with each wallet. They are optional, they apply to every wallet of the request, and each wallet may carry its own copy to override them. They have their own section below.

The response names what was enrolled and what was skipped, with a reason per skipped wallet, and for each enrolled wallet the daily rate (tx_per_day) and the budget (budget_native) that were drawn for it. An address you had enrolled before is re-enrolled on the new plan, flagged reenrolled. A wallet bought on the marketplace is flagged purchased: it stays in your purchases and farms on top.

With a user session this call needs an organisation admin. With an API key it does not: a backend integration is expected to drive enrolment, and an API key is already the organisation's credential.

POST
/aging/external/enroll

Authorization

bearerAuth
AuthorizationBearer <token>

JWT from /auth/login (users) or an org API key (mk_...) for integrations.

In: header

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Per-wallet farming limits: how much native to trade with, and which tokens.

These fields appear both on the request (as the default for every wallet in it) and on each wallet (overriding that default). The budget range and the token list each move as a unit: a wallet naming one bound, or one mint, replaces that whole setting rather than half of it.

Response Body

application/json

curl -X POST "https://example.com/aging/external/enroll" \  -H "Content-Type: application/json" \  -d '{    "chains": [      "string"    ],    "duration_days": 0,    "persona": "string",    "timezone_profile": "string",    "tx_per_day_max": 0,    "tx_per_day_min": 0,    "wallets": [      {        "secret_key": "string"      }    ]  }'
{  "enrolled": [    {      "budget_native": "string",      "buyer_ref": "string",      "chains": [        "string"      ],      "ends_at": "string",      "pubkey": "string",      "purchased": true,      "reenrolled": true,      "tx_per_day": 0,      "wallet_id": "string"    }  ],  "skipped": [    {      "reason": "string",      "reference": "string"    }  ]}

How much it trades with

Left to itself, a farm trades with the wallet's whole balance: every buy is sized as a share of what the wallet holds, as the persona dictates. A customer handing over a wallet with 10 SOL on it has all 10 SOL in play. The budget fields cap that.

The budget

budget_min_native and budget_max_native give, in base units of the home chain, the range the wallet's budget is drawn from. Each wallet draws its own figure, the way it draws its own daily rate, so a batch enrolled on one range does not trade in lockstep. Name one bound only and the budget is pinned to it exactly. Name neither and there is no cap, which is how every farm behaved before these fields existed.

The budget is checked against the wallet itself, at enrolment:

  • the maximum may not exceed what the wallet actually holds, since the budget is a slice of the balance and not a promise to fund it;
  • the minimum has to be large enough to fund one swap on the wallet's chains, or the farm would schedule buys that can only ever fail.

Either refusal skips that one wallet with a reason, and the rest of the request goes through.

It revolves

The budget is an envelope, not a spend cap. Nothing counts how much the farm has spent so far. The one invariant is that the native balance never falls below what the wallet held at enrolment minus the budget: a 10 SOL wallet on a 1 SOL budget never goes under 9 SOL. Buying moves money out of the envelope into a position, selling moves it back, and the farm keeps cycling on the same slice for as long as it runs.

Mid-position the envelope reads smaller, because the native is deployed, so the next buy scales down to what is actually free. It never reads larger than the truth, and the floor holds either way.

Compounding

budget_compound, on by default, lets realised gains grow the envelope. A 1 SOL budget whose positions sell back for 1.5 SOL then trades with 1.5 SOL. Switch it off and the envelope stays at its nominal size: the gains sit on the wallet, untouched by farming, above the floor.

Losses need no setting. A position that sells for less than it cost leaves the envelope smaller, and the floor is what stops a losing streak from eating into the rest of the wallet.

Which tokens

token_mints pins the wallet to a list of tokens. By default (token_inherit_default: true) they are added to the persona's own universe for each chain; set it to false and the list is the universe, and the wallet trades nothing else. Every pinned mint must be known and tradeable on at least one of the wallet's chains, or the wallet is skipped with the offending mints named. A replacing list that resolves to nothing on one of the wallet's chains is refused too, since it would leave that chain with nothing to trade.

Unlike the budget, the token list is not checked against the wallet's holdings: it says what the farm may buy, not what the wallet has.

Both settings move as a unit. A wallet naming one budget bound, or one mint, replaces the request's whole budget range, or whole token list, rather than half of it.

Following the farm

GET /aging/external lists your farmed wallets, running ones by default and stopped ones too with include_stopped=true, filterable by buyer_ref. Each row carries the plan (chains, the rate actually drawn as tx_per_day, duration_days, started_at, ends_at), where it stands (state is running, stopped or finished, stop_reason says why when it stopped), and what the wallet looks like now: balance on its home chain, tx_count, persona, timezone, tier. The limits it was enrolled with are there too: the budget drawn (budget_native, null when uncapped) with the range it came from, budget_compound, and the pinned token_mints with token_inherit_default.

A farm ends on its own at ends_at. The keys are kept; stop with forget if you want them gone.

GET
/aging/external

Authorization

bearerAuth
AuthorizationBearer <token>

JWT from /auth/login (users) or an org API key (mk_...) for integrations.

In: header

Query Parameters

buyer_ref?|

Only the wallets tagged with this buyer reference.

Defaultnull
include_stopped?boolean
Defaultfalse
limit?integer
Formatint64
Default50
offset?integer
Formatint64
Default0

Response Body

application/json

curl -X GET "https://example.com/aging/external"
[  {    "aging_status": "string",    "balance": "string",    "budget_compound": true,    "budget_max_native": "string",    "budget_min_native": "string",    "budget_native": "string",    "buyer_ref": "string",    "chains": [      "string"    ],    "duration_days": 0,    "ends_at": "string",    "label": "string",    "network": "string",    "next_op_at": "string",    "ops_completed": 0,    "ops_failed": 0,    "ops_pending": 0,    "ops_skipped": 0,    "org_id": "string",    "org_name": "string",    "persona": "string",    "pubkey": "string",    "purchased": true,    "start_balance": "string",    "started_at": "string",    "state": "string",    "stop_reason": "string",    "stopped_at": "string",    "tier": "string",    "timezone": "string",    "token_inherit_default": true,    "token_mints": [      "string"    ],    "tx_count": 0,    "tx_per_day": 0,    "tx_per_day_max": 0,    "tx_per_day_min": 0,    "wallet_id": "string",    "wallet_status": "string"  }]

Stopping

POST /aging/external/stop takes a list of addresses and stops their farms. With "forget": true the platform also drops the wallet and replaces its key by a tombstone, the same way key retention does. The same key can be enrolled again later; it just has to be sent again.

Addresses that are not yours, or not farmed, come back under skipped with a reason, and the rest is stopped.

POST
/aging/external/stop

Authorization

bearerAuth
AuthorizationBearer <token>

JWT from /auth/login (users) or an org API key (mk_...) for integrations.

In: header

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

curl -X POST "https://example.com/aging/external/stop" \  -H "Content-Type: application/json" \  -d '{    "pubkeys": [      "string"    ]  }'
{  "skipped": [    {      "reason": "string",      "reference": "string"    }  ],  "stopped": [    "string"  ]}

Last updated on

On this page