shield-swap-sdk 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- shield_swap_sdk-0.2.0/.gitignore +2 -0
- shield_swap_sdk-0.2.0/PKG-INFO +182 -0
- shield_swap_sdk-0.2.0/README.md +165 -0
- shield_swap_sdk-0.2.0/codegen/amm_api.openapi.json +5928 -0
- shield_swap_sdk-0.2.0/codegen/regen-abi.sh +52 -0
- shield_swap_sdk-0.2.0/codegen/regen-openapi.sh +15 -0
- shield_swap_sdk-0.2.0/codegen/shield_swap.abi.json +2777 -0
- shield_swap_sdk-0.2.0/codegen/shield_swap.aleo +6437 -0
- shield_swap_sdk-0.2.0/pyproject.toml +19 -0
- shield_swap_sdk-0.2.0/pyrightconfig.json +8 -0
- shield_swap_sdk-0.2.0/pytest.ini +10 -0
- shield_swap_sdk-0.2.0/python/aleo_shield_swap/__init__.py +60 -0
- shield_swap_sdk-0.2.0/python/aleo_shield_swap/_api_models.py +832 -0
- shield_swap_sdk-0.2.0/python/aleo_shield_swap/_calls.py +98 -0
- shield_swap_sdk-0.2.0/python/aleo_shield_swap/_core.py +311 -0
- shield_swap_sdk-0.2.0/python/aleo_shield_swap/_generated.py +508 -0
- shield_swap_sdk-0.2.0/python/aleo_shield_swap/agent.py +177 -0
- shield_swap_sdk-0.2.0/python/aleo_shield_swap/api.py +236 -0
- shield_swap_sdk-0.2.0/python/aleo_shield_swap/async_client.py +323 -0
- shield_swap_sdk-0.2.0/python/aleo_shield_swap/client.py +603 -0
- shield_swap_sdk-0.2.0/python/aleo_shield_swap/derivations.py +179 -0
- shield_swap_sdk-0.2.0/python/aleo_shield_swap/errors.py +56 -0
- shield_swap_sdk-0.2.0/python/aleo_shield_swap/mcp.py +101 -0
- shield_swap_sdk-0.2.0/python/aleo_shield_swap/tick_hints.py +29 -0
- shield_swap_sdk-0.2.0/python/aleo_shield_swap/tick_math.py +58 -0
- shield_swap_sdk-0.2.0/python/aleo_shield_swap/types.py +108 -0
- shield_swap_sdk-0.2.0/tests/__init__.py +0 -0
- shield_swap_sdk-0.2.0/tests/conftest.py +221 -0
- shield_swap_sdk-0.2.0/tests/fixtures/pools_response.json +41 -0
- shield_swap_sdk-0.2.0/tests/fixtures/programs/shield_swap_v3.aleo +6439 -0
- shield_swap_sdk-0.2.0/tests/fixtures/programs/test_shield_swap_multisig_core.aleo +827 -0
- shield_swap_sdk-0.2.0/tests/fixtures/programs/test_token_a.aleo +193 -0
- shield_swap_sdk-0.2.0/tests/fixtures/programs/test_token_b.aleo +193 -0
- shield_swap_sdk-0.2.0/tests/integration/__init__.py +0 -0
- shield_swap_sdk-0.2.0/tests/integration/conftest.py +61 -0
- shield_swap_sdk-0.2.0/tests/integration/devnode_amm.py +276 -0
- shield_swap_sdk-0.2.0/tests/integration/test_devnode_lifecycle.py +334 -0
- shield_swap_sdk-0.2.0/tests/integration/test_drift.py +37 -0
- shield_swap_sdk-0.2.0/tests/integration/test_reads_live.py +153 -0
- shield_swap_sdk-0.2.0/tests/integration/test_swap_lifecycle.py +84 -0
- shield_swap_sdk-0.2.0/tests/test_agent.py +38 -0
- shield_swap_sdk-0.2.0/tests/test_api_client.py +90 -0
- shield_swap_sdk-0.2.0/tests/test_api_models.py +40 -0
- shield_swap_sdk-0.2.0/tests/test_async_client.py +192 -0
- shield_swap_sdk-0.2.0/tests/test_blinding.py +92 -0
- shield_swap_sdk-0.2.0/tests/test_claim.py +58 -0
- shield_swap_sdk-0.2.0/tests/test_client_reads.py +74 -0
- shield_swap_sdk-0.2.0/tests/test_core.py +129 -0
- shield_swap_sdk-0.2.0/tests/test_derivations.py +37 -0
- shield_swap_sdk-0.2.0/tests/test_errors.py +27 -0
- shield_swap_sdk-0.2.0/tests/test_generated.py +42 -0
- shield_swap_sdk-0.2.0/tests/test_liquidity.py +141 -0
- shield_swap_sdk-0.2.0/tests/test_mcp.py +31 -0
- shield_swap_sdk-0.2.0/tests/test_package.py +5 -0
- shield_swap_sdk-0.2.0/tests/test_swap.py +95 -0
- shield_swap_sdk-0.2.0/tests/test_tick_math.py +47 -0
- shield_swap_sdk-0.2.0/tests/test_types.py +37 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: shield-swap-sdk
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Python SDK for the shield swap AMM Dex on Aleo
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Requires-Dist: aleo-sdk>=0.2
|
|
7
|
+
Requires-Dist: requests>=2
|
|
8
|
+
Provides-Extra: async
|
|
9
|
+
Requires-Dist: httpx>=0.27; extra == 'async'
|
|
10
|
+
Provides-Extra: dev
|
|
11
|
+
Requires-Dist: datamodel-code-generator>=0.25; extra == 'dev'
|
|
12
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
13
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
14
|
+
Provides-Extra: mcp
|
|
15
|
+
Requires-Dist: mcp>=1.0; extra == 'mcp'
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# shield-swap-sdk
|
|
19
|
+
|
|
20
|
+
Typed Python client for the **shield_swap** AMM on Aleo. Sits on top of the
|
|
21
|
+
Aleo Python SDK's facade (`aleo.Aleo`): signer, record provider, proving
|
|
22
|
+
configuration, and network all come from the client you bind — this package
|
|
23
|
+
adds the DEX verbs, the typed results, and the off-chain DEX API, nothing
|
|
24
|
+
else.
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
from aleo import Aleo
|
|
28
|
+
from aleo_shield_swap import ShieldSwap
|
|
29
|
+
|
|
30
|
+
aleo = Aleo(Aleo.HTTPProvider("https://api.provable.com"))
|
|
31
|
+
aleo.default_account = account
|
|
32
|
+
dex = ShieldSwap(aleo)
|
|
33
|
+
|
|
34
|
+
pools = dex.api.get_pools() # requires a live DEX API
|
|
35
|
+
handle = dex.swap(pool_key=pools[0].key,
|
|
36
|
+
token_in_id=pools[0].token0,
|
|
37
|
+
amount_in=10**9).delegate() # broadcasts; spends funds
|
|
38
|
+
out = dex.claim_swap_output(handle).delegate() # broadcasts; spends funds
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Install
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install -e shield-swap-sdk # from the repo root
|
|
45
|
+
pip install -e "shield-swap-sdk[async]" # + AsyncShieldSwap (httpx)
|
|
46
|
+
pip install -e "shield-swap-sdk[mcp]" # + the MCP server
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Requires `aleo-sdk>=0.2` (this repo's SDK; imports as `aleo`) and Python 3.10+.
|
|
50
|
+
|
|
51
|
+
## How calls work
|
|
52
|
+
|
|
53
|
+
Every read returns a value immediately. Every write returns a prepared
|
|
54
|
+
`DexCall` — nothing touches the network until you invoke a terminal verb:
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
call = dex.swap(pool_key=key, token_in_id=token, amount_in=10**9)
|
|
58
|
+
|
|
59
|
+
call.simulate() # runs locally; no broadcast, no fee
|
|
60
|
+
call.transact(account) # proves locally, broadcasts, pays the fee
|
|
61
|
+
call.delegate(account) # proves via the delegated proving service
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`transact` and `delegate` return the verb's *typed result* (a `SwapHandle`,
|
|
65
|
+
`MintResult`, `ClaimResult`, …) built from the transaction's root-transition
|
|
66
|
+
outputs — not a bare transaction id. Local proving downloads SNARK parameters
|
|
67
|
+
on first use and takes minutes for the larger entrypoints; `delegate` is the
|
|
68
|
+
practical path and requires DPS credentials on the provider
|
|
69
|
+
(`api_key=`, `network_client.consumer_id`).
|
|
70
|
+
|
|
71
|
+
Chain reads and writes live directly on `ShieldSwap`; the off-chain DEX API
|
|
72
|
+
is namespaced under `.api`, so a call site always shows whether a value came
|
|
73
|
+
from the chain or the service.
|
|
74
|
+
|
|
75
|
+
## The verb surface
|
|
76
|
+
|
|
77
|
+
**Chain reads** (node REST API):
|
|
78
|
+
|
|
79
|
+
| Verb | Returns |
|
|
80
|
+
|---|---|
|
|
81
|
+
| `get_pool(pool_key)` | The pool struct from the `pools` mapping. |
|
|
82
|
+
| `get_slot(pool_key)` | `SlotView` — current tick, sqrt price, liquidity, spacing. |
|
|
83
|
+
| `get_swap_output(swap_id)` | The finalized swap outcome; raises `SwapOutputNotFinalizedError` until the finalize lands (and again after the claim consumes it). |
|
|
84
|
+
| `is_pool_initialized(pool_key)` | Whether the pool exists on chain. |
|
|
85
|
+
| `get_private_balances(programs)` | Summed unspent record amounts per token program (needs a registered record provider). |
|
|
86
|
+
| `get_balances()` | Public + private balances in one shape. |
|
|
87
|
+
| `derive_pool_key(token0, token1, fee)` / `derive_tick_key(pool_key, tick)` | Mapping keys derived locally — no network. |
|
|
88
|
+
|
|
89
|
+
**Writes** (each returns a `DexCall`):
|
|
90
|
+
|
|
91
|
+
| Verb | What it does |
|
|
92
|
+
|---|---|
|
|
93
|
+
| `swap(...)` | Phase one of the two-transaction private swap: locks the input record against a blinded identity. Returns a `SwapHandle` — persist it if the process might die before the claim. |
|
|
94
|
+
| `claim_swap_output(handle)` | Phase two: claims the finalized output as a private record. |
|
|
95
|
+
| `create_pool(...)` | Initializes a pool for a token pair + fee tier. |
|
|
96
|
+
| `mint(...)` | Opens a position in a tick range; returns a `MintResult` with the position's token id. |
|
|
97
|
+
| `increase_liquidity(...)` / `decrease_liquidity(...)` | Resizes a position (spends the position NFT record and returns a fresh one). |
|
|
98
|
+
| `collect(...)` | Pays out `tokens_owed` as private records. |
|
|
99
|
+
| `burn(...)` | Closes an emptied position and removes it from the `positions` mapping. |
|
|
100
|
+
|
|
101
|
+
Quote before you swap: pass `expected_out` from `dex.api.get_route(...)` —
|
|
102
|
+
without it a spot estimate is used, which ignores fees and price impact.
|
|
103
|
+
Amounts are `u128` base units of the token; fees are microcredits.
|
|
104
|
+
|
|
105
|
+
**DEX API** (`dex.api`, standalone as `ApiClient`): `get_pools`,
|
|
106
|
+
`get_tokens`, `get_route`, `get_swap`, `get_ohlcv`, `get_public_balances`.
|
|
107
|
+
Route quoting, OHLCV, and balances are auth-gated — call
|
|
108
|
+
`api.authenticate(address, sign)` once (challenge/verify by signature, no
|
|
109
|
+
funds required); some deployments additionally gate them behind an invite
|
|
110
|
+
code.
|
|
111
|
+
|
|
112
|
+
## Privacy
|
|
113
|
+
|
|
114
|
+
The swap flow never puts your address on chain next to the output. `swap`
|
|
115
|
+
derives a single-use **blinded identity** from the signer's view key
|
|
116
|
+
(`derive_blinding_factor` / `derive_blinded_address` are exported for
|
|
117
|
+
verification against the TS SDK's vectors); the claim proves knowledge of the
|
|
118
|
+
blinding factor instead of revealing the owner.
|
|
119
|
+
|
|
120
|
+
Two conveniences trade secret material for service:
|
|
121
|
+
|
|
122
|
+
- `delegate` sends the transaction *authorization* to the proving service —
|
|
123
|
+
it can see the transaction's contents (not your private key). Prove
|
|
124
|
+
locally with `transact` if that is unacceptable.
|
|
125
|
+
- The hosted record scanner behind `get_private_balances` /
|
|
126
|
+
`aleo.records.register` shares the account's **view key** with the
|
|
127
|
+
scanning service, which can then see everything the account owns.
|
|
128
|
+
Self-host the scanner if that is unacceptable.
|
|
129
|
+
|
|
130
|
+
## Async
|
|
131
|
+
|
|
132
|
+
`AsyncShieldSwap` / `AsyncApiClient` mirror the sync surface verb-for-verb on
|
|
133
|
+
`aleo.AsyncAleo` (install the `[async]` extra):
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
from aleo_shield_swap import AsyncShieldSwap
|
|
137
|
+
|
|
138
|
+
dex = AsyncShieldSwap(async_aleo)
|
|
139
|
+
handle = await (await dex.swap(pool_key=key, token_in_id=token,
|
|
140
|
+
amount_in=10**9)).delegate()
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Agent tools and MCP
|
|
144
|
+
|
|
145
|
+
`shield_swap_tools()` returns JSON-schema tool definitions for the whole verb
|
|
146
|
+
surface; `dispatch_tool(dex, name, args)` executes one. For MCP hosts, the
|
|
147
|
+
`[mcp]` extra ships a stdio server over the same definitions:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
ALEO_PRIVATE_KEY=APrivateKey1... python -m aleo_shield_swap.mcp
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Omit `ALEO_PRIVATE_KEY` for a read-only server. See the module docstring for
|
|
154
|
+
the full environment (`ALEO_ENDPOINT`, `ALEO_NETWORK`, DPS credentials).
|
|
155
|
+
|
|
156
|
+
## Generated bindings
|
|
157
|
+
|
|
158
|
+
The contract surface is pinned, not hand-written: `codegen/` holds the
|
|
159
|
+
deployed program source, its ABI, and the DEX API's OpenAPI document.
|
|
160
|
+
`_generated.py` (program structs + entrypoints via `aleo.codegen`) and
|
|
161
|
+
`_api_models.py` (API response models) are built from those pins. When the
|
|
162
|
+
deployed contract or API drifts, rerun `codegen/regen-abi.sh` /
|
|
163
|
+
`codegen/regen-openapi.sh` and reconcile.
|
|
164
|
+
|
|
165
|
+
## Tests
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
python -m pytest # hermetic tier — no network
|
|
169
|
+
python -m pytest -m live # read-only against the REAL testnet + DEX API
|
|
170
|
+
python -m pytest -m "live and slow" # spends real testnet funds (DPS proving)
|
|
171
|
+
ALEO_DEVNODE_UNPROVEN=1 \
|
|
172
|
+
python -m pytest -m devnode # full AMM lifecycle on a local aleo-devnode
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
The devnode tier deploys the vendored `shield_swap_v3.aleo` stack and drives
|
|
176
|
+
pool creation, liquidity, swaps, and burn end-to-end, hermetically. It needs
|
|
177
|
+
the `aleo-devnode` binary (`ALEO_DEVNODE_BIN` or on `PATH`) and skips
|
|
178
|
+
otherwise. Deployments are proofless (dummy verifying keys — the devnode
|
|
179
|
+
skips certificate verification); `ALEO_DEVNODE_UNPROVEN=1` extends that to
|
|
180
|
+
executions and is the fast path (~5 minutes). Without it, executions are
|
|
181
|
+
fully proven locally: expect SNARK parameter downloads and key synthesis on
|
|
182
|
+
first use.
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# shield-swap-sdk
|
|
2
|
+
|
|
3
|
+
Typed Python client for the **shield_swap** AMM on Aleo. Sits on top of the
|
|
4
|
+
Aleo Python SDK's facade (`aleo.Aleo`): signer, record provider, proving
|
|
5
|
+
configuration, and network all come from the client you bind — this package
|
|
6
|
+
adds the DEX verbs, the typed results, and the off-chain DEX API, nothing
|
|
7
|
+
else.
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
from aleo import Aleo
|
|
11
|
+
from aleo_shield_swap import ShieldSwap
|
|
12
|
+
|
|
13
|
+
aleo = Aleo(Aleo.HTTPProvider("https://api.provable.com"))
|
|
14
|
+
aleo.default_account = account
|
|
15
|
+
dex = ShieldSwap(aleo)
|
|
16
|
+
|
|
17
|
+
pools = dex.api.get_pools() # requires a live DEX API
|
|
18
|
+
handle = dex.swap(pool_key=pools[0].key,
|
|
19
|
+
token_in_id=pools[0].token0,
|
|
20
|
+
amount_in=10**9).delegate() # broadcasts; spends funds
|
|
21
|
+
out = dex.claim_swap_output(handle).delegate() # broadcasts; spends funds
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Install
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install -e shield-swap-sdk # from the repo root
|
|
28
|
+
pip install -e "shield-swap-sdk[async]" # + AsyncShieldSwap (httpx)
|
|
29
|
+
pip install -e "shield-swap-sdk[mcp]" # + the MCP server
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Requires `aleo-sdk>=0.2` (this repo's SDK; imports as `aleo`) and Python 3.10+.
|
|
33
|
+
|
|
34
|
+
## How calls work
|
|
35
|
+
|
|
36
|
+
Every read returns a value immediately. Every write returns a prepared
|
|
37
|
+
`DexCall` — nothing touches the network until you invoke a terminal verb:
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
call = dex.swap(pool_key=key, token_in_id=token, amount_in=10**9)
|
|
41
|
+
|
|
42
|
+
call.simulate() # runs locally; no broadcast, no fee
|
|
43
|
+
call.transact(account) # proves locally, broadcasts, pays the fee
|
|
44
|
+
call.delegate(account) # proves via the delegated proving service
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`transact` and `delegate` return the verb's *typed result* (a `SwapHandle`,
|
|
48
|
+
`MintResult`, `ClaimResult`, …) built from the transaction's root-transition
|
|
49
|
+
outputs — not a bare transaction id. Local proving downloads SNARK parameters
|
|
50
|
+
on first use and takes minutes for the larger entrypoints; `delegate` is the
|
|
51
|
+
practical path and requires DPS credentials on the provider
|
|
52
|
+
(`api_key=`, `network_client.consumer_id`).
|
|
53
|
+
|
|
54
|
+
Chain reads and writes live directly on `ShieldSwap`; the off-chain DEX API
|
|
55
|
+
is namespaced under `.api`, so a call site always shows whether a value came
|
|
56
|
+
from the chain or the service.
|
|
57
|
+
|
|
58
|
+
## The verb surface
|
|
59
|
+
|
|
60
|
+
**Chain reads** (node REST API):
|
|
61
|
+
|
|
62
|
+
| Verb | Returns |
|
|
63
|
+
|---|---|
|
|
64
|
+
| `get_pool(pool_key)` | The pool struct from the `pools` mapping. |
|
|
65
|
+
| `get_slot(pool_key)` | `SlotView` — current tick, sqrt price, liquidity, spacing. |
|
|
66
|
+
| `get_swap_output(swap_id)` | The finalized swap outcome; raises `SwapOutputNotFinalizedError` until the finalize lands (and again after the claim consumes it). |
|
|
67
|
+
| `is_pool_initialized(pool_key)` | Whether the pool exists on chain. |
|
|
68
|
+
| `get_private_balances(programs)` | Summed unspent record amounts per token program (needs a registered record provider). |
|
|
69
|
+
| `get_balances()` | Public + private balances in one shape. |
|
|
70
|
+
| `derive_pool_key(token0, token1, fee)` / `derive_tick_key(pool_key, tick)` | Mapping keys derived locally — no network. |
|
|
71
|
+
|
|
72
|
+
**Writes** (each returns a `DexCall`):
|
|
73
|
+
|
|
74
|
+
| Verb | What it does |
|
|
75
|
+
|---|---|
|
|
76
|
+
| `swap(...)` | Phase one of the two-transaction private swap: locks the input record against a blinded identity. Returns a `SwapHandle` — persist it if the process might die before the claim. |
|
|
77
|
+
| `claim_swap_output(handle)` | Phase two: claims the finalized output as a private record. |
|
|
78
|
+
| `create_pool(...)` | Initializes a pool for a token pair + fee tier. |
|
|
79
|
+
| `mint(...)` | Opens a position in a tick range; returns a `MintResult` with the position's token id. |
|
|
80
|
+
| `increase_liquidity(...)` / `decrease_liquidity(...)` | Resizes a position (spends the position NFT record and returns a fresh one). |
|
|
81
|
+
| `collect(...)` | Pays out `tokens_owed` as private records. |
|
|
82
|
+
| `burn(...)` | Closes an emptied position and removes it from the `positions` mapping. |
|
|
83
|
+
|
|
84
|
+
Quote before you swap: pass `expected_out` from `dex.api.get_route(...)` —
|
|
85
|
+
without it a spot estimate is used, which ignores fees and price impact.
|
|
86
|
+
Amounts are `u128` base units of the token; fees are microcredits.
|
|
87
|
+
|
|
88
|
+
**DEX API** (`dex.api`, standalone as `ApiClient`): `get_pools`,
|
|
89
|
+
`get_tokens`, `get_route`, `get_swap`, `get_ohlcv`, `get_public_balances`.
|
|
90
|
+
Route quoting, OHLCV, and balances are auth-gated — call
|
|
91
|
+
`api.authenticate(address, sign)` once (challenge/verify by signature, no
|
|
92
|
+
funds required); some deployments additionally gate them behind an invite
|
|
93
|
+
code.
|
|
94
|
+
|
|
95
|
+
## Privacy
|
|
96
|
+
|
|
97
|
+
The swap flow never puts your address on chain next to the output. `swap`
|
|
98
|
+
derives a single-use **blinded identity** from the signer's view key
|
|
99
|
+
(`derive_blinding_factor` / `derive_blinded_address` are exported for
|
|
100
|
+
verification against the TS SDK's vectors); the claim proves knowledge of the
|
|
101
|
+
blinding factor instead of revealing the owner.
|
|
102
|
+
|
|
103
|
+
Two conveniences trade secret material for service:
|
|
104
|
+
|
|
105
|
+
- `delegate` sends the transaction *authorization* to the proving service —
|
|
106
|
+
it can see the transaction's contents (not your private key). Prove
|
|
107
|
+
locally with `transact` if that is unacceptable.
|
|
108
|
+
- The hosted record scanner behind `get_private_balances` /
|
|
109
|
+
`aleo.records.register` shares the account's **view key** with the
|
|
110
|
+
scanning service, which can then see everything the account owns.
|
|
111
|
+
Self-host the scanner if that is unacceptable.
|
|
112
|
+
|
|
113
|
+
## Async
|
|
114
|
+
|
|
115
|
+
`AsyncShieldSwap` / `AsyncApiClient` mirror the sync surface verb-for-verb on
|
|
116
|
+
`aleo.AsyncAleo` (install the `[async]` extra):
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
from aleo_shield_swap import AsyncShieldSwap
|
|
120
|
+
|
|
121
|
+
dex = AsyncShieldSwap(async_aleo)
|
|
122
|
+
handle = await (await dex.swap(pool_key=key, token_in_id=token,
|
|
123
|
+
amount_in=10**9)).delegate()
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Agent tools and MCP
|
|
127
|
+
|
|
128
|
+
`shield_swap_tools()` returns JSON-schema tool definitions for the whole verb
|
|
129
|
+
surface; `dispatch_tool(dex, name, args)` executes one. For MCP hosts, the
|
|
130
|
+
`[mcp]` extra ships a stdio server over the same definitions:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
ALEO_PRIVATE_KEY=APrivateKey1... python -m aleo_shield_swap.mcp
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Omit `ALEO_PRIVATE_KEY` for a read-only server. See the module docstring for
|
|
137
|
+
the full environment (`ALEO_ENDPOINT`, `ALEO_NETWORK`, DPS credentials).
|
|
138
|
+
|
|
139
|
+
## Generated bindings
|
|
140
|
+
|
|
141
|
+
The contract surface is pinned, not hand-written: `codegen/` holds the
|
|
142
|
+
deployed program source, its ABI, and the DEX API's OpenAPI document.
|
|
143
|
+
`_generated.py` (program structs + entrypoints via `aleo.codegen`) and
|
|
144
|
+
`_api_models.py` (API response models) are built from those pins. When the
|
|
145
|
+
deployed contract or API drifts, rerun `codegen/regen-abi.sh` /
|
|
146
|
+
`codegen/regen-openapi.sh` and reconcile.
|
|
147
|
+
|
|
148
|
+
## Tests
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
python -m pytest # hermetic tier — no network
|
|
152
|
+
python -m pytest -m live # read-only against the REAL testnet + DEX API
|
|
153
|
+
python -m pytest -m "live and slow" # spends real testnet funds (DPS proving)
|
|
154
|
+
ALEO_DEVNODE_UNPROVEN=1 \
|
|
155
|
+
python -m pytest -m devnode # full AMM lifecycle on a local aleo-devnode
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
The devnode tier deploys the vendored `shield_swap_v3.aleo` stack and drives
|
|
159
|
+
pool creation, liquidity, swaps, and burn end-to-end, hermetically. It needs
|
|
160
|
+
the `aleo-devnode` binary (`ALEO_DEVNODE_BIN` or on `PATH`) and skips
|
|
161
|
+
otherwise. Deployments are proofless (dummy verifying keys — the devnode
|
|
162
|
+
skips certificate verification); `ALEO_DEVNODE_UNPROVEN=1` extends that to
|
|
163
|
+
executions and is the fast path (~5 minutes). Without it, executions are
|
|
164
|
+
fully proven locally: expect SNARK parameter downloads and key synthesis on
|
|
165
|
+
first use.
|