Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Martinh/solidity sdk #101

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .snippets/code/build/toolkit/solidity-sdk/solidity-sdk-1.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.19;

import "wormhole-sdk/interfaces/IWormholeReceiver.sol";
import "wormhole-sdk/interfaces/IWormholeRelayer.sol";
import "wormhole-sdk/constants/Chains.sol";
import "wormhole-sdk/Utils.sol";

import {Base} from "wormhole-sdk/WormholeRelayer/Base.sol";
import {TokenBase, TokenReceiver, TokenSender} from "wormhole-sdk/WormholeRelayer/TokenBase.sol";
import {CCTPBase, CCTPReceiver, CCTPSender} from "wormhole-sdk/WormholeRelayer/CCTPBase.sol";
import {CCTPAndTokenBase, CCTPAndTokenReceiver, CCTPAndTokenSender} from "wormhole-sdk/WormholeRelayer/CCTPAndTokenBase.sol";
55 changes: 55 additions & 0 deletions .snippets/code/build/toolkit/solidity-sdk/solidity-sdk-2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.19;

import "wormhole-sdk/interfaces/IWormholeReceiver.sol";
import "wormhole-sdk/interfaces/IWormholeRelayer.sol";
import "wormhole-sdk/interfaces/IWormhole.sol";
import "wormhole-sdk/Utils.sol";

abstract contract Base {
IWormholeRelayer public immutable wormholeRelayer;
IWormhole public immutable wormhole;

address registrationOwner;
mapping(uint16 => bytes32) registeredSenders;

constructor(address _wormholeRelayer, address _wormhole) {
wormholeRelayer = IWormholeRelayer(_wormholeRelayer);
wormhole = IWormhole(_wormhole);
registrationOwner = msg.sender;
}

modifier onlyWormholeRelayer() {
require(
msg.sender == address(wormholeRelayer),
"Msg.sender is not Wormhole Relayer"
);
_;
}

modifier isRegisteredSender(uint16 sourceChain, bytes32 sourceAddress) {
require(
registeredSenders[sourceChain] == sourceAddress,
"Not registered sender"
);
_;
}

/**
* Sets the registered address for 'sourceChain' to 'sourceAddress'
* So that for messages from 'sourceChain', only ones from 'sourceAddress' are valid
*
* Assumes only one sender per chain is valid
* Sender is the address that called 'send' on the Wormhole Relayer contract on the source chain)
*/
function setRegisteredSender(
uint16 sourceChain,
bytes32 sourceAddress
) public {
require(
msg.sender == registrationOwner,
"Not allowed to set registered sender"
);
registeredSenders[sourceChain] = sourceAddress;
}
}
26 changes: 26 additions & 0 deletions .snippets/code/build/toolkit/solidity-sdk/solidity-sdk-3.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
pragma solidity ^0.8.19;

import "@wormhole-foundation/wormhole-solidity-sdk/src/WormholeRelayer/Base.sol";

contract CrossChainSender is Base {
constructor(
address _wormholeRelayer,
address _wormhole
) Base(_wormholeRelayer, _wormhole) {}

function sendMessage(
bytes memory message,
uint16 targetChain,
bytes32 targetAddress
) external payable {
// Register sender and send message through WormholeRelayer
setRegisteredSender(targetChain, msg.sender);
onlyWormholeRelayer().sendPayloadToEvm(
targetChain,
address(targetAddress),
message,
0,
500_000
);
}
}
20 changes: 20 additions & 0 deletions .snippets/code/build/toolkit/solidity-sdk/solidity-sdk-4.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
pragma solidity ^0.8.19;

import "@wormhole-foundation/wormhole-solidity-sdk/src/WormholeRelayer/TokenBase.sol";

contract CrossChainTokenSender is TokenSender {
constructor(
address _wormholeRelayer,
address _wormhole
) TokenSender(_wormholeRelayer, _wormhole) {}

function sendToken(
address token,
uint256 amount,
uint16 targetChain,
bytes32 targetAddress
) external payable {
// Send tokens across chains
transferTokenToTarget(token, amount, targetChain, targetAddress);
}
}
22 changes: 22 additions & 0 deletions .snippets/code/build/toolkit/solidity-sdk/solidity-sdk-5.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
pragma solidity ^0.8.19;

import "@wormhole-foundation/wormhole-solidity-sdk/src/WormholeRelayer/TokenBase.sol";

contract CrossChainTokenReceiver is TokenReceiver {
constructor(
address _wormholeRelayer,
address _wormhole
) TokenReceiver(_wormholeRelayer, _wormhole) {}

// Function to handle received tokens from another chain
function receiveWormholeMessages(
bytes memory payload,
bytes[] memory additionalMessages,
bytes32 sourceAddress,
uint16 sourceChain,
bytes32 deliveryHash
) external payable override {
// Process the received tokens here
receiveTokens(payload);
}
}
1 change: 1 addition & 0 deletions build/toolkit/.pages
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ nav:
- 'Wormholescan': 'https://wormholescan.io/'
- 'Wormhole CLI' : 'cli.md'
- 'Wormhole SDK' : '/docs/build/applications/wormhole-sdk/'
- 'Solidity SDK': 'solidity-sdk.md'
- 'Tilt': 'tilt.md'
8 changes: 8 additions & 0 deletions build/toolkit/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ Regardless of which network development environment you are using, there are a f

[:octicons-arrow-right-16: Get started with the SDK](/docs/build/applications/wormhole-sdk/)

- :octicons-file-code-16:{ .lg .middle } **Solidity SDK**

---

Learn about Wormhole's Solidity SDK, including key components, interfaces, and tools for developing cross-chain decentralized applications on EVM-compatible blockchains.

[:octicons-arrow-right-16: Get started with the SDK](/docs/build/applications/solidity-sdk/)

- :octicons-beaker-16:{ .lg .middle } **Tilt**

---
Expand Down
232 changes: 232 additions & 0 deletions build/toolkit/solidity-sdk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
---
title: Solidity SDK
description: How to use the Wormhole Solidity SDK for cross-chain messaging, token transfers, and integrating decentralized applications on EVM-compatible blockchains.
---

# Solidity SDK

## Introduction

The [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} simplifies cross-chain messaging on EVM-compatible chains by providing essential Solidity interfaces, utility libraries, and testing tools. It allows developers to build secure and efficient cross-chain decentralized applications (dApps) without manually interacting with Wormhole’s core contracts across multiple chains.
martin0995 marked this conversation as resolved.
Show resolved Hide resolved

By abstracting away complex interactions, the SDK drastically reduces the overhead associated with cross-chain development. It provides:

- **Unified interfaces** - developers can use a standardized set of Solidity interfaces to handle cross-chain messaging, token transfers, and verifiable action approvals (VAAs) without needing to manage the underlying infrastructure
- **Automated message delivery** - the SDK leverages Wormhole’s relayer infrastructure, automatically delivering messages across chains, reducing the need for manual intervention, and simplifying gas management on the target chain
- **Seamless integration with Wormhole services** - the SDK integrates with Wormhole’s `TokenBridge` and Circle’s CCTP, providing built-in mechanisms for cross-chain asset transfers, making token bridges and cross-chain messaging easy to implement
- **Testing and development tools** - it comes with comprehensive tools for local testing and simulation, allowing developers to validate their cross-chain logic before deployment, minimizing the risk of errors in production environments

These features significantly streamline the development workflow by reducing complexity and offering tools compatible with various EVM versions. This helps developers avoid issues that arise from differences in EVM equivalence across chains.

This guide covers installation, key concepts, and usage examples to help you build secure cross-chain applications using the SDK, from token transfers to advanced message passing.

## Installation

To install the SDK, use [Foundry and Forge](https://book.getfoundry.sh/getting-started/installation){target=\_blank}. This pulls the necessary libraries into your project:

```bash
forge install wormhole-foundation/[email protected]
```

When developing cross-chain applications, ensure that the chains you target support the EVM version you’re using. For instance, the PUSH0 opcode (introduced in Solidity 0.8.20) may not be available on all chains. To avoid compatibility issues, you can set the EVM version in your `foundry.toml` file:

```toml
evm_version = "paris"
```

This ensures compatibility across all targeted chains, even if some do not yet support the latest EVM upgrades.

## Key Considerations

Before deploying applications using the Wormhole Solidity SDK, keep these considerations in mind:

- **Version compatibility** - the SDK is evolving, and using tagged releases for production is crucial, as the main branch may introduce breaking changes
- **IERC-20 remapping** - the SDK provides a remapping mechanism to handle potential conflicts between different implementations of IERC20, ensuring seamless integration with other libraries
- **Testing** - given the cross-chain dependencies, testing all integrations is critical to avoid issues in production environments

## Concepts and Components

The Wormhole Solidity SDK consists of key components that streamline cross-chain communication, allowing developers to securely and efficiently interact with Wormhole’s infrastructure. Below are the critical concepts and contracts you'll encounter when working with the SDK.

### Cross-Chain Messaging with `WormholeRelayerSDK.sol`

The [`WormholeRelayerSDK.sol`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/WormholeRelayerSDK.sol){target=\_blank} contract simplifies cross-chain messaging and asset transfers by integrating several necessary modules, including the Wormhole relayer. By automating message delivery between chains, the Wormhole relayer removes the need for developers to manage relayer infrastructure or handle gas on the target chain. Delivery providers handle the message payload, ensuring secure and efficient communication.

- **Why it’s important?** - the relayer automates message delivery, removing manual intervention and ensuring secure, gas-efficient communication across chains
- **Learn more** - refer to the [Wormhole Relayer documentation](/docs/build/contract-integrations/wormhole-relayers/){target=\_blank} for deeper details

Key Modules in the SDK include:

- **`Base.sol`** - the core module for cross-chain messaging. It provides utility functions like `onlyWormholeRelayer()` and `setRegisteredSender()`, ensuring that only messages from trusted relayers are processed

- **`TokenBase.sol`** - this module extends the base messaging functionality to support cross-chain token transfers. It includes utilities for securely sending and receiving tokens between EVM-compatible chains

- **`CCTPBase.sol`** - designed for Circle’s Cross-Chain Transfer Protocol, this module manages asset transfers such as USDC between chains. It includes functionalities for both sending and receiving CCTP-based assets

- **`CCTPAndTokenBase.sol`** - a combined module that supports token and CCTP-based asset transfers in a single implementation. This module simplifies development for applications needing to handle both types of transfers

The Wormhole Solidity SDK offers a unified framework for cross-chain communication. Developers can select specific modules based on their application’s requirements, whether for messaging, token transfers, or CCTP. Each module includes built-in security measures, ensuring that only authorized senders or relayers are accepted, thereby protecting the application from unauthorized interactions.

Please refer to the complete `WormholeRelayerSDK.sol` file below for further details.

???- code "`WormholeRelayerSDK.sol`"
```solidity
--8<-- "code/build/toolkit/solidity-sdk/solidity-sdk-1.sol"
```

### `Base.sol` Contract Overview

The [`Base.sol`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/WormholeRelayer/Base.sol){target=\_blank} contract is a core part of the SDK, providing fundamental helper functions and modifiers to manage cross-chain messages securely. This contract integrates both the Wormhole relayer and the `TokenBridge`.

- **`onlyWormholeRelayer()`** - ensures only authorized messages from the Wormhole Relayer contract are processed

```solidity
--8<-- "code/build/toolkit/solidity-sdk/solidity-sdk-2.sol:22:28"
```

- **`setRegisteredSender()`** - restricts message acceptance to a registered sender from a specific chain, ensuring messages are only processed from trusted sources

```solidity
--8<-- "code/build/toolkit/solidity-sdk/solidity-sdk-2.sol:45:54"
```

These security measures ensure messages come from the correct source and are processed securely. Please refer to the complete `Base.sol` contract below for further details.

???- code "`Base.sol`"
```solidity
--8<-- "code/build/toolkit/solidity-sdk/solidity-sdk-2.sol"
```

### Interface for Sending Cross-Chain Messages

The [`IWormholeRelayer`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/IWormholeRelayer.sol){target=\_blank} interface provides key methods for sending messages across chains. It is integral for developers who want to pass instructions, token transfers, or any custom payload between EVM-compatible chains without maintaining their relaying infrastructure.

- **`sendPayloadToEvm()`** - sends a message to a specific chain along with gas and value. Valid for general cross-chain messaging

```solidity
function sendPayloadToEvm(
uint16 targetChain,
address targetAddress,
bytes memory payload,
uint256 receiverValue,
uint256 gasLimit
) external payable returns (uint64 sequence);
```

- **`sendVaasToEvm()`** - sends both a payload and any associated VAAs, such as those required for cross-chain token transfers, to another chain

```solidity
function sendVaasToEvm(
uint16 targetChain,
address targetAddress,
bytes memory payload,
uint256 receiverValue,
uint256 gasLimit,
VaaKey[] memory vaaKeys
) external payable returns (uint64 sequence);
```

- **`quoteEVMDeliveryPrice()`** - calculates the required gas for a cross-chain delivery to help developers avoid underfunded transactions

```solidity
function quoteEVMDeliveryPrice(
uint16 targetChain,
uint256 receiverValue,
uint256 gasLimit
) external view returns (uint256 nativePriceQuote, uint256 targetChainRefundPerGasUnused);
```

- **`sendToEvm()`** - supports cross-chain token transfers through the `TokenBridge` and Circle CCTP. It allows transferring tokens and other data between chains, handling both the messaging and token aspects of the transaction

```solidity
function sendToEvm(
uint16 targetChain,
address targetAddress,
bytes memory payload,
uint256 receiverValue,
uint256 paymentForExtraReceiverValue,
uint256 gasLimit,
uint16 refundChain,
address refundAddress,
address deliveryProviderAddress,
MessageKey[] memory messageKeys,
uint8 consistencyLevel
) external payable returns (uint64 sequence);
```

These functions enable seamless communication across chains, reducing the complexity of multi-chain dApp development. By using `quoteEVMDeliveryPrice()`, developers can calculate the gas fees required for cross-chain deliveries, ensuring the transaction is adequately funded.

### Interface for Receiving Cross-Chain Messages

The [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interface defines the function your contract must implement to receive messages sent from other chains. This entry point for cross-chain messaging must be secured to accept messages only from the Wormhole relayer.

- **`receiveWormholeMessages()`** - handles the incoming message, allowing your contract to process cross-chain payloads

```solidity
function receiveWormholeMessages(
bytes memory payload,
bytes[] memory additionalMessages,
bytes32 sourceAddress,
uint16 sourceChain,
bytes32 deliveryHash
) external payable;
```

This function is the backbone of cross-chain message handling, ensuring payloads are processed correctly on the target chain.

### Advanced Concepts

For developers interested in exploring additional advanced topics, the following sections provide insights into key aspects of the SDK’s functionality.

???- note "Error Handling and Reverts"
The SDK defines several custom errors to help developers handle common issues like incorrect gas fees, invalid senders, and more. For example, `InvalidMsgValue` is thrown when the message value for a relayed message is erroneous.

```solidity
error InvalidMsgValue(uint256 msgValue, uint256 totalFee);
```

## Usage

This section covers cross-chain messaging and token transfers and shows how to use the Wormhole Solidity SDK in real-world scenarios.

### Send a Cross-Chain Message

To send a cross-chain message, inherit from the base contract provided by the SDK and use its helper methods to define your message and sender address. Here’s a basic example:

```solidity
--8<-- "code/build/toolkit/solidity-sdk/solidity-sdk-3.sol"
```

This contract extends `Base.sol` and allows sending cross-chain messages securely using the `WormholeRelayer`.

### Send Tokens Across Chains

The SDK enables seamless token transfers between EVM-compatible chains in addition to sending messages. To facilitate cross-chain token transfers, you can extend the SDK's `TokenSender` and `TokenReceiver` base contracts.

```solidity
--8<-- "code/build/toolkit/solidity-sdk/solidity-sdk-4.sol"
```

In this example, `TokenSender` initiates a token transfer to another chain. The SDK’s built-in utilities securely handle token transfers, ensuring proper VAAs are generated and processed.

### Receive Tokens Across Chains

To receive tokens on the target chain, implement a contract that inherits from `TokenReceiver` and overrides the `receiveWormholeMessages` function.

```solidity
--8<-- "code/build/toolkit/solidity-sdk/solidity-sdk-5.sol"
```

In this example, `TokenReceiver` allows the contract to handle tokens sent from the source chain. Once the cross-chain message is received, the `receiveWormholeMessages` function processes the incoming tokens. Always validate the message's authenticity and source.

!!! note
Always verify the source of incoming messages and tokens to prevent unauthorized access to your contract. Please refer to the [Emitter Verification](/docs/build/contract-integrations/core-contracts/#validating-the-emitter/){target=\_blank} section for more details.

## Testing Environment

The SDK includes built-in support for Forge-based testing, which allows you to test your cross-chain applications locally before deploying them to production. Testing with the same Solidity compiler version and configuration you plan to use in production is highly recommended to catch any potential issues early.

For a detailed example, check out the below repositories:

- [Cross chain messaging](/docs/tutorials/messaging/cross-chain-contracts/){target=\_blank}
- [Cross chain token transfer](/docs/tutorials/messaging/cross-chain-token-contracts/){target=\_blank}
Loading