Skip to content

Commit

Permalink
merge 'hyperlane/feat-token-extensions' into 'feat-token-extensions'
Browse files Browse the repository at this point in the history
  • Loading branch information
EgeCaner committed Sep 15, 2024
2 parents f92d6d1 + c89b758 commit 18263ce
Show file tree
Hide file tree
Showing 45 changed files with 2,695 additions and 104 deletions.
33 changes: 33 additions & 0 deletions .github/workflows/label-prs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Label PRs for feat-token-extensions

on:
pull_request:
branches:
- feat-token-extensions

jobs:
tag-and-label:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Add label to PR
uses: actions/github-script@v7
with:
script: |
github.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
labels: ['feat-token-extensions']
})
- name: Add Tag to PR Title
run: |
gh pr edit ${{ github.event.pull_request.number }} --add-label "feat-token-extensions"
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
scripts/node_modules
scripts/.env
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,23 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d

<!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!


## 🪛 Deployment

This section details the steps to deploy Hyperlane contracts on Starknet. Note that the deployment script will set a basic configuration for all the required contracts. Further configuration process might be required based on the use case. Constructors parameters can be specified in the `contract_config.json`.
Firstly, set the following environment variables, important for the deployment process:
```bash
STARKNET_RPC_URL=
ACCOUNT_ADDRESS=
BENEFICIARY_ADDRESS=
NETWORK=
PRIVATE_KEY=
```
The beneficiary address is the account that will be used to recover funds from the protocol fee.
Once set, the contracts can be deployed using this command( assuming `ts-node` is installed):

```bash
ts-node deploy.ts
```
14 changes: 7 additions & 7 deletions cairo/Scarb.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version = 1
[[package]]
name = "alexandria_bytes"
version = "0.1.0"
source = "git+https://github.com/keep-starknet-strange/alexandria.git#b5c8356ce7d46a3665e08a8016d5abc02d9b0fe2"
source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=bcdca70#bcdca70afdf59c9976148e95cebad5cf63d75a7f"
dependencies = [
"alexandria_data_structures",
"alexandria_math",
Expand All @@ -13,15 +13,15 @@ dependencies = [
[[package]]
name = "alexandria_data_structures"
version = "0.2.0"
source = "git+https://github.com/keep-starknet-strange/alexandria.git#b5c8356ce7d46a3665e08a8016d5abc02d9b0fe2"
source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=bcdca70#bcdca70afdf59c9976148e95cebad5cf63d75a7f"
dependencies = [
"alexandria_encoding",
]

[[package]]
name = "alexandria_encoding"
version = "0.1.0"
source = "git+https://github.com/keep-starknet-strange/alexandria.git#b5c8356ce7d46a3665e08a8016d5abc02d9b0fe2"
source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=bcdca70#bcdca70afdf59c9976148e95cebad5cf63d75a7f"
dependencies = [
"alexandria_bytes",
"alexandria_math",
Expand All @@ -31,15 +31,15 @@ dependencies = [
[[package]]
name = "alexandria_math"
version = "0.2.0"
source = "git+https://github.com/keep-starknet-strange/alexandria.git#b5c8356ce7d46a3665e08a8016d5abc02d9b0fe2"
source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=bcdca70#bcdca70afdf59c9976148e95cebad5cf63d75a7f"
dependencies = [
"alexandria_data_structures",
]

[[package]]
name = "alexandria_numeric"
version = "0.1.0"
source = "git+https://github.com/keep-starknet-strange/alexandria.git#b5c8356ce7d46a3665e08a8016d5abc02d9b0fe2"
source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=bcdca70#bcdca70afdf59c9976148e95cebad5cf63d75a7f"
dependencies = [
"alexandria_math",
"alexandria_searching",
Expand All @@ -48,15 +48,15 @@ dependencies = [
[[package]]
name = "alexandria_searching"
version = "0.1.0"
source = "git+https://github.com/keep-starknet-strange/alexandria.git#b5c8356ce7d46a3665e08a8016d5abc02d9b0fe2"
source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=bcdca70#bcdca70afdf59c9976148e95cebad5cf63d75a7f"
dependencies = [
"alexandria_data_structures",
]

[[package]]
name = "alexandria_storage"
version = "0.3.0"
source = "git+https://github.com/keep-starknet-strange/alexandria.git#bcdca70afdf59c9976148e95cebad5cf63d75a7f"
source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=bcdca70#bcdca70afdf59c9976148e95cebad5cf63d75a7f"

[[package]]
name = "hyperlane_starknet"
Expand Down
4 changes: 2 additions & 2 deletions cairo/Scarb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ cairo-version = "2.6.3"

[dependencies]
starknet = "2.6.3"
alexandria_bytes = { git = "https://github.com/keep-starknet-strange/alexandria.git" }
alexandria_storage = { git = "https://github.com/keep-starknet-strange/alexandria.git" }
alexandria_bytes = { git = "https://github.com/keep-starknet-strange/alexandria.git", rev = "bcdca70" }
alexandria_storage = { git = "https://github.com/keep-starknet-strange/alexandria.git", rev = "bcdca70" }
openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.14.0" }


Expand Down
48 changes: 48 additions & 0 deletions cairo/src/contracts/client/gas_router_component.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,25 @@ pub trait IGasRouter<TState> {
fn quote_gas_payment(self: @TState, destination_domain: u32) -> u256;
}

/// # Gas Router Component Module
///
/// This module provides a gas management mechanism for routing messages across domains.
/// It allows setting gas limits for specific destinations and quoting gas payments for
/// message dispatches.
///
/// ## Key Concepts
///
/// - **Gas Configuration**: This module allows users to set gas limits for specific destination
/// domains, either individually or through an array of configurations.
///
/// - **Message Dispatching**: Gas management is integrated with the message dispatch system,
/// enabling the module to quote gas payments for dispatching messages to other domains.
///
/// - **Ownership-based Access Control**: The ability to set gas limits is restricted to the
/// contract owner.
///
/// - **Component Composition**: The `GasRouterComponent` integrates with other components such as
/// `RouterComponent` for dispatching messages and `MailboxclientComponent` for mailbox interactions.
#[starknet::component]
pub mod GasRouterComponent {
use alexandria_bytes::{Bytes, BytesTrait};
Expand Down Expand Up @@ -47,6 +66,22 @@ pub mod GasRouterComponent {
impl Router: RouterComponent::HasComponent<TContractState>,
impl Owner: OwnableComponent::HasComponent<TContractState>,
> of super::IGasRouter<ComponentState<TContractState>> {
/// Sets the gas limit for a specified domain or applies an array of gas configurations.
///
/// This function allows the contract owner to configure gas limits for one or multiple domains.
/// If an array of `GasRouterConfig` is provided via `gas_configs`, the function iterates over
/// the array and applies each configuration. If a specific `domain` and `gas` are provided,
/// the function sets the gas limit for that domain.
///
/// # Arguments
///
/// * `gas_configs` - An optional array of `GasRouterConfig`, each containing a `domain` and a `gas` value.
/// * `domain` - An optional `u32` representing the domain for which the gas limit is being set.
/// * `gas` - An optional `u256` representing the gas limit for the given domain.
///
/// # Panics
///
/// Panics if neither `gas_configs` nor a valid `domain` and `gas` are provided.
fn set_destination_gas(
ref self: ComponentState<TContractState>,
gas_configs: Option<Array<GasRouterConfig>>,
Expand Down Expand Up @@ -78,6 +113,19 @@ pub mod GasRouterComponent {
}
}

/// Returns the quoted gas payment for dispatching a message to the specified domain.
///
/// This function calculates and returns the gas payment required to dispatch a message
/// to a specified destination domain. It uses the router and mailbox components to compute
/// the necessary gas amount for the message dispatch.
///
/// # Arguments
///
/// * `destination_domain` - A `u32` representing the domain to which the message is being sent.
///
/// # Returns
///
/// A `u256` value representing the quoted gas payment.
fn quote_gas_payment(
self: @ComponentState<TContractState>, destination_domain: u32
) -> u256 {
Expand Down
84 changes: 83 additions & 1 deletion cairo/src/contracts/client/router_component.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ pub trait IRouter<TState> {
fn routers(self: @TState, domain: u32) -> u256;
}

/// # Router Component Module
///
/// This module implements a router component that manages the enrollment and
/// unenrollment of remote routers across various domains. It provides the
/// functionality for dispatching messages to remote routers and handling incoming
/// messages. The core functionality is split across traits, with the primary logic
/// provided by the `IRouter` trait and the additional internal mechanisms handled
/// by the `RouterComponent`.
#[starknet::component]
pub mod RouterComponent {
use alexandria_bytes::Bytes;
Expand Down Expand Up @@ -46,14 +54,23 @@ pub mod RouterComponent {
}

#[embeddable_as(RouterImpl)]
impl Router<
pub impl Router<
TContractState,
+HasComponent<TContractState>,
+MailboxclientComponent::HasComponent<TContractState>,
impl Owner: OwnableComponent::HasComponent<TContractState>,
+Drop<TContractState>,
impl Hook: IMessageRecipientInternalHookTrait<TContractState>
> of super::IRouter<ComponentState<TContractState>> {
/// Enrolls a remote router for the specified `domain`.
///
/// This function requires ownership verification before proceeding. Once verified,
/// it calls the internal method `_enroll_remote_router` to complete the enrollment.
///
/// # Arguments
///
/// * `domain` - A `u32` representing the domain for which the router is being enrolled.
/// * `router` - A `u256` representing the address of the router to be enrolled.
fn enroll_remote_router(
ref self: ComponentState<TContractState>, domain: u32, router: u256
) {
Expand All @@ -62,6 +79,20 @@ pub mod RouterComponent {
self._enroll_remote_router(domain, router);
}

/// Enrolls multiple remote routers across multiple `domains`.
///
/// This function requires ownership verification. It checks that the lengths of the
/// `domains` and `addresses` arrays are the same, then enrolls each router for its
/// corresponding domain using `_enroll_remote_router`.
///
/// # Arguments
///
/// * `domains` - An array of `u32` values representing the domains for which routers are being enrolled.
/// * `addresses` - An array of `u256` values representing the addresses of the routers to be enrolled.
///
/// # Panics
///
/// Panics if the lengths of `domains` and `addresses` do not match.
fn enroll_remote_routers(
ref self: ComponentState<TContractState>, domains: Array<u32>, addresses: Array<u256>
) {
Expand All @@ -80,13 +111,29 @@ pub mod RouterComponent {
}
}

/// Unenrolls the router for the specified `domain`.
///
/// This function requires ownership verification. Once verified, it calls the internal method
/// `_unenroll_remote_router` to complete the unenrollment.
///
/// # Arguments
///
/// * `domain` - A `u32` representing the domain for which the router is being unenrolled.
fn unenroll_remote_router(ref self: ComponentState<TContractState>, domain: u32) {
let mut ownable_comp = get_dep_component_mut!(ref self, Owner);
ownable_comp.assert_only_owner();

self._unenroll_remote_router(domain);
}

/// Unenrolls the routers for multiple `domains`.
///
/// This function removes the router for each domain in the `domains` array
/// using the `_unenroll_remote_router` method.
///
/// # Arguments
///
/// * `domains` - An array of `u32` values representing the domains for which routers are being unenrolled.
fn unenroll_remote_routers(ref self: ComponentState<TContractState>, domains: Array<u32>,) {
let domains_len = domains.len();
let mut i = 0;
Expand All @@ -96,6 +143,21 @@ pub mod RouterComponent {
}
}

/// Handles an incoming message from a remote router.
///
/// This function checks if a remote router is enrolled for the `origin` domain, verifies that the
/// `sender` matches the enrolled router, and calls the `_handle` method on the `Hook` to process
/// the message.
///
/// # Arguments
///
/// * `origin` - A `u32` representing the origin domain of the message.
/// * `sender` - A `u256` representing the address of the message sender.
/// * `message` - The message payload as a `Bytes` object.
///
/// # Panics
///
/// Panics if the sender does not match the enrolled router for the origin domain.
fn handle(
ref self: ComponentState<TContractState>, origin: u32, sender: u256, message: Bytes
) {
Expand All @@ -105,10 +167,30 @@ pub mod RouterComponent {
Hook::_handle(ref self, origin, sender, message);
}

/// Returns an array of enrolled domains.
///
/// This function reads the keys from the `routers` map, which represent the enrolled
/// domains.
///
/// # Returns
///
/// An array of `u32` values representing the enrolled domains.
fn domains(self: @ComponentState<TContractState>) -> Array<u32> {
self.routers.read().keys()
}

/// Returns the router address for a given `domain`.
///
/// This function retrieves the address of the enrolled router for the specified
/// `domain` from the `routers` map.
///
/// # Arguments
///
/// * `domain` - A `u32` representing the domain for which the router address is being queried.
///
/// # Returns
///
/// A `u256` value representing the router address for the specified domain.
fn routers(self: @ComponentState<TContractState>, domain: u32) -> u256 {
self.routers.read().get(domain)
}
Expand Down
Loading

0 comments on commit 18263ce

Please sign in to comment.