Add local instaswap E2E workspace harness
This commit is contained in:
79
.env.local.example
Normal file
79
.env.local.example
Normal file
@@ -0,0 +1,79 @@
|
||||
COMPOSE_PROJECT_NAME=skunk-net
|
||||
|
||||
# Compose runtime user mapping. `./local-compose.sh` overwrites these with your
|
||||
# current uid/gid at runtime so generated files are not owned by root.
|
||||
LOCAL_UID=1000
|
||||
LOCAL_GID=1000
|
||||
|
||||
# Branch-aligned repo paths. For coworker handoff, clone each dependency repo
|
||||
# into these top-level directories and check out the branch recorded in
|
||||
# WORKSPACE-MANIFEST.md.
|
||||
WIRE_SYSIO_REPO_DIR=wire-sysio
|
||||
WIRE_SYSIO_CONTEXT=./wire-sysio
|
||||
WIRE_ETHEREUM_REPO_DIR=wire-ethereum
|
||||
CAPITAL_STAKING_REPO_DIR=capital-staking
|
||||
CAPITAL_STAKING_BUILD_CONTEXT=./capital-staking
|
||||
WIRE_HUB_WEBAPP_REPO_DIR=wire-hub-webapp
|
||||
|
||||
# Wire SysIO
|
||||
WIRE_SYSIO_IMAGE=wire/sysio:platform-dev-batchop-local
|
||||
WIRE_NODE_ROOT=/srv/wire-node/chain-001
|
||||
WIRE_HTTP_PORT=8887
|
||||
WIRE_P2P_PORT=4443
|
||||
WIRE_ETH_DEPOT_ACCOUNT=sysio.dpeth
|
||||
WIRE_SOL_DEPOT_ACCOUNT=sysio.dpsol
|
||||
WIRE_INSTASWAP_ACCOUNT=sysio.iswap
|
||||
WIRE_WYIELD_ACCOUNT=sysio.wyield
|
||||
WIRE_TEST_USER_ACCOUNT=userinsta1
|
||||
WIRE_BATCH_OPERATOR_ETH_ACCOUNT=bopeth111111
|
||||
WIRE_BATCH_OPERATOR_SOL_ACCOUNT=bopsol111111
|
||||
WIRE_BATCH_OPERATOR_ETH_WIRE_PROVIDER_ID=wire-bopeth-1
|
||||
WIRE_BATCH_OPERATOR_SOL_WIRE_PROVIDER_ID=wire-bopsol-1
|
||||
|
||||
# Solana / Anchor
|
||||
CAPITAL_STAKING_IMAGE=skunk-net/capital-staking-dev:local
|
||||
SOLANA_DOCKER_IMAGE=skunk-net/solana-validator:local
|
||||
SOLANA_RPC=http://solana-validator:8899
|
||||
RPC_URL=http://solana-validator:8899
|
||||
ANCHOR_PROVIDER_URL=http://solana-validator:8899
|
||||
ANCHOR_WALLET=/workspace/capital-staking/wallets/deploymentWallet/universalDeploymentWallet.json
|
||||
REQUIRED_VALIDATORS=1
|
||||
SOLANA_SLOTS_PER_EPOCH=64
|
||||
SOLANA_GOSSIP_PORT=8001
|
||||
SOLANA_RPC_PORT=8899
|
||||
SOLANA_WS_PORT=8900
|
||||
SOLANA_FAUCET_PORT=9900
|
||||
SOLANA_RUN_SH_VALIDATOR_ARGS=
|
||||
|
||||
# Ethereum / Hardhat
|
||||
HARDHAT_PORT=8545
|
||||
|
||||
# Batch operator relay
|
||||
WIRE_BATCH_OPERATOR_WIRE_RPC_URL=http://wire-nodeop:8887
|
||||
WIRE_BATCH_OPERATOR_POLL_INTERVAL_MS=5000
|
||||
|
||||
# ETH route operator
|
||||
WIRE_BATCH_OPERATOR_ETH_WIRE_DEPOT_ACCOUNT=sysio.dpeth
|
||||
WIRE_BATCH_OPERATOR_ETH_WIRE_ACCOUNT=
|
||||
WIRE_BATCH_OPERATOR_ETH_WIRE_PROVIDER_ID=
|
||||
WIRE_BATCH_OPERATOR_ETH_WIRE_PROVIDER_SPEC=
|
||||
WIRE_BATCH_OPERATOR_ETH_CLIENT_ID=eth-local-1
|
||||
WIRE_BATCH_OPERATOR_ETH_PROVIDER_ID=eth-local-1
|
||||
WIRE_BATCH_OPERATOR_ETH_PROVIDER_SPEC=
|
||||
WIRE_BATCH_OPERATOR_ETH_RPC_URL=http://hardhat:8545
|
||||
WIRE_BATCH_OPERATOR_ETH_CHAIN_ID=31337
|
||||
WIRE_BATCH_OPERATOR_ETH_ABI_FILE=/wire/.local/e2e/ethereum-outpost-abi.json
|
||||
WIRE_BATCH_OPERATOR_ETH_OPP_ADDRESS=
|
||||
WIRE_BATCH_OPERATOR_ETH_OPP_INBOUND_ADDRESS=
|
||||
|
||||
# SOL route operator
|
||||
WIRE_BATCH_OPERATOR_SOL_WIRE_DEPOT_ACCOUNT=sysio.dpsol
|
||||
WIRE_BATCH_OPERATOR_SOL_WIRE_ACCOUNT=
|
||||
WIRE_BATCH_OPERATOR_SOL_WIRE_PROVIDER_ID=
|
||||
WIRE_BATCH_OPERATOR_SOL_WIRE_PROVIDER_SPEC=
|
||||
WIRE_BATCH_OPERATOR_SOL_CLIENT_ID=sol-local-1
|
||||
WIRE_BATCH_OPERATOR_SOL_PROVIDER_ID=sol-local-1
|
||||
WIRE_BATCH_OPERATOR_SOL_PROVIDER_SPEC=
|
||||
WIRE_BATCH_OPERATOR_SOL_RPC_URL=http://solana-validator:8899
|
||||
WIRE_BATCH_OPERATOR_SOL_PROGRAM_ID=
|
||||
WIRE_BATCH_OPERATOR_SOL_IDL_FILE=/wire/capital-staking/target/idl/liqsol_core.json
|
||||
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
.env.local
|
||||
.codex
|
||||
.local/
|
||||
.branch-worktrees/
|
||||
capital-staking/
|
||||
wire-ethereum/
|
||||
wire-sysio/
|
||||
wire-hub-webapp/
|
||||
wire-cdt/
|
||||
solana-docker-setup/
|
||||
124
CHECKPOINT-2026-04-03.md
Normal file
124
CHECKPOINT-2026-04-03.md
Normal file
@@ -0,0 +1,124 @@
|
||||
# Checkpoint 2026-04-03
|
||||
|
||||
This checkpoint captures the latest live state of the local instant-swap E2E bring-up.
|
||||
|
||||
## What Is Working
|
||||
|
||||
- Clean end-to-end bootstrap through `./local-e2e-up.sh` after resetting local state.
|
||||
- `wire-nodeop` comes up cleanly and the Wire batch operator services stay running.
|
||||
- Real `Eth -> Wire` delivery is working through the live ETH batch operator.
|
||||
- The Wire depot emits a real outbound `Wire -> Sol` epoch for the instaswap settlement.
|
||||
- Solana `ingest_epoch` succeeds for that outbound epoch on the fresh chain.
|
||||
|
||||
## Current Blocker
|
||||
|
||||
The Solana batch operator fails on `process_messages` for the first live
|
||||
`instaswap_settlement` message.
|
||||
|
||||
Observed error:
|
||||
|
||||
```text
|
||||
Transaction simulation failed: Error processing Instruction 1:
|
||||
custom program error: 0xbc4
|
||||
```
|
||||
|
||||
`0xbc4` is decimal `3012`, which maps to Anchor `AccountNotInitialized`.
|
||||
|
||||
## Current Diagnosis
|
||||
|
||||
The transport path is not the blocker anymore.
|
||||
|
||||
What we proved on the fresh cluster:
|
||||
|
||||
- ETH emits `OPPMessage` / `OPPEpoch`
|
||||
- ETH batch operator ingests that epoch into Wire
|
||||
- Wire depot creates the `xswap`
|
||||
- Wire depot emits outbound Solana epoch `0`
|
||||
- Solana `ingest_epoch` accepts that epoch
|
||||
|
||||
The remaining failure is inside Solana settlement execution for
|
||||
`handle_instaswap_settlement()` in:
|
||||
|
||||
- `capital-staking/programs/liqsol-core/src/instructions/opp/yield_hub.rs`
|
||||
|
||||
The most likely issue is one missing or wrongly-derived account in the
|
||||
batch-operator `process_messages` remaining account list, or one account that
|
||||
the live deploy path did not initialize even though the test harness does.
|
||||
|
||||
Primary suspects:
|
||||
|
||||
- `extra_account_meta_list`
|
||||
- `distribution_state`
|
||||
- `bridge_vault_ata`
|
||||
- `bucket_token_account`
|
||||
- `liqsol_mint`
|
||||
|
||||
## Reproduction
|
||||
|
||||
Fresh bring-up:
|
||||
|
||||
```bash
|
||||
./local-compose.sh down -v
|
||||
rm -rf .local/wire-node .local/wire-batch-operators .local/e2e
|
||||
./local-e2e-up.sh
|
||||
```
|
||||
|
||||
Trigger the live ETH instaswap:
|
||||
|
||||
```bash
|
||||
./local-compose.sh exec -T hardhat bash -lc \
|
||||
'cd /workspace/wire-ethereum && \
|
||||
HH_SCRIPT_ARGS="instaswap 5.0000 1.0000 B3bVKtqAJxRp4RUbzmUXVUdF4CRtaHfjnNfKzCd9Fy7T" \
|
||||
npx hardhat run src/scripts/outpost/wire_yield_hub_live.ts --network anvil_local'
|
||||
```
|
||||
|
||||
Inspect the Solana batch operator log:
|
||||
|
||||
```bash
|
||||
tail -n 120 .local/wire-batch-operators/sol/1/log/relay.log
|
||||
```
|
||||
|
||||
Expected current failure:
|
||||
|
||||
```text
|
||||
Submitting solana process_messages for epoch 0 with 1 message(s) and 15 remaining account(s)
|
||||
batch operator pass failed: -32002 ... custom program error: 0xbc4
|
||||
```
|
||||
|
||||
## Useful Live Checks
|
||||
|
||||
Wire chain health:
|
||||
|
||||
```bash
|
||||
./local-compose.sh exec -T wire-nodeop clio -u http://127.0.0.1:8887 get info
|
||||
```
|
||||
|
||||
Wire ETH depot inbound epochs:
|
||||
|
||||
```bash
|
||||
./local-compose.sh exec -T wire-nodeop \
|
||||
clio -u http://127.0.0.1:8887 get table sysio.dpeth ............2 oppepochin --limit 20
|
||||
```
|
||||
|
||||
Wire xswap rows:
|
||||
|
||||
```bash
|
||||
./local-compose.sh exec -T wire-nodeop \
|
||||
clio -u http://127.0.0.1:8887 get table sysio.iswap sysio.iswap xswaps --limit 20
|
||||
```
|
||||
|
||||
Wire Sol outbound epochs:
|
||||
|
||||
```bash
|
||||
./local-compose.sh exec -T wire-nodeop \
|
||||
clio -u http://127.0.0.1:8887 get table sysio.dpsol ............3 oppepochout --limit 20
|
||||
```
|
||||
|
||||
## Suggested Next Step
|
||||
|
||||
Reproduce the failing Solana `process_messages` call with the same 15 remaining
|
||||
accounts in a TypeScript helper or test so the full simulation logs identify the
|
||||
exact uninitialized account. Once that account is known, patch either:
|
||||
|
||||
- the local Solana deploy/bootstrap path, or
|
||||
- the batch operator account derivation / account ordering.
|
||||
187
LOCAL-E2E.md
Normal file
187
LOCAL-E2E.md
Normal file
@@ -0,0 +1,187 @@
|
||||
# Local Docker-First Stack
|
||||
|
||||
This workspace can be run locally on Arch without shell-profile exports.
|
||||
|
||||
For the current live checkpoint, known blocker, and exact repo matrix, see
|
||||
`CHECKPOINT-2026-04-03.md` and `WORKSPACE-MANIFEST.md`.
|
||||
|
||||
The setup below uses top-level dependency checkouts:
|
||||
|
||||
- `wire-sysio` in Docker, using the maintained Dockerfile under `wire-sysio/etc/docker/Dockerfile`
|
||||
- `wire-ethereum` in a Node 20 container on a local Hardhat network
|
||||
- `capital-staking` in a custom Anchor/Solana toolchain container against the local `solana-docker-setup` genesis validator
|
||||
|
||||
## What I Could Confirm
|
||||
|
||||
- The remote setup document at `swarm.gitgo.app/.../TESTNET-SETUP-README.md` returned `Not found` on April 2, 2026, so this runbook is based on the local repos and `OPP.pdf`.
|
||||
- `OPP.pdf` is still useful for the protocol shape, but message encoding details are stale because the live code is moving to protobuf-backed payloads.
|
||||
- `wire-ethereum` still models OPP delivery around sequential epoch envelopes.
|
||||
- `capital-staking` is the Solana-side outpost/wire harness in this workspace.
|
||||
- `solana-docker-setup` is now the intended local validator path so epoch timing is configurable through `SOLANA_SLOTS_PER_EPOCH`.
|
||||
- `wire-sysio` contains the local node/bootstrap path plus the batch-operator relay implementation we are exercising in this workspace.
|
||||
- The current Solana withdraw flow still has a placeholder instead of real OPP emission:
|
||||
`capital-staking/programs/liqsol-core/src/instructions/wire_syndication/desyndicate_liqsol.rs`
|
||||
|
||||
## One-Time Setup
|
||||
|
||||
```bash
|
||||
cd /home/dtaghavi/Documents/Projects/skunk-net
|
||||
cp .env.local.example .env.local
|
||||
```
|
||||
|
||||
Then use the checked-in wrapper:
|
||||
|
||||
```bash
|
||||
./local-compose.sh ps
|
||||
```
|
||||
|
||||
Nothing in this flow depends on `~/.bashrc`, and the wrapper injects your live uid/gid at runtime so container-generated files stay owned by your Arch user. Adjust `.env.local` if you want different ports, wallet path, or ledger location.
|
||||
|
||||
Important Solana knobs:
|
||||
|
||||
- `SOLANA_SLOTS_PER_EPOCH=64` keeps local epoch turnover fast for tests.
|
||||
- `SOLANA_RUN_SH_VALIDATOR_ARGS` lets you append raw `agave-validator` flags from `.env.local`.
|
||||
|
||||
## Build The Containers
|
||||
|
||||
```bash
|
||||
./local-compose.sh build capital-staking-dev wire-sysio-dev
|
||||
```
|
||||
|
||||
If you also need to rebuild the Solana validator image explicitly:
|
||||
|
||||
```bash
|
||||
./local-compose.sh build solana-validator
|
||||
```
|
||||
|
||||
`wire-sysio-dev` is the expensive image because it builds the Wire toolchain and Clang 18 layer. The upstream Wire docs call out a 32 GiB RAM expectation for this build path.
|
||||
|
||||
## Solana / Capital Staking
|
||||
|
||||
Start the local validator:
|
||||
|
||||
```bash
|
||||
./local-compose.sh up -d solana-validator
|
||||
```
|
||||
|
||||
Check the local epoch cadence:
|
||||
|
||||
```bash
|
||||
./local-compose.sh run --rm --no-deps capital-staking-dev bash -lc '
|
||||
solana -u "$ANCHOR_PROVIDER_URL" epoch-info
|
||||
'
|
||||
```
|
||||
|
||||
Reset the local Solana ledger when you want a fresh cluster:
|
||||
|
||||
```bash
|
||||
./local-compose.sh down -v
|
||||
./local-compose.sh up -d solana-validator
|
||||
```
|
||||
|
||||
Prepare program IDs, build, deploy, and initialize the local cluster:
|
||||
|
||||
```bash
|
||||
./local-compose.sh run --rm capital-staking-dev bash -lc '
|
||||
solana config set --url "$ANCHOR_PROVIDER_URL" --keypair "$ANCHOR_WALLET" &&
|
||||
./bash-scripts/prep-anchor-toml.sh &&
|
||||
npm ci &&
|
||||
./bash-scripts/reset-local-cluster.sh --wait-for-cluster
|
||||
'
|
||||
```
|
||||
|
||||
Run the Wire-related Solana suites:
|
||||
|
||||
```bash
|
||||
./local-compose.sh run --rm capital-staking-dev bash -lc '
|
||||
solana config set --url "$ANCHOR_PROVIDER_URL" --keypair "$ANCHOR_WALLET" &&
|
||||
npm ci &&
|
||||
npm run test:wire-syndication &&
|
||||
npm run test:wire-pretokens &&
|
||||
npm run test:bar
|
||||
'
|
||||
```
|
||||
|
||||
Those are the closest existing local tests to the instant-swap / outpost lifecycle in this checkout.
|
||||
|
||||
## Ethereum / OPP
|
||||
|
||||
For contract-level OPP validation you can either run one-shot tests or keep a local Hardhat node up.
|
||||
|
||||
One-shot OPP tests:
|
||||
|
||||
```bash
|
||||
./local-compose.sh run --rm wire-ethereum-dev bash -lc '
|
||||
cd /workspace/wire-ethereum &&
|
||||
npm ci &&
|
||||
npx hardhat test src/test/outpost/OPPSend.ts src/test/outpost/OPPRecv.ts
|
||||
'
|
||||
```
|
||||
|
||||
Long-lived local JSON-RPC:
|
||||
|
||||
```bash
|
||||
./local-compose.sh up -d hardhat
|
||||
```
|
||||
|
||||
Then run additional tests or scripts from a disposable shell:
|
||||
|
||||
```bash
|
||||
./local-compose.sh run --rm wire-ethereum-dev bash
|
||||
```
|
||||
|
||||
Inside the container:
|
||||
|
||||
```bash
|
||||
cd /workspace/wire-ethereum
|
||||
npm ci
|
||||
npx hardhat test src/test/outpost/Depositor.integration.ts
|
||||
```
|
||||
|
||||
## Wire SysIO
|
||||
|
||||
Make sure the Wire submodules are present once on the host:
|
||||
|
||||
```bash
|
||||
git -C wire-sysio submodule update --init --recursive
|
||||
```
|
||||
|
||||
Bring up the local Wire node:
|
||||
|
||||
```bash
|
||||
./local-compose.sh up wire-nodeop
|
||||
```
|
||||
|
||||
That service now:
|
||||
|
||||
- builds the required `wire-sysio` targets inside Docker
|
||||
- applies the local BoringSSL/OpenSSL pkg-config shim needed by this checkout
|
||||
- runs `sys-util chain-configure`
|
||||
- boots `kiod` and `nodeop` with the canonical 5-part `--signature-provider` format
|
||||
|
||||
If you want it detached:
|
||||
|
||||
```bash
|
||||
./local-compose.sh up -d wire-nodeop
|
||||
```
|
||||
|
||||
Check the node:
|
||||
|
||||
```bash
|
||||
curl -s http://127.0.0.1:${WIRE_HTTP_PORT:-8887}/v1/chain/get_info -X POST
|
||||
```
|
||||
|
||||
## Current Protocol Gap
|
||||
|
||||
From the code currently in this directory:
|
||||
|
||||
- Ethereum OPP is still epoch-based and sequential, but outbound epoch rollover no longer stalls on an unsubmitted prior epoch.
|
||||
- Solana wire syndication is still mostly local-accounting plus admin completion hooks.
|
||||
- The Solana PostLaunch withdraw path logs that it should send an OPP message, but does not do it yet.
|
||||
- I do not see the inbound Wire-side OPP gate you described inside `wire-sysio` itself in this checkout.
|
||||
|
||||
That means the fastest path to a real end-to-end instant-swap test is:
|
||||
|
||||
1. Stand up the local Solana and Ethereum stacks above.
|
||||
2. Use the existing wire-related Solana tests and OPP Ethereum tests as the starting harness.
|
||||
3. Identify where the missing Wire-side depot / batch-operator logic actually lives if it is not in these repos.
|
||||
377
OPP-COHESIVE-DESIGN.md
Normal file
377
OPP-COHESIVE-DESIGN.md
Normal file
@@ -0,0 +1,377 @@
|
||||
# Cohesive OPP Design
|
||||
|
||||
## Problem
|
||||
|
||||
The current repos already show the shape of the system, but not a single transport model that works cleanly for all four directions:
|
||||
|
||||
- `wire-ethereum` has a real outbound OPP sender and a partially implemented inbound verifier.
|
||||
- `capital-staking` has several concrete business flows and several OPP placeholders.
|
||||
- `wire-sysio` has protobuf ABI support and chain identity types, but no shared OPP depot/runtime in this checkout.
|
||||
|
||||
The main failure mode in the current shape is coupling unrelated traffic through global epoch state. That is the wrong abstraction for instant swaps and for the broader outpost/depot model.
|
||||
|
||||
The correct abstraction is:
|
||||
|
||||
- four independent directed OPP routes:
|
||||
- `Ethereum -> Wire`
|
||||
- `Wire -> Ethereum`
|
||||
- `Solana -> Wire`
|
||||
- `Wire -> Solana`
|
||||
- optional sub-lanes inside each route so BAR traffic cannot stall Depositor traffic
|
||||
- consensus on matching submissions of the same batch data
|
||||
- request/response correlation by payload ID, not by shared epoch numbering across directions
|
||||
|
||||
## Design Goals
|
||||
|
||||
- No global OPP epoch across chains or directions.
|
||||
- Ordering is only required inside a single directed stream.
|
||||
- Batching exists for operator consensus and gas/tx sizing, not as a business rule.
|
||||
- Multiple batch operators can submit the same batch independently; the depot accepts the batch once matching weight reaches threshold.
|
||||
- Reverse-direction flows are independent streams. A `Wire -> Solana` completion is not transport-coupled to the `Solana -> Wire` request batch that caused it.
|
||||
- Payloads are canonical protobuf messages, even if some origin repos still need a temporary translator while migrating.
|
||||
- Delivery is idempotent and replay-safe.
|
||||
|
||||
## Route And Stream Model
|
||||
|
||||
There are four mandatory top-level OPP routes:
|
||||
|
||||
| Route | Meaning |
|
||||
| --- | --- |
|
||||
| `Ethereum -> Wire` | Ethereum outposts mirror facts into Wire |
|
||||
| `Wire -> Ethereum` | Wire depot sends commands or acknowledgements to Ethereum outposts |
|
||||
| `Solana -> Wire` | Solana outposts mirror facts into Wire |
|
||||
| `Wire -> Solana` | Wire depot sends commands or acknowledgements to Solana outposts |
|
||||
|
||||
Each route may contain one or more logical lanes. Lanes are required because the current business surfaces already split into different domains:
|
||||
|
||||
- `depositor`
|
||||
- `pretoken`
|
||||
- `bar`
|
||||
- `admin`
|
||||
|
||||
The minimum stream identity must therefore be:
|
||||
|
||||
```text
|
||||
stream_key = (
|
||||
from_chain,
|
||||
to_chain,
|
||||
origin_system,
|
||||
destination_system,
|
||||
lane
|
||||
)
|
||||
```
|
||||
|
||||
Where:
|
||||
|
||||
- `from_chain` and `to_chain` use `chain_kind_t`
|
||||
- `origin_system` is the origin contract/program/depot identifier
|
||||
- `destination_system` is the destination contract/program/depot identifier
|
||||
- `lane` is a stable logical channel inside the route
|
||||
|
||||
This keeps the four chain directions independent while still allowing multiple application lanes per directed pair.
|
||||
|
||||
## Transport Units
|
||||
|
||||
The transport has three layers:
|
||||
|
||||
1. `Assertion`
|
||||
2. `Message`
|
||||
3. `Batch`
|
||||
|
||||
Definitions:
|
||||
|
||||
- An `Assertion` is one business fact or command.
|
||||
- A `Message` is a deterministic ordered set of assertions derived from one origin transaction or one origin-side decision.
|
||||
- A `Batch` is a transport seal over a contiguous message range in one stream.
|
||||
|
||||
Important rule:
|
||||
|
||||
- `Batch` replaces the old global `epoch` concept.
|
||||
- Batch numbering is per `stream_key`.
|
||||
- Batches can be sealed by time, size, or explicit flush.
|
||||
- Failing to deliver batch `N` on one stream must not stall batch creation or delivery on any other stream.
|
||||
|
||||
## Protobuf Canonical Format
|
||||
|
||||
The canonical transport format should be defined once and shared by all three repos. The simplest shape that fits the current codebase is:
|
||||
|
||||
```proto
|
||||
syntax = "proto3";
|
||||
|
||||
package wire.opp.v1;
|
||||
|
||||
message StreamKey {
|
||||
uint32 from_chain = 1;
|
||||
uint32 to_chain = 2;
|
||||
bytes origin_system = 3;
|
||||
bytes destination_system = 4;
|
||||
uint32 lane = 5;
|
||||
}
|
||||
|
||||
message Assertion {
|
||||
uint32 assertion_type = 1;
|
||||
bytes payload = 2;
|
||||
}
|
||||
|
||||
message Uint256 {
|
||||
bytes be_bytes = 1;
|
||||
}
|
||||
|
||||
message MessageHeader {
|
||||
StreamKey stream = 1;
|
||||
uint64 sequence = 2;
|
||||
bytes previous_message_hash = 3;
|
||||
uint64 source_timestamp_ms = 4;
|
||||
bytes source_event_id = 5;
|
||||
bytes payload_hash = 6;
|
||||
}
|
||||
|
||||
message Message {
|
||||
MessageHeader header = 1;
|
||||
repeated Assertion assertions = 2;
|
||||
}
|
||||
|
||||
message BatchHeader {
|
||||
StreamKey stream = 1;
|
||||
uint64 batch_number = 2;
|
||||
bytes previous_batch_hash = 3;
|
||||
uint64 first_sequence = 4;
|
||||
uint64 last_sequence = 5;
|
||||
uint64 sealed_at_ms = 6;
|
||||
bytes merkle_root = 7;
|
||||
}
|
||||
|
||||
message Batch {
|
||||
BatchHeader header = 1;
|
||||
repeated Assertion summary_assertions = 2;
|
||||
}
|
||||
|
||||
message BatchSubmission {
|
||||
BatchHeader header = 1;
|
||||
bytes batch_hash = 2;
|
||||
bytes operator_id = 3;
|
||||
bytes signature = 4;
|
||||
}
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- `assertion_type` stays numeric because the current Ethereum code and manager wiring already depend on a numeric registry.
|
||||
- `payload` becomes a protobuf-encoded business message specific to that assertion type.
|
||||
- `source_event_id` is the deterministic origin reference used for replay protection and migration from legacy encoders.
|
||||
- Protobuf has no native `uint256`, so business payload schemas should use a canonical `Uint256` wrapper. The wrapper should be encoded as exactly 32 unsigned big-endian bytes.
|
||||
|
||||
## Consensus Model
|
||||
|
||||
Consensus happens at the destination depot or endpoint, not at the sender.
|
||||
|
||||
For each `(stream_key, batch_number)` the destination keeps:
|
||||
|
||||
- every operator submission keyed by `(operator_id, batch_hash)`
|
||||
- cumulative weight per `batch_hash`
|
||||
- a single accepted `batch_hash` once threshold is met
|
||||
|
||||
Rules:
|
||||
|
||||
- A batch is accepted when matching submission weight reaches threshold.
|
||||
- Conflicting submissions for the same `(stream_key, batch_number)` are retained as evidence.
|
||||
- Acceptance is per stream only. No other stream is affected.
|
||||
- Operators may submit late. Late submission is a liveness concern, not a protocol deadlock.
|
||||
|
||||
This is the core point the current design needs: consensus is "multiple operators submitted the same batch digest", not "the whole system advanced the next epoch".
|
||||
|
||||
## Delivery Model
|
||||
|
||||
Once a batch is accepted, any operator may deliver messages from that batch with Merkle proofs.
|
||||
|
||||
Execution state is per stream:
|
||||
|
||||
- `next_sequence`
|
||||
- `last_applied_message_hash`
|
||||
- `next_batch_number`
|
||||
- optionally one currently accepted batch being drained
|
||||
|
||||
The simplest execution rule is:
|
||||
|
||||
- delivery chunks must be contiguous within the accepted batch
|
||||
- the first delivered sequence must equal `next_sequence`
|
||||
- successful execution increments `next_sequence`
|
||||
|
||||
That preserves deterministic ordering while still allowing large batches to be split across multiple destination transactions.
|
||||
|
||||
If arbitrary subset delivery is needed later, a per-batch bitmap can be added. It is not required for the first correct implementation.
|
||||
|
||||
## Request/Response Correlation
|
||||
|
||||
Transport ordering and business correlation are separate concerns.
|
||||
|
||||
Any payload that expects a reverse-direction response must include:
|
||||
|
||||
- `request_id`
|
||||
- `origin_message_id` or `source_event_id`
|
||||
|
||||
Examples:
|
||||
|
||||
- `Solana -> Wire` withdraw request carries `request_id`
|
||||
- `Wire -> Solana` withdraw completion references the same `request_id`
|
||||
- `Ethereum -> Wire` unbond request carries `request_id`
|
||||
- `Wire -> Ethereum` unbond completion or slash references the same `request_id`
|
||||
|
||||
This removes the false dependency on shared epoch numbers between opposite directions.
|
||||
|
||||
## Current Repo Surfaces Mapped To The Model
|
||||
|
||||
### Ethereum -> Wire
|
||||
|
||||
Current origin surfaces already emitting OPP payloads:
|
||||
|
||||
- `wire-ethereum/contracts/outpost/Depositor.sol`
|
||||
- `3001` stake
|
||||
- `3002` unstake
|
||||
- `3004` liq pretoken purchase
|
||||
- `3006` yield pretoken purchase
|
||||
- `wire-ethereum/contracts/outpost/Pretoken.sol`
|
||||
- `3005` pretoken purchase
|
||||
- `wire-ethereum/contracts/outpost/BAR.sol`
|
||||
- `2001` bonded actor
|
||||
- `2002` unbonded actor
|
||||
- `2003` bond slashed
|
||||
|
||||
Design meaning:
|
||||
|
||||
- This route is a facts-to-Wire route.
|
||||
- Messages represent Ethereum-local state transitions that Wire mirrors.
|
||||
- The sender can continue producing batches even if a prior batch has not yet been submitted to Wire.
|
||||
|
||||
### Wire -> Ethereum
|
||||
|
||||
Current transport surface exists in `wire-ethereum/contracts/outpost/OPPInbound.sol`, but it is still globally sequential and not yet attached to real business handlers.
|
||||
|
||||
Design meaning:
|
||||
|
||||
- This route is a commands/acknowledgements route.
|
||||
- It needs a real endpoint contract per lane, or one endpoint with per-type handlers.
|
||||
- State must move from one global queue to per-stream state keyed by `stream_key`.
|
||||
|
||||
Immediate commands that fit this route:
|
||||
|
||||
- approvals or rejections for cross-chain requests
|
||||
- BAR role outcomes if Wire is authoritative
|
||||
- settlement callbacks for future instant swap flows
|
||||
|
||||
### Solana -> Wire
|
||||
|
||||
Current business surfaces that should emit outbound OPP requests or facts:
|
||||
|
||||
- `capital-staking/.../wire_syndication/syndicate_liqsol.rs`
|
||||
- stake mirror
|
||||
- `capital-staking/.../wire_syndication/desyndicate_liqsol.rs`
|
||||
- post-launch withdraw request to Wire is currently a TODO
|
||||
- `capital-staking/.../wire_pretokens/purchase_pretoken.rs`
|
||||
- pretoken purchase mirror
|
||||
- `capital-staking/.../wire_pretokens/purchase_pretokens_from_yield.rs`
|
||||
- yield purchase mirror
|
||||
- `capital-staking/.../bar/bond_ops.rs`
|
||||
- bond request
|
||||
- unbond request
|
||||
|
||||
Design meaning:
|
||||
|
||||
- This route is the Solana mirror/request route.
|
||||
- Solana should emit canonical protobuf messages, or a deterministic translator must derive them from Solana instruction data until native protobuf encoding exists.
|
||||
|
||||
### Wire -> Solana
|
||||
|
||||
Current destination-side business surfaces already exist:
|
||||
|
||||
- `capital-staking/.../wire_config/admin_instructions.rs`
|
||||
- `complete_withdraw_handler`
|
||||
- `capital-staking/.../bar/admin_instructions.rs`
|
||||
- `complete_unbond_role_handler`
|
||||
- `slash_bond_handler`
|
||||
- `admin_force_unbond_role_handler`
|
||||
|
||||
Design meaning:
|
||||
|
||||
- This route is a commands/acknowledgements route.
|
||||
- These handlers should stop being human-admin-only settlement paths.
|
||||
- They should become callable by an OPP authority PDA or gateway that verifies accepted Wire batches and enforces idempotency.
|
||||
|
||||
## Authority And Idempotency Rules
|
||||
|
||||
Every destination endpoint needs the same guarantees:
|
||||
|
||||
- only accepted OPP deliveries can execute privileged effects
|
||||
- the same `request_id` cannot execute twice
|
||||
- the same `(stream_key, sequence)` cannot execute twice
|
||||
|
||||
Practical requirements by repo:
|
||||
|
||||
- Ethereum:
|
||||
- replace global inbound state in `OPPInbound.sol` with per-stream state
|
||||
- register real assertion handlers for business routes
|
||||
- Solana:
|
||||
- add an OPP authority PDA or gateway instruction layer
|
||||
- move current admin settlement handlers behind that authority
|
||||
- Wire:
|
||||
- implement an actual depot contract or plugin state machine for stream state, operator submissions, accepted batches, and handler dispatch
|
||||
|
||||
## Migration Strategy
|
||||
|
||||
The clean migration path is:
|
||||
|
||||
1. Define the shared protobuf schema in one place and vendor it into all repos.
|
||||
2. Keep the current numeric assertion type registry.
|
||||
3. Canonicalize every observed origin event into the shared protobuf `Message`.
|
||||
4. Run consensus on protobuf `Batch` hashes.
|
||||
5. Dispatch protobuf payloads at the destination.
|
||||
|
||||
This allows migration even if some origin contracts still emit legacy byte payloads for a short time, because the operator canonicalization step can deterministically translate them into the protobuf form used for batch hashing and destination execution.
|
||||
|
||||
## Immediate Implementation Plan
|
||||
|
||||
### Phase 1: Shared Schema
|
||||
|
||||
- Add `wire.opp.v1` protobuf definitions to the shared contract/protocol area.
|
||||
- Add a registry document mapping numeric `assertion_type` values to protobuf payload messages.
|
||||
|
||||
### Phase 2: Wire Depot
|
||||
|
||||
- Implement per-stream tables:
|
||||
- `stream_state`
|
||||
- `batch_submission`
|
||||
- `accepted_batch`
|
||||
- `executed_message`
|
||||
- Implement threshold matching on `(stream_key, batch_number, batch_hash)`.
|
||||
- Implement contiguous chunk delivery with Merkle proof validation.
|
||||
|
||||
### Phase 3: Ethereum Endpoint
|
||||
|
||||
- Refactor inbound state from one global queue to `mapping(stream_hash => StreamState)`.
|
||||
- Keep the sender-side forward progress behavior already added in `OPP.sol`.
|
||||
- Add real business handlers for `Wire -> Ethereum`.
|
||||
|
||||
### Phase 4: Solana Endpoint
|
||||
|
||||
- Add an OPP gateway account model and authority PDA.
|
||||
- Convert current admin settlement instructions into OPP-executable handlers.
|
||||
- Emit outbound request/fact messages for the existing TODO sites.
|
||||
|
||||
### Phase 5: End-To-End Instant Swap Tests
|
||||
|
||||
Build the first full-path tests around request/response pairs that prove route independence:
|
||||
|
||||
- `Solana -> Wire` withdraw request followed by `Wire -> Solana` completion
|
||||
- `Ethereum -> Wire` BAR unbond request followed by `Wire -> Ethereum` completion or slash
|
||||
- one route deliberately delayed while another route continues progressing
|
||||
|
||||
## Non-Goals
|
||||
|
||||
- No global epoch shared across all routes.
|
||||
- No requirement that opposite directions share batch numbers.
|
||||
- No requirement that batch sealing blocks new origin-side messages.
|
||||
- No special transport rule for instant swaps beyond per-stream ordering and request/response correlation.
|
||||
|
||||
## Decision
|
||||
|
||||
The system should be built as independent directed OPP streams with per-stream batching and per-stream operator consensus. "Epoch" becomes a local batching mechanism, not a system-wide gating primitive. Reverse-direction actions are correlated by payload IDs, not by transport epoch state.
|
||||
28
README.md
Normal file
28
README.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# skunk-net-e2e
|
||||
|
||||
This repo is the cross-repo local E2E harness for the instant-swap / OPP work.
|
||||
|
||||
It is intentionally not a monorepo mirror of the underlying projects. The real
|
||||
code stays in the original repos; this workspace repo tracks:
|
||||
|
||||
- Docker compose and bootstrap scripts
|
||||
- local environment examples
|
||||
- protocol notes used for this bring-up
|
||||
- a dated checkpoint with the current blocker and reproduction steps
|
||||
- the dependency repo matrix and expected branches
|
||||
|
||||
## Start Here
|
||||
|
||||
1. Read `WORKSPACE-MANIFEST.md`.
|
||||
2. Clone each dependency repo into the top-level paths listed there.
|
||||
3. Check out the recorded branches in those repos.
|
||||
4. Copy `.env.local.example` to `.env.local` if you need overrides.
|
||||
5. Use `./local-e2e-up.sh` or the individual commands in `LOCAL-E2E.md`.
|
||||
|
||||
## Key Files
|
||||
|
||||
- `WORKSPACE-MANIFEST.md`: remotes, branches, and current local heads
|
||||
- `CHECKPOINT-2026-04-03.md`: current live state, blocker, and next steps
|
||||
- `LOCAL-E2E.md`: bring-up and runtime commands
|
||||
- `OPP-COHESIVE-DESIGN.md`: directional OPP design notes
|
||||
- `protocol/opp/v1/opp.proto`: shared protobuf draft used for the cohesive design
|
||||
66
WORKSPACE-MANIFEST.md
Normal file
66
WORKSPACE-MANIFEST.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# Workspace Manifest
|
||||
|
||||
This workspace expects the dependency repos to be cloned into fixed top-level
|
||||
paths under the workspace root.
|
||||
|
||||
## Dependency Repos
|
||||
|
||||
| Path | Remote | Working Branch | Current Head |
|
||||
| --- | --- | --- | --- |
|
||||
| `wire-sysio` | `https://swarm.gitgo.app/experimental/wire-sysio.git` | `codex/local-kv-batchop` | `0525ce01789c4fc5f8799a1c89f881908ed77b64` |
|
||||
| `wire-ethereum` | `https://swarm.gitgo.app/experimental/wire-ethereum.git` | `runtime/opp-parity-ethereum` | `cd240e751330356dfe59511e0d97405194cedd2b` |
|
||||
| `capital-staking` | `https://swarm.gitgo.app/experimental/capital-staking.git` | `runtime/opp-parity-solana` | `b9bd80d9b436c60d8010a1a119f37dab824742f7` |
|
||||
| `wire-hub-webapp` | `https://swarm.gitgo.app/experimental/wire-hub-webapp.git` | `runtime/instaswap-ui-dev-clean` | `87d9ea1c3fadc169b494f4599ae4e27324539206` |
|
||||
| `solana-docker-setup` | `https://swarm.gitgo.app/experimental/solana-docker-setup` | `master` | `5c9d912e4e1e4dbd1d84402f9210d7daf09ca420` |
|
||||
| `wire-cdt` | `https://swarm.gitgo.app/experimental/wire-cdt.git` | `master` | `c81b0b90a7118975dcfdb53ca4da225226aae505` |
|
||||
|
||||
## Local Change Summary
|
||||
|
||||
`wire-sysio`
|
||||
- KV migration for the depot / instaswap path.
|
||||
- batch operator relay implementation for ETH and SOL flows.
|
||||
- Wire bootstrap / nodeop local harness adjustments.
|
||||
- Local branch does not have an upstream configured yet.
|
||||
|
||||
`wire-ethereum`
|
||||
- Live local outpost script updated for a real user/admin split and Solana base58 destination parsing.
|
||||
|
||||
`capital-staking`
|
||||
- Docker-validator Anchor target support.
|
||||
- local deploy now initializes OPP epoch state.
|
||||
- relay artifact writer added.
|
||||
- local tranche-state init adjusted for the Docker validator path.
|
||||
|
||||
`wire-hub-webapp`
|
||||
- No local changes in this checkpoint.
|
||||
|
||||
## Workspace Files Tracked Here
|
||||
|
||||
- `docker-compose.local.yml`
|
||||
- `local-compose.sh`
|
||||
- `local-e2e-up.sh`
|
||||
- `bootstrap-ethereum-local.sh`
|
||||
- `bootstrap-solana-local.sh`
|
||||
- `wire-nodeop-local.sh`
|
||||
- `wire-batch-operator-local.sh`
|
||||
- `.env.local.example`
|
||||
- `LOCAL-E2E.md`
|
||||
- `CHECKPOINT-2026-04-03.md`
|
||||
- `OPP-COHESIVE-DESIGN.md`
|
||||
- `protocol/opp/v1/opp.proto`
|
||||
- `protocol/opp/v1/assertion-registry.md`
|
||||
|
||||
## Expected Directory Layout
|
||||
|
||||
```text
|
||||
skunk-net/
|
||||
README.md
|
||||
docker-compose.local.yml
|
||||
local-e2e-up.sh
|
||||
wire-sysio/
|
||||
wire-ethereum/
|
||||
capital-staking/
|
||||
wire-hub-webapp/
|
||||
solana-docker-setup/
|
||||
wire-cdt/
|
||||
```
|
||||
127
bootstrap-ethereum-local.sh
Executable file
127
bootstrap-ethereum-local.sh
Executable file
@@ -0,0 +1,127 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
WIRE_ETHEREUM_DIR="${WIRE_ETHEREUM_DIR:-$(pwd)}"
|
||||
WIRE_ETHEREUM_REPO_REL="${WIRE_ETHEREUM_REPO_REL:-$(realpath --relative-to "${ROOT_DIR}" "${WIRE_ETHEREUM_DIR}")}"
|
||||
LOCAL_DEPLOY_DIR="${WIRE_ETHEREUM_DIR}/.local/deployments"
|
||||
ARTIFACTS_DIR="${ROOT_DIR}/.local/e2e"
|
||||
HARDHAT_RPC_URL="${HARDHAT_RPC_URL:-http://127.0.0.1:8545}"
|
||||
WIRE_BATCH_ETH_RPC_URL="${WIRE_BATCH_ETH_RPC_URL:-http://hardhat:8545}"
|
||||
HARDHAT_DEPLOYER_KEY="${HARDHAT_DEPLOYER_KEY:-0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80}"
|
||||
ETH_CLIENT_ID="${ETH_CLIENT_ID:-eth-local-1}"
|
||||
ETH_PROVIDER_ID="${ETH_PROVIDER_ID:-eth-local-1}"
|
||||
ETH_ABI_FILE="${ETH_ABI_FILE:-}"
|
||||
|
||||
wait_for_rpc() {
|
||||
for _ in $(seq 1 60); do
|
||||
if curl -fsS -H 'Content-Type: application/json' \
|
||||
--data '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}' \
|
||||
"${HARDHAT_RPC_URL}" >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo "Hardhat RPC did not become ready at ${HARDHAT_RPC_URL}" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
write_deploy_configs() {
|
||||
mkdir -p "${LOCAL_DEPLOY_DIR}"
|
||||
|
||||
cat >"${LOCAL_DEPLOY_DIR}/liqeth.json" <<EOF
|
||||
{
|
||||
"url": "${HARDHAT_RPC_URL}",
|
||||
"key": "${HARDHAT_DEPLOYER_KEY}",
|
||||
"addressFile": "${LOCAL_DEPLOY_DIR}/liqeth-addrs.json",
|
||||
"gasLimitFile": "${LOCAL_DEPLOY_DIR}/liqeth-gas-limits.json"
|
||||
}
|
||||
EOF
|
||||
|
||||
cat >"${LOCAL_DEPLOY_DIR}/outpost.json" <<EOF
|
||||
{
|
||||
"url": "${HARDHAT_RPC_URL}",
|
||||
"key": "${HARDHAT_DEPLOYER_KEY}",
|
||||
"useMockAggregator": true,
|
||||
"addressFile": "${LOCAL_DEPLOY_DIR}/outpost-addrs.json",
|
||||
"gasLimitFile": "${LOCAL_DEPLOY_DIR}/outpost-gas-limits.json"
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
deploy_local_stack() {
|
||||
npm ci
|
||||
write_deploy_configs
|
||||
npx hardhat run src/scripts/deployLocal.ts --network anvil_local
|
||||
}
|
||||
|
||||
write_artifacts() {
|
||||
local out_file="${ARTIFACTS_DIR}/ethereum.env"
|
||||
|
||||
mkdir -p "${ARTIFACTS_DIR}"
|
||||
|
||||
ROOT_DIR="${ROOT_DIR}" \
|
||||
WIRE_ETHEREUM_DIR="${WIRE_ETHEREUM_DIR}" \
|
||||
WIRE_ETHEREUM_REPO_REL="${WIRE_ETHEREUM_REPO_REL}" \
|
||||
ETH_PROVIDER_ID="${ETH_PROVIDER_ID}" \
|
||||
ETH_CLIENT_ID="${ETH_CLIENT_ID}" \
|
||||
HARDHAT_DEPLOYER_KEY="${HARDHAT_DEPLOYER_KEY}" \
|
||||
WIRE_BATCH_ETH_RPC_URL="${WIRE_BATCH_ETH_RPC_URL}" \
|
||||
ETH_ABI_FILE="${ETH_ABI_FILE}" \
|
||||
node <<'EOF' >"${out_file}"
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const { ethers } = require("ethers");
|
||||
|
||||
const rootDir = process.env.ROOT_DIR;
|
||||
const repoDir = process.env.WIRE_ETHEREUM_DIR;
|
||||
const repoRel = process.env.WIRE_ETHEREUM_REPO_REL;
|
||||
const providerId = process.env.ETH_PROVIDER_ID;
|
||||
const clientId = process.env.ETH_CLIENT_ID;
|
||||
const privateKey = process.env.HARDHAT_DEPLOYER_KEY;
|
||||
const rpcUrl = process.env.WIRE_BATCH_ETH_RPC_URL;
|
||||
const abiFileOverride = process.env.ETH_ABI_FILE;
|
||||
const addrsPath = path.join(repoDir, ".local", "deployments", "outpost-addrs.json");
|
||||
const addrs = JSON.parse(fs.readFileSync(addrsPath, "utf8"));
|
||||
const publicKey = new ethers.SigningKey(privateKey).publicKey;
|
||||
const abiOutputPath = path.join(rootDir, ".local", "e2e", "ethereum-outpost-abi.json");
|
||||
|
||||
let abiFile = abiFileOverride;
|
||||
if (!abiFile) {
|
||||
const artifactPaths = [
|
||||
path.join(repoDir, "artifacts", "contracts", "outpost", "OPP.sol", "OPP.json"),
|
||||
path.join(repoDir, "artifacts", "contracts", "outpost", "OPPInbound.sol", "OPPInbound.json"),
|
||||
];
|
||||
const combinedAbi = artifactPaths.flatMap((artifactPath) => {
|
||||
const artifact = JSON.parse(fs.readFileSync(artifactPath, "utf8"));
|
||||
if (!Array.isArray(artifact.abi)) {
|
||||
throw new Error(`Artifact missing abi array: ${artifactPath}`);
|
||||
}
|
||||
return artifact.abi;
|
||||
});
|
||||
fs.mkdirSync(path.dirname(abiOutputPath), { recursive: true });
|
||||
fs.writeFileSync(abiOutputPath, `${JSON.stringify(combinedAbi, null, 2)}\n`);
|
||||
abiFile = "/wire/.local/e2e/ethereum-outpost-abi.json";
|
||||
}
|
||||
|
||||
console.log(`LOCAL_ETH_CLIENT_ID=${clientId}`);
|
||||
console.log(`LOCAL_ETH_PROVIDER_ID=${providerId}`);
|
||||
console.log(`LOCAL_ETH_PROVIDER_SPEC=${providerId},ethereum,ethereum,${publicKey},KEY:${privateKey}`);
|
||||
console.log(`LOCAL_ETH_RPC_URL=${rpcUrl}`);
|
||||
console.log(`LOCAL_ETH_OPP_ADDRESS=${addrs.OPP}`);
|
||||
console.log(`LOCAL_ETH_OPP_INBOUND_ADDRESS=${addrs.OPPInbound}`);
|
||||
console.log(`LOCAL_ETH_ABI_FILE=${abiFile}`);
|
||||
console.log(`LOCAL_ETH_REPO_DIR=${repoRel}`);
|
||||
console.log(`LOCAL_ETH_OUTPOST_ADDRS=${path.join(rootDir, repoRel, ".local", "deployments", "outpost-addrs.json")}`);
|
||||
EOF
|
||||
}
|
||||
|
||||
main() {
|
||||
cd "${WIRE_ETHEREUM_DIR}"
|
||||
wait_for_rpc
|
||||
deploy_local_stack
|
||||
write_artifacts
|
||||
}
|
||||
|
||||
main "$@"
|
||||
184
bootstrap-solana-local.sh
Executable file
184
bootstrap-solana-local.sh
Executable file
@@ -0,0 +1,184 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
CAPITAL_STAKING_DIR="${CAPITAL_STAKING_DIR:-$(pwd)}"
|
||||
CAPITAL_STAKING_REPO_REL="${CAPITAL_STAKING_REPO_REL:-$(realpath --relative-to "${ROOT_DIR}" "${CAPITAL_STAKING_DIR}")}"
|
||||
ARTIFACTS_DIR="${ROOT_DIR}/.local/e2e"
|
||||
ANCHOR_PROVIDER_URL="${ANCHOR_PROVIDER_URL:-http://solana-validator:8899}"
|
||||
ANCHOR_WALLET="${ANCHOR_WALLET:-${CAPITAL_STAKING_DIR}/wallets/deploymentWallet/universalDeploymentWallet.json}"
|
||||
WIRE_BATCH_SOL_RPC_URL="${WIRE_BATCH_SOL_RPC_URL:-http://solana-validator:8899}"
|
||||
AIRDROP_AMOUNT="${AIRDROP_AMOUNT:-100}"
|
||||
LOCAL_BOOTSTRAP_ROOT="${LOCAL_BOOTSTRAP_ROOT:-${ROOT_DIR}/.local/solana-bootstrap}"
|
||||
LOCAL_CARGO_HOME="${LOCAL_CARGO_HOME:-${LOCAL_BOOTSTRAP_ROOT}/cargo-home}"
|
||||
LOCAL_SOLANA_HOME="${LOCAL_SOLANA_HOME:-${LOCAL_BOOTSTRAP_ROOT}/home}"
|
||||
LOCAL_RUSTUP_HOME="${LOCAL_RUSTUP_HOME:-${LOCAL_BOOTSTRAP_ROOT}/rustup-home}"
|
||||
LOCAL_SBF_SDK_PATH="${LOCAL_SBF_SDK_PATH:-${LOCAL_SOLANA_HOME}/sdk/sbf}"
|
||||
CAPITAL_STAKING_FEATURES="${CAPITAL_STAKING_FEATURES:-development}"
|
||||
SOL_CLIENT_ID="${SOL_CLIENT_ID:-sol-local-1}"
|
||||
SOL_PROVIDER_ID="${SOL_PROVIDER_ID:-sol-local-1}"
|
||||
SOL_PROGRAM_ID="${SOL_PROGRAM_ID:-}"
|
||||
SOL_IDL_FILE="/wire/${CAPITAL_STAKING_REPO_REL}/target/idl/liqsol_core.json"
|
||||
|
||||
prepare_sbf_sdk() {
|
||||
local default_sbf_sdk="/opt/solana/.local/share/solana/install/active_release/bin/sdk/sbf"
|
||||
|
||||
mkdir -p "$(dirname "${LOCAL_SBF_SDK_PATH}")"
|
||||
if [[ ! -d "${LOCAL_SBF_SDK_PATH}" ]]; then
|
||||
cp -a "${default_sbf_sdk}" "${LOCAL_SBF_SDK_PATH}"
|
||||
fi
|
||||
|
||||
export SBF_SDK_PATH="${LOCAL_SBF_SDK_PATH}"
|
||||
}
|
||||
|
||||
prepare_rustup_home() {
|
||||
if [[ ! -d "${LOCAL_RUSTUP_HOME}/toolchains" ]]; then
|
||||
mkdir -p "${LOCAL_RUSTUP_HOME}"
|
||||
cp -a /opt/rustup/. "${LOCAL_RUSTUP_HOME}/"
|
||||
fi
|
||||
|
||||
export RUSTUP_HOME="${LOCAL_RUSTUP_HOME}"
|
||||
}
|
||||
|
||||
resolve_sol_program_id() {
|
||||
if [[ -n "${SOL_PROGRAM_ID}" ]]; then
|
||||
printf '%s\n' "${SOL_PROGRAM_ID}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
node <<'EOF'
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const { Keypair } = require("@solana/web3.js");
|
||||
|
||||
const keypairPath = path.resolve("target/deploy/liqsol_core-keypair.json");
|
||||
if (fs.existsSync(keypairPath)) {
|
||||
const secret = Uint8Array.from(JSON.parse(fs.readFileSync(keypairPath, "utf8")));
|
||||
console.log(Keypair.fromSecretKey(secret).publicKey.toBase58());
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const idlPath = path.resolve("target/idl/liqsol_core.json");
|
||||
if (fs.existsSync(idlPath)) {
|
||||
const idl = JSON.parse(fs.readFileSync(idlPath, "utf8"));
|
||||
if (idl.address) {
|
||||
console.log(idl.address);
|
||||
process.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
process.exit(1);
|
||||
EOF
|
||||
}
|
||||
|
||||
deploy_local_cluster() {
|
||||
export HOME="${LOCAL_SOLANA_HOME}"
|
||||
export XDG_CACHE_HOME="${HOME}/.cache"
|
||||
export XDG_CONFIG_HOME="${HOME}/.config"
|
||||
npm ci
|
||||
export ANCHOR_PROVIDER_URL
|
||||
export ANCHOR_WALLET
|
||||
export AIRDROP_AMOUNT
|
||||
export CAPITAL_STAKING_FEATURES
|
||||
export CARGO_HOME="${LOCAL_CARGO_HOME}"
|
||||
export SOLANA_RPC="${ANCHOR_PROVIDER_URL}"
|
||||
mkdir -p "${HOME}" "${XDG_CACHE_HOME}" "${XDG_CONFIG_HOME}" "${CARGO_HOME}" "${LOCAL_BOOTSTRAP_ROOT}"
|
||||
prepare_rustup_home
|
||||
prepare_sbf_sdk
|
||||
solana config set --url "${ANCHOR_PROVIDER_URL}" --keypair "${ANCHOR_WALLET}" >/dev/null
|
||||
bash bash-scripts/local-deploy.sh --wait-for-cluster --features "${CAPITAL_STAKING_FEATURES}"
|
||||
SOL_PROGRAM_ID="$(resolve_sol_program_id)"
|
||||
export SOL_PROGRAM_ID
|
||||
}
|
||||
|
||||
set_signature_weight() {
|
||||
ANCHOR_WALLET="${ANCHOR_WALLET}" \
|
||||
ANCHOR_PROVIDER_URL="${ANCHOR_PROVIDER_URL}" \
|
||||
SOL_PROGRAM_ID="${SOL_PROGRAM_ID}" \
|
||||
node <<'EOF'
|
||||
const fs = require("fs");
|
||||
const anchor = require("@coral-xyz/anchor");
|
||||
const { Connection, Keypair, PublicKey } = require("@solana/web3.js");
|
||||
const idl = require("./target/idl/liqsol_core.json");
|
||||
|
||||
const walletPath = process.env.ANCHOR_WALLET;
|
||||
const providerUrl = process.env.ANCHOR_PROVIDER_URL;
|
||||
const programId = new PublicKey(process.env.SOL_PROGRAM_ID || idl.address);
|
||||
idl.address = programId.toBase58();
|
||||
const secret = Uint8Array.from(JSON.parse(fs.readFileSync(walletPath, "utf8")));
|
||||
const wallet = new anchor.Wallet(Keypair.fromSecretKey(secret));
|
||||
const provider = new anchor.AnchorProvider(new Connection(providerUrl, "confirmed"), wallet, {
|
||||
commitment: "confirmed",
|
||||
});
|
||||
anchor.setProvider(provider);
|
||||
|
||||
const program = new anchor.Program(idl, provider);
|
||||
const [globalConfig] = PublicKey.findProgramAddressSync([Buffer.from("global_config")], programId);
|
||||
const [controllerState] = PublicKey.findProgramAddressSync([Buffer.from("stake_controller")], programId);
|
||||
|
||||
async function main() {
|
||||
await program.methods
|
||||
.updateConfigU16({ oppRequiredSignatureWeight: {} }, 1)
|
||||
.accounts({
|
||||
globalConfig,
|
||||
controllerState,
|
||||
authority: wallet.publicKey,
|
||||
})
|
||||
.rpc();
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
EOF
|
||||
}
|
||||
|
||||
write_artifacts() {
|
||||
local out_file="${ARTIFACTS_DIR}/solana.env"
|
||||
|
||||
mkdir -p "${ARTIFACTS_DIR}"
|
||||
|
||||
ANCHOR_WALLET="${ANCHOR_WALLET}" \
|
||||
SOL_PROVIDER_ID="${SOL_PROVIDER_ID}" \
|
||||
SOL_CLIENT_ID="${SOL_CLIENT_ID}" \
|
||||
WIRE_BATCH_SOL_RPC_URL="${WIRE_BATCH_SOL_RPC_URL}" \
|
||||
SOL_PROGRAM_ID="${SOL_PROGRAM_ID}" \
|
||||
SOL_IDL_FILE="${SOL_IDL_FILE}" \
|
||||
CAPITAL_STAKING_REPO_REL="${CAPITAL_STAKING_REPO_REL}" \
|
||||
node <<'EOF' >"${out_file}"
|
||||
const fs = require("fs");
|
||||
const bs58 = require("bs58");
|
||||
const { Keypair } = require("@solana/web3.js");
|
||||
|
||||
const walletPath = process.env.ANCHOR_WALLET;
|
||||
const providerId = process.env.SOL_PROVIDER_ID;
|
||||
const clientId = process.env.SOL_CLIENT_ID;
|
||||
const rpcUrl = process.env.WIRE_BATCH_SOL_RPC_URL;
|
||||
const programId = process.env.SOL_PROGRAM_ID;
|
||||
const idlFile = process.env.SOL_IDL_FILE;
|
||||
const repoRel = process.env.CAPITAL_STAKING_REPO_REL;
|
||||
|
||||
const secret = Uint8Array.from(JSON.parse(fs.readFileSync(walletPath, "utf8")));
|
||||
const keypair = Keypair.fromSecretKey(secret);
|
||||
const secretBase58 = bs58.encode(Buffer.from(keypair.secretKey));
|
||||
|
||||
console.log(`LOCAL_SOL_CLIENT_ID=${clientId}`);
|
||||
console.log(`LOCAL_SOL_PROVIDER_ID=${providerId}`);
|
||||
console.log(`LOCAL_SOL_PROVIDER_SPEC=${providerId},solana,solana,${keypair.publicKey.toBase58()},KEY:${secretBase58}`);
|
||||
console.log(`LOCAL_SOL_RPC_URL=${rpcUrl}`);
|
||||
console.log(`LOCAL_SOL_PROGRAM_ID=${programId}`);
|
||||
console.log(`LOCAL_SOL_IDL_FILE=${idlFile}`);
|
||||
console.log(`LOCAL_SOL_REPO_DIR=${repoRel}`);
|
||||
console.log(`LOCAL_SOL_OPP_REQUIRED_SIGNATURE_WEIGHT=1`);
|
||||
EOF
|
||||
}
|
||||
|
||||
main() {
|
||||
cd "${CAPITAL_STAKING_DIR}"
|
||||
deploy_local_cluster
|
||||
set_signature_weight
|
||||
write_artifacts
|
||||
}
|
||||
|
||||
main "$@"
|
||||
215
docker-compose.local.yml
Normal file
215
docker-compose.local.yml
Normal file
@@ -0,0 +1,215 @@
|
||||
services:
|
||||
wire-sysio-dev:
|
||||
build:
|
||||
context: ${WIRE_SYSIO_CONTEXT:-./wire-sysio}
|
||||
dockerfile: etc/docker/Dockerfile
|
||||
target: platform-dev
|
||||
additional_contexts:
|
||||
clang-18-scripts: ${WIRE_SYSIO_CONTEXT:-./wire-sysio}/scripts/clang-18
|
||||
app-root: ${WIRE_SYSIO_CONTEXT:-./wire-sysio}
|
||||
image: ${WIRE_SYSIO_IMAGE:-wire/sysio:platform-dev-local}
|
||||
user: "${LOCAL_UID:-1000}:${LOCAL_GID:-1000}"
|
||||
working_dir: /wire
|
||||
volumes:
|
||||
- .:/wire
|
||||
- ./.local/wire-node:/srv/wire-node
|
||||
environment:
|
||||
WIRE_ROOT: /wire/${WIRE_SYSIO_REPO_DIR:-wire-sysio}
|
||||
WIRE_SYSIO_DIR: /wire/${WIRE_SYSIO_REPO_DIR:-wire-sysio}
|
||||
command: ["bash", "-lc", "sleep infinity"]
|
||||
|
||||
wire-nodeop:
|
||||
build:
|
||||
context: ${WIRE_SYSIO_CONTEXT:-./wire-sysio}
|
||||
dockerfile: etc/docker/Dockerfile
|
||||
target: platform-dev
|
||||
additional_contexts:
|
||||
clang-18-scripts: ${WIRE_SYSIO_CONTEXT:-./wire-sysio}/scripts/clang-18
|
||||
app-root: ${WIRE_SYSIO_CONTEXT:-./wire-sysio}
|
||||
image: ${WIRE_SYSIO_IMAGE:-wire/sysio:platform-dev-local}
|
||||
user: "${LOCAL_UID:-1000}:${LOCAL_GID:-1000}"
|
||||
working_dir: /wire
|
||||
init: true
|
||||
volumes:
|
||||
- .:/wire
|
||||
- ./.local/wire-node:/srv/wire-node
|
||||
environment:
|
||||
WIRE_ROOT: /wire/${WIRE_SYSIO_REPO_DIR:-wire-sysio}
|
||||
WIRE_SYSIO_DIR: /wire/${WIRE_SYSIO_REPO_DIR:-wire-sysio}
|
||||
WIRE_NODE_ROOT: ${WIRE_NODE_ROOT:-/srv/wire-node/chain-001}
|
||||
WIRE_ARTIFACTS_DIR: /wire/.local/e2e
|
||||
WIRE_ETH_DEPOT_ACCOUNT: ${WIRE_ETH_DEPOT_ACCOUNT:-sysio.dpeth}
|
||||
WIRE_SOL_DEPOT_ACCOUNT: ${WIRE_SOL_DEPOT_ACCOUNT:-sysio.dpsol}
|
||||
WIRE_INSTASWAP_ACCOUNT: ${WIRE_INSTASWAP_ACCOUNT:-sysio.iswap}
|
||||
WIRE_WYIELD_ACCOUNT: ${WIRE_WYIELD_ACCOUNT:-sysio.wyield}
|
||||
WIRE_TEST_USER_ACCOUNT: ${WIRE_TEST_USER_ACCOUNT:-userinsta1}
|
||||
WIRE_BATCH_OPERATOR_ETH_ACCOUNT: ${WIRE_BATCH_OPERATOR_ETH_ACCOUNT:-bopeth111111}
|
||||
WIRE_BATCH_OPERATOR_SOL_ACCOUNT: ${WIRE_BATCH_OPERATOR_SOL_ACCOUNT:-bopsol111111}
|
||||
WIRE_BATCH_OPERATOR_ETH_WIRE_PROVIDER_ID: ${WIRE_BATCH_OPERATOR_ETH_WIRE_PROVIDER_ID:-wire-bopeth-1}
|
||||
WIRE_BATCH_OPERATOR_SOL_WIRE_PROVIDER_ID: ${WIRE_BATCH_OPERATOR_SOL_WIRE_PROVIDER_ID:-wire-bopsol-1}
|
||||
ports:
|
||||
- "${WIRE_HTTP_PORT:-8887}:8887"
|
||||
- "${WIRE_P2P_PORT:-4443}:4443"
|
||||
command: ["bash", "-lc", "bash /wire/wire-nodeop-local.sh"]
|
||||
|
||||
batch-operator-eth-1:
|
||||
build:
|
||||
context: ${WIRE_SYSIO_CONTEXT:-./wire-sysio}
|
||||
dockerfile: etc/docker/Dockerfile
|
||||
target: platform-dev
|
||||
additional_contexts:
|
||||
clang-18-scripts: ${WIRE_SYSIO_CONTEXT:-./wire-sysio}/scripts/clang-18
|
||||
app-root: ${WIRE_SYSIO_CONTEXT:-./wire-sysio}
|
||||
image: ${WIRE_SYSIO_IMAGE:-wire/sysio:platform-dev-local}
|
||||
user: "${LOCAL_UID:-1000}:${LOCAL_GID:-1000}"
|
||||
working_dir: /wire
|
||||
init: true
|
||||
volumes:
|
||||
- .:/wire
|
||||
environment:
|
||||
WIRE_ROOT: /wire/${WIRE_SYSIO_REPO_DIR:-wire-sysio}
|
||||
WIRE_SYSIO_DIR: /wire/${WIRE_SYSIO_REPO_DIR:-wire-sysio}
|
||||
WIRE_BATCH_OPERATOR_ROUTE: eth
|
||||
WIRE_BATCH_OPERATOR_INDEX: "1"
|
||||
WIRE_BATCH_OPERATOR_ROOT: /wire/.local/wire-batch-operators
|
||||
WIRE_BATCH_OPERATOR_ARTIFACTS_DIR: /wire/.local/e2e
|
||||
WIRE_BATCH_OPERATOR_WIRE_RPC_URL: ${WIRE_BATCH_OPERATOR_WIRE_RPC_URL:-http://wire-nodeop:8887}
|
||||
WIRE_BATCH_OPERATOR_WIRE_DEPOT_ACCOUNT: ${WIRE_BATCH_OPERATOR_ETH_WIRE_DEPOT_ACCOUNT:-sysio.dpeth}
|
||||
WIRE_BATCH_OPERATOR_WIRE_ACCOUNT: ${WIRE_BATCH_OPERATOR_ETH_WIRE_ACCOUNT:-}
|
||||
WIRE_BATCH_OPERATOR_WIRE_PROVIDER_ID: ${WIRE_BATCH_OPERATOR_ETH_WIRE_PROVIDER_ID:-}
|
||||
WIRE_BATCH_OPERATOR_WIRE_PROVIDER_SPEC: ${WIRE_BATCH_OPERATOR_ETH_WIRE_PROVIDER_SPEC:-}
|
||||
WIRE_BATCH_OPERATOR_SOURCE_CLIENT_ID: ${WIRE_BATCH_OPERATOR_ETH_CLIENT_ID:-eth-local-1}
|
||||
WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_ID: ${WIRE_BATCH_OPERATOR_ETH_PROVIDER_ID:-eth-local-1}
|
||||
WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_SPEC: ${WIRE_BATCH_OPERATOR_ETH_PROVIDER_SPEC:-}
|
||||
WIRE_BATCH_OPERATOR_SOURCE_RPC_URL: ${WIRE_BATCH_OPERATOR_ETH_RPC_URL:-http://hardhat:8545}
|
||||
WIRE_BATCH_OPERATOR_ETH_CHAIN_ID: ${WIRE_BATCH_OPERATOR_ETH_CHAIN_ID:-31337}
|
||||
WIRE_BATCH_OPERATOR_ETH_ABI_FILE: ${WIRE_BATCH_OPERATOR_ETH_ABI_FILE:-/wire/.local/e2e/ethereum-outpost-abi.json}
|
||||
WIRE_BATCH_OPERATOR_ETH_OPP_ADDRESS: ${WIRE_BATCH_OPERATOR_ETH_OPP_ADDRESS:-}
|
||||
WIRE_BATCH_OPERATOR_ETH_OPP_INBOUND_ADDRESS: ${WIRE_BATCH_OPERATOR_ETH_OPP_INBOUND_ADDRESS:-}
|
||||
WIRE_BATCH_OPERATOR_POLL_INTERVAL_MS: ${WIRE_BATCH_OPERATOR_POLL_INTERVAL_MS:-5000}
|
||||
depends_on:
|
||||
wire-nodeop:
|
||||
condition: service_started
|
||||
hardhat:
|
||||
condition: service_started
|
||||
command: ["bash", "-lc", "bash /wire/wire-batch-operator-local.sh eth 1"]
|
||||
|
||||
batch-operator-sol-1:
|
||||
build:
|
||||
context: ${WIRE_SYSIO_CONTEXT:-./wire-sysio}
|
||||
dockerfile: etc/docker/Dockerfile
|
||||
target: platform-dev
|
||||
additional_contexts:
|
||||
clang-18-scripts: ${WIRE_SYSIO_CONTEXT:-./wire-sysio}/scripts/clang-18
|
||||
app-root: ${WIRE_SYSIO_CONTEXT:-./wire-sysio}
|
||||
image: ${WIRE_SYSIO_IMAGE:-wire/sysio:platform-dev-local}
|
||||
user: "${LOCAL_UID:-1000}:${LOCAL_GID:-1000}"
|
||||
working_dir: /wire
|
||||
init: true
|
||||
volumes:
|
||||
- .:/wire
|
||||
environment:
|
||||
WIRE_ROOT: /wire/${WIRE_SYSIO_REPO_DIR:-wire-sysio}
|
||||
WIRE_SYSIO_DIR: /wire/${WIRE_SYSIO_REPO_DIR:-wire-sysio}
|
||||
WIRE_BATCH_OPERATOR_ROUTE: sol
|
||||
WIRE_BATCH_OPERATOR_INDEX: "1"
|
||||
WIRE_BATCH_OPERATOR_ROOT: /wire/.local/wire-batch-operators
|
||||
WIRE_BATCH_OPERATOR_ARTIFACTS_DIR: /wire/.local/e2e
|
||||
WIRE_BATCH_OPERATOR_WIRE_RPC_URL: ${WIRE_BATCH_OPERATOR_WIRE_RPC_URL:-http://wire-nodeop:8887}
|
||||
WIRE_BATCH_OPERATOR_WIRE_DEPOT_ACCOUNT: ${WIRE_BATCH_OPERATOR_SOL_WIRE_DEPOT_ACCOUNT:-sysio.dpsol}
|
||||
WIRE_BATCH_OPERATOR_WIRE_ACCOUNT: ${WIRE_BATCH_OPERATOR_SOL_WIRE_ACCOUNT:-}
|
||||
WIRE_BATCH_OPERATOR_WIRE_PROVIDER_ID: ${WIRE_BATCH_OPERATOR_SOL_WIRE_PROVIDER_ID:-}
|
||||
WIRE_BATCH_OPERATOR_WIRE_PROVIDER_SPEC: ${WIRE_BATCH_OPERATOR_SOL_WIRE_PROVIDER_SPEC:-}
|
||||
WIRE_BATCH_OPERATOR_SOURCE_CLIENT_ID: ${WIRE_BATCH_OPERATOR_SOL_CLIENT_ID:-sol-local-1}
|
||||
WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_ID: ${WIRE_BATCH_OPERATOR_SOL_PROVIDER_ID:-sol-local-1}
|
||||
WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_SPEC: ${WIRE_BATCH_OPERATOR_SOL_PROVIDER_SPEC:-}
|
||||
WIRE_BATCH_OPERATOR_SOURCE_RPC_URL: ${WIRE_BATCH_OPERATOR_SOL_RPC_URL:-http://solana-validator:8899}
|
||||
WIRE_BATCH_OPERATOR_SOL_PROGRAM_ID: ${WIRE_BATCH_OPERATOR_SOL_PROGRAM_ID:-}
|
||||
WIRE_BATCH_OPERATOR_SOL_IDL_FILE: ${WIRE_BATCH_OPERATOR_SOL_IDL_FILE:-/wire/.branch-worktrees/capital-staking-opp-parity/target/idl/liqsol_core.json}
|
||||
WIRE_BATCH_OPERATOR_POLL_INTERVAL_MS: ${WIRE_BATCH_OPERATOR_POLL_INTERVAL_MS:-5000}
|
||||
depends_on:
|
||||
wire-nodeop:
|
||||
condition: service_started
|
||||
solana-validator:
|
||||
condition: service_healthy
|
||||
command: ["bash", "-lc", "bash /wire/wire-batch-operator-local.sh sol 1"]
|
||||
|
||||
wire-ethereum-dev:
|
||||
image: node:20-bookworm
|
||||
user: "${LOCAL_UID:-1000}:${LOCAL_GID:-1000}"
|
||||
working_dir: /workspace/${WIRE_ETHEREUM_REPO_DIR:-wire-ethereum}
|
||||
volumes:
|
||||
- .:/workspace
|
||||
command: ["bash", "-lc", "sleep infinity"]
|
||||
|
||||
hardhat:
|
||||
image: node:20-bookworm
|
||||
user: "${LOCAL_UID:-1000}:${LOCAL_GID:-1000}"
|
||||
working_dir: /workspace/${WIRE_ETHEREUM_REPO_DIR:-wire-ethereum}
|
||||
volumes:
|
||||
- .:/workspace
|
||||
ports:
|
||||
- "${HARDHAT_PORT:-8545}:8545"
|
||||
command: ["bash", "-lc", "npm ci && npx hardhat node --hostname 0.0.0.0"]
|
||||
|
||||
capital-staking-dev:
|
||||
build:
|
||||
context: ${CAPITAL_STAKING_BUILD_CONTEXT:-./capital-staking}
|
||||
dockerfile: docker/anchor-toolchain.Dockerfile
|
||||
image: ${CAPITAL_STAKING_IMAGE:-skunk-net/capital-staking-dev:local}
|
||||
user: "${LOCAL_UID:-1000}:${LOCAL_GID:-1000}"
|
||||
working_dir: /workspace/${CAPITAL_STAKING_REPO_DIR:-capital-staking}
|
||||
volumes:
|
||||
- .:/workspace
|
||||
environment:
|
||||
ANCHOR_PROVIDER_URL: ${ANCHOR_PROVIDER_URL:-http://solana-validator:8899}
|
||||
ANCHOR_WALLET: ${ANCHOR_WALLET:-/workspace/.branch-worktrees/capital-staking-opp-parity/wallets/deploymentWallet/universalDeploymentWallet.json}
|
||||
DOCKER_CLUSTER: "1"
|
||||
RPC_URL: ${RPC_URL:-http://solana-validator:8899}
|
||||
REQUIRED_VALIDATORS: ${REQUIRED_VALIDATORS:-1}
|
||||
SOLANA_RPC: ${SOLANA_RPC:-http://solana-validator:8899}
|
||||
depends_on:
|
||||
solana-validator:
|
||||
condition: service_healthy
|
||||
command: ["bash", "-lc", "sleep infinity"]
|
||||
|
||||
solana-validator:
|
||||
build:
|
||||
context: ./solana-docker-setup
|
||||
dockerfile: Dockerfile
|
||||
image: ${SOLANA_DOCKER_IMAGE:-skunk-net/solana-validator:local}
|
||||
working_dir: /solana
|
||||
volumes:
|
||||
- solana-validator-data:/solana-data
|
||||
ports:
|
||||
- "${SOLANA_GOSSIP_PORT:-8001}:8001/udp"
|
||||
- "${SOLANA_RPC_PORT:-8899}:8899"
|
||||
- "${SOLANA_WS_PORT:-8900}:8900"
|
||||
- "${SOLANA_FAUCET_PORT:-9900}:9900"
|
||||
environment:
|
||||
IS_GENESIS: "true"
|
||||
NODE_NAME: genesis
|
||||
GOSSIP_HOST: solana-validator
|
||||
GOSSIP_PORT: ${SOLANA_GOSSIP_PORT:-8001}
|
||||
RPC_PORT: 8899
|
||||
RPC_BIND_ADDRESS: 0.0.0.0
|
||||
BIND_ADDRESS: 0.0.0.0
|
||||
FAUCET_ENABLE: "true"
|
||||
FAUCET_ADDRESS: 0.0.0.0
|
||||
FAUCET_PORT: 9900
|
||||
SLOTS_PER_EPOCH: ${SOLANA_SLOTS_PER_EPOCH:-64}
|
||||
DATA_DIR: /solana-data/genesis
|
||||
SOLANA_RUN_SH_VALIDATOR_ARGS: ${SOLANA_RUN_SH_VALIDATOR_ARGS:-}
|
||||
ulimits:
|
||||
nofile:
|
||||
soft: 1000000
|
||||
hard: 1000000
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -fsS http://127.0.0.1:8899/health >/dev/null"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 60
|
||||
start_period: 120s
|
||||
|
||||
volumes:
|
||||
solana-validator-data:
|
||||
23
local-compose.sh
Executable file
23
local-compose.sh
Executable file
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ENV_FILE="${ROOT_DIR}/.env.local"
|
||||
|
||||
if [[ ! -f "${ENV_FILE}" ]]; then
|
||||
if [[ -f "${ROOT_DIR}/.env.local.example" ]]; then
|
||||
cp "${ROOT_DIR}/.env.local.example" "${ENV_FILE}"
|
||||
echo "Created ${ENV_FILE} from .env.local.example" >&2
|
||||
else
|
||||
echo "Missing ${ENV_FILE} and .env.local.example" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
exec env \
|
||||
LOCAL_UID="$(id -u)" \
|
||||
LOCAL_GID="$(id -g)" \
|
||||
docker compose \
|
||||
--env-file "${ENV_FILE}" \
|
||||
-f "${ROOT_DIR}/docker-compose.local.yml" \
|
||||
"$@"
|
||||
25
local-e2e-up.sh
Executable file
25
local-e2e-up.sh
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ENV_FILE="${ROOT_DIR}/.env.local"
|
||||
|
||||
if [[ -f "${ENV_FILE}" ]]; then
|
||||
set -a
|
||||
# shellcheck disable=SC1090
|
||||
source "${ENV_FILE}"
|
||||
set +a
|
||||
fi
|
||||
|
||||
WIRE_ETHEREUM_REPO_DIR="${WIRE_ETHEREUM_REPO_DIR:-wire-ethereum}"
|
||||
CAPITAL_STAKING_REPO_DIR="${CAPITAL_STAKING_REPO_DIR:-capital-staking}"
|
||||
|
||||
"${ROOT_DIR}/local-compose.sh" up -d hardhat solana-validator wire-nodeop
|
||||
|
||||
"${ROOT_DIR}/local-compose.sh" exec hardhat bash -lc \
|
||||
"cd /workspace/${WIRE_ETHEREUM_REPO_DIR} && ROOT_DIR=/workspace WIRE_ETHEREUM_DIR=/workspace/${WIRE_ETHEREUM_REPO_DIR} bash /workspace/bootstrap-ethereum-local.sh"
|
||||
|
||||
"${ROOT_DIR}/local-compose.sh" run --rm --no-deps capital-staking-dev bash -lc \
|
||||
"cd /workspace/${CAPITAL_STAKING_REPO_DIR} && ROOT_DIR=/workspace CAPITAL_STAKING_DIR=/workspace/${CAPITAL_STAKING_REPO_DIR} bash /workspace/bootstrap-solana-local.sh"
|
||||
|
||||
"${ROOT_DIR}/local-compose.sh" up -d batch-operator-eth-1 batch-operator-sol-1
|
||||
53
protocol/opp/v1/assertion-registry.md
Normal file
53
protocol/opp/v1/assertion-registry.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# OPP Assertion Registry
|
||||
|
||||
This file is the numeric assertion registry for the shared OPP protobuf schema in `protocol/opp/v1/opp.proto`.
|
||||
|
||||
## Rules
|
||||
|
||||
- Numeric assertion IDs remain stable once assigned.
|
||||
- Direction is part of the assignment. The same business meaning in opposite directions gets a different numeric ID.
|
||||
- Payload bytes are protobuf messages from `wire.opp.v1`.
|
||||
- Request/response flows correlate through `request_id`, not through shared batch numbers.
|
||||
|
||||
## Assigned Ranges
|
||||
|
||||
| Range | Route | Notes |
|
||||
| --- | --- | --- |
|
||||
| `2000-2099` | `Ethereum -> Wire` BAR | Existing Ethereum BAR assertions |
|
||||
| `3000-3099` | `Ethereum -> Wire` Depositor/Pretoken | Existing Ethereum depositor and pretoken assertions |
|
||||
| `4000-4199` | `Solana -> Wire` | Solana facts and requests |
|
||||
| `5000-5199` | `Wire -> Solana` | Wire settlement and admin commands |
|
||||
| `6000-6199` | `Wire -> Ethereum` | Wire settlement and admin commands |
|
||||
|
||||
## Active Assignments
|
||||
|
||||
| ID | Route | Lane | Payload | Current surface |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `2001` | `Ethereum -> Wire` | `bar` | `BondedActorMirror` | `wire-ethereum/contracts/outpost/BAR.sol` |
|
||||
| `2002` | `Ethereum -> Wire` | `bar` | `UnbondedActorMirror` | `wire-ethereum/contracts/outpost/BAR.sol` |
|
||||
| `2003` | `Ethereum -> Wire` | `bar` | `BondSlashMirror` | `wire-ethereum/contracts/outpost/BAR.sol` |
|
||||
| `3001` | `Ethereum -> Wire` | `depositor` | `StakeMirror` | `wire-ethereum/contracts/outpost/Depositor.sol` |
|
||||
| `3002` | `Ethereum -> Wire` | `depositor` | `UnstakeMirror` | `wire-ethereum/contracts/outpost/Depositor.sol` |
|
||||
| `3004` | `Ethereum -> Wire` | `pretoken` | `PretokenPurchaseMirror` | `wire-ethereum/contracts/outpost/Depositor.sol` |
|
||||
| `3005` | `Ethereum -> Wire` | `pretoken` | `PretokenPurchaseMirror` | `wire-ethereum/contracts/outpost/Pretoken.sol` |
|
||||
| `3006` | `Ethereum -> Wire` | `pretoken` | `PretokenPurchaseMirror` | `wire-ethereum/contracts/outpost/Depositor.sol` |
|
||||
| `4001` | `Solana -> Wire` | `depositor` | `StakeMirror` | `capital-staking/.../wire_syndication/syndicate_liqsol.rs` |
|
||||
| `4002` | `Solana -> Wire` | `depositor` | `WithdrawRequest` | `capital-staking/.../wire_syndication/desyndicate_liqsol.rs` |
|
||||
| `4003` | `Solana -> Wire` | `pretoken` | `PretokenPurchaseMirror` | `capital-staking/.../wire_pretokens/purchase_pretoken.rs` |
|
||||
| `4004` | `Solana -> Wire` | `pretoken` | `PretokenPurchaseMirror` | `capital-staking/.../wire_pretokens/purchase_pretokens_from_yield.rs` |
|
||||
| `4101` | `Solana -> Wire` | `bar` | `RoleBondRequest` | `capital-staking/.../bar/bond_ops.rs` |
|
||||
| `4102` | `Solana -> Wire` | `bar` | `RoleUnbondRequest` | `capital-staking/.../bar/bond_ops.rs` |
|
||||
| `5001` | `Wire -> Solana` | `admin` | `CompleteWithdrawCommand` | `capital-staking/.../wire_config/admin_instructions.rs` |
|
||||
| `5002` | `Wire -> Solana` | `admin` | `CompleteUnbondCommand` | `capital-staking/.../bar/admin_instructions.rs` |
|
||||
| `5003` | `Wire -> Solana` | `admin` | `SlashBondCommand` | `capital-staking/.../bar/admin_instructions.rs` |
|
||||
| `5004` | `Wire -> Solana` | `admin` | `AdminForceUnbondCommand` | `capital-staking/.../bar/admin_instructions.rs` |
|
||||
| `5009` | `Wire -> Solana` | `admin` | `RequestRejected` | Reserved for failed Solana request outcomes |
|
||||
| `6001` | `Wire -> Ethereum` | `admin` | `CompleteUnbondCommand` | Reserved for Ethereum endpoint implementation |
|
||||
| `6002` | `Wire -> Ethereum` | `admin` | `SlashBondCommand` | Reserved for Ethereum endpoint implementation |
|
||||
| `6009` | `Wire -> Ethereum` | `admin` | `RequestRejected` | Reserved for Ethereum endpoint implementation |
|
||||
|
||||
## Notes
|
||||
|
||||
- `3004`, `3005`, and `3006` all currently describe pretoken-related state, but they remain distinct numeric IDs because they originate from different Ethereum business actions.
|
||||
- `4002` and the `500x` series are the first Solana request/response pair that should be implemented for end-to-end testing.
|
||||
- `600x` is intentionally small right now because `Wire -> Ethereum` business handlers do not yet exist in this checkout.
|
||||
215
protocol/opp/v1/opp.proto
Normal file
215
protocol/opp/v1/opp.proto
Normal file
@@ -0,0 +1,215 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package wire.opp.v1;
|
||||
|
||||
enum ChainKind {
|
||||
CHAIN_KIND_UNKNOWN = 0;
|
||||
CHAIN_KIND_WIRE = 1;
|
||||
CHAIN_KIND_ETHEREUM = 2;
|
||||
CHAIN_KIND_SOLANA = 3;
|
||||
CHAIN_KIND_SUI = 4;
|
||||
}
|
||||
|
||||
enum OppLane {
|
||||
OPP_LANE_UNSPECIFIED = 0;
|
||||
OPP_LANE_DEPOSITOR = 1;
|
||||
OPP_LANE_PRETOKEN = 2;
|
||||
OPP_LANE_BAR = 3;
|
||||
OPP_LANE_ADMIN = 4;
|
||||
OPP_LANE_SWAP = 5;
|
||||
}
|
||||
|
||||
enum Role {
|
||||
ROLE_UNSPECIFIED = 0;
|
||||
ROLE_YIELD_OPERATOR = 1;
|
||||
ROLE_BATCH_OPERATOR = 2;
|
||||
ROLE_UNDERWRITER = 4;
|
||||
ROLE_POOL_OPERATOR = 8;
|
||||
}
|
||||
|
||||
enum AssertionType {
|
||||
ASSERTION_TYPE_UNSPECIFIED = 0;
|
||||
|
||||
ASSERTION_TYPE_ETH_BAR_BONDED_ACTOR = 2001;
|
||||
ASSERTION_TYPE_ETH_BAR_UNBONDED_ACTOR = 2002;
|
||||
ASSERTION_TYPE_ETH_BAR_BOND_SLASHED = 2003;
|
||||
|
||||
ASSERTION_TYPE_ETH_DEPOSITOR_STAKE = 3001;
|
||||
ASSERTION_TYPE_ETH_DEPOSITOR_UNSTAKE = 3002;
|
||||
ASSERTION_TYPE_ETH_DEPOSITOR_LIQ_PRETOKEN_PURCHASE = 3004;
|
||||
ASSERTION_TYPE_ETH_PRETOKEN_PURCHASE = 3005;
|
||||
ASSERTION_TYPE_ETH_DEPOSITOR_YIELD_PRETOKEN_PURCHASE = 3006;
|
||||
|
||||
ASSERTION_TYPE_SOL_STAKE = 4001;
|
||||
ASSERTION_TYPE_SOL_WITHDRAW_REQUEST = 4002;
|
||||
ASSERTION_TYPE_SOL_PRETOKEN_PURCHASE = 4003;
|
||||
ASSERTION_TYPE_SOL_YIELD_PRETOKEN_PURCHASE = 4004;
|
||||
ASSERTION_TYPE_SOL_BAR_BOND_ROLE = 4101;
|
||||
ASSERTION_TYPE_SOL_BAR_UNBOND_REQUEST = 4102;
|
||||
|
||||
ASSERTION_TYPE_WIRE_SOL_COMPLETE_WITHDRAW = 5001;
|
||||
ASSERTION_TYPE_WIRE_SOL_COMPLETE_UNBOND = 5002;
|
||||
ASSERTION_TYPE_WIRE_SOL_SLASH_BOND = 5003;
|
||||
ASSERTION_TYPE_WIRE_SOL_ADMIN_FORCE_UNBOND = 5004;
|
||||
ASSERTION_TYPE_WIRE_SOL_REQUEST_REJECTED = 5009;
|
||||
|
||||
ASSERTION_TYPE_WIRE_ETH_COMPLETE_UNBOND = 6001;
|
||||
ASSERTION_TYPE_WIRE_ETH_SLASH_BOND = 6002;
|
||||
ASSERTION_TYPE_WIRE_ETH_REQUEST_REJECTED = 6009;
|
||||
}
|
||||
|
||||
message StreamKey {
|
||||
ChainKind from_chain = 1;
|
||||
ChainKind to_chain = 2;
|
||||
bytes origin_system = 3;
|
||||
bytes destination_system = 4;
|
||||
OppLane lane = 5;
|
||||
}
|
||||
|
||||
message Assertion {
|
||||
AssertionType assertion_type = 1;
|
||||
bytes payload = 2;
|
||||
}
|
||||
|
||||
message Uint256 {
|
||||
// Exactly 32 bytes, big-endian, unsigned.
|
||||
bytes be_bytes = 1;
|
||||
}
|
||||
|
||||
message MessageHeader {
|
||||
StreamKey stream = 1;
|
||||
uint64 sequence = 2;
|
||||
bytes previous_message_hash = 3;
|
||||
uint64 source_timestamp_ms = 4;
|
||||
bytes source_event_id = 5;
|
||||
bytes payload_hash = 6;
|
||||
}
|
||||
|
||||
message Message {
|
||||
MessageHeader header = 1;
|
||||
repeated Assertion assertions = 2;
|
||||
}
|
||||
|
||||
message BatchHeader {
|
||||
StreamKey stream = 1;
|
||||
uint64 batch_number = 2;
|
||||
bytes previous_batch_hash = 3;
|
||||
uint64 first_sequence = 4;
|
||||
uint64 last_sequence = 5;
|
||||
uint64 sealed_at_ms = 6;
|
||||
bytes merkle_root = 7;
|
||||
}
|
||||
|
||||
message Batch {
|
||||
BatchHeader header = 1;
|
||||
repeated Assertion summary_assertions = 2;
|
||||
}
|
||||
|
||||
message BatchSubmission {
|
||||
BatchHeader header = 1;
|
||||
bytes batch_hash = 2;
|
||||
bytes operator_id = 3;
|
||||
bytes signature = 4;
|
||||
}
|
||||
|
||||
message RequestRef {
|
||||
bytes request_id = 1;
|
||||
bytes origin_message_id = 2;
|
||||
bytes source_event_id = 3;
|
||||
}
|
||||
|
||||
message StakeMirror {
|
||||
bytes user = 1;
|
||||
Uint256 principal = 2;
|
||||
Uint256 shares = 3;
|
||||
Uint256 index_at_mint = 4;
|
||||
}
|
||||
|
||||
message UnstakeMirror {
|
||||
bytes user = 1;
|
||||
Uint256 amount = 2;
|
||||
Uint256 shares = 3;
|
||||
Uint256 index_at_burn = 4;
|
||||
bytes receipt_id = 5;
|
||||
}
|
||||
|
||||
message PretokenPurchaseMirror {
|
||||
bytes buyer = 1;
|
||||
Uint256 principal = 2;
|
||||
Uint256 shares = 3;
|
||||
Uint256 index_at_mint = 4;
|
||||
Uint256 pretokens_out = 5;
|
||||
}
|
||||
|
||||
message BondedActorMirror {
|
||||
bytes actor = 1;
|
||||
bytes owner = 2;
|
||||
bytes bond_level_id = 3;
|
||||
Uint256 token_id = 4;
|
||||
uint64 bonded_at_unix_seconds = 5;
|
||||
}
|
||||
|
||||
message UnbondedActorMirror {
|
||||
bytes actor = 1;
|
||||
bytes bond_level_id = 2;
|
||||
Uint256 token_id = 3;
|
||||
uint64 unbonded_at_unix_seconds = 4;
|
||||
}
|
||||
|
||||
message BondSlashMirror {
|
||||
bytes actor = 1;
|
||||
bytes bond_level_id = 2;
|
||||
Uint256 slashed_amount = 3;
|
||||
}
|
||||
|
||||
message WithdrawRequest {
|
||||
bytes request_id = 1;
|
||||
bytes user = 2;
|
||||
Uint256 amount = 3;
|
||||
}
|
||||
|
||||
message RoleBondRequest {
|
||||
bytes request_id = 1;
|
||||
bytes user = 2;
|
||||
Role role = 3;
|
||||
Uint256 principal = 4;
|
||||
uint64 warmup_ends_at_unix_seconds = 5;
|
||||
}
|
||||
|
||||
message RoleUnbondRequest {
|
||||
bytes request_id = 1;
|
||||
bytes user = 2;
|
||||
Role role = 3;
|
||||
}
|
||||
|
||||
message CompleteWithdrawCommand {
|
||||
RequestRef request = 1;
|
||||
bytes user = 2;
|
||||
Uint256 amount = 3;
|
||||
}
|
||||
|
||||
message CompleteUnbondCommand {
|
||||
RequestRef request = 1;
|
||||
bytes user = 2;
|
||||
Role role = 3;
|
||||
Uint256 principal = 4;
|
||||
}
|
||||
|
||||
message SlashBondCommand {
|
||||
RequestRef request = 1;
|
||||
bytes user = 2;
|
||||
Role role = 3;
|
||||
Uint256 slashed_amount = 4;
|
||||
}
|
||||
|
||||
message AdminForceUnbondCommand {
|
||||
RequestRef request = 1;
|
||||
bytes user = 2;
|
||||
Role role = 3;
|
||||
}
|
||||
|
||||
message RequestRejected {
|
||||
RequestRef request = 1;
|
||||
uint32 code = 2;
|
||||
string reason = 3;
|
||||
}
|
||||
345
wire-batch-operator-local.sh
Normal file
345
wire-batch-operator-local.sh
Normal file
@@ -0,0 +1,345 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
WIRE_SYSIO_DIR="${WIRE_SYSIO_DIR:-${ROOT_DIR}/wire-sysio}"
|
||||
BUILD_DIR="${WIRE_SYSIO_BUILD_DIR:-${WIRE_SYSIO_DIR}/build/debug-docker}"
|
||||
VCPKG_DIR="${BUILD_DIR}/vcpkg_installed/x64-linux"
|
||||
WIRE_CDT_DIR="${WIRE_CDT_DIR:-${ROOT_DIR}/wire-cdt}"
|
||||
WIRE_CDT_BUILD_DIR="${WIRE_CDT_BUILD_DIR:-${WIRE_CDT_DIR}/build/debug-docker}"
|
||||
WIRE_SYSIO_SUBMODULE_FALLBACK_DIR="${WIRE_SYSIO_SUBMODULE_FALLBACK_DIR:-${ROOT_DIR}/wire-sysio}"
|
||||
WIRE_SYSIO_BUILD_FALLBACK_DIR="${WIRE_SYSIO_BUILD_FALLBACK_DIR:-${ROOT_DIR}/wire-sysio/build/debug-docker}"
|
||||
ROUTE="${1:-${WIRE_BATCH_OPERATOR_ROUTE:-}}"
|
||||
INDEX="${2:-${WIRE_BATCH_OPERATOR_INDEX:-1}}"
|
||||
OP_ROOT="${WIRE_BATCH_OPERATOR_ROOT:-/srv/wire-batch-operators}"
|
||||
WIRE_BATCH_OPERATOR_ARTIFACTS_DIR="${WIRE_BATCH_OPERATOR_ARTIFACTS_DIR:-${ROOT_DIR}/.local/e2e}"
|
||||
CONFIG_DIR="${OP_ROOT}/${ROUTE}/${INDEX}/config"
|
||||
DATA_DIR="${OP_ROOT}/${ROUTE}/${INDEX}/data"
|
||||
LOG_DIR="${OP_ROOT}/${ROUTE}/${INDEX}/log"
|
||||
LOG_FILE="${LOG_DIR}/relay.log"
|
||||
BUILD_LOCK_FILE="${BUILD_DIR}/batch-operator-relay.lock"
|
||||
|
||||
CMAKE_COMMON_ARGS=(
|
||||
-S "${WIRE_SYSIO_DIR}"
|
||||
-B "${BUILD_DIR}"
|
||||
-G Ninja
|
||||
-DCMAKE_BUILD_TYPE=Debug
|
||||
-DCMAKE_TOOLCHAIN_FILE="${WIRE_SYSIO_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake"
|
||||
-DCMAKE_C_COMPILER=/opt/clang/clang-18/bin/clang
|
||||
-DCMAKE_CXX_COMPILER=/opt/clang/clang-18/bin/clang++
|
||||
-DCMAKE_INSTALL_PREFIX=/opt/wire
|
||||
-DCMAKE_PREFIX_PATH="/opt/wire;/opt/clang/clang-18;${WIRE_CDT_BUILD_DIR}"
|
||||
-DENABLE_TESTS=OFF
|
||||
-DBUILD_SYSTEM_CONTRACTS=ON
|
||||
-DBUILD_TEST_CONTRACTS=OFF
|
||||
-DCDT_ROOT="${WIRE_CDT_BUILD_DIR}"
|
||||
)
|
||||
|
||||
dir_is_empty() {
|
||||
local path="$1"
|
||||
[[ -d "${path}" ]] && [[ -z "$(find "${path}" -mindepth 1 -maxdepth 1 -print -quit 2>/dev/null)" ]]
|
||||
}
|
||||
|
||||
link_submodule_from_fallback() {
|
||||
local relative_path="$1"
|
||||
local target_path="${WIRE_SYSIO_DIR}/${relative_path}"
|
||||
local source_path="${WIRE_SYSIO_SUBMODULE_FALLBACK_DIR}/${relative_path}"
|
||||
local link_source
|
||||
|
||||
if [[ ! -e "${source_path}" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
link_source="$(realpath --relative-to "$(dirname "${target_path}")" "${source_path}")"
|
||||
|
||||
if [[ -L "${target_path}" ]] && [[ "$(readlink "${target_path}")" == "${link_source}" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ -L "${target_path}" ]]; then
|
||||
ln -sfn "${link_source}" "${target_path}"
|
||||
return
|
||||
fi
|
||||
|
||||
if dir_is_empty "${target_path}"; then
|
||||
rmdir "${target_path}"
|
||||
fi
|
||||
|
||||
if [[ ! -e "${target_path}" ]]; then
|
||||
ln -sfn "${link_source}" "${target_path}"
|
||||
fi
|
||||
}
|
||||
|
||||
hydrate_wire_submodules() {
|
||||
link_submodule_from_fallback "libraries/appbase"
|
||||
link_submodule_from_fallback "vcpkg"
|
||||
}
|
||||
|
||||
hydrate_wire_build_cache() {
|
||||
local target_install_dir="${BUILD_DIR}/vcpkg_installed"
|
||||
local source_install_dir="${WIRE_SYSIO_BUILD_FALLBACK_DIR}/vcpkg_installed"
|
||||
local link_source
|
||||
|
||||
if [[ ! -d "${source_install_dir}" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
mkdir -p "$(dirname "${target_install_dir}")"
|
||||
link_source="$(realpath --relative-to "$(dirname "${target_install_dir}")" "${source_install_dir}")"
|
||||
|
||||
if [[ -L "${target_install_dir}" ]] && [[ "$(readlink "${target_install_dir}")" == "${link_source}" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ -L "${target_install_dir}" ]]; then
|
||||
ln -sfn "${link_source}" "${target_install_dir}"
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ -d "${target_install_dir}" ]] && [[ ! -f "${BUILD_DIR}/bin/batch-operator-relay" ]]; then
|
||||
mv "${target_install_dir}" "${target_install_dir}.partial.$(date +%s)"
|
||||
fi
|
||||
|
||||
if [[ ! -e "${target_install_dir}" ]]; then
|
||||
ln -s "${link_source}" "${target_install_dir}"
|
||||
fi
|
||||
}
|
||||
|
||||
require_wire_submodules() {
|
||||
hydrate_wire_submodules
|
||||
|
||||
if [[ ! -f "${WIRE_SYSIO_DIR}/vcpkg/bootstrap-vcpkg.sh" ]] || [[ ! -f "${WIRE_SYSIO_DIR}/libraries/appbase/CMakeLists.txt" ]]; then
|
||||
echo "wire-sysio submodules are missing. Run: git -C ${WIRE_SYSIO_DIR} submodule update --init --recursive" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
write_pkgconfig_shims() {
|
||||
local pc_dir="$1"
|
||||
local lib_dir="$2"
|
||||
|
||||
mkdir -p "${pc_dir}"
|
||||
|
||||
cat >"${pc_dir}/libssl.pc" <<EOF
|
||||
prefix=${VCPKG_DIR}
|
||||
exec_prefix=\${prefix}
|
||||
libdir=${lib_dir}
|
||||
includedir=${VCPKG_DIR}/include
|
||||
|
||||
Name: libssl
|
||||
Description: BoringSSL compatibility shim for curl configure
|
||||
Version: 1.0.0
|
||||
Libs: -L${lib_dir} -lssl
|
||||
Cflags: -I${VCPKG_DIR}/include
|
||||
EOF
|
||||
|
||||
cat >"${pc_dir}/libcrypto.pc" <<EOF
|
||||
prefix=${VCPKG_DIR}
|
||||
exec_prefix=\${prefix}
|
||||
libdir=${lib_dir}
|
||||
includedir=${VCPKG_DIR}/include
|
||||
|
||||
Name: libcrypto
|
||||
Description: BoringSSL compatibility shim for curl configure
|
||||
Version: 1.0.0
|
||||
Libs: -L${lib_dir} -lbscrypto
|
||||
Cflags: -I${VCPKG_DIR}/include
|
||||
EOF
|
||||
}
|
||||
|
||||
configure_wire_sysio() {
|
||||
mkdir -p "${BUILD_DIR}"
|
||||
hydrate_wire_build_cache
|
||||
|
||||
if [[ ! -x "${WIRE_SYSIO_DIR}/vcpkg/vcpkg" ]]; then
|
||||
"${WIRE_SYSIO_DIR}/vcpkg/bootstrap-vcpkg.sh"
|
||||
fi
|
||||
cmake "${CMAKE_COMMON_ARGS[@]}" >/dev/null 2>&1 || true
|
||||
|
||||
write_pkgconfig_shims "${VCPKG_DIR}/lib/pkgconfig" "${VCPKG_DIR}/lib"
|
||||
write_pkgconfig_shims "${VCPKG_DIR}/debug/lib/pkgconfig" "${VCPKG_DIR}/debug/lib"
|
||||
|
||||
cmake \
|
||||
"${CMAKE_COMMON_ARGS[@]}" \
|
||||
-DOPENSSL_INCLUDE_DIR="${VCPKG_DIR}/include" \
|
||||
-DOPENSSL_SSL_LIBRARY="${VCPKG_DIR}/debug/lib/libssl.a" \
|
||||
-DOPENSSL_CRYPTO_LIBRARY="${VCPKG_DIR}/debug/lib/libbscrypto.a"
|
||||
}
|
||||
|
||||
build_batch_operator() {
|
||||
cmake --build "${BUILD_DIR}" --target batch-operator-relay -- -j"$(nproc)"
|
||||
}
|
||||
|
||||
require_var() {
|
||||
local name="$1"
|
||||
if [[ -z "${!name:-}" ]]; then
|
||||
echo "Missing required environment variable: ${name}" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
prepare_dirs() {
|
||||
mkdir -p "${CONFIG_DIR}" "${DATA_DIR}" "${LOG_DIR}"
|
||||
}
|
||||
|
||||
append_log() {
|
||||
printf '[%s] %s\n' "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" "$*" >>"${LOG_FILE}"
|
||||
}
|
||||
|
||||
configure_and_build_batch_operator() {
|
||||
mkdir -p "${BUILD_DIR}"
|
||||
|
||||
append_log "Waiting for build lock: ${BUILD_LOCK_FILE}"
|
||||
{
|
||||
flock 9
|
||||
append_log "Acquired build lock"
|
||||
|
||||
configure_wire_sysio >>"${LOG_FILE}" 2>&1
|
||||
build_batch_operator >>"${LOG_FILE}" 2>&1
|
||||
} 9>"${BUILD_LOCK_FILE}"
|
||||
}
|
||||
|
||||
wait_for_artifact() {
|
||||
local path="$1"
|
||||
local attempts="${2:-120}"
|
||||
|
||||
for _ in $(seq 1 "${attempts}"); do
|
||||
if [[ -f "${path}" ]]; then
|
||||
return 0
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo "Timed out waiting for artifact: ${path}" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
source_env_file() {
|
||||
local path="$1"
|
||||
set -a
|
||||
# shellcheck disable=SC1090
|
||||
source "${path}"
|
||||
set +a
|
||||
}
|
||||
|
||||
load_generated_artifacts() {
|
||||
local wire_env="${WIRE_BATCH_OPERATOR_ARTIFACTS_DIR}/wire.env"
|
||||
local source_env
|
||||
|
||||
wait_for_artifact "${wire_env}"
|
||||
source_env_file "${wire_env}"
|
||||
|
||||
case "${ROUTE}" in
|
||||
eth)
|
||||
source_env="${WIRE_BATCH_OPERATOR_ARTIFACTS_DIR}/ethereum.env"
|
||||
;;
|
||||
sol)
|
||||
source_env="${WIRE_BATCH_OPERATOR_ARTIFACTS_DIR}/solana.env"
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported route '${ROUTE}'. Expected 'eth' or 'sol'." >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
wait_for_artifact "${source_env}"
|
||||
source_env_file "${source_env}"
|
||||
|
||||
if [[ "${ROUTE}" == "eth" ]]; then
|
||||
[[ -n "${WIRE_BATCH_OPERATOR_WIRE_RPC_URL:-}" ]] || WIRE_BATCH_OPERATOR_WIRE_RPC_URL="${LOCAL_WIRE_RPC_URL:-http://wire-nodeop:8887}"
|
||||
[[ -n "${WIRE_BATCH_OPERATOR_WIRE_DEPOT_ACCOUNT:-}" ]] || WIRE_BATCH_OPERATOR_WIRE_DEPOT_ACCOUNT="${LOCAL_WIRE_ETH_DEPOT_ACCOUNT:-}"
|
||||
[[ -n "${WIRE_BATCH_OPERATOR_WIRE_ACCOUNT:-}" ]] || WIRE_BATCH_OPERATOR_WIRE_ACCOUNT="${LOCAL_WIRE_ETH_OPERATOR_ACCOUNT:-}"
|
||||
[[ -n "${WIRE_BATCH_OPERATOR_WIRE_PROVIDER_ID:-}" ]] || WIRE_BATCH_OPERATOR_WIRE_PROVIDER_ID="${LOCAL_WIRE_ETH_OPERATOR_PROVIDER_ID:-}"
|
||||
[[ -n "${WIRE_BATCH_OPERATOR_WIRE_PROVIDER_SPEC:-}" ]] || WIRE_BATCH_OPERATOR_WIRE_PROVIDER_SPEC="${LOCAL_WIRE_ETH_OPERATOR_PROVIDER_SPEC:-}"
|
||||
[[ -n "${WIRE_BATCH_OPERATOR_SOURCE_CLIENT_ID:-}" ]] || WIRE_BATCH_OPERATOR_SOURCE_CLIENT_ID="${LOCAL_ETH_CLIENT_ID:-}"
|
||||
[[ -n "${WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_ID:-}" ]] || WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_ID="${LOCAL_ETH_PROVIDER_ID:-}"
|
||||
[[ -n "${WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_SPEC:-}" ]] || WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_SPEC="${LOCAL_ETH_PROVIDER_SPEC:-}"
|
||||
[[ -n "${WIRE_BATCH_OPERATOR_SOURCE_RPC_URL:-}" ]] || WIRE_BATCH_OPERATOR_SOURCE_RPC_URL="${LOCAL_ETH_RPC_URL:-}"
|
||||
[[ -n "${WIRE_BATCH_OPERATOR_ETH_ABI_FILE:-}" ]] || WIRE_BATCH_OPERATOR_ETH_ABI_FILE="${LOCAL_ETH_ABI_FILE:-}"
|
||||
[[ -n "${WIRE_BATCH_OPERATOR_ETH_OPP_ADDRESS:-}" ]] || WIRE_BATCH_OPERATOR_ETH_OPP_ADDRESS="${LOCAL_ETH_OPP_ADDRESS:-}"
|
||||
[[ -n "${WIRE_BATCH_OPERATOR_ETH_OPP_INBOUND_ADDRESS:-}" ]] || WIRE_BATCH_OPERATOR_ETH_OPP_INBOUND_ADDRESS="${LOCAL_ETH_OPP_INBOUND_ADDRESS:-}"
|
||||
else
|
||||
[[ -n "${WIRE_BATCH_OPERATOR_WIRE_RPC_URL:-}" ]] || WIRE_BATCH_OPERATOR_WIRE_RPC_URL="${LOCAL_WIRE_RPC_URL:-http://wire-nodeop:8887}"
|
||||
[[ -n "${WIRE_BATCH_OPERATOR_WIRE_DEPOT_ACCOUNT:-}" ]] || WIRE_BATCH_OPERATOR_WIRE_DEPOT_ACCOUNT="${LOCAL_WIRE_SOL_DEPOT_ACCOUNT:-}"
|
||||
[[ -n "${WIRE_BATCH_OPERATOR_WIRE_ACCOUNT:-}" ]] || WIRE_BATCH_OPERATOR_WIRE_ACCOUNT="${LOCAL_WIRE_SOL_OPERATOR_ACCOUNT:-}"
|
||||
[[ -n "${WIRE_BATCH_OPERATOR_WIRE_PROVIDER_ID:-}" ]] || WIRE_BATCH_OPERATOR_WIRE_PROVIDER_ID="${LOCAL_WIRE_SOL_OPERATOR_PROVIDER_ID:-}"
|
||||
[[ -n "${WIRE_BATCH_OPERATOR_WIRE_PROVIDER_SPEC:-}" ]] || WIRE_BATCH_OPERATOR_WIRE_PROVIDER_SPEC="${LOCAL_WIRE_SOL_OPERATOR_PROVIDER_SPEC:-}"
|
||||
[[ -n "${WIRE_BATCH_OPERATOR_SOURCE_CLIENT_ID:-}" ]] || WIRE_BATCH_OPERATOR_SOURCE_CLIENT_ID="${LOCAL_SOL_CLIENT_ID:-}"
|
||||
[[ -n "${WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_ID:-}" ]] || WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_ID="${LOCAL_SOL_PROVIDER_ID:-}"
|
||||
[[ -n "${WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_SPEC:-}" ]] || WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_SPEC="${LOCAL_SOL_PROVIDER_SPEC:-}"
|
||||
[[ -n "${WIRE_BATCH_OPERATOR_SOURCE_RPC_URL:-}" ]] || WIRE_BATCH_OPERATOR_SOURCE_RPC_URL="${LOCAL_SOL_RPC_URL:-}"
|
||||
[[ -n "${WIRE_BATCH_OPERATOR_SOL_PROGRAM_ID:-}" ]] || WIRE_BATCH_OPERATOR_SOL_PROGRAM_ID="${LOCAL_SOL_PROGRAM_ID:-}"
|
||||
[[ -n "${WIRE_BATCH_OPERATOR_SOL_IDL_FILE:-}" ]] || WIRE_BATCH_OPERATOR_SOL_IDL_FILE="${LOCAL_SOL_IDL_FILE:-}"
|
||||
fi
|
||||
}
|
||||
|
||||
build_args() {
|
||||
local -n out_args=$1
|
||||
local route="$2"
|
||||
|
||||
require_var WIRE_BATCH_OPERATOR_WIRE_ACCOUNT
|
||||
require_var WIRE_BATCH_OPERATOR_WIRE_PROVIDER_ID
|
||||
require_var WIRE_BATCH_OPERATOR_WIRE_PROVIDER_SPEC
|
||||
require_var WIRE_BATCH_OPERATOR_SOURCE_CLIENT_ID
|
||||
require_var WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_ID
|
||||
require_var WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_SPEC
|
||||
require_var WIRE_BATCH_OPERATOR_SOURCE_RPC_URL
|
||||
|
||||
out_args=(
|
||||
--config-dir "${CONFIG_DIR}"
|
||||
--data-dir "${DATA_DIR}"
|
||||
--batch-operator-wire-rpc-url "${WIRE_BATCH_OPERATOR_WIRE_RPC_URL:-http://wire-nodeop:8887}"
|
||||
--batch-operator-wire-depot-account "${WIRE_BATCH_OPERATOR_WIRE_DEPOT_ACCOUNT:-sysio.depot}"
|
||||
--batch-operator-wire-operator "${WIRE_BATCH_OPERATOR_WIRE_ACCOUNT},${WIRE_BATCH_OPERATOR_WIRE_PROVIDER_ID}"
|
||||
--batch-operator-poll-interval-ms "${WIRE_BATCH_OPERATOR_POLL_INTERVAL_MS:-5000}"
|
||||
--signature-provider "${WIRE_BATCH_OPERATOR_WIRE_PROVIDER_SPEC}"
|
||||
--signature-provider "${WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_SPEC}"
|
||||
)
|
||||
|
||||
if [[ "${route}" == "eth" ]]; then
|
||||
require_var WIRE_BATCH_OPERATOR_ETH_OPP_ADDRESS
|
||||
require_var WIRE_BATCH_OPERATOR_ETH_OPP_INBOUND_ADDRESS
|
||||
require_var WIRE_BATCH_OPERATOR_ETH_ABI_FILE
|
||||
|
||||
out_args+=(
|
||||
--outpost-ethereum-client "${WIRE_BATCH_OPERATOR_SOURCE_CLIENT_ID},${WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_ID},${WIRE_BATCH_OPERATOR_SOURCE_RPC_URL},${WIRE_BATCH_OPERATOR_ETH_CHAIN_ID:-31337}"
|
||||
--ethereum-abi-file "${WIRE_BATCH_OPERATOR_ETH_ABI_FILE}"
|
||||
--batch-operator-ethereum-client-id "${WIRE_BATCH_OPERATOR_SOURCE_CLIENT_ID}"
|
||||
--batch-operator-ethereum-opp-address "${WIRE_BATCH_OPERATOR_ETH_OPP_ADDRESS}"
|
||||
--batch-operator-ethereum-opp-inbound-address "${WIRE_BATCH_OPERATOR_ETH_OPP_INBOUND_ADDRESS}"
|
||||
)
|
||||
elif [[ "${route}" == "sol" ]]; then
|
||||
require_var WIRE_BATCH_OPERATOR_SOL_PROGRAM_ID
|
||||
require_var WIRE_BATCH_OPERATOR_SOL_IDL_FILE
|
||||
|
||||
out_args+=(
|
||||
--outpost-solana-client "${WIRE_BATCH_OPERATOR_SOURCE_CLIENT_ID},${WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_ID},${WIRE_BATCH_OPERATOR_SOURCE_RPC_URL}"
|
||||
--solana-idl-file "${WIRE_BATCH_OPERATOR_SOL_IDL_FILE}"
|
||||
--batch-operator-solana-client-id "${WIRE_BATCH_OPERATOR_SOURCE_CLIENT_ID}"
|
||||
--batch-operator-solana-program-id "${WIRE_BATCH_OPERATOR_SOL_PROGRAM_ID}"
|
||||
)
|
||||
else
|
||||
echo "Unsupported route '${route}'. Expected 'eth' or 'sol'." >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
require_wire_submodules
|
||||
prepare_dirs
|
||||
load_generated_artifacts
|
||||
append_log "Loaded generated artifacts for route=${ROUTE} index=${INDEX}"
|
||||
configure_and_build_batch_operator
|
||||
|
||||
local binary="${BUILD_DIR}/bin/batch-operator-relay"
|
||||
local args=()
|
||||
build_args args "${ROUTE}"
|
||||
|
||||
append_log "Starting batch-operator route=${ROUTE} index=${INDEX}"
|
||||
append_log "Config dir: ${CONFIG_DIR}"
|
||||
append_log "Data dir: ${DATA_DIR}"
|
||||
|
||||
exec "${binary}" "${args[@]}" >>"${LOG_FILE}" 2>&1
|
||||
}
|
||||
|
||||
main "$@"
|
||||
567
wire-nodeop-local.sh
Normal file
567
wire-nodeop-local.sh
Normal file
@@ -0,0 +1,567 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
WIRE_SYSIO_DIR="${WIRE_SYSIO_DIR:-${ROOT_DIR}/wire-sysio}"
|
||||
BUILD_DIR="${WIRE_SYSIO_BUILD_DIR:-${WIRE_SYSIO_DIR}/build/debug-docker}"
|
||||
VCPKG_DIR="${BUILD_DIR}/vcpkg_installed/x64-linux"
|
||||
WIRE_CDT_DIR="${WIRE_CDT_DIR:-${ROOT_DIR}/wire-cdt}"
|
||||
WIRE_CDT_BUILD_DIR="${WIRE_CDT_BUILD_DIR:-${WIRE_CDT_DIR}/build/debug-docker}"
|
||||
TARGET_ROOT="${WIRE_NODE_ROOT:-/srv/wire-node/chain-001}"
|
||||
CONTRACTS_DIR="${WIRE_SYSIO_CONTRACTS_DIR:-${BUILD_DIR}/contracts}"
|
||||
WIRE_ARTIFACTS_DIR="${WIRE_ARTIFACTS_DIR:-${ROOT_DIR}/.local/e2e}"
|
||||
WIRE_SYSIO_SUBMODULE_FALLBACK_DIR="${WIRE_SYSIO_SUBMODULE_FALLBACK_DIR:-${ROOT_DIR}/wire-sysio}"
|
||||
WIRE_SYSIO_BUILD_FALLBACK_DIR="${WIRE_SYSIO_BUILD_FALLBACK_DIR:-${ROOT_DIR}/wire-sysio/build/debug-docker}"
|
||||
WIRE_ETH_DEPOT_ACCOUNT="${WIRE_ETH_DEPOT_ACCOUNT:-sysio.dpeth}"
|
||||
WIRE_SOL_DEPOT_ACCOUNT="${WIRE_SOL_DEPOT_ACCOUNT:-sysio.dpsol}"
|
||||
WIRE_INSTASWAP_ACCOUNT="${WIRE_INSTASWAP_ACCOUNT:-sysio.iswap}"
|
||||
WIRE_WYIELD_ACCOUNT="${WIRE_WYIELD_ACCOUNT:-sysio.wyield}"
|
||||
WIRE_TEST_USER_ACCOUNT="${WIRE_TEST_USER_ACCOUNT:-userinsta1}"
|
||||
WIRE_BATCH_OPERATOR_ETH_ACCOUNT="${WIRE_BATCH_OPERATOR_ETH_ACCOUNT:-bopeth111111}"
|
||||
WIRE_BATCH_OPERATOR_SOL_ACCOUNT="${WIRE_BATCH_OPERATOR_SOL_ACCOUNT:-bopsol111111}"
|
||||
WIRE_BATCH_OPERATOR_ETH_WIRE_PROVIDER_ID="${WIRE_BATCH_OPERATOR_ETH_WIRE_PROVIDER_ID:-wire-bopeth-1}"
|
||||
WIRE_BATCH_OPERATOR_SOL_WIRE_PROVIDER_ID="${WIRE_BATCH_OPERATOR_SOL_WIRE_PROVIDER_ID:-wire-bopsol-1}"
|
||||
WIRE_DEPOT_ACCOUNT_RAM_BYTES="${WIRE_DEPOT_ACCOUNT_RAM_BYTES:-8388608}"
|
||||
WIRE_APP_ACCOUNT_RAM_BYTES="${WIRE_APP_ACCOUNT_RAM_BYTES:-8388608}"
|
||||
WIRE_OPERATOR_ACCOUNT_RAM_BYTES="${WIRE_OPERATOR_ACCOUNT_RAM_BYTES:-1048576}"
|
||||
WIRE_USER_ACCOUNT_RAM_BYTES="${WIRE_USER_ACCOUNT_RAM_BYTES:-1048576}"
|
||||
|
||||
CMAKE_COMMON_ARGS=(
|
||||
-S "${WIRE_SYSIO_DIR}"
|
||||
-B "${BUILD_DIR}"
|
||||
-G Ninja
|
||||
-DCMAKE_BUILD_TYPE=Debug
|
||||
-DCMAKE_TOOLCHAIN_FILE="${WIRE_SYSIO_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake"
|
||||
-DCMAKE_C_COMPILER=/opt/clang/clang-18/bin/clang
|
||||
-DCMAKE_CXX_COMPILER=/opt/clang/clang-18/bin/clang++
|
||||
-DCMAKE_INSTALL_PREFIX=/opt/wire
|
||||
-DCMAKE_PREFIX_PATH="/opt/wire;/opt/clang/clang-18;${WIRE_CDT_BUILD_DIR}"
|
||||
-DENABLE_TESTS=OFF
|
||||
-DBUILD_SYSTEM_CONTRACTS=ON
|
||||
-DCDT_ROOT="${WIRE_CDT_BUILD_DIR}"
|
||||
)
|
||||
|
||||
cleanup() {
|
||||
if [[ -n "${NODEOP_PID:-}" ]]; then
|
||||
kill "${NODEOP_PID}" >/dev/null 2>&1 || true
|
||||
wait "${NODEOP_PID}" >/dev/null 2>&1 || true
|
||||
fi
|
||||
if [[ -n "${KIOD_PID:-}" ]]; then
|
||||
kill "${KIOD_PID}" >/dev/null 2>&1 || true
|
||||
wait "${KIOD_PID}" >/dev/null 2>&1 || true
|
||||
fi
|
||||
}
|
||||
|
||||
dir_is_empty() {
|
||||
local path="$1"
|
||||
[[ -d "${path}" ]] && [[ -z "$(find "${path}" -mindepth 1 -maxdepth 1 -print -quit 2>/dev/null)" ]]
|
||||
}
|
||||
|
||||
link_submodule_from_fallback() {
|
||||
local relative_path="$1"
|
||||
local target_path="${WIRE_SYSIO_DIR}/${relative_path}"
|
||||
local source_path="${WIRE_SYSIO_SUBMODULE_FALLBACK_DIR}/${relative_path}"
|
||||
local link_source
|
||||
|
||||
if [[ ! -e "${source_path}" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
link_source="$(realpath --relative-to "$(dirname "${target_path}")" "${source_path}")"
|
||||
|
||||
if [[ -L "${target_path}" ]] && [[ "$(readlink "${target_path}")" == "${link_source}" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ -L "${target_path}" ]]; then
|
||||
ln -sfn "${link_source}" "${target_path}"
|
||||
return
|
||||
fi
|
||||
|
||||
if dir_is_empty "${target_path}"; then
|
||||
rmdir "${target_path}"
|
||||
fi
|
||||
|
||||
if [[ ! -e "${target_path}" ]]; then
|
||||
ln -sfn "${link_source}" "${target_path}"
|
||||
fi
|
||||
}
|
||||
|
||||
hydrate_wire_submodules() {
|
||||
link_submodule_from_fallback "libraries/appbase"
|
||||
link_submodule_from_fallback "vcpkg"
|
||||
}
|
||||
|
||||
hydrate_wire_build_cache() {
|
||||
local target_install_dir="${BUILD_DIR}/vcpkg_installed"
|
||||
local source_install_dir="${WIRE_SYSIO_BUILD_FALLBACK_DIR}/vcpkg_installed"
|
||||
local link_source
|
||||
|
||||
if [[ ! -d "${source_install_dir}" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
mkdir -p "$(dirname "${target_install_dir}")"
|
||||
link_source="$(realpath --relative-to "$(dirname "${target_install_dir}")" "${source_install_dir}")"
|
||||
|
||||
if [[ -L "${target_install_dir}" ]] && [[ "$(readlink "${target_install_dir}")" == "${link_source}" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ -L "${target_install_dir}" ]]; then
|
||||
ln -sfn "${link_source}" "${target_install_dir}"
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ -d "${target_install_dir}" ]] && [[ ! -f "${BUILD_DIR}/bin/nodeop" ]]; then
|
||||
mv "${target_install_dir}" "${target_install_dir}.partial.$(date +%s)"
|
||||
fi
|
||||
|
||||
if [[ ! -e "${target_install_dir}" ]]; then
|
||||
ln -s "${link_source}" "${target_install_dir}"
|
||||
fi
|
||||
}
|
||||
|
||||
require_wire_submodules() {
|
||||
hydrate_wire_submodules
|
||||
|
||||
if [[ ! -f "${WIRE_SYSIO_DIR}/vcpkg/bootstrap-vcpkg.sh" ]] || [[ ! -f "${WIRE_SYSIO_DIR}/libraries/appbase/CMakeLists.txt" ]]; then
|
||||
echo "wire-sysio submodules are missing. Run: git -C ${WIRE_SYSIO_DIR} submodule update --init --recursive" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
write_pkgconfig_shims() {
|
||||
local pc_dir="$1"
|
||||
local lib_dir="$2"
|
||||
|
||||
mkdir -p "${pc_dir}"
|
||||
|
||||
cat >"${pc_dir}/libssl.pc" <<EOF
|
||||
prefix=${VCPKG_DIR}
|
||||
exec_prefix=\${prefix}
|
||||
libdir=${lib_dir}
|
||||
includedir=${VCPKG_DIR}/include
|
||||
|
||||
Name: libssl
|
||||
Description: BoringSSL compatibility shim for curl configure
|
||||
Version: 1.0.0
|
||||
Libs: -L${lib_dir} -lssl
|
||||
Cflags: -I${VCPKG_DIR}/include
|
||||
EOF
|
||||
|
||||
cat >"${pc_dir}/libcrypto.pc" <<EOF
|
||||
prefix=${VCPKG_DIR}
|
||||
exec_prefix=\${prefix}
|
||||
libdir=${lib_dir}
|
||||
includedir=${VCPKG_DIR}/include
|
||||
|
||||
Name: libcrypto
|
||||
Description: BoringSSL compatibility shim for curl configure
|
||||
Version: 1.0.0
|
||||
Libs: -L${lib_dir} -lbscrypto
|
||||
Cflags: -I${VCPKG_DIR}/include
|
||||
EOF
|
||||
}
|
||||
|
||||
configure_wire_sysio() {
|
||||
mkdir -p "${BUILD_DIR}"
|
||||
hydrate_wire_build_cache
|
||||
|
||||
if [[ ! -x "${WIRE_SYSIO_DIR}/vcpkg/vcpkg" ]]; then
|
||||
"${WIRE_SYSIO_DIR}/vcpkg/bootstrap-vcpkg.sh"
|
||||
fi
|
||||
|
||||
# First configure pass materializes the vcpkg tree used by the shim files.
|
||||
cmake "${CMAKE_COMMON_ARGS[@]}" >/dev/null 2>&1 || true
|
||||
|
||||
write_pkgconfig_shims "${VCPKG_DIR}/lib/pkgconfig" "${VCPKG_DIR}/lib"
|
||||
write_pkgconfig_shims "${VCPKG_DIR}/debug/lib/pkgconfig" "${VCPKG_DIR}/debug/lib"
|
||||
|
||||
cmake \
|
||||
"${CMAKE_COMMON_ARGS[@]}" \
|
||||
-DOPENSSL_INCLUDE_DIR="${VCPKG_DIR}/include" \
|
||||
-DOPENSSL_SSL_LIBRARY="${VCPKG_DIR}/debug/lib/libssl.a" \
|
||||
-DOPENSSL_CRYPTO_LIBRARY="${VCPKG_DIR}/debug/lib/libbscrypto.a"
|
||||
}
|
||||
|
||||
build_wire_sysio() {
|
||||
cmake --build \
|
||||
"${BUILD_DIR}" \
|
||||
--target contracts_project-build sys-util clio kiod nodeop \
|
||||
-- -j"$(nproc)"
|
||||
}
|
||||
|
||||
configure_chain() {
|
||||
export WIRE_ROOT="${WIRE_ROOT:-${WIRE_SYSIO_DIR}}"
|
||||
export PATH="${BUILD_DIR}/bin:${PATH}"
|
||||
|
||||
sys-util chain-configure \
|
||||
--contracts="${CONTRACTS_DIR}" \
|
||||
--target="${TARGET_ROOT}" \
|
||||
--template=aio \
|
||||
--overwrite
|
||||
}
|
||||
|
||||
extract_secret() {
|
||||
local pattern="$1"
|
||||
local file="$2"
|
||||
sed -n "s/^${pattern}: //p" "${file}"
|
||||
}
|
||||
|
||||
run_clio() {
|
||||
clio -u http://127.0.0.1:8887 "$@"
|
||||
}
|
||||
|
||||
run_clio_wallet() {
|
||||
clio wallet "$@"
|
||||
}
|
||||
|
||||
key_file_for_account() {
|
||||
local account_name="$1"
|
||||
echo "${TARGET_ROOT}/secrets/${account_name}_key.txt"
|
||||
}
|
||||
|
||||
ensure_local_key() {
|
||||
local account_name="$1"
|
||||
local key_file
|
||||
local output
|
||||
|
||||
key_file="$(key_file_for_account "${account_name}")"
|
||||
if [[ -f "${key_file}" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
output="$(clio create key --to-console)"
|
||||
printf '%s\n' "${output}" >"${key_file}"
|
||||
}
|
||||
|
||||
import_key_if_needed() {
|
||||
local key_file="$1"
|
||||
local private_key
|
||||
|
||||
private_key="$(extract_secret "Private key" "${key_file}")"
|
||||
if [[ -z "${private_key}" ]]; then
|
||||
echo "Missing private key in ${key_file}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
run_clio_wallet import --name default --private-key "${private_key}" >/dev/null 2>&1 || true
|
||||
}
|
||||
|
||||
ensure_account_exists() {
|
||||
local account_name="$1"
|
||||
local key_file
|
||||
local public_key
|
||||
|
||||
key_file="$(key_file_for_account "${account_name}")"
|
||||
public_key="$(extract_secret "Public key" "${key_file}")"
|
||||
if [[ -z "${public_key}" ]]; then
|
||||
echo "Missing public key in ${key_file}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if run_clio get account "${account_name}" >/dev/null 2>&1; then
|
||||
return
|
||||
fi
|
||||
|
||||
run_clio create account sysio "${account_name}" "${public_key}" >/dev/null
|
||||
}
|
||||
|
||||
ensure_contract_deployed() {
|
||||
local account_name="$1"
|
||||
local contract_dir="$2"
|
||||
|
||||
run_clio set contract "${account_name}" "${contract_dir}" >/dev/null
|
||||
}
|
||||
|
||||
ensure_account_ram() {
|
||||
local account_name="$1"
|
||||
local ram_bytes="$2"
|
||||
|
||||
run_clio push action \
|
||||
sysio \
|
||||
setacctram \
|
||||
"[\"${account_name}\",${ram_bytes}]" \
|
||||
-p sysio@active >/dev/null
|
||||
}
|
||||
|
||||
ensure_account_code_permission() {
|
||||
local account_name="$1"
|
||||
|
||||
run_clio set account permission \
|
||||
"${account_name}" \
|
||||
active \
|
||||
--add-code \
|
||||
-p "${account_name}@active" >/dev/null
|
||||
}
|
||||
|
||||
table_has_rows() {
|
||||
local account="$1"
|
||||
local scope="$2"
|
||||
local table="$3"
|
||||
! run_clio get table "${account}" "${scope}" "${table}" | grep -Eq '"rows": *\[[[:space:]]*\]'
|
||||
}
|
||||
|
||||
currency_exists() {
|
||||
local code="$1"
|
||||
local output
|
||||
|
||||
output="$(run_clio get currency stats sysio.token "${code}" 2>/dev/null || true)"
|
||||
grep -q "\"${code}\"" <<<"${output}"
|
||||
}
|
||||
|
||||
wire_env_path() {
|
||||
echo "${WIRE_ARTIFACTS_DIR}/wire.env"
|
||||
}
|
||||
|
||||
write_wire_artifacts() {
|
||||
local eth_key_file
|
||||
local sol_key_file
|
||||
local eth_pub
|
||||
local eth_priv
|
||||
local sol_pub
|
||||
local sol_priv
|
||||
local out_file
|
||||
|
||||
mkdir -p "${WIRE_ARTIFACTS_DIR}"
|
||||
|
||||
eth_key_file="$(key_file_for_account "${WIRE_BATCH_OPERATOR_ETH_ACCOUNT}")"
|
||||
sol_key_file="$(key_file_for_account "${WIRE_BATCH_OPERATOR_SOL_ACCOUNT}")"
|
||||
eth_pub="$(extract_secret "Public key" "${eth_key_file}")"
|
||||
eth_priv="$(extract_secret "Private key" "${eth_key_file}")"
|
||||
sol_pub="$(extract_secret "Public key" "${sol_key_file}")"
|
||||
sol_priv="$(extract_secret "Private key" "${sol_key_file}")"
|
||||
out_file="$(wire_env_path)"
|
||||
|
||||
cat >"${out_file}" <<EOF
|
||||
LOCAL_WIRE_RPC_URL=http://wire-nodeop:8887
|
||||
LOCAL_WIRE_ETH_DEPOT_ACCOUNT=${WIRE_ETH_DEPOT_ACCOUNT}
|
||||
LOCAL_WIRE_SOL_DEPOT_ACCOUNT=${WIRE_SOL_DEPOT_ACCOUNT}
|
||||
LOCAL_WIRE_INSTASWAP_ACCOUNT=${WIRE_INSTASWAP_ACCOUNT}
|
||||
LOCAL_WIRE_WYIELD_ACCOUNT=${WIRE_WYIELD_ACCOUNT}
|
||||
LOCAL_WIRE_TEST_USER_ACCOUNT=${WIRE_TEST_USER_ACCOUNT}
|
||||
LOCAL_WIRE_ETH_OPERATOR_ACCOUNT=${WIRE_BATCH_OPERATOR_ETH_ACCOUNT}
|
||||
LOCAL_WIRE_ETH_OPERATOR_PROVIDER_ID=${WIRE_BATCH_OPERATOR_ETH_WIRE_PROVIDER_ID}
|
||||
LOCAL_WIRE_ETH_OPERATOR_PROVIDER_SPEC=${WIRE_BATCH_OPERATOR_ETH_WIRE_PROVIDER_ID},wire,wire,${eth_pub},KEY:${eth_priv}
|
||||
LOCAL_WIRE_SOL_OPERATOR_ACCOUNT=${WIRE_BATCH_OPERATOR_SOL_ACCOUNT}
|
||||
LOCAL_WIRE_SOL_OPERATOR_PROVIDER_ID=${WIRE_BATCH_OPERATOR_SOL_WIRE_PROVIDER_ID}
|
||||
LOCAL_WIRE_SOL_OPERATOR_PROVIDER_SPEC=${WIRE_BATCH_OPERATOR_SOL_WIRE_PROVIDER_ID},wire,wire,${sol_pub},KEY:${sol_priv}
|
||||
EOF
|
||||
}
|
||||
|
||||
bootstrap_wire_stack() {
|
||||
local eth_seed_id="6574682d706f6f6c2d736565642d3031"
|
||||
local sol_seed_id="736f6c2d706f6f6c2d736565642d3031"
|
||||
|
||||
ensure_local_key "${WIRE_ETH_DEPOT_ACCOUNT}"
|
||||
ensure_local_key "${WIRE_SOL_DEPOT_ACCOUNT}"
|
||||
ensure_local_key "${WIRE_INSTASWAP_ACCOUNT}"
|
||||
ensure_local_key "${WIRE_WYIELD_ACCOUNT}"
|
||||
ensure_local_key "${WIRE_TEST_USER_ACCOUNT}"
|
||||
ensure_local_key "${WIRE_BATCH_OPERATOR_ETH_ACCOUNT}"
|
||||
ensure_local_key "${WIRE_BATCH_OPERATOR_SOL_ACCOUNT}"
|
||||
|
||||
import_key_if_needed "$(key_file_for_account "${WIRE_ETH_DEPOT_ACCOUNT}")"
|
||||
import_key_if_needed "$(key_file_for_account "${WIRE_SOL_DEPOT_ACCOUNT}")"
|
||||
import_key_if_needed "$(key_file_for_account "${WIRE_INSTASWAP_ACCOUNT}")"
|
||||
import_key_if_needed "$(key_file_for_account "${WIRE_WYIELD_ACCOUNT}")"
|
||||
import_key_if_needed "$(key_file_for_account "${WIRE_TEST_USER_ACCOUNT}")"
|
||||
import_key_if_needed "$(key_file_for_account "${WIRE_BATCH_OPERATOR_ETH_ACCOUNT}")"
|
||||
import_key_if_needed "$(key_file_for_account "${WIRE_BATCH_OPERATOR_SOL_ACCOUNT}")"
|
||||
|
||||
ensure_account_exists "${WIRE_ETH_DEPOT_ACCOUNT}"
|
||||
ensure_account_exists "${WIRE_SOL_DEPOT_ACCOUNT}"
|
||||
ensure_account_exists "${WIRE_INSTASWAP_ACCOUNT}"
|
||||
ensure_account_exists "${WIRE_WYIELD_ACCOUNT}"
|
||||
ensure_account_exists "${WIRE_TEST_USER_ACCOUNT}"
|
||||
ensure_account_exists "${WIRE_BATCH_OPERATOR_ETH_ACCOUNT}"
|
||||
ensure_account_exists "${WIRE_BATCH_OPERATOR_SOL_ACCOUNT}"
|
||||
|
||||
ensure_account_ram "${WIRE_ETH_DEPOT_ACCOUNT}" "${WIRE_DEPOT_ACCOUNT_RAM_BYTES}"
|
||||
ensure_account_ram "${WIRE_SOL_DEPOT_ACCOUNT}" "${WIRE_DEPOT_ACCOUNT_RAM_BYTES}"
|
||||
ensure_account_ram "${WIRE_INSTASWAP_ACCOUNT}" "${WIRE_APP_ACCOUNT_RAM_BYTES}"
|
||||
ensure_account_ram "${WIRE_WYIELD_ACCOUNT}" "${WIRE_APP_ACCOUNT_RAM_BYTES}"
|
||||
ensure_account_ram "${WIRE_TEST_USER_ACCOUNT}" "${WIRE_USER_ACCOUNT_RAM_BYTES}"
|
||||
ensure_account_ram "${WIRE_BATCH_OPERATOR_ETH_ACCOUNT}" "${WIRE_OPERATOR_ACCOUNT_RAM_BYTES}"
|
||||
ensure_account_ram "${WIRE_BATCH_OPERATOR_SOL_ACCOUNT}" "${WIRE_OPERATOR_ACCOUNT_RAM_BYTES}"
|
||||
|
||||
ensure_account_code_permission "${WIRE_ETH_DEPOT_ACCOUNT}"
|
||||
ensure_account_code_permission "${WIRE_SOL_DEPOT_ACCOUNT}"
|
||||
ensure_account_code_permission "${WIRE_INSTASWAP_ACCOUNT}"
|
||||
ensure_account_code_permission "${WIRE_WYIELD_ACCOUNT}"
|
||||
|
||||
ensure_contract_deployed "${WIRE_ETH_DEPOT_ACCOUNT}" "${CONTRACTS_DIR}/sysio.depot"
|
||||
ensure_contract_deployed "${WIRE_SOL_DEPOT_ACCOUNT}" "${CONTRACTS_DIR}/sysio.depot"
|
||||
ensure_contract_deployed "${WIRE_INSTASWAP_ACCOUNT}" "${CONTRACTS_DIR}/sysio.instaswap"
|
||||
ensure_contract_deployed "${WIRE_WYIELD_ACCOUNT}" "${CONTRACTS_DIR}/sysio.wyield"
|
||||
|
||||
if ! table_has_rows "${WIRE_ETH_DEPOT_ACCOUNT}" "${WIRE_ETH_DEPOT_ACCOUNT}" depotstate; then
|
||||
run_clio push action \
|
||||
"${WIRE_ETH_DEPOT_ACCOUNT}" \
|
||||
init \
|
||||
"[2,\"sysio.token\"]" \
|
||||
-p "${WIRE_ETH_DEPOT_ACCOUNT}@active" >/dev/null
|
||||
fi
|
||||
|
||||
if ! table_has_rows "${WIRE_SOL_DEPOT_ACCOUNT}" "${WIRE_SOL_DEPOT_ACCOUNT}" depotstate; then
|
||||
run_clio push action \
|
||||
"${WIRE_SOL_DEPOT_ACCOUNT}" \
|
||||
init \
|
||||
"[3,\"sysio.token\"]" \
|
||||
-p "${WIRE_SOL_DEPOT_ACCOUNT}@active" >/dev/null
|
||||
fi
|
||||
|
||||
if ! currency_exists WIRE; then
|
||||
run_clio push action \
|
||||
sysio.token \
|
||||
create \
|
||||
"[\"${WIRE_INSTASWAP_ACCOUNT}\",\"1000000000.0000 WIRE\"]" \
|
||||
-p sysio.token@active >/dev/null
|
||||
fi
|
||||
|
||||
if ! currency_exists LIQETH; then
|
||||
run_clio push action \
|
||||
sysio.token \
|
||||
create \
|
||||
"[\"${WIRE_INSTASWAP_ACCOUNT}\",\"1000000000.0000 LIQETH\"]" \
|
||||
-p sysio.token@active >/dev/null
|
||||
fi
|
||||
|
||||
if ! currency_exists LIQSOL; then
|
||||
run_clio push action \
|
||||
sysio.token \
|
||||
create \
|
||||
"[\"${WIRE_INSTASWAP_ACCOUNT}\",\"1000000000.0000 LIQSOL\"]" \
|
||||
-p sysio.token@active >/dev/null
|
||||
fi
|
||||
|
||||
if ! run_clio get currency balance sysio.token "${WIRE_INSTASWAP_ACCOUNT}" WIRE | grep -q "WIRE"; then
|
||||
run_clio push action \
|
||||
sysio.token \
|
||||
issue \
|
||||
"[\"${WIRE_INSTASWAP_ACCOUNT}\",\"1000000.0000 WIRE\",\"local pool seed\"]" \
|
||||
-p "${WIRE_INSTASWAP_ACCOUNT}@active" >/dev/null
|
||||
fi
|
||||
|
||||
if ! table_has_rows "${WIRE_INSTASWAP_ACCOUNT}" "${WIRE_INSTASWAP_ACCOUNT}" config; then
|
||||
run_clio push action \
|
||||
"${WIRE_INSTASWAP_ACCOUNT}" \
|
||||
init \
|
||||
"[\"sysio.token\",\"${WIRE_ETH_DEPOT_ACCOUNT}\",\"${WIRE_SOL_DEPOT_ACCOUNT}\",\"${WIRE_INSTASWAP_ACCOUNT}\",\"4,WIRE\",\"4,LIQETH\",\"4,LIQSOL\",30]" \
|
||||
-p "${WIRE_INSTASWAP_ACCOUNT}@active" >/dev/null
|
||||
fi
|
||||
|
||||
if ! table_has_rows "${WIRE_WYIELD_ACCOUNT}" "${WIRE_WYIELD_ACCOUNT}" config; then
|
||||
run_clio push action \
|
||||
"${WIRE_WYIELD_ACCOUNT}" \
|
||||
init \
|
||||
"[\"sysio.token\",\"${WIRE_INSTASWAP_ACCOUNT}\",\"${WIRE_ETH_DEPOT_ACCOUNT}\",\"${WIRE_SOL_DEPOT_ACCOUNT}\",\"4,WIRE\",\"4,LIQETH\",\"4,LIQSOL\"]" \
|
||||
-p "${WIRE_WYIELD_ACCOUNT}@active" >/dev/null
|
||||
fi
|
||||
|
||||
run_clio push action \
|
||||
"${WIRE_INSTASWAP_ACCOUNT}" \
|
||||
ondeposit \
|
||||
"[2,\"${eth_seed_id}\",\"${WIRE_INSTASWAP_ACCOUNT}\",\"10000.0000 LIQETH\"]" \
|
||||
-p "${WIRE_ETH_DEPOT_ACCOUNT}@active" >/dev/null
|
||||
|
||||
run_clio push action \
|
||||
"${WIRE_INSTASWAP_ACCOUNT}" \
|
||||
ondeposit \
|
||||
"[3,\"${sol_seed_id}\",\"${WIRE_INSTASWAP_ACCOUNT}\",\"10000.0000 LIQSOL\"]" \
|
||||
-p "${WIRE_SOL_DEPOT_ACCOUNT}@active" >/dev/null
|
||||
|
||||
if ! run_clio get table "${WIRE_ETH_DEPOT_ACCOUNT}" 2 knownops | grep -q "\"wire_account\": \"${WIRE_BATCH_OPERATOR_ETH_ACCOUNT}\""; then
|
||||
run_clio push action \
|
||||
"${WIRE_ETH_DEPOT_ACCOUNT}" \
|
||||
regoperator \
|
||||
"[\"${WIRE_BATCH_OPERATOR_ETH_ACCOUNT}\",1,\"010101010101010101010101010101010101010101010101010101010101010101\",\"0202020202020202020202020202020202020202020202020202020202020202\",\"1000.0000 WIRE\"]" \
|
||||
-p "${WIRE_BATCH_OPERATOR_ETH_ACCOUNT}@active" >/dev/null
|
||||
fi
|
||||
|
||||
if ! run_clio get table "${WIRE_SOL_DEPOT_ACCOUNT}" 3 knownops | grep -q "\"wire_account\": \"${WIRE_BATCH_OPERATOR_SOL_ACCOUNT}\""; then
|
||||
run_clio push action \
|
||||
"${WIRE_SOL_DEPOT_ACCOUNT}" \
|
||||
regoperator \
|
||||
"[\"${WIRE_BATCH_OPERATOR_SOL_ACCOUNT}\",1,\"030303030303030303030303030303030303030303030303030303030303030303\",\"0404040404040404040404040404040404040404040404040404040404040404\",\"1000.0000 WIRE\"]" \
|
||||
-p "${WIRE_BATCH_OPERATOR_SOL_ACCOUNT}@active" >/dev/null
|
||||
fi
|
||||
|
||||
if ! run_clio get table "${WIRE_ETH_DEPOT_ACCOUNT}" 2 knownops | grep -q "\"wire_account\": \"${WIRE_BATCH_OPERATOR_ETH_ACCOUNT}\",.*\"status\": 1"; then
|
||||
run_clio push action \
|
||||
"${WIRE_ETH_DEPOT_ACCOUNT}" \
|
||||
activateop \
|
||||
"[\"${WIRE_BATCH_OPERATOR_ETH_ACCOUNT}\"]" \
|
||||
-p "${WIRE_ETH_DEPOT_ACCOUNT}@active" >/dev/null
|
||||
fi
|
||||
|
||||
if ! run_clio get table "${WIRE_SOL_DEPOT_ACCOUNT}" 3 knownops | grep -q "\"wire_account\": \"${WIRE_BATCH_OPERATOR_SOL_ACCOUNT}\",.*\"status\": 1"; then
|
||||
run_clio push action \
|
||||
"${WIRE_SOL_DEPOT_ACCOUNT}" \
|
||||
activateop \
|
||||
"[\"${WIRE_BATCH_OPERATOR_SOL_ACCOUNT}\"]" \
|
||||
-p "${WIRE_SOL_DEPOT_ACCOUNT}@active" >/dev/null
|
||||
fi
|
||||
|
||||
write_wire_artifacts
|
||||
}
|
||||
|
||||
start_nodeop() {
|
||||
local key_file="${TARGET_ROOT}/secrets/sysio_key.txt"
|
||||
local wallet_pw
|
||||
local sys_public_key
|
||||
local sys_private_key
|
||||
local sys_bls_public_key
|
||||
local sys_bls_private_key
|
||||
local ready=0
|
||||
|
||||
wallet_pw="$(cat "${TARGET_ROOT}/secrets/sysio_wallet_pw.txt")"
|
||||
sys_public_key="$(extract_secret "Public key" "${key_file}")"
|
||||
sys_private_key="$(extract_secret "Private key" "${key_file}")"
|
||||
sys_bls_public_key="$(extract_secret "BLS Pub key" "${key_file}")"
|
||||
sys_bls_private_key="$(extract_secret "BLS Priv key" "${key_file}")"
|
||||
|
||||
pkill -9 kiod >/dev/null 2>&1 || true
|
||||
kiod --wallet-dir "${TARGET_ROOT}/wallet" >"${TARGET_ROOT}/kiod.log" 2>&1 &
|
||||
KIOD_PID=$!
|
||||
|
||||
sleep 1
|
||||
clio wallet unlock --name default --password "${wallet_pw}" >/dev/null
|
||||
|
||||
nodeop \
|
||||
--config-dir "${TARGET_ROOT}/config" \
|
||||
--data-dir "${TARGET_ROOT}/data" \
|
||||
--genesis-json "${TARGET_ROOT}/config/genesis.json" \
|
||||
--contracts-console \
|
||||
--signature-provider "wire-${sys_public_key},wire,wire,${sys_public_key},KEY:${sys_private_key}" \
|
||||
--signature-provider "wire-bls-${sys_bls_public_key},wire,wire_bls,${sys_bls_public_key},KEY:${sys_bls_private_key}" \
|
||||
>"${TARGET_ROOT}/nodeop.log" 2>&1 &
|
||||
NODEOP_PID=$!
|
||||
|
||||
for _ in $(seq 1 30); do
|
||||
if clio -u http://127.0.0.1:8887 get info >/dev/null 2>&1; then
|
||||
ready=1
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
if [[ "${ready}" -ne 1 ]]; then
|
||||
echo "nodeop did not become ready within 30 seconds" >&2
|
||||
tail -n 80 "${TARGET_ROOT}/nodeop.log" >&2 || true
|
||||
return 1
|
||||
fi
|
||||
|
||||
bootstrap_wire_stack
|
||||
|
||||
wait "${NODEOP_PID}"
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
require_wire_submodules
|
||||
configure_wire_sysio
|
||||
build_wire_sysio
|
||||
configure_chain
|
||||
start_nodeop
|
||||
Reference in New Issue
Block a user