chapter 3 content additions

This commit is contained in:
chase-45 2022-08-17 21:25:36 -04:00
parent d00934ff4a
commit b0ba22e493
15 changed files with 940 additions and 3 deletions

View File

@ -15,7 +15,7 @@
- [Advantages of xDapps](./dapps/5_advantages.md)
- [Wormhole](./wormhole/0_wormholeOverview.md)
- [What is Wormhole?](./wormhole/1_whatIsWormhole.md)
- [Architecture Overview](./wormhole/2_architectureOverview.md)
- [Core Layer Contracts](./wormhole/3_coreLayerContracts.md)
@ -25,6 +25,14 @@
- [Portal xAsset Bridge](./wormhole/7_portalTokenBridge.md)
- [Wormchain](./wormhole/8_wormchain.md)
- [xDapp Design](./dapps/architecture/0_dappDesign.md)
- [Key Considerations](./dapps/architecture/1_keyConsiderations.md)
- [Ecosystems](./dapps/architecture/2_ecosystems.md)
- [Protocol Design](./dapps/architecture/3_protocolDesign.md)
- [Topology](./dapps/architecture/4_topology.md)
- [Relayers](./dapps/architecture/5_relayers.md)
---
# xDapp Development
@ -47,8 +55,8 @@
- [Receving Messages](./development/messages/receiving/overview.md)
- [EVM](./development/messages/receiving/evm.md)
- [Projects](./projects/summary.md)
- [EVM Messenger](./projects/evm-messenger/overview.md)
- [Solidity](./projects/evm-messenger/messenger.md)
- [EVM Messenger](./projects/evm-messenger/overview.md)
- [Solidity](./projects/evm-messenger/messenger.md)
- [JS Client](./projects/evm-messenger/client.md)
- [Messenger](./projects/messenger/introduction.md)
- [Prerequistes]()

View File

@ -0,0 +1,5 @@
# xDapp Design
Now that we've established the concepts underlying xDapps and the major components, let's dive into the design process surrounding xDapps. This chapter will help guide you through the considerations you should make before developing an xDapp, including topics like security, network topology, protocol design and more.
By the end of this chapter, you should have all the tools you need to lay out a design for your xDapp and start building.

View File

@ -0,0 +1,19 @@
# Key Considerations
Before we get started, we should outline the key considerations which will shape your xDapp. Over the course of the chapter, we'll elaborate on how decisions made about these key points impact the way you may want to structure your application as a whole.
### Why?
Why you are building an xDapp is definitely the foremost consideration. In the first chapter, we went over the [advantages](../5_advantages.md) of cross-chain development. Which of these advantages are most important to you? Are you building a brand new application and you want the widest reach? Are you trying to increase the performance of an existing Dapp? Are you interested in composing on top of protocols which only exist in certain ecosystems? Deciding what your key priorities are will help you make the correct technical decisions and tradeoffs when designing your xDapp.
### Target Ecosystems & Languages
A major consideration is which blockchains you intend to support. Because blockchains utilize different virtual machines, supporting more blockchains often (but not always) requires writing smart contracts in more than one language.
### Data Flows
Where does your data originate from and where does it have to go? Does all your data come from user-initiated transactions? Do you have governance messages which need to be emitted from a central governance location? Do you have automated actions which need to happen periodically to synchronize your data?
### Liquidity & Tokens
Not all xDapps deal with tokens, but certainly quite a few do. If your app is centered around tokens, you'll have to decide what tokens will be utilized, where liquidity is aggregated (or fractured), and how this liquidity can be best utilized across your application.

View File

@ -0,0 +1,32 @@
# Ecosystems
At present, there are 3 ecosystems supported by Wormhole, though the number of ecosystems supported is always growing.
### EVM
EVM is the most popular ecosystem, and most xDapps will have some support for this platform. These contracts are written in Solidity, and are generally a 'jack of all trades' type of computation environment. A common strategy for xDapps is to develop one single contract in Solidity, and then deploy that contract to all the supported EVM blockchains.
Example chains:
- Ethereum
- Polygon
- BNB Chain
- Avalanche (C Chain)
- Aurora (Near Network)
- Karura (Polkadot Network)
- Acala (Polkadot Network)
- Celo
- Fantom
- Oasis (Emerald)
### Solana
Solana is characterized by its high transaction throughput, increased computation power, and cheap data storage when compared to EVM environments. These contracts are written in Rust.
### Cosmos
Cosmos is a network of blockchains which share a common ecosystem. Cosmos is a general purpose environment, but excels in certain areas such as application-specific blockchains, and having Cosmos-wide standards via its sdk 'modules'. It uses CosmWasm for its smart contract runtime, which is based in Rust.
### Read-Only Chains
Some chains in the Wormhole ecosystem are 'Read-Only'. These chains are able to verify messages which are emitted from other chains in the network, but are not able to emit messages themselves. For information about these chains, check the [contracts page](../../reference/contracts.md).

View File

@ -0,0 +1,31 @@
# Protocol Design
Wormhole's key feature is that it brings message passing to the world of blockchain. As such, it's worthwhile to take some inspiration from other areas of software development which are based on similar principles.
Much of the traditional web stack is based on distributed systems, which rely on message passing to create well-defined interfaces and boundaries for disparate systems to work together. We should similarly think of xDapps as web3 distributed systems based on similar paradigms.
## Protocol First Design
Protocol first design is a design philosophy where you first lay out your data types, message formats, and supported operations into a well-defined protocol. This creates a solid protocol layer which can serve as the foundation for your application, and the code instantiating that protocol can be treated as an implementation detail when reasoning about the protocol itself.
At this stage in the design, you should first consider the incentive structures surrounding your protocol. What is the incentive for each party to engage? Are there economic attack vectors in your application which might jeopardize its security? Do certain market conditions result in perverse outcomes? This stage of the process could be as simple as stating "people will want my NFT", or as difficult as designing an entire ecosystem with multiple competing interests. It depends on what your goals are.
Once you have a clear idea of your core product, incentives, and users, you can begin to lay out your data model, and from there define your message types and operations.
## Common Strategies and Conventions
### Address Space
Because there are many different formats for addresses across the ecosystem, a compatibility format is necessary. Wormhole uses its own address format (generally referred to as Wormhole format) in order to solve this issue. These addresses correspond 1 to 1 with native addresses on each chain.
A Wormhole address consists of a tuple containing the 2 byte Wormhole chain ID, and also a 32 byte shim address. The Wormhole address format is then 34 bytes.
For example, because EVM addresses are only 20 bytes in length, to convert this to a Wormhole address, the address is left-padded with zeros until it's length 32.
When dealing with addresses inside your messages, it's recommended to always convert to Wormhole format and transmit in that format. Primarily because you will regularly encounter these addresses when interacting with parts of the Wormhole ecosystem, but also because it will enhance your forward compatibility as you add more chains to your protocol.
### Trusted Contract Network
If your application has smart contracts deployed to multipe chains, it will be important for your contracts to know which other contracts are 'in network' for your application, as commonly the first check performed when receiving a message is to validate that it originates from a trusted contract.
Generally, this list of trusted contracts is stored in the state of each contract individually, and updating the trusted contracts is tied into the governance mechanism of the application.

View File

@ -0,0 +1,69 @@
# Topology
Topology describes how data flows through your application, and the responsibilities of each component. The primary decision to be made with regard to topology is mainly where your smart contracts will live, and what responsibilities each contract holds.
## Ultra-light Clients
![Ultra-light client](../../diagrams/images/ultralight.png "Ultra Light Clients")
Ultra-light Clients are often the best option when designing an MVP for your xDapp. The defining feature of an Ultra-light Client is that you are able to support users from every chain in the Wormhole ecosystem while **only having smart contracts on a single chain (!!!)**.
The way this works is by deploying a single _hub_ contract (or just using an existing Dapp). You then add an entrypoint which supports _contract controlled transfers_ from the Asset Layer to send tokens to your hub contract, along with instructions for what to do with the tokens. Once you've performed the necessary operation, you bridge the resultant tokens back to the wallet which originally sent the CCT. The only on-chain components is the relatively lightweight wrapper around the core Dapp logic. All other aspects of this topology are off-chain and untrusted. This pushes most of the development work out of smart contracts and into client-side typescript, without altering the trust assumptions of your application.
**_Advantages:_**
- Very little added smart contract risk.
- Simple to develop.
- Easiest way to get heterogenous ecosystem support.
**_Disadvantages:_**
- Latency: Because all transactions have to bridge in and out of the hub chain, each transaction incurs the finality latency of both the remote and hub chain.
- Transaction Fees: There are always a grand total of three transactions. Two on the remote chain, and one on the hub chain.
- Use cases: There is no place to perform trusted computation on the remote chain, so some use cases are more difficult to implement (or potentially not possible).
## Hub and Spoke
Hub and Spoke models are somewhat of a natural evolution of the ultra-light client. There is still a hub contract which handles all transactions, but there is not also a contract deployed to the remote chain.
Advantages:
- Remote contracts are lightweight and don't carry huge amounts of risk.
- Can perform trusted checks on the remote chain. (Such as validating wallet balance)
Disadvantages:
- Latency (same as Ultra Lightweight Clients) - Transaction Fees: - Managing multiple contracts
## Mesh
A Mesh topology is one where each chain implements the full logic for a process, such that each contract is a peer of other contracts in the trusted network and can act autonomously.
Advantages:
- Latency: Users can perform their operation without waiting for other chains.
- Transaction Fees: Does not stack the transaction fees of multiple chains.
Disadvantages:
- Complexity: there are now quite a few contracts to manage, especially if they are implemented multiple times across different VMs.
- Data desync: because each blockchain acts independently, each chain will have independent state. This can open up unwanted arbitrage opportunities and other discontinuities.
- Race conditions: In cases where an event is supposed to propage through the entire system at a fixed time (example: closing a governance vote), it will be difficult to synchronize all the blockchains.
## Distributed
A distributed topology is one where different blockchains have different responsibilities.
Advantages:
- Power: utilize each blockchain for whatever is most optimal.
Disadvantages:
- Complexity: requires multiple specialized smart contracts, and potentially additional on-chain processes.
## Mix & Match
Different use cases have different optimal topologies, and it's possible to use different topologies for different workflows in your application. This means your should not feel 'locked in' to a single topology, and should instead consider designing each workflow independently. For example, Governance is generally best implemented using a Hub and Spoke topology, even if the rest of your application uses a Mesh architecture. As such, your contracts will likely evolve over time as your xDapp evolves and adds in additional workflows.
You can also progress through different topologies. A common strategy is to start off with an ultra-light client, move to a hub and spoke configuration, and then add optimizations and specialties to your contracts as the need arises.

View File

@ -0,0 +1,69 @@
# Relayers
In Chapter 2, we discussed the [general concepts associated with relayers in the Wormhole ecosystem](../../wormhole/6_relayers.md). In this section, the primary focus is to outline what considerations need to be taken into account when designing relayers in your application.
## Fundamentals
The most important thing to remember about relayers is that they are _untrusted_. This means you don't have to trust them, but it also means you can't trust them. This is true of both generic and specialized relayers.
Let's dive into a little bit more detail about _why_ relayers are untrusted, and what this means for you when laying out a protocol.
A few key properties of VAAs are that they:
- are publicly emitted from the Guardian Network
- need to be signed by the Guardian Network to be considered authentic
- can be verified as authentic by _any_ Wormhole Core Contract they are brought to _by anyone_.
Relayers are untrusted as an inherent consequence of these properties. Anyone can pick up a VAA and deliver it anywhere they feel like, however, no one can alter the content of the VAA without invalidating the signatures.
So, when writing your contracts, it's incredibly important to only trust information _inside your contract_ or _inside of VAA content_. If you trust information provided by a relayer, you are opening yourself up to untrusted input attacks.
The easiest and most secure way to interact with relayers then is to _only accept the VAA as input_. If the relayer can't provide any additional args, then there's no way for them to provide untrusted input.
There are more advanced strategies whereby the relayer performs **untrusted** off-chain computation which is passed into the destination contract. These strategies can optimize gas costs, but must be used carefully, as they can create attack vectors if not used correctly.
Designing relayers is mostly a matter of structuring the messages in your protocol in a manner such that there is a single, deterministic way that they can be processed. Once you've designed your protocol, your relayers just need to be implemented correctly. Relayers are conceptually quite similar to "crank turner" processes used elsewhere in blockchain, in that there is only a single action which can be taken (pulling the crank), and their sole responsibility is to initiate this action and pay for the costs.
---
## Generic Relayers
Generic Relayers are a decentralized relayer network which can deliver arbitrary VAAs, so long as the recipient contract is conformant with the generic relayer API.
### Advantages:
- Purely done on-chain. No need to host or maintain relayers
### Disadvantages:
- Less room for optimization via features like conditional delivery, batching, off-chain calculations, etc.
---
## Specialized Relayers
Specialized Relayers are relayers which are purpose-built to relay messages for a certain application.
### Advantages:
- Can perform off-chain untrusted computation
- Highly customizeable. Can perform batching, conditional delivery, multi-chain deliveries, etc.
- Can home-roll an incentive structure
### Disadvantages
- Requires development work, and requires that someone continuously run these.
In the future, there may be ways to customize generic relayers such that they will gain the advantages of today's specialized relayers.
### Relayer Incentives
Relayers have to cover the costs of executing the downstream transactions resulting from the original 'source' transaction. Unless the relayers are running at a loss, there must be a mechanism for reimbursing the relayer in exchange for message delivery.
There are tons of strategies here, and the 'best' strategy for an application is often dependent on the specifics of that application. However, a few of the most common strategies are:
- pay the relayer with a potion of the tokens being sent cross-chain
- collect a safe amount of gas money from the end user prior to performing any actions
- 'lazy' relaying, where relaying might only become profitable in certain, potentially rare, market conditions

View File

View File

View File

View File

View File

14
src/dapps/xDex/xDex.md Normal file
View File

@ -0,0 +1,14 @@
## Example: xDex
- Why: The goal of xDex is to make the world's best dex. We want to support users from every chain, we want to support every asset those users could want, and we want this dex to be managed by on-chain governance.
- Target Ecosystems: We want to support wallet users from every blockchain which has full Wormhole support, but we are less concerned about smart contract developers being able to compose on top of us.
- Data flows: There are three key data flows. Swaps, liquidity providing, and governance.
- Liquidity & Tokens: We want to minimize liquidity fragmentation in order to support large swaps. We also want users from any chain to be able to vote in governance or provision liquidity.
## Example: xDex
- We needs to support users from all these ecosystems.
- We want to minimize our number of contracts so as to reduce implementation complexity and smart contract risk.

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

View File

@ -0,0 +1,690 @@
{
"type": "excalidraw",
"version": 2,
"source": "https://excalidraw.com",
"elements": [
{
"type": "ellipse",
"version": 135,
"versionNonce": 768546443,
"isDeleted": false,
"id": "NbbbY9EVQfg7rd_afNpYY",
"fillStyle": "hachure",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"angle": 0,
"x": 470,
"y": 221.5,
"strokeColor": "#000000",
"backgroundColor": "transparent",
"width": 22,
"height": 21,
"seed": 1843991813,
"groupIds": [],
"strokeSharpness": "sharp",
"boundElements": [],
"updated": 1660658442824,
"link": null,
"locked": false
},
{
"type": "ellipse",
"version": 224,
"versionNonce": 725330853,
"isDeleted": false,
"id": "Go0OxQVkX0X2m9jx5Bf_G",
"fillStyle": "hachure",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"angle": 0,
"x": 1350,
"y": 221.5,
"strokeColor": "#000000",
"backgroundColor": "transparent",
"width": 22,
"height": 21,
"seed": 279079371,
"groupIds": [],
"strokeSharpness": "sharp",
"boundElements": [],
"updated": 1660658442824,
"link": null,
"locked": false
},
{
"type": "ellipse",
"version": 148,
"versionNonce": 2019691819,
"isDeleted": false,
"id": "PqxENRNqTpvPnZM8eQhpI",
"fillStyle": "hachure",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"angle": 0,
"x": 470,
"y": 961.5,
"strokeColor": "#000000",
"backgroundColor": "transparent",
"width": 22,
"height": 21,
"seed": 275393637,
"groupIds": [],
"strokeSharpness": "sharp",
"boundElements": [],
"updated": 1660658442824,
"link": null,
"locked": false
},
{
"type": "ellipse",
"version": 150,
"versionNonce": 1081143045,
"isDeleted": false,
"id": "O8vOxifDk2VUYfbrsHAgD",
"fillStyle": "hachure",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"angle": 0,
"x": 1350,
"y": 961.5,
"strokeColor": "#000000",
"backgroundColor": "transparent",
"width": 22,
"height": 21,
"seed": 602470507,
"groupIds": [],
"strokeSharpness": "sharp",
"boundElements": [],
"updated": 1660658442824,
"link": null,
"locked": false
},
{
"id": "7tycgTrlIwWUIYouO52v1",
"type": "rectangle",
"x": 531,
"y": 787,
"width": 440,
"height": 134,
"angle": 0,
"strokeColor": "#000000",
"backgroundColor": "transparent",
"fillStyle": "hachure",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"groupIds": [],
"strokeSharpness": "round",
"seed": 954648165,
"version": 68,
"versionNonce": 60365675,
"isDeleted": false,
"boundElements": [
{
"id": "DQyXiYF_swzbHKTnJgWV0",
"type": "arrow"
}
],
"updated": 1660658585285,
"link": null,
"locked": false
},
{
"id": "vRXD9VfYpftfI3N7mn-Gd",
"type": "arrow",
"x": 601.7741878115013,
"y": 754.6497146422788,
"width": 1,
"height": 74,
"angle": 0,
"strokeColor": "#000000",
"backgroundColor": "transparent",
"fillStyle": "hachure",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"groupIds": [],
"strokeSharpness": "round",
"seed": 482841195,
"version": 43,
"versionNonce": 1693972971,
"isDeleted": false,
"boundElements": null,
"updated": 1660658572677,
"link": null,
"locked": false,
"points": [
[
0,
0
],
[
1,
-74
]
],
"lastCommittedPoint": null,
"startBinding": null,
"endBinding": null,
"startArrowhead": null,
"endArrowhead": "arrow"
},
{
"id": "Lo7L-SSQitvDd0me0ArFk",
"type": "rectangle",
"x": 513,
"y": 334,
"width": 286,
"height": 301,
"angle": 0,
"strokeColor": "#000000",
"backgroundColor": "transparent",
"fillStyle": "hachure",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"groupIds": [],
"strokeSharpness": "round",
"seed": 1384772389,
"version": 115,
"versionNonce": 2061579141,
"isDeleted": false,
"boundElements": null,
"updated": 1660658531328,
"link": null,
"locked": false
},
{
"id": "ehq2knMV5F3_1e_PpVBWH",
"type": "rectangle",
"x": 1080,
"y": 340,
"width": 260,
"height": 320,
"angle": 0,
"strokeColor": "#000000",
"backgroundColor": "transparent",
"fillStyle": "hachure",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"groupIds": [],
"strokeSharpness": "round",
"seed": 94466891,
"version": 99,
"versionNonce": 775888619,
"isDeleted": false,
"boundElements": [
{
"id": "rYB6hRqqfDm5aTJtLBGcS",
"type": "arrow"
},
{
"id": "o0H-v8h1HGHciwOH0Ljyc",
"type": "arrow"
}
],
"updated": 1660658578733,
"link": null,
"locked": false
},
{
"id": "rYB6hRqqfDm5aTJtLBGcS",
"type": "arrow",
"x": 840,
"y": 360,
"width": 220,
"height": 0,
"angle": 0,
"strokeColor": "#000000",
"backgroundColor": "transparent",
"fillStyle": "hachure",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"groupIds": [],
"strokeSharpness": "round",
"seed": 2143940907,
"version": 22,
"versionNonce": 829343435,
"isDeleted": false,
"boundElements": null,
"updated": 1660658713005,
"link": null,
"locked": false,
"points": [
[
0,
0
],
[
220,
0
]
],
"lastCommittedPoint": null,
"startBinding": null,
"endBinding": {
"elementId": "ehq2knMV5F3_1e_PpVBWH",
"focus": 0.875,
"gap": 20
},
"startArrowhead": null,
"endArrowhead": "arrow"
},
{
"id": "o0H-v8h1HGHciwOH0Ljyc",
"type": "arrow",
"x": 1060,
"y": 580,
"width": 220,
"height": 0,
"angle": 0,
"strokeColor": "#000000",
"backgroundColor": "transparent",
"fillStyle": "hachure",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"groupIds": [],
"strokeSharpness": "round",
"seed": 1398244491,
"version": 20,
"versionNonce": 1994268517,
"isDeleted": false,
"boundElements": null,
"updated": 1660658713005,
"link": null,
"locked": false,
"points": [
[
0,
0
],
[
-220,
0
]
],
"lastCommittedPoint": null,
"startBinding": {
"elementId": "ehq2knMV5F3_1e_PpVBWH",
"focus": -0.5,
"gap": 20
},
"endBinding": null,
"startArrowhead": null,
"endArrowhead": "arrow"
},
{
"id": "DQyXiYF_swzbHKTnJgWV0",
"type": "arrow",
"x": 740,
"y": 680,
"width": 0,
"height": 80,
"angle": 0,
"strokeColor": "#000000",
"backgroundColor": "transparent",
"fillStyle": "hachure",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"groupIds": [],
"strokeSharpness": "round",
"seed": 955854661,
"version": 7,
"versionNonce": 1689213285,
"isDeleted": false,
"boundElements": null,
"updated": 1660658585285,
"link": null,
"locked": false,
"points": [
[
0,
0
],
[
0,
80
]
],
"lastCommittedPoint": null,
"startBinding": null,
"endBinding": {
"elementId": "7tycgTrlIwWUIYouO52v1",
"focus": -0.05,
"gap": 27
},
"startArrowhead": null,
"endArrowhead": "arrow"
},
{
"id": "0COi-1znrSkFnzKLwa2nZ",
"type": "text",
"x": 860,
"y": 300,
"width": 169,
"height": 25,
"angle": 0,
"strokeColor": "#000000",
"backgroundColor": "transparent",
"fillStyle": "hachure",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"groupIds": [],
"strokeSharpness": "round",
"seed": 361987243,
"version": 19,
"versionNonce": 633884555,
"isDeleted": false,
"boundElements": null,
"updated": 1660658661252,
"link": null,
"locked": false,
"text": "CCT (Payload 3)",
"fontSize": 20,
"fontFamily": 1,
"textAlign": "left",
"verticalAlign": "top",
"baseline": 18,
"containerId": null,
"originalText": "CCT (Payload 3)"
},
{
"id": "GOeo7bMI5UomjDs4gggUU",
"type": "text",
"x": 872,
"y": 609,
"width": 93,
"height": 25,
"angle": 0,
"strokeColor": "#000000",
"backgroundColor": "transparent",
"fillStyle": "hachure",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"groupIds": [],
"strokeSharpness": "round",
"seed": 290042603,
"version": 29,
"versionNonce": 1372433323,
"isDeleted": false,
"boundElements": null,
"updated": 1660658609493,
"link": null,
"locked": false,
"text": "Payload 1",
"fontSize": 20,
"fontFamily": 1,
"textAlign": "left",
"verticalAlign": "top",
"baseline": 18,
"containerId": null,
"originalText": "Payload 1"
},
{
"id": "PvGVhBQP8k0L9JKuOs4Qs",
"type": "text",
"x": 460,
"y": 680,
"width": 120,
"height": 75,
"angle": 0,
"strokeColor": "#000000",
"backgroundColor": "transparent",
"fillStyle": "hachure",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"groupIds": [],
"strokeSharpness": "round",
"seed": 126942443,
"version": 38,
"versionNonce": 1186306917,
"isDeleted": false,
"boundElements": null,
"updated": 1660658626284,
"link": null,
"locked": false,
"text": "Tokens\n+\nInstructions",
"fontSize": 20,
"fontFamily": 1,
"textAlign": "left",
"verticalAlign": "top",
"baseline": 68,
"containerId": null,
"originalText": "Tokens\n+\nInstructions"
},
{
"id": "Qc7TUAJKX-dAauc2vxyko",
"type": "text",
"x": 766,
"y": 711,
"width": 69,
"height": 25,
"angle": 0,
"strokeColor": "#000000",
"backgroundColor": "transparent",
"fillStyle": "hachure",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"groupIds": [],
"strokeSharpness": "round",
"seed": 1995949605,
"version": 14,
"versionNonce": 390045291,
"isDeleted": false,
"boundElements": null,
"updated": 1660658633957,
"link": null,
"locked": false,
"text": "Tokens",
"fontSize": 20,
"fontFamily": 1,
"textAlign": "left",
"verticalAlign": "top",
"baseline": 18,
"containerId": null,
"originalText": "Tokens"
},
{
"id": "c7gi0tTVTNV1URj8uCxlj",
"type": "text",
"x": 625,
"y": 838,
"width": 161,
"height": 25,
"angle": 0,
"strokeColor": "#000000",
"backgroundColor": "transparent",
"fillStyle": "hachure",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"groupIds": [],
"strokeSharpness": "round",
"seed": 14913829,
"version": 29,
"versionNonce": 1740389477,
"isDeleted": false,
"boundElements": null,
"updated": 1660658644949,
"link": null,
"locked": false,
"text": "End User Wallet",
"fontSize": 20,
"fontFamily": 1,
"textAlign": "left",
"verticalAlign": "top",
"baseline": 18,
"containerId": null,
"originalText": "End User Wallet"
},
{
"id": "2Kb1vlwx5LQ5HECeVoTRv",
"type": "text",
"x": 560,
"y": 460,
"width": 194,
"height": 25,
"angle": 0,
"strokeColor": "#000000",
"backgroundColor": "transparent",
"fillStyle": "hachure",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"groupIds": [],
"strokeSharpness": "round",
"seed": 853385995,
"version": 36,
"versionNonce": 1610184677,
"isDeleted": false,
"boundElements": null,
"updated": 1660658657935,
"link": null,
"locked": false,
"text": "Wormhole Contracts",
"fontSize": 20,
"fontFamily": 1,
"textAlign": "left",
"verticalAlign": "top",
"baseline": 18,
"containerId": null,
"originalText": "Wormhole Contracts"
},
{
"id": "N4_9tSTbCy6viiNuYtIfb",
"type": "text",
"x": 600,
"y": 300,
"width": 131,
"height": 25,
"angle": 0,
"strokeColor": "#000000",
"backgroundColor": "transparent",
"fillStyle": "hachure",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"groupIds": [],
"strokeSharpness": "round",
"seed": 1253632197,
"version": 32,
"versionNonce": 252867915,
"isDeleted": false,
"boundElements": null,
"updated": 1660658695973,
"link": null,
"locked": false,
"text": "Remote Chain",
"fontSize": 20,
"fontFamily": 1,
"textAlign": "left",
"verticalAlign": "top",
"baseline": 18,
"containerId": null,
"originalText": "Remote Chain"
},
{
"id": "yqZBl2AHX7eqNQCimd87q",
"type": "text",
"x": 1160,
"y": 300,
"width": 93,
"height": 25,
"angle": 0,
"strokeColor": "#000000",
"backgroundColor": "transparent",
"fillStyle": "hachure",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"groupIds": [],
"strokeSharpness": "round",
"seed": 467153989,
"version": 13,
"versionNonce": 1364173797,
"isDeleted": false,
"boundElements": null,
"updated": 1660658702071,
"link": null,
"locked": false,
"text": "Hub Chain",
"fontSize": 20,
"fontFamily": 1,
"textAlign": "left",
"verticalAlign": "top",
"baseline": 18,
"containerId": null,
"originalText": "Hub Chain"
},
{
"id": "nuva4zhNpJpwgn-AzHsWQ",
"type": "text",
"x": 1160,
"y": 460,
"width": 89,
"height": 50,
"angle": 0,
"strokeColor": "#000000",
"backgroundColor": "transparent",
"fillStyle": "hachure",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 1,
"opacity": 100,
"groupIds": [],
"strokeSharpness": "round",
"seed": 1506304907,
"version": 35,
"versionNonce": 259197899,
"isDeleted": false,
"boundElements": null,
"updated": 1660658736208,
"link": null,
"locked": false,
"text": "Your \nContract",
"fontSize": 20,
"fontFamily": 1,
"textAlign": "left",
"verticalAlign": "top",
"baseline": 43,
"containerId": null,
"originalText": "Your \nContract"
}
],
"appState": {
"gridSize": 20,
"viewBackgroundColor": "#ffffff"
},
"files": {}
}