take an axe to the docs
Delete outdated documentation and generic-ify the remainder. Change-Id: I4e11e59e6da00d49f9ea4fd5d1155769debda55e
This commit is contained in:
parent
d1a24f745d
commit
9fce2e9ded
57
README.md
57
README.md
|
@ -1,7 +1,4 @@
|
||||||
# Wormhole
|
# Wormhole v2
|
||||||
|
|
||||||
Read our [introduction blog article](https://medium.com/certus-one/introducing-the-wormhole-bridge-24911b7335f7)
|
|
||||||
for more details on Wormhole and its major design decisions.
|
|
||||||
|
|
||||||
See [DEVELOP.md](DEVELOP.md) for instructions on how to set up a local devnet, and
|
See [DEVELOP.md](DEVELOP.md) for instructions on how to set up a local devnet, and
|
||||||
[CONTRIBUTING.md](CONTRIBUTING.md) for instructions on how to contribute to this project.
|
[CONTRIBUTING.md](CONTRIBUTING.md) for instructions on how to contribute to this project.
|
||||||
|
@ -9,49 +6,45 @@ See [DEVELOP.md](DEVELOP.md) for instructions on how to set up a local devnet, a
|
||||||
See [docs/operations.md](docs/operations.md) for node operator instructions.
|
See [docs/operations.md](docs/operations.md) for node operator instructions.
|
||||||
|
|
||||||
![](docs/images/overview.svg)
|
![](docs/images/overview.svg)
|
||||||
### Audit / Feature Status
|
|
||||||
|
|
||||||
| Feature | Maintainer | Auditor | Status |
|
### Audit / Feature Status
|
||||||
|-------------------|------------|----------|-----------------|
|
|
||||||
| Ethereum contract | Certus One | Kudelski | ✔️ Audited |
|
|
||||||
| Solana contract | Certus One | Kudelski | ✔️ Audited |
|
|
||||||
| Bridge node | Certus One | Kudelski | ✔️ Audited |
|
|
||||||
| Terra contract | Everstake | Kudelski | ✔️ Audited |
|
|
||||||
|
|
||||||
⚠ **This software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
⚠ **This software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
implied. See the License for the specific language governing permissions and limitations under the License.** Or plainly
|
implied. See the License for the specific language governing permissions and limitations under the License.** Or plainly
|
||||||
spoken - this is a very complex software which targets a bleeding-edge, experimental smart contract runtime. Mistakes
|
spoken - this is a very complex piece of software which targets a bleeding-edge, experimental smart contract runtime.
|
||||||
happens, and no matter how hard you try and whether or not you pay someone to audit it, it may eat your tokens, set your
|
Mistakes happen, and no matter how hard you try and whether you pay someone to audit it, it may eat your tokens, set
|
||||||
printer on fire or startle your cat.
|
your printer on fire or startle your cat. Cryptocurrencies are a high-risk investment, no matter how fancy.
|
||||||
|
|
||||||
Cryptocurrencies in general are a high-risk investment, there's decent chance you'll lose your money, and you most
|
|
||||||
certainly shouldn't put your life savings into a Wormhole contract (or any other).
|
|
||||||
|
|
||||||
### Repo overview
|
### Repo overview
|
||||||
|
|
||||||
- **[bridge/](bridge/)** — The guardian node which connects to both chains, observes lockups and submits VAAs.
|
- **[bridge/](bridge/)** — The guardian node which connects to both chains, observes data and submits VAAs.
|
||||||
Written in pure Go.
|
Written in pure Go.
|
||||||
|
|
||||||
- [cmd/](bridge/cmd/) - CLI entry point, deals with the mechanics of parsing command line flags and loading keys.
|
- [cmd/](bridge/cmd/) - CLI entry points for the guardiand service and all other command line tools.
|
||||||
|
- [e2e](bridge/e2e) — The end-to-end testing framework (as regular Go tests, to be ran locally).
|
||||||
- **[pkg/processor](bridge/pkg/processor)** — Most of the business logic for cross-chain communication
|
- **[pkg/processor](bridge/pkg/processor)** — Most of the business logic for cross-chain communication
|
||||||
lives here. Talks to multiple loosely coupled services communicating via Go channels.
|
lives here. Talks to multiple loosely coupled services communicating via Go channels.
|
||||||
|
- [pkg/common](bridge/pkg/common) — Shared libraries and types. No business logic.
|
||||||
- [pkg/p2p](bridge/pkg/p2p) — libp2p-based gossip network.
|
- [pkg/p2p](bridge/pkg/p2p) — libp2p-based gossip network.
|
||||||
- [pkg/devnet](bridge/pkg/devnet) — Constants and helper functions for the deterministic local devnet.
|
- [pkg/devnet](bridge/pkg/devnet) — Constants and helper functions for the deterministic local devnet.
|
||||||
- [pkg/ethereum](bridge/pkg/ethereum) — Ethereum chain interface with auto-generated contract ABI.
|
- [pkg/ethereum](bridge/pkg/ethereum) — Ethereum chain interface with auto-generated contract ABI.
|
||||||
Uses go-ethereum to directly connect to an Eth node.
|
Uses go-ethereum to directly connect to an Eth node.
|
||||||
- [pkg/solana](bridge/pkg/ethereum) — Solana chain interface. Light gRPC wrapper around a Rust agent (see below)
|
- [pkg/solana](bridge/pkg/solana) — Solana chain interface. Light gRPC wrapper around a Rust agent (see below)
|
||||||
which actually talks to Solana.
|
which actually talks to Solana.
|
||||||
|
- [pkg/terra](bridge/pkg/terra) — Terra chain interface, using the upstream Terra RPC client.
|
||||||
- [pkg/supervisor](bridge/pkg/supervisor) — Erlang-inspired process supervision tree imported from Certus One's
|
- [pkg/supervisor](bridge/pkg/supervisor) — Erlang-inspired process supervision tree imported from Certus One's
|
||||||
internal code base. We use this everywhere in the bridge code for fault tolerance and fast convergence.
|
internal code base. We use this everywhere in the bridge code for fault tolerance and fast convergence.
|
||||||
- [pkg/vaa](bridge/pkg/vaa) — Go implementation of our VAA structure, including serialization code.
|
- [pkg/vaa](bridge/pkg/vaa) — Go implementation of our VAA structure, including serialization code.
|
||||||
|
- [pkg/readiness](bridge/pkg/readiness) — Global stateful singleton package to manage the /ready endpoint,
|
||||||
|
similar to how Prometheus metrics are implemented using a global registry.
|
||||||
|
|
||||||
- **[ethereum/](ethereum/)** — Ethereum wormhole contract, tests and fixtures.
|
- **[ethereum/](ethereum/)** — Ethereum wormhole contract, tests and fixtures.
|
||||||
|
|
||||||
- **[contracts/](ethereum/contracts)** — Wormhole itself, the wrapped token and helper libraries.
|
- **[contracts/](ethereum/contracts)** — Wormhole itself, a wrapped token example and helper libraries.
|
||||||
- [migrations/](ethereum/migrations) — Ganache migration that deploys the contracts to a local devnet.
|
- [migrations/](ethereum/migrations) — Ganache migration that deploys the contracts to a local devnet.
|
||||||
This is the starting point for both the tests and the devnet. Note that devnet and tests result
|
This is the starting point for both the tests and the devnet. Note that devnet and tests result
|
||||||
in different devnet states.
|
in different devnet states.
|
||||||
- [src/send-lockups.js](ethereum/src/send-lockups.js) — Sends ETH lockups in a loop.
|
- [src/send-lockups.js](ethereum/src/send-lockups.js) — Sends example ETH lockups in a loop.
|
||||||
See DEVELOP.md for usage.
|
See DEVELOP.md for usage.
|
||||||
|
|
||||||
- **[solana/](solana/)** — Solana sidecar agent, contract and CLI.
|
- **[solana/](solana/)** — Solana sidecar agent, contract and CLI.
|
||||||
|
@ -60,18 +53,20 @@ certainly shouldn't put your life savings into a Wormhole contract (or any other
|
||||||
pure-Go Solana client.
|
pure-Go Solana client.
|
||||||
- **[bridge/](solana/bridge/)** — Solana Wormhole smart contract code.
|
- **[bridge/](solana/bridge/)** — Solana Wormhole smart contract code.
|
||||||
- [cli/](solana/cli/) — Wormhole user CLI tool for interaction with the smart contract.
|
- [cli/](solana/cli/) — Wormhole user CLI tool for interaction with the smart contract.
|
||||||
- [devnet_setup.sh](solana/devnet_setup.sh) — Devnet initialization and lockup generator
|
- [devnet_setup.sh](solana/devnet_setup.sh) — Devnet initialization and example code for a lockup program
|
||||||
(the Solana equivalent to the Ganache migration + send-lockups.js). Runs as a sidecar alongside the Solana devnet.
|
(the Solana equivalent to the Ganache migration + send-lockups.js). Runs as a sidecar alongside the Solana devnet.
|
||||||
|
|
||||||
|
- **[terra/](terra/)** — Terra-side smart contracts.
|
||||||
|
|
||||||
- **[proto/](proto/)** — Protocol Buffer definitions for the P2P network and the local Solana agent RPC.
|
- **[proto/](proto/)** — Protocol Buffer definitions for the P2P network and the local Solana agent RPC.
|
||||||
These are heavily commented and a good intro.
|
These are heavily commented and a good intro.
|
||||||
|
|
||||||
- **[third_party/](third_party/)** — Build machinery and tooling for third party applications we use.
|
- **[third_party/](third_party/)** — Build machinery and tooling for third party applications we use.
|
||||||
- [abigen/](third_party/abigen/) — Reproducible build for the go-ethereum ABI code generator we use.
|
- [googleapis/](third_party/googleapis/) — Google protobuf libraries end up here at runtime. Not checked un.
|
||||||
- **[solana/](third_party/solana/)** — Build for the full Solana project plus a floating patchset we maintain while
|
|
||||||
waiting for features to be implemented in the upstream project.
|
|
||||||
|
|
||||||
- **[docs/](docs/)** — Operator documentation and project specs.
|
- **[docs/](docs/)** — Operator documentation and project specs.
|
||||||
|
|
||||||
|
- **[design/](design/)** — Design documents/RfC for changes to the protocol.
|
||||||
|
|
||||||
- **[web/](web/)** — User interface for cross-chain transfers. Not yet wired into the local devnet.
|
- **[web/](web/)** — User interface for cross-chain transfers. Not yet wired into the local devnet.
|
||||||
Uses Metamask and Web3.js to initiate transfers from a browser.
|
Uses Metamask and Web3.js to initiate transfers from a browser.
|
||||||
|
@ -79,10 +74,12 @@ certainly shouldn't put your life savings into a Wormhole contract (or any other
|
||||||
|
|
||||||
- [tools/](tools/) — Reproducible builds for local development tooling like buf and protoc-gen-go.
|
- [tools/](tools/) — Reproducible builds for local development tooling like buf and protoc-gen-go.
|
||||||
|
|
||||||
- [Tiltfile](Tiltfile), [devnet/](devnet/) and various Dockerfiles — deployment code and fixtures for local development.
|
- [dashboards/](dashboards/) — Example Grafana dashboards for the Prometheus metrics exposed by guardiand.
|
||||||
Deploys a deterministic devnet with an Ethereum devnet, Solana devnet, and a variably sized guardian set
|
|
||||||
that can be used to simulate full cross-chain transfers. The Dockerfiles are carefully designed for fast incremental
|
- [Tiltfile](Tiltfile), [tilt_modules](tilt_modules/), [devnet/](devnet/) and various Dockerfiles — deployment code and
|
||||||
builds with local caching, and require a recent Docker version with Buildkit support. See DEVELOP.md for usage.
|
fixtures for local development. Deploys a deterministic devnet with an Ethereum devnet, Solana devnet, and a variably
|
||||||
|
sized guardian set that can be used to simulate full cross-chain transfers. The Dockerfiles are carefully designed for
|
||||||
|
fast incremental builds with local caching, and require a recent Docker version with Buildkit support.
|
||||||
|
|
||||||
- [generate-abi.sh](generate-abi.sh) and [generate-protos.sh](generate-protos.sh) —
|
- [generate-abi.sh](generate-abi.sh) and [generate-protos.sh](generate-protos.sh) —
|
||||||
Helper scripts to (re-)build generated code. The Eth ABI is committed to the repo, so you only
|
Helper scripts to (re-)build generated code. The Eth ABI is committed to the repo, so you only
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
This page details various assumptions that Wormhole relies on for security and availability. Many of these are
|
This page details various assumptions that Wormhole relies on for security and availability. Many of these are
|
||||||
universal assumptions that apply to various decentralized protocols.
|
universal assumptions that apply to various decentralized protocols.
|
||||||
|
|
||||||
This document assumes familiarity with Wormhole concepts like VAAs and lockups/transfers.
|
This document assumes familiarity with Wormhole concepts like VAAs.
|
||||||
|
|
||||||
## Gossip network availability
|
## Gossip network availability
|
||||||
|
|
||||||
|
@ -16,24 +16,24 @@ We do _not_ rely on libp2p for security, only for availability. libp2p's channel
|
||||||
default, but we do not rely on that property. A compromise of libp2p transport security could, at worst, result in
|
default, but we do not rely on that property. A compromise of libp2p transport security could, at worst, result in
|
||||||
denial of service attacks on the gossip network or individual nodes.
|
denial of service attacks on the gossip network or individual nodes.
|
||||||
|
|
||||||
Gossip network unavailability can result in transfers getting temporarily stuck, but never permanently. Nodes will
|
Gossip network unavailability can result in missing events, but never permanently. Nodes will periodically
|
||||||
periodically attempt to retransmit signatures for VAAs which failed to reach consensus in order to mitigate short-term
|
attempt to retransmit signatures for VAAs which failed to reach consensus in order to mitigate short-term
|
||||||
network outages. Longer network outages, leading to timeouts, and correlated crashes of a superminority of nodes may
|
network outages. Longer network outages, leading to timeouts, and correlated crashes of a superminority of
|
||||||
result in lockups being dropped.
|
nodes may result in observations being dropped.
|
||||||
|
|
||||||
The mitigation for this is a polling control loop in the case of Solana or chain replay for other chains. On Solana, the
|
The mitigation for this is a polling control loop in the case of Solana or chain replay for other chains. On Solana, the
|
||||||
node will consistently poll for unprocessed lockups, resulting in re-observation by nodes and another round of
|
node will consistently poll for unprocessed observations, resulting in re-observation by nodes and another round of
|
||||||
consensus. During chain replay, nodes will re-process events from connected chains up from a given block height, check
|
consensus. During chain replay, nodes will re-process events from connected chains up from a given block height, check
|
||||||
whether a VAA has already been submitted to Solana, and initiate a round of consensus for missed lockups.
|
whether a VAA has already been submitted to Solana, and initiate a round of consensus for missed observations.
|
||||||
|
|
||||||
This carries no risk and can be done any number of times. VAAs are fully deterministic and idempotent - any given
|
This carries no risk and can be done any number of times. VAAs are fully deterministic and idempotent - any
|
||||||
lockup will always result in the same VAA body hash. All connected chains keep a permanent record of whether a given VAA
|
given observation will always result in the same VAA body hash. All connected chains keep a permanent record
|
||||||
body - identified by its hash - has already been executed, therefore, VAAs can safely undergo multiple rounds of
|
of whether a given VAA body - identified by its hash - has already been executed, therefore, VAAs can safely
|
||||||
consensus until they are executed on all chains.
|
undergo multiple rounds of consensus until they are executed on all chains.
|
||||||
|
|
||||||
The bridge does not yet implement chain replay (see https://github.com/certusone/wormhole/issues/123). Network outages
|
The bridge does not yet implement chain replay (see https://github.com/certusone/wormhole/issues/123). Network outages
|
||||||
can therefore result in stuck transfers from chains other than Solana in the case of a prolonged network outage. It
|
can therefore result in missed observations from chains other than Solana in the case of a prolonged network outage. It
|
||||||
would be possible to retroactively recover locked funds after chain replay has been implemented.
|
will be possible to retroactively replay blocks after chain replay has been implemented to catch up on missed events.
|
||||||
|
|
||||||
## Chain consistency and finality
|
## Chain consistency and finality
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
"elements": [
|
"elements": [
|
||||||
{
|
{
|
||||||
"type": "rectangle",
|
"type": "rectangle",
|
||||||
"version": 81,
|
"version": 130,
|
||||||
"versionNonce": 1505853226,
|
"versionNonce": 526326665,
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"id": "sCKknWK5gOtk7aQyiPt0Q",
|
"id": "sCKknWK5gOtk7aQyiPt0Q",
|
||||||
"fillStyle": "cross-hatch",
|
"fillStyle": "cross-hatch",
|
||||||
|
@ -15,8 +15,8 @@
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"x": 747.3333740234375,
|
"x": 761.619088309152,
|
||||||
"y": 413.3333435058594,
|
"y": 418.0952627999442,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"backgroundColor": "#fab005",
|
"backgroundColor": "#fab005",
|
||||||
"width": 135.33331298828125,
|
"width": 135.33331298828125,
|
||||||
|
@ -31,8 +31,8 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "rectangle",
|
"type": "rectangle",
|
||||||
"version": 346,
|
"version": 348,
|
||||||
"versionNonce": 1166619510,
|
"versionNonce": 980999977,
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"id": "OgGKrVx53b487RcYG7GQ9",
|
"id": "OgGKrVx53b487RcYG7GQ9",
|
||||||
"fillStyle": "cross-hatch",
|
"fillStyle": "cross-hatch",
|
||||||
|
@ -83,8 +83,8 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"version": 24,
|
"version": 69,
|
||||||
"versionNonce": 1225644650,
|
"versionNonce": 785550665,
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"id": "W-7TUzZOWaf-F2KGY00Ru",
|
"id": "W-7TUzZOWaf-F2KGY00Ru",
|
||||||
"fillStyle": "hachure",
|
"fillStyle": "hachure",
|
||||||
|
@ -93,8 +93,8 @@
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"x": 770.5000305175781,
|
"x": 784.7857448032926,
|
||||||
"y": 429.1666717529297,
|
"y": 433.9285910470145,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
"width": 89,
|
"width": 89,
|
||||||
|
@ -396,7 +396,9 @@
|
||||||
-28
|
-28
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"lastCommittedPoint": null
|
"lastCommittedPoint": null,
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "line",
|
"type": "line",
|
||||||
|
@ -432,7 +434,9 @@
|
||||||
1.3333740234375
|
1.3333740234375
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"lastCommittedPoint": null
|
"lastCommittedPoint": null,
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "line",
|
"type": "line",
|
||||||
|
@ -468,7 +472,9 @@
|
||||||
24.66668701171875
|
24.66668701171875
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"lastCommittedPoint": null
|
"lastCommittedPoint": null,
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "line",
|
"type": "line",
|
||||||
|
@ -504,7 +510,9 @@
|
||||||
27.33331298828125
|
27.33331298828125
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"lastCommittedPoint": null
|
"lastCommittedPoint": null,
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "line",
|
"type": "line",
|
||||||
|
@ -540,7 +548,9 @@
|
||||||
6.66668701171875
|
6.66668701171875
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"lastCommittedPoint": null
|
"lastCommittedPoint": null,
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "line",
|
"type": "line",
|
||||||
|
@ -576,7 +586,9 @@
|
||||||
9.33331298828125
|
9.33331298828125
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"lastCommittedPoint": null
|
"lastCommittedPoint": null,
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "line",
|
"type": "line",
|
||||||
|
@ -612,7 +624,9 @@
|
||||||
24.6666259765625
|
24.6666259765625
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"lastCommittedPoint": null
|
"lastCommittedPoint": null,
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "line",
|
"type": "line",
|
||||||
|
@ -648,7 +662,9 @@
|
||||||
-11.33331298828125
|
-11.33331298828125
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"lastCommittedPoint": null
|
"lastCommittedPoint": null,
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "line",
|
"type": "line",
|
||||||
|
@ -684,7 +700,9 @@
|
||||||
-17.33331298828125
|
-17.33331298828125
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"lastCommittedPoint": null
|
"lastCommittedPoint": null,
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "line",
|
"type": "line",
|
||||||
|
@ -720,7 +738,9 @@
|
||||||
-13.3333740234375
|
-13.3333740234375
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"lastCommittedPoint": null
|
"lastCommittedPoint": null,
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "line",
|
"type": "line",
|
||||||
|
@ -756,7 +776,9 @@
|
||||||
1.33331298828125
|
1.33331298828125
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"lastCommittedPoint": null
|
"lastCommittedPoint": null,
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "line",
|
"type": "line",
|
||||||
|
@ -792,7 +814,9 @@
|
||||||
16
|
16
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"lastCommittedPoint": null
|
"lastCommittedPoint": null,
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "line",
|
"type": "line",
|
||||||
|
@ -828,7 +852,9 @@
|
||||||
14.66668701171875
|
14.66668701171875
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"lastCommittedPoint": null
|
"lastCommittedPoint": null,
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "line",
|
"type": "line",
|
||||||
|
@ -864,12 +890,14 @@
|
||||||
4
|
4
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"lastCommittedPoint": null
|
"lastCommittedPoint": null,
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"version": 76,
|
"version": 186,
|
||||||
"versionNonce": 2014279734,
|
"versionNonce": 233095785,
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"id": "NI9ug2WbMsfekcmi3MbHa",
|
"id": "NI9ug2WbMsfekcmi3MbHa",
|
||||||
"fillStyle": "hachure",
|
"fillStyle": "hachure",
|
||||||
|
@ -878,12 +906,12 @@
|
||||||
"roughness": 2,
|
"roughness": 2,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"x": 861.3333740234375,
|
"x": 873.7531240940943,
|
||||||
"y": 472,
|
"y": 476.7619192940848,
|
||||||
"strokeColor": "#a61e4d",
|
"strokeColor": "#a61e4d",
|
||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
"width": 96.6666259765625,
|
"width": 84.49987369504424,
|
||||||
"height": 55.3333740234375,
|
"height": 50.24227926232709,
|
||||||
"seed": 767123201,
|
"seed": 767123201,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"strokeSharpness": "round",
|
"strokeSharpness": "round",
|
||||||
|
@ -904,11 +932,13 @@
|
||||||
0
|
0
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
96.6666259765625,
|
84.49987369504424,
|
||||||
55.3333740234375
|
50.24227926232709
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"lastCommittedPoint": null
|
"lastCommittedPoint": null,
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": "arrow"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
|
@ -948,12 +978,14 @@
|
||||||
78
|
78
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"lastCommittedPoint": null
|
"lastCommittedPoint": null,
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": "arrow"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"version": 307,
|
"version": 373,
|
||||||
"versionNonce": 52363638,
|
"versionNonce": 985492585,
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"id": "wltib7el8aYeC2e7nUsKB",
|
"id": "wltib7el8aYeC2e7nUsKB",
|
||||||
"fillStyle": "hachure",
|
"fillStyle": "hachure",
|
||||||
|
@ -962,12 +994,12 @@
|
||||||
"roughness": 2,
|
"roughness": 2,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"x": 853.3333740234376,
|
"x": 853.3333740234375,
|
||||||
"y": 631.3557357130856,
|
"y": 627.4385470299487,
|
||||||
"strokeColor": "#a61e4d",
|
"strokeColor": "#a61e4d",
|
||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
"width": 114.78378071898476,
|
"width": 127.94827892744422,
|
||||||
"height": 42.24405385173236,
|
"height": 45.310365787157025,
|
||||||
"seed": 1134318273,
|
"seed": 1134318273,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"strokeSharpness": "round",
|
"strokeSharpness": "round",
|
||||||
|
@ -984,16 +1016,18 @@
|
||||||
0
|
0
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
114.78378071898476,
|
127.94827892744422,
|
||||||
-42.24405385173236
|
-45.310365787157025
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"lastCommittedPoint": null
|
"lastCommittedPoint": null,
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": "arrow"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"version": 125,
|
"version": 205,
|
||||||
"versionNonce": 1629871478,
|
"versionNonce": 73736201,
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"id": "MT5NM89SFPtRsCoa3Lyuu",
|
"id": "MT5NM89SFPtRsCoa3Lyuu",
|
||||||
"fillStyle": "hachure",
|
"fillStyle": "hachure",
|
||||||
|
@ -1002,19 +1036,21 @@
|
||||||
"roughness": 2,
|
"roughness": 2,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"x": 907.3333740234375,
|
"x": 824.0000261579243,
|
||||||
"y": 425.666748046875,
|
"y": 525.666748046875,
|
||||||
"strokeColor": "#a61e4d",
|
"strokeColor": "#a61e4d",
|
||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
"width": 111,
|
"width": 121,
|
||||||
"height": 51,
|
"height": 51,
|
||||||
"seed": 1650516385,
|
"seed": 1650516385,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"strokeSharpness": "sharp",
|
"strokeSharpness": "sharp",
|
||||||
"boundElementIds": [],
|
"boundElementIds": [
|
||||||
|
"wltib7el8aYeC2e7nUsKB"
|
||||||
|
],
|
||||||
"fontSize": 20,
|
"fontSize": 20,
|
||||||
"fontFamily": 1,
|
"fontFamily": 1,
|
||||||
"text": "Lockup\nobservation",
|
"text": "Data\nobservations",
|
||||||
"baseline": 43,
|
"baseline": 43,
|
||||||
"textAlign": "left",
|
"textAlign": "left",
|
||||||
"verticalAlign": "top"
|
"verticalAlign": "top"
|
||||||
|
@ -1061,52 +1097,14 @@
|
||||||
-80
|
-80
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"lastCommittedPoint": null
|
"lastCommittedPoint": null,
|
||||||
},
|
"startArrowhead": null,
|
||||||
{
|
"endArrowhead": "arrow"
|
||||||
"type": "arrow",
|
|
||||||
"version": 192,
|
|
||||||
"versionNonce": 152796202,
|
|
||||||
"isDeleted": false,
|
|
||||||
"id": "_9zjwMOLnRasOCqFWujjU",
|
|
||||||
"fillStyle": "hachure",
|
|
||||||
"strokeWidth": 1,
|
|
||||||
"strokeStyle": "solid",
|
|
||||||
"roughness": 2,
|
|
||||||
"opacity": 100,
|
|
||||||
"angle": 0,
|
|
||||||
"x": 970.000244140625,
|
|
||||||
"y": 602.6667175292969,
|
|
||||||
"strokeColor": "#0b7285",
|
|
||||||
"backgroundColor": "transparent",
|
|
||||||
"width": 110.000244140625,
|
|
||||||
"height": 45.99993896484375,
|
|
||||||
"seed": 1622859754,
|
|
||||||
"groupIds": [],
|
|
||||||
"strokeSharpness": "round",
|
|
||||||
"boundElementIds": [],
|
|
||||||
"startBinding": null,
|
|
||||||
"endBinding": {
|
|
||||||
"elementId": "OgGKrVx53b487RcYG7GQ9",
|
|
||||||
"focus": 1.0111297059958109,
|
|
||||||
"gap": 12.6666259765625
|
|
||||||
},
|
|
||||||
"points": [
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
],
|
|
||||||
[
|
|
||||||
-110.000244140625,
|
|
||||||
45.99993896484375
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"lastCommittedPoint": null
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"version": 256,
|
"version": 273,
|
||||||
"versionNonce": 454663158,
|
"versionNonce": 1579098407,
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"id": "Al_x8qQKl3-glzn5YV7Ve",
|
"id": "Al_x8qQKl3-glzn5YV7Ve",
|
||||||
"fillStyle": "hachure",
|
"fillStyle": "hachure",
|
||||||
|
@ -1119,7 +1117,7 @@
|
||||||
"y": 451.6667785644531,
|
"y": 451.6667785644531,
|
||||||
"strokeColor": "#0b7285",
|
"strokeColor": "#0b7285",
|
||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
"width": 87,
|
"width": 102,
|
||||||
"height": 51,
|
"height": 51,
|
||||||
"seed": 807351791,
|
"seed": 807351791,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
|
@ -1127,15 +1125,15 @@
|
||||||
"boundElementIds": [],
|
"boundElementIds": [],
|
||||||
"fontSize": 20,
|
"fontSize": 20,
|
||||||
"fontFamily": 1,
|
"fontFamily": 1,
|
||||||
"text": "PostVAA\nby bridge",
|
"text": "Data\navailability",
|
||||||
"baseline": 43,
|
"baseline": 43,
|
||||||
"textAlign": "left",
|
"textAlign": "left",
|
||||||
"verticalAlign": "top"
|
"verticalAlign": "top"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "diamond",
|
"type": "diamond",
|
||||||
"version": 694,
|
"version": 699,
|
||||||
"versionNonce": 1890457130,
|
"versionNonce": 808025447,
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"id": "inJcSRbT69V_jEbzmNMfN",
|
"id": "inJcSRbT69V_jEbzmNMfN",
|
||||||
"fillStyle": "cross-hatch",
|
"fillStyle": "cross-hatch",
|
||||||
|
@ -1157,8 +1155,8 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"version": 378,
|
"version": 379,
|
||||||
"versionNonce": 1025246390,
|
"versionNonce": 418882919,
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"id": "RnmFmIKXCAaAu_SUnSttl",
|
"id": "RnmFmIKXCAaAu_SUnSttl",
|
||||||
"fillStyle": "hachure",
|
"fillStyle": "hachure",
|
||||||
|
@ -1168,7 +1166,7 @@
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"x": 834.6666259765625,
|
"x": 834.6666259765625,
|
||||||
"y": 237.6666259765625,
|
"y": 238.14280918666293,
|
||||||
"strokeColor": "#862e9c",
|
"strokeColor": "#862e9c",
|
||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
"width": 85,
|
"width": 85,
|
||||||
|
@ -1222,7 +1220,9 @@
|
||||||
-42.52408563756143
|
-42.52408563756143
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"lastCommittedPoint": null
|
"lastCommittedPoint": null,
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": "arrow"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "text",
|
"type": "text",
|
||||||
|
@ -1255,8 +1255,8 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"version": 1618,
|
"version": 1675,
|
||||||
"versionNonce": 56918262,
|
"versionNonce": 1099805863,
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"id": "ZE6FhNQFYu6AYrvqdRLU6",
|
"id": "ZE6FhNQFYu6AYrvqdRLU6",
|
||||||
"fillStyle": "hachure",
|
"fillStyle": "hachure",
|
||||||
|
@ -1266,11 +1266,11 @@
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"x": 872.5969816218751,
|
"x": 872.5969816218751,
|
||||||
"y": 330.5479426569268,
|
"y": 331.0241476652974,
|
||||||
"strokeColor": "#5f3dc4",
|
"strokeColor": "#5f3dc4",
|
||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
"width": 39.93017253984385,
|
"width": 33.71238621455768,
|
||||||
"height": 67.45199630791694,
|
"height": 72.21391560200175,
|
||||||
"seed": 1727638817,
|
"seed": 1727638817,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"strokeSharpness": "round",
|
"strokeSharpness": "round",
|
||||||
|
@ -1278,8 +1278,8 @@
|
||||||
"startBinding": null,
|
"startBinding": null,
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "sCKknWK5gOtk7aQyiPt0Q",
|
"elementId": "sCKknWK5gOtk7aQyiPt0Q",
|
||||||
"focus": 0.21367688360477113,
|
"focus": 0.05256774672249361,
|
||||||
"gap": 15.333404541015625
|
"gap": 14.85719953264504
|
||||||
},
|
},
|
||||||
"points": [
|
"points": [
|
||||||
[
|
[
|
||||||
|
@ -1291,16 +1291,60 @@
|
||||||
29.452057343073193
|
29.452057343073193
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
-39.93017253984385,
|
-33.71238621455768,
|
||||||
67.45199630791694
|
72.21391560200175
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"lastCommittedPoint": null
|
"lastCommittedPoint": null,
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": "arrow"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "arrow",
|
||||||
|
"version": 1940,
|
||||||
|
"versionNonce": 1700404967,
|
||||||
|
"isDeleted": false,
|
||||||
|
"id": "0rKBEZQ_Nr7_AXvWTouGL",
|
||||||
|
"fillStyle": "hachure",
|
||||||
|
"strokeWidth": 1,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 2,
|
||||||
|
"opacity": 100,
|
||||||
|
"angle": 0,
|
||||||
|
"x": 867.3589663107703,
|
||||||
|
"y": 328.1669612116143,
|
||||||
|
"strokeColor": "#5f3dc4",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"width": 143.16811373683038,
|
||||||
|
"height": 246.9654650238051,
|
||||||
|
"seed": 1138759303,
|
||||||
|
"groupIds": [],
|
||||||
|
"strokeSharpness": "round",
|
||||||
|
"boundElementIds": [],
|
||||||
|
"startBinding": null,
|
||||||
|
"endBinding": null,
|
||||||
|
"points": [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
-143.16811373683038,
|
||||||
|
94.6901380489885
|
||||||
|
],
|
||||||
|
[
|
||||||
|
-133.2635204053572,
|
||||||
|
246.9654650238051
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"lastCommittedPoint": null,
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": "arrow"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"version": 891,
|
"version": 1093,
|
||||||
"versionNonce": 222121718,
|
"versionNonce": 1178279021,
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"id": "y2PJg0h4wOfU7ziwuzNgP",
|
"id": "y2PJg0h4wOfU7ziwuzNgP",
|
||||||
"fillStyle": "cross-hatch",
|
"fillStyle": "cross-hatch",
|
||||||
|
@ -1309,26 +1353,26 @@
|
||||||
"roughness": 2,
|
"roughness": 2,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"x": 674.6664428710938,
|
"x": 565.6187853131976,
|
||||||
"y": 351,
|
"y": 485.3808942522322,
|
||||||
"strokeColor": "#5f3dc4",
|
"strokeColor": "#5f3dc4",
|
||||||
"backgroundColor": "#15aabf",
|
"backgroundColor": "#15aabf",
|
||||||
"width": 138,
|
"width": 138,
|
||||||
"height": 40,
|
"height": 80,
|
||||||
"seed": 1348924047,
|
"seed": 1348924047,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"strokeSharpness": "sharp",
|
"strokeSharpness": "sharp",
|
||||||
"boundElementIds": [],
|
"boundElementIds": [],
|
||||||
"fontSize": 16,
|
"fontSize": 16,
|
||||||
"fontFamily": 1,
|
"fontFamily": 1,
|
||||||
"text": "PostVAA with\nfees paid by user",
|
"text": "Call to target\ncontract with \nfees paid by user\n",
|
||||||
"baseline": 34,
|
"baseline": 74,
|
||||||
"textAlign": "right",
|
"textAlign": "right",
|
||||||
"verticalAlign": "top"
|
"verticalAlign": "top"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"appState": {
|
"appState": {
|
||||||
"viewBackgroundColor": "#ffffff",
|
"gridSize": null,
|
||||||
"gridSize": null
|
"viewBackgroundColor": "#ffffff"
|
||||||
}
|
}
|
||||||
}
|
}
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 112 KiB |
|
@ -22,8 +22,8 @@ In addition to Wormhole itself, you need to run your own verifying node for ever
|
||||||
to somebody else's full node would be sufficient, but you'd then depend on that single node for availability unless
|
to somebody else's full node would be sufficient, but you'd then depend on that single node for availability unless
|
||||||
you set up a load balancer pointing to a set of nodes.\]
|
you set up a load balancer pointing to a set of nodes.\]
|
||||||
|
|
||||||
Do NOT use third-party RPC service providers for any of the chains! You'd fully trust them and they could lie to you on
|
Do NOT use third-party RPC service providers for any of the chains! You'd fully trust them, and they could lie to you on
|
||||||
whether a lockup has actually been observed, and the whole point of Wormhole is to not rely on centralized nodes.
|
whether an event has actually been observed. The whole point of Wormhole is not to rely on centralized nodes!
|
||||||
|
|
||||||
### Ethereum node requirements
|
### Ethereum node requirements
|
||||||
|
|
||||||
|
|
321
docs/protocol.md
321
docs/protocol.md
|
@ -1,321 +0,0 @@
|
||||||
# Wormhole Protocol
|
|
||||||
|
|
||||||
The Wormhole protocol is a way of transferring assets between a **root chain** and multiple **foreign chains**.
|
|
||||||
It makes use of decentralized oracles called **guardians** to relay transfer information about token transfers
|
|
||||||
between the chains.
|
|
||||||
|
|
||||||
## The role of guardians
|
|
||||||
|
|
||||||
Guardians are responsible for monitoring the root and foreign chains for token transfers to bridge *smart contracts*.
|
|
||||||
This can be done using full or light clients of the particular network.
|
|
||||||
They need to make sure to monitor finality of transactions (e.g. track number of confirmations) before relaying messages.
|
|
||||||
|
|
||||||
A guardian is identified by an **admin key** and **voter key**.
|
|
||||||
|
|
||||||
The **admin key** is supposed to be held in cold-storage and is used to manage rewards and assign a signer key.
|
|
||||||
|
|
||||||
The **signer key** is a hot-key that is used to confirm asset transfers between chains by reporting lockups of tokens
|
|
||||||
on a foreign chain on the root chain or the other way around.
|
|
||||||
|
|
||||||
## Protocol
|
|
||||||
|
|
||||||
The following section describes the protocol and design decisions made.
|
|
||||||
|
|
||||||
### Signature scheme
|
|
||||||
|
|
||||||
In order to implement a decentralized bridge, there needs to be a consensus mechanism to measure whether there is a quorum
|
|
||||||
on a cross chain transfer to prevent a single malicious actor from unlocking or minting an infinite amount of assets.
|
|
||||||
|
|
||||||
There are multiple ways to measure whether enough validators have approved a decision:
|
|
||||||
|
|
||||||
#### Multiple signatures - MultiSig
|
|
||||||
|
|
||||||
The most simple solution is by using a *MultiSig* mechanism. This means that each guardian would sign a message
|
|
||||||
and submit it via a P2P gossip network.
|
|
||||||
|
|
||||||
Once the consensus threshold has been reached, a guardian will aggregate all signatures into a VAA and execute/submit it
|
|
||||||
on the chain.
|
|
||||||
|
|
||||||
The downside here is that gas costs increase with larger guardian sets bringing verification costs to
|
|
||||||
`(5k+5k)*n` (`ECRECOVER+GTXDATANONZERO*72`).
|
|
||||||
|
|
||||||
To prevent lagging and complex gas price handling by validators or relayers, we always submit VAAs to Solana where txs
|
|
||||||
are negligibly cheap. In the case of a Solana -> ETH transfer. Guardians would publish a signed VAA on Solana and a user
|
|
||||||
or independently paid relayer would publish said VAA on Ethereum, paying for gas costs. This mechanism is similar to a
|
|
||||||
check issued by the guardians (a VAA) which can be used on another chain to claim assets.
|
|
||||||
|
|
||||||
#### Threshold signatures
|
|
||||||
|
|
||||||
Most of the disadvantages of the MultiSig solution come down to the high gas costs of verifying multiple transactions
|
|
||||||
and tracking individual guardian key changes / set changes on other chains.
|
|
||||||
|
|
||||||
In order to prove a quorum on a single signature, there exist different mechanisms for so-called Threshold signatures.
|
|
||||||
A single signature is generated using a multi party computation process or aggregation of signatures from different
|
|
||||||
parties of a group and only valid if a previously specified quorum has participated in the generation of such signature.
|
|
||||||
|
|
||||||
This would essentially mean that such a signature could be published on the Solana chain and relayed by anyone to
|
|
||||||
authorize an action on another chain, the same concept as described above but implemented with the cost of only
|
|
||||||
sending and verifying one signature.
|
|
||||||
|
|
||||||
Since we target Ethereum as primary foreign chain, there are 3 viable options of threshold signatures:
|
|
||||||
|
|
||||||
**t-ECDSA**
|
|
||||||
|
|
||||||
Threshold ECDSA signatures generated using [GG20](https://eprint.iacr.org/2020/540.pdf).
|
|
||||||
This is a highly complex, cutting edge cryptographic protocol that requires significant amounts of compute to generate
|
|
||||||
signatures with larger quorums.
|
|
||||||
|
|
||||||
Still, it generates plain ECDSA signatures that can easily be verified on Ethereum (`5k gas`) or even be used for Bitcoin
|
|
||||||
transactions.
|
|
||||||
|
|
||||||
**BLS**
|
|
||||||
|
|
||||||
Boneh–Lynn–Shacham threshold signatures are very lightweight because they don't require a multi-round process and can
|
|
||||||
simply be aggregated from multiple individual signatures. This would eliminate the need for a p2p layer for MPC
|
|
||||||
communication.
|
|
||||||
However, verifying a BLS signature on Ethereum costs about 130k gas using the precompiled pairing functions over bn128.
|
|
||||||
Also there's very little prior work on this scheme especially in the context of Solidity.
|
|
||||||
|
|
||||||
**Schnorr-Threshold**
|
|
||||||
|
|
||||||
Schnorr threshold signatures require a multi-round computation and distributed key generation.
|
|
||||||
They can be verified on Ethereum extremely cheaply (https://blog.chain.link/threshold-signatures-in-chainlink/) and scale
|
|
||||||
well with more signing parties.
|
|
||||||
There's been significant prior work in the blockchain space, several implementations over different curves and a proposal
|
|
||||||
to implement support on Bitcoin (BIP340).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
A great overview can be found [here](https://github.com/Turing-Chain/TSSKit-Threshold-Signature-Scheme-Toolkit)
|
|
||||||
|
|
||||||
#### Design choices
|
|
||||||
|
|
||||||
For transfers we implement a simple MultiSig schema.
|
|
||||||
We'll create a portable "action blob" with a threshold signature to allow anyone to relay action approvals
|
|
||||||
between chains. We call this structure: **VAA** (Verifiable Action Approval).
|
|
||||||
|
|
||||||
A validator action approval guarantees eventual consistency across chains - if the validators have submitted a VAA to a token lockup
|
|
||||||
on Solana, this VAA can be used to unlock the tokens on the specified foreign chain.
|
|
||||||
|
|
||||||
While for the above mentioned transfers from Solana => foreign chain we use Solana for data availability of the VAAs,
|
|
||||||
in the other direction data availability i.e. the guardians posting the VAA on the foreign chain (where the transfer
|
|
||||||
was initiated) is optional because in most cases it will be substantially cheaper for the guardians to directly submit
|
|
||||||
the VAA on Solana itself to unlock/mint the transferred tokens there.
|
|
||||||
|
|
||||||
### VAA - Verifiable Action Approval
|
|
||||||
|
|
||||||
Verifiable action approvals are used to approve the execution of a specified action on a chain.
|
|
||||||
|
|
||||||
They are structured as follows:
|
|
||||||
|
|
||||||
```
|
|
||||||
Header:
|
|
||||||
uint8 version (0x01)
|
|
||||||
uint32 guardian set index
|
|
||||||
uint8 len signatures
|
|
||||||
|
|
||||||
per signature:
|
|
||||||
uint8 index of the signer (in guardian keys)
|
|
||||||
[65]uint8 signature
|
|
||||||
|
|
||||||
body:
|
|
||||||
uint32 unix seconds
|
|
||||||
uint8 action
|
|
||||||
[payload_size]uint8 payload
|
|
||||||
```
|
|
||||||
|
|
||||||
The `guardian set index` does not need to be in the signed body since it is verifiable using the signature itself which
|
|
||||||
is created using the guardian set's key. It is a number that's monotonically increasing every time a validator set
|
|
||||||
update happens and tracks the public key hashes of the set.
|
|
||||||
|
|
||||||
#### Actions
|
|
||||||
|
|
||||||
##### Guardian set update
|
|
||||||
|
|
||||||
ID: `0x01`
|
|
||||||
|
|
||||||
Payload:
|
|
||||||
|
|
||||||
```
|
|
||||||
uint32 new_index
|
|
||||||
uint8 len(keys)
|
|
||||||
[][20]uint8 guardian addresses
|
|
||||||
```
|
|
||||||
|
|
||||||
The `new_index` must be monotonically increasing and is manually specified here to fix a potential guardian_set index
|
|
||||||
desynchronization between the any of the chains in the system.
|
|
||||||
|
|
||||||
##### Contract upgrade
|
|
||||||
|
|
||||||
ID: `0x02`
|
|
||||||
|
|
||||||
Payload:
|
|
||||||
|
|
||||||
```
|
|
||||||
uint8 chain_id
|
|
||||||
[32]uint8 new_contract
|
|
||||||
```
|
|
||||||
|
|
||||||
`chain_id` specifies the chain on which the contract should be updated. `new_contract` is the address of the updated
|
|
||||||
contract.
|
|
||||||
|
|
||||||
##### Transfer
|
|
||||||
|
|
||||||
ID: `0x10`
|
|
||||||
|
|
||||||
Payload:
|
|
||||||
|
|
||||||
```
|
|
||||||
uint32 nonce
|
|
||||||
uint8 source_chain
|
|
||||||
uint8 target_chain
|
|
||||||
[32]uint8 source_address
|
|
||||||
[32]uint8 target_address
|
|
||||||
uint8 token_chain
|
|
||||||
[32]uint8 token_address
|
|
||||||
uint8 decimals
|
|
||||||
uint256 amount
|
|
||||||
```
|
|
||||||
|
|
||||||
### Cross-Chain Transfers
|
|
||||||
|
|
||||||
#### Transfer of assets Foreign Chain -> Root Chain
|
|
||||||
|
|
||||||
If this is the first time the asset is transferred to the root chain, the user inititates a `CreateWrapped` instruction
|
|
||||||
on the root chain to initialize the wrapped asset.
|
|
||||||
|
|
||||||
The user creates a token account for the wrapped asset on the root chain.
|
|
||||||
|
|
||||||
The user sends a chain native asset to the bridge on the foreign chain using the `Lock` function.
|
|
||||||
The lock function takes a Solana `address` as parameter which is the TokenAccount that should receive the wrapped token.
|
|
||||||
|
|
||||||
Guardians will pick up the *Lock transaction* once it has enough confirmations on the foreign chain. The amount of
|
|
||||||
confirmations required is a parameter that guardians can specify individually.
|
|
||||||
|
|
||||||
They check for the validity, parse it and will then initiate a threshold signature ceremony on a deterministically
|
|
||||||
produced VAA (`Transfer`) testifying that they have seen a foreign lockup. They will post this VAA on the root chain
|
|
||||||
using the `SubmitVAA` instruction.
|
|
||||||
|
|
||||||
This instruction will either mint a new wrapped asset or release tokens from custody.
|
|
||||||
Custody is used for Solana-native tokens that have previously been transferred to a foreign chain, minting will be used
|
|
||||||
to create new units of a wrapped foreign-chain asset.
|
|
||||||
|
|
||||||
If this is the first time a foreign asset is minted, a new **Mint** (token) will be created on quorum.
|
|
||||||
|
|
||||||
### Transfer of assets Root Chain -> Foreign Chain
|
|
||||||
|
|
||||||
The user sends a **Lock** or **LockNative** instruction to the *Bridge program*.
|
|
||||||
|
|
||||||
**Lock** has to be used for wrapped assets that should be transferred to a foreign chain. They will be burned on Solana.
|
|
||||||
|
|
||||||
**LockNative** has to be used for Solana-native assets that should be transferred to a foreign chain. They will be held
|
|
||||||
in a custody account until the tokens are transferred back from the foreign chain.
|
|
||||||
|
|
||||||
The lock function takes a `chain_id` which identifies the foreign chain the tokens should be sent to and a `foreign_address`
|
|
||||||
which is a left-zero-padded address on the foreign chain. This operation creates a **LockProposal** account
|
|
||||||
that tracks the status of the transfer.
|
|
||||||
|
|
||||||
Guardians will pick up the **LockProposal** once it has enough confirmations on the Solana network. It defaults to
|
|
||||||
full confirmation (i.e. the max lockup, currently 32 slots), but can be changed to a different commitment levels
|
|
||||||
on each guardian's discretion.
|
|
||||||
|
|
||||||
They check for the validity of the tx, parse it and will initiate an off-chain signature aggregation ceremony which will
|
|
||||||
output a **VAA** that can be used with a foreign chain smart contract to reclaim an unwrapped local asset or mint a
|
|
||||||
wrapped `spl-token`.
|
|
||||||
|
|
||||||
This VAA will be posted on Solana by one of the guardians using the `SubmitVAA` instruction and will be stored in the
|
|
||||||
`LockProposal`.
|
|
||||||
|
|
||||||
The user can then get the VAA from the `LockProposal` and submit it on the foreign chain.
|
|
||||||
|
|
||||||
### Fees
|
|
||||||
|
|
||||||
Fees exist for 2 reasons: spam prevention and guardian cost coverage.
|
|
||||||
|
|
||||||
Costs for guardians:
|
|
||||||
|
|
||||||
Assuming no hosting costs for a guardian operation (blockchain and guardian nodes), the only costs
|
|
||||||
that need to be covered by a guardian operator are Solana transaction fees as well as rent costs for newly
|
|
||||||
created account (used to store application information).
|
|
||||||
|
|
||||||
**For a transfer from Solana to a foreign chain (20 guardians; 14 quorum):**
|
|
||||||
|
|
||||||
Transactions required: `3 (signatures + verify) + 1 (post VAA)`
|
|
||||||
|
|
||||||
Accounts created: `1 ClaimedVAA + 1 SignatureState`
|
|
||||||
|
|
||||||
Costs:
|
|
||||||
```
|
|
||||||
4 TX (14 secp signatures + 4 ed25519) + ClaimedVAA (exemption rent) + SignatureState (exemption rent)
|
|
||||||
18 * 10_000 + (40+128) * 6962 + (1340+128) * 6962
|
|
||||||
11569832 lamports = 0.0116 SOL
|
|
||||||
```
|
|
||||||
|
|
||||||
**For a transfer from a foreign chain to Solana (20 guardians; 14 quorum):**
|
|
||||||
|
|
||||||
Transactions required: `3 (signatures + verify) + 1 (post VAA)`
|
|
||||||
|
|
||||||
Accounts created: `1 ClaimedVAA + 1 SignatureState (temporary; evicted in PostVAA)`
|
|
||||||
|
|
||||||
Costs:
|
|
||||||
```
|
|
||||||
4 TX (14 secp signatures + 4 ed25519) + ClaimedVAA (exemption rent)
|
|
||||||
18 * 10_000 + (40+128) * 6962
|
|
||||||
1349616 lamports = 0.0013 SOL
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
In order to cover rent costs there exists a subsidy pool controlled by the bridge to cover rent payments.
|
|
||||||
While the guardian needs to hold enough SOL to pay for the rent, it is automatically refunded by the pool,
|
|
||||||
in case the pool has sufficient balance.
|
|
||||||
|
|
||||||
This subsidy pool is funded by transaction fees.
|
|
||||||
Additionally, the subsidy pool subsidizes the transactions fees paid by the guardian submitting the VAA.
|
|
||||||
As long as the pool has a sufficient balance, it will try to refund transaction fees to the guardian.
|
|
||||||
|
|
||||||
Since Wormhole does not require foreign chain users to own SOL, Wormhole can't charge subsidy fees on inbound
|
|
||||||
transfers. Assuming a balance between inbound and outbound transfers, outbound transfers need to subsidize
|
|
||||||
inbound Solana transfers.
|
|
||||||
|
|
||||||
Additionally, foreign chain contracts might start charging additional fees in the future.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
The bridge can handle fewer transactions per second than Solana. Therefore, the fees should prevent spam
|
|
||||||
by dynamically adjusting to load. This is particularly useful on Solana where fees are low and spamming
|
|
||||||
would be cheap.
|
|
||||||
|
|
||||||
Dynamic fees should be cheap while the system is under low and medium load and high while the system is
|
|
||||||
close or above its capacity.
|
|
||||||
To prevent sudden fee changes, the fee system has inertia.
|
|
||||||
|
|
||||||
Fees scale as follows `fee = (tps/tps_max)^6`.
|
|
||||||
The result is the fee per transfer in SOL. So at max capacity, the price per transfer is 1SOL.
|
|
||||||
TPS is measured over a 30 second window.
|
|
||||||
|
|
||||||
The minimum fee is the equivalent of 2x the rent of SignatureState and ClaimedVAA to cover the cost
|
|
||||||
of this transfer and about 10 inbound transfers.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
The above design can currently not be implemented due to limitations in the Solana BPF VM.
|
|
||||||
|
|
||||||
In the current design, tx fees are refunded, rents are subsidized by the bridge and transfers out of Solana
|
|
||||||
cost a fixed fee of 2x (ClaimedVAA rent + SignatureState rent + VAA submission fee), which will roughly
|
|
||||||
pay for 1 outbound + ~10 inbound transfers.
|
|
||||||
|
|
||||||
### Config changes
|
|
||||||
#### Guardian set changes
|
|
||||||
|
|
||||||
The guardians need to make sure that the sets are synchronized between all chains.
|
|
||||||
If the guardian set is changed, the guardian must also be replaced on all foreign chains. Therefore we
|
|
||||||
conduct these changes via VAAs that are universally valid on all chains.
|
|
||||||
|
|
||||||
That way, if a change is made on the root chain, the same signatures can be used to trigger the same
|
|
||||||
update on the foreign chain. This allows all parties in the system to propagate bridge state changes across all
|
|
||||||
chains.
|
|
||||||
|
|
||||||
If all VAAs issued by the previous guardian set would immediately become invalid once a new guardian set takes over, that would
|
|
||||||
lead to some payments being "stuck". Therefore we track a list of previous guardian sets. VAAs issued by old
|
|
||||||
guardian sets stay valid for one day from the time that the change happens in the default configuration.
|
|
|
@ -1,293 +0,0 @@
|
||||||
# Solana Wormhole Program
|
|
||||||
|
|
||||||
The `Wormhole` program acts as a bridge for Solana \<> Foreign Chain transfers using the WhP (WormHoleProtocol).
|
|
||||||
|
|
||||||
## Instructions
|
|
||||||
|
|
||||||
#### Initialize
|
|
||||||
|
|
||||||
Initializes a new Bridge at `bridge`.
|
|
||||||
|
|
||||||
| Index | Name | Type | signer | writeable | empty | derived |
|
|
||||||
| ----- | ------ | ------------ | ------ | --------- | ----- | ------- |
|
|
||||||
| 0 | sys | SystemProgram | | | | |
|
|
||||||
| 1 | clock | Sysvar | | | | ✅ |
|
|
||||||
| 2 | bridge | BridgeConfig | | ✅ | ✅ | ✅ |
|
|
||||||
| 3 | guardian_set | GuardianSet | | ✅ | ✅ | ✅ |
|
|
||||||
| 4 | payer | Account | ✅ | | | |
|
|
||||||
|
|
||||||
#### PokeProposal
|
|
||||||
|
|
||||||
Pokes a `TransferOutProposal` so it is reprocessed by the guardians.
|
|
||||||
|
|
||||||
**Deprecated:** PokeProposals were a workaround for unreliable message delivery on Solana. Now that this has been fixed
|
|
||||||
using a control loop (https://github.com/certusone/wormhole/commit/fd6c54de836cb9f4c423aa334b73546a139c0ee6), poking is
|
|
||||||
no longer required. The feature is left in place for backwards compatibility reasons.
|
|
||||||
|
|
||||||
| Index | Name | Type | signer | writeable | empty | derived |
|
|
||||||
| ----- | ------ | ------------ | ------ | --------- | ----- | ------- |
|
|
||||||
| 0 | proposal | TransferOutProposal | | ✅ | ️ | ✅ |
|
|
||||||
|
|
||||||
#### CreateWrappedAsset
|
|
||||||
|
|
||||||
Creates a new `WrappedAsset` to be used to create accounts and later receive transfers on chain.
|
|
||||||
|
|
||||||
| Index | Name | Type | signer | writeable | empty | derived |
|
|
||||||
| ----- | -------- | ------------------- | ------ | --------- | ----- | ------- |
|
|
||||||
| 0 | sys | SystemProgram | | | | |
|
|
||||||
| 1 | token_program | SplToken | | | | |
|
|
||||||
| 2 | rent | Sysvar | | | | ✅ |
|
|
||||||
| 3 | bridge | BridgeConfig | | | | |
|
|
||||||
| 4 | payer | Account | ✅ | | | |
|
|
||||||
| 5 | wrapped_mint | WrappedAsset | | | ✅ | ✅ |
|
|
||||||
| 6 | wrapped_meta_account | WrappedAssetMeta | | ✅ | ✅ | ✅ |
|
|
||||||
|
|
||||||
#### VerifySignatures
|
|
||||||
|
|
||||||
Checks secp checks (in the previous instruction) and stores results.
|
|
||||||
|
|
||||||
| Index | Name | Type | signer | writeable | empty | derived |
|
|
||||||
| ----- | ------ | ------------ | ------ | --------- | ----- | ------- |
|
|
||||||
| 0 | bridge_p | BridgeProgram | | | | |
|
|
||||||
| 1 | sys | SystemProgram | | | | |
|
|
||||||
| 2 | instructions | Sysvar | | | | ✅ |
|
|
||||||
| 3 | bridge_config | BridgeConfig | | ✅ | | ✅ |
|
|
||||||
| 4 | sig_status | SignatureState | | ✅ | | |
|
|
||||||
| 5 | guardian_set | GuardianSet | | | | ✅ |
|
|
||||||
| 6 | payer | Account | ✅ | | | |
|
|
||||||
|
|
||||||
#### TransferOut
|
|
||||||
|
|
||||||
Burns a wrapped asset `token` from `sender` on the Solana chain.
|
|
||||||
|
|
||||||
The transfer proposal will be tracked at a new account `proposal` where VAAs will be submitted by guardians.
|
|
||||||
|
|
||||||
This instruction needs to be preceded by a SOL Transfer instruction that transfers the fee to the BridgeConfig.
|
|
||||||
The fee can be calculated using the rules explained in the protocol documentation and `Bridge::transfer_fee()`.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
|
|
||||||
| Index | Name | Type | signer | writeable | empty | derived |
|
|
||||||
| ----- | -------- | ------------------- | ------ | --------- | ----- | ------- |
|
|
||||||
| 0 | bridge_p | BridgeProgram | | | | |
|
|
||||||
| 1 | sys | SystemProgram | | | | |
|
|
||||||
| 2 | token_program | SplToken | | | | |
|
|
||||||
| 3 | rent | Sysvar | | | | ✅ |
|
|
||||||
| 4 | clock | Sysvar | | | | ✅ |
|
|
||||||
| 5 | instructions | Sysvar | | | | ✅ |
|
|
||||||
| 6 | token_account | TokenAccount | | ✅ | | |
|
|
||||||
| 7 | bridge | BridgeConfig | | | | |
|
|
||||||
| 8 | proposal | TransferOutProposal | | ✅ | ✅ | ✅ |
|
|
||||||
| 9 | token | WrappedAsset | | ✅ | | ✅ |
|
|
||||||
| 10 | payer | Account | ✅ | | | |
|
|
||||||
|
|
||||||
#### TransferOutNative
|
|
||||||
|
|
||||||
Locks a Solana native token (spl-token) `token` from `sender` on the Solana chain by transferring it to the
|
|
||||||
`custody_account`.
|
|
||||||
|
|
||||||
The transfer proposal will be tracked at a new account `proposal` where a VAA will be submitted by guardians.
|
|
||||||
|
|
||||||
This instruction needs to be preceded by a SOL Transfer instruction that transfers the fee to the BridgeConfig.
|
|
||||||
The fee can be calculated using the rules explained in the protocol documentation and `Bridge::transfer_fee()`.
|
|
||||||
|
|
||||||
| Index | Name | Type | signer | writeable | empty | derived |
|
|
||||||
| ----- | --------------- | ------------------- | ------ | --------- | ----- | ------- |
|
|
||||||
| 0 | bridge_p | BridgeProgram | | | | |
|
|
||||||
| 1 | sys | SystemProgram | | | | |
|
|
||||||
| 2 | token_program | SplToken | | | | |
|
|
||||||
| 3 | rent | Sysvar | | | | ✅ |
|
|
||||||
| 4 | clock | Sysvar | | | | ✅ |
|
|
||||||
| 5 | instructions | Sysvar | | | | ✅ |
|
|
||||||
| 6 | token_account | TokenAccount | | ✅ | | |
|
|
||||||
| 7 | bridge | BridgeConfig | | | | |
|
|
||||||
| 8 | proposal | TransferOutProposal | | ✅ | ✅ | ✅ |
|
|
||||||
| 9 | token | Mint | | ✅ | | |
|
|
||||||
| 10 | payer | Account | ✅ | | | |
|
|
||||||
| 11 | custody_account | TokenAccount | | ✅ | opt | ✅ |
|
|
||||||
|
|
||||||
#### EvictTransferOut
|
|
||||||
|
|
||||||
Deletes a `proposal` after the `VAA_EXPIRATION_TIME` to free up space on chain. This returns the rent to `guardian`.
|
|
||||||
|
|
||||||
| Index | Name | Type | signer | writeable | empty | derived |
|
|
||||||
| ----- | -------- | ------------------- | ------ | --------- | ----- | ------- |
|
|
||||||
| 0 | bridge_p | BridgeProgram | | | | |
|
|
||||||
| 1 | guardian | Account | ✅ | | | |
|
|
||||||
| 2 | clock | Sysvar | | | | ✅ |
|
|
||||||
| 3 | bridge | BridgeConfig | | | | |
|
|
||||||
| 4 | proposal | TransferOutProposal | | ✅ | | ✅ |
|
|
||||||
|
|
||||||
#### EvictClaimedVAA
|
|
||||||
|
|
||||||
Deletes a `ClaimedVAA` after the `VAA_EXPIRATION_TIME` to free up space on chain. This returns the rent to `guardian`.
|
|
||||||
|
|
||||||
| Index | Name | Type | signer | writeable | empty | derived |
|
|
||||||
| ----- | -------- | ------------------- | ------ | --------- | ----- | ------- |
|
|
||||||
| 0 | bridge_p | BridgeProgram | | | | |
|
|
||||||
| 1 | guardian | Account | ✅ | | | |
|
|
||||||
| 2 | clock | Sysvar | | | | ✅ |
|
|
||||||
| 3 | bridge | BridgeConfig | | | | |
|
|
||||||
| 4 | claim | ClaimedVAA | | ✅ | | ✅ |
|
|
||||||
|
|
||||||
#### SubmitVAA
|
|
||||||
|
|
||||||
Submits a VAA signed by the guardians to perform an action.
|
|
||||||
|
|
||||||
The required accounts depend on the `action` of the VAA:
|
|
||||||
|
|
||||||
All require:
|
|
||||||
|
|
||||||
| Index | Name | Type | signer | writeable | empty | derived |
|
|
||||||
| ----- | ------------ | ------------ | ------ | --------- | ----- | ------- |
|
|
||||||
| 0 | bridge_p | BridgeProgram | | | | |
|
|
||||||
| 1 | sys | SystemProgram | | | | |
|
|
||||||
| 2 | rent | Sysvar | | | | ✅ |
|
|
||||||
| 3 | clock | Sysvar | | | | ✅ |
|
|
||||||
| 4 | bridge | BridgeConfig | | ✅ | | |
|
|
||||||
| 5 | guardian_set | GuardianSet | | | | |
|
|
||||||
| 6 | claim | ExecutedVAA | | ✅ | ✅ | ✅ |
|
|
||||||
| 7 | sig_info | SigState | | ✅ | ✅ | |
|
|
||||||
| 8 | payer | Account | ✅ | | | |
|
|
||||||
|
|
||||||
followed by:
|
|
||||||
|
|
||||||
##### Guardian set update
|
|
||||||
|
|
||||||
| Index | Name | Type | signer | writeable | empty | derived |
|
|
||||||
| ----- | ------------ | ------------------- | ------ | --------- | ----- | ------- |
|
|
||||||
| 9 | guardian_set_new | GuardianSet | | ✅ | ✅ | ✅ |
|
|
||||||
|
|
||||||
##### Contract upgrade
|
|
||||||
|
|
||||||
| Index | Name | Type | signer | writeable | empty | derived |
|
|
||||||
| ----- | ------------------ | ----------------- | ------ | --------- | ----- | ------- |
|
|
||||||
| 9 | new_contract | Account | | | ✅ | |
|
|
||||||
| 10 | program_data | Account | | ✅ | ✅ | ✅ |
|
|
||||||
| 11 | upgradeable_loader | UpgradeableLoader | | | | |
|
|
||||||
|
|
||||||
##### Transfer: Ethereum (native) -> Solana (wrapped)
|
|
||||||
|
|
||||||
| Index | Name | Type | signer | writeable | empty | derived |
|
|
||||||
| ----- | ------------ | ------------ | ------ | --------- | ----- | ------- |
|
|
||||||
| 9 | token_program | SplToken | | | | |
|
|
||||||
| 10 | token | WrappedAsset | | | | ✅ |
|
|
||||||
| 11 | destination | TokenAccount | | ✅ | | |
|
|
||||||
| 12 | wrapped_meta | WrappedMeta | | ✅ | opt | ✅ |
|
|
||||||
|
|
||||||
##### Transfer: Ethereum (wrapped) -> Solana (native)
|
|
||||||
|
|
||||||
| Index | Name | Type | signer | writeable | empty | derived |
|
|
||||||
| ----- | ------------ | ------------ | ------ | --------- | ----- | ------- |
|
|
||||||
| 9 | token_program | SplToken | | | | |
|
|
||||||
| 10 | token | Mint | | | | ✅ |
|
|
||||||
| 11 | destination | TokenAccount | | ✅ | opt | |
|
|
||||||
| 12 | custody_src | TokenAccount | | ✅ | | ✅ |
|
|
||||||
|
|
||||||
##### Transfer: Solana (any) -> Ethereum (any)
|
|
||||||
|
|
||||||
| Index | Name | Type | signer | writeable | empty | derived |
|
|
||||||
| ----- | ------------ | ------------------- | ------ | --------- | ----- | ------- |
|
|
||||||
| 9 | out_proposal | TransferOutProposal | | ✅ | | ✅ |
|
|
||||||
|
|
||||||
## Accounts
|
|
||||||
|
|
||||||
The following types of accounts are owned by creators of bridges:
|
|
||||||
|
|
||||||
#### _BridgeConfig_ Account
|
|
||||||
|
|
||||||
This account tracks the configuration of the transfer bridge.
|
|
||||||
|
|
||||||
| Parameter | Description |
|
|
||||||
| ------------------ | -------------------------------------------------------------------------------------------------------- |
|
|
||||||
| VAA_EXPIRATION_TIME | Period for how long a VAA is valid. This exists to guarantee data availability and prevent replays |
|
|
||||||
| GUARDIAN_SET_INDEX | Index of the current active guardian set //TODO do we need to track this if the VAA contains the index? |
|
|
||||||
|
|
||||||
## Program Accounts
|
|
||||||
|
|
||||||
The program own the following types of accounts:
|
|
||||||
|
|
||||||
#### _ClaimedVAA_ Account
|
|
||||||
|
|
||||||
> Seed derivation: `claim || <bridge> || <hash>`
|
|
||||||
>
|
|
||||||
> **bridge**: Pubkey of the bridge
|
|
||||||
>
|
|
||||||
> **hash**: signing hash of the VAA
|
|
||||||
|
|
||||||
This account is created when a VAA is executed/consumed on Solana (i.e. not when a TransferOutProposal is approved).
|
|
||||||
It tracks a used VAA to protect from replay attacks where a VAA is executed multiple times. This account stays active
|
|
||||||
until the `VAA_EXPIRATION_TIME` has passed and can then be evicted using `IEvictClaimedVAA`.
|
|
||||||
|
|
||||||
#### _GuardianSet_ Account
|
|
||||||
|
|
||||||
> Seed derivation: `guardian || <bridge> || <index>`
|
|
||||||
>
|
|
||||||
> **bridge**: Pubkey of the bridge
|
|
||||||
>
|
|
||||||
> **index**: Index of the guardian set
|
|
||||||
|
|
||||||
This account is created when a new guardian set is set. It tracks the public key hash, creation time and expiration time of
|
|
||||||
this set.
|
|
||||||
The expiration time is set when this guardian set is abandoned. When a switchover happens, the guardian-issued VAAs will
|
|
||||||
still be valid until the expiration time.
|
|
||||||
|
|
||||||
#### _TransferOutProposal_ Account
|
|
||||||
|
|
||||||
> Seed derivation: `transfer || <bridge> || <asset_chain> || <asset> || <target_chain> || <target_address> || <sender> || <nonce>`
|
|
||||||
>
|
|
||||||
> **bridge**: Pubkey of the bridge
|
|
||||||
>
|
|
||||||
> **asset_chain**: CHAIN_ID of the native chain of this asset
|
|
||||||
>
|
|
||||||
> **asset**: address of the asset
|
|
||||||
>
|
|
||||||
> **target_chain**: ChainID of the recipient
|
|
||||||
>
|
|
||||||
> **target_address**: address of the recipient
|
|
||||||
>
|
|
||||||
> **sender**: pubkey of the sender
|
|
||||||
>
|
|
||||||
> **nonce**: nonce of the transfer
|
|
||||||
|
|
||||||
This account is created when a user wants to lock tokens to transfer them to a foreign chain using the `ITransferOut`
|
|
||||||
instruction.
|
|
||||||
|
|
||||||
It is used to signal a pending transfer to a foreign chain and will also store the respective VAA provided using
|
|
||||||
`ISubmitVAA`.
|
|
||||||
|
|
||||||
Once the VAA has been published this TransferOut is considered completed and can be evicted using `EvictTransferOut`
|
|
||||||
after `VAA_EXPIRATION_TIME` has passed.
|
|
||||||
|
|
||||||
#### _WrappedAsset_ Mint
|
|
||||||
|
|
||||||
> Seed derivation: `wrapped || <bridge> || <chain> || <asset>`
|
|
||||||
>
|
|
||||||
> **bridge**: Pubkey of the bridge
|
|
||||||
>
|
|
||||||
> **chain**: CHAIN_ID of the native chain of this asset
|
|
||||||
>
|
|
||||||
> **asset**: address of the asset on the foreign chain
|
|
||||||
|
|
||||||
This account is an instance of `spl-token/Mint` tracks a wrapped asset on the Solana chain.
|
|
||||||
|
|
||||||
#### _WrappedAssetMeta_ Mint
|
|
||||||
|
|
||||||
> Seed derivation: `meta || <bridge> || <wrapped>`
|
|
||||||
>
|
|
||||||
> **bridge**: Pubkey of the bridge
|
|
||||||
>
|
|
||||||
> **wrapped**: address of the wrapped asset
|
|
||||||
|
|
||||||
This account tracks the metadata about a wrapped asset to allow reverse lookups.
|
|
||||||
|
|
||||||
#### _Custody_ TokenAccount
|
|
||||||
|
|
||||||
> Seed derivation: `custody || <bridge> || <asset>`
|
|
||||||
>
|
|
||||||
> **bridge**: Pubkey of the bridge
|
|
||||||
>
|
|
||||||
> **asset**: address of the asset mint on the native chain
|
|
||||||
|
|
||||||
This account is an instance of `spl-token/TokenAccount` and holds spl tokens in custody that have been transferred to a
|
|
||||||
foreign chain.
|
|
Loading…
Reference in New Issue