# Galactic Bridge

## Whats is it?

Galactic bridge is a protocol that allows users to bridge multiple blockchain tokens into internet computer. Galactic bridge v1 is mainly focused on Solana native token and SPL tokens. It will enable seamless bi-directional value exchange between Solana and ICP.  In next versions it could re-use the core logic and amend support for additional blockchains and assets.&#x20;

## Technical Overview

Galactic Bridge is using similar approach to ckETH and ckBTC. However, there are some differences caused by the Signature incompatibility. ICP can sign payload using tECDSA, where as Solana account generation is based on EdDSA. Because, of these specifics we cannot have a Solana account controlled by ICP Canister. We are solving this problem by implementing a Solana treasury Program that executes withdraws only after a valid tECDSA signed payload is provided and verified.

**Main technologies used:**

* Chain-key cryptography&#x20;
* Https Outcall
* ICP Canisters
* SNS\*

## System Components

There are 4 main components in Galactic Bridge v1:

* ICP Minter and Ledger Canisters
* Solana Treasury Program
* Solana RPC provider
* Frontend Application

### ICP Minter and Ledger Canister

**Mint**

Mint method manually generates Chain-key Sol asset. This functionality will become part of solana scrapper.

```
dfx canister call minter mint "(principal \"$USER_PRINCIPAL\", 1_000)"

dfx canister call ledger icrc1_balance_of "(record { owner = principal \"$USER_PRINCIPAL\" })"
```

**Burn**

Mint method manually removes Chain-key Sol asset. This functionality will become part of the withdraw flow.

```
dfx canister call ledger icrc2_approve "(record {
    spender = record { owner = principal \"$(dfx canister id minter)\" };
    amount = 1_000_000;
  })" --identity $USER_PRINCIPAL_NAME

dfx canister call minter burn "(1_000)" --identity $USER_PRINCIPAL_NAME

dfx canister call ledger icrc1_balance_of "(record { owner = principal \"$USER_PRINCIPAL\" })"

dfx canister call ledger icrc1_total_supply
```

**Key Functions**

**get\_address**

Returns Threshold ECDSA address ("ecdsa\_public\_key") in 3 formats:

1. compressed public key (size: 33 bytes, generated from icp)
2. uncompressed public key (size: 64 bytes, generated from compressed version via "libsecp256k1" library)
3. ethereum address (size: 20 bytes)

```
dfx canister call minter get_address
```

**sign message**

Signs a predefined message with "sign\_with\_ecdsa":

```
    let coupon = Coupon {
        address: "9gVndQ5SdugdFfGzyuKmePLRJZkCreKZ2iUTEg4agR5g".to_string(),
        amount: 10_000_000,
    };
```

Returns:

1. coupon in json format
2. hex of coupon
3. signature

```
dfx canister call minter sign
```

**verify**

Input:

1. signature
2. message
3. compressed key pair (via "k256" library)

Return: true/false

Example:

```
dfx canister call minter verify \
  '("fff722f41eb1cae151458c2d9acf16695984d1376a6a0a6ab56a385204f889370aec600906f278c5d9522d1df16ab50940827f96d7f62f61cd2ba33b28f2b7df", "{\"address\":\"9gVndQ5SdugdFfGzyuKmePLRJZkCreKZ2iUTEg4agR5g\",\"amount\":10000000}", "0269b3e4f4295275d99217c8d4f31a872d7af55c671fde7b0ed293650f9d1a4115")'
```

**y\_parity / recovery id**

Input:

1. signature
2. message
3. compressed public key (via "k256" library)

Return: Recovery id -> 0/1

```
dfx canister call minter y_parity \
  '("fff722f41eb1cae151458c2d9acf16695984d1376a6a0a6ab56a385204f889370aec600906f278c5d9522d1df16ab50940827f96d7f62f61cd2ba33b28f2b7df", "{\"address\":\"9gVndQ5SdugdFfGzyuKmePLRJZkCreKZ2iUTEg4agR5g\",\"amount\":10000000}", "0269b3e4f4295275d99217c8d4f31a872d7af55c671fde7b0ed293650f9d1a4115")'
```

**get\_ledger\_id**

```
dfx canister call minter get_ledger_id
```

### Solana Treasury Program

It implements the main business logic related to Solana.\
The main functions supported by the program are:

**Depositing SOL:**

* Users can deposit SOL by calling the `deposit` function with the desired amount and their ICP address.

  **Inputs:**

  * **Context ctx:** Provides access to relevant accounts and program information.
    * **payer:** This `Signer` account represents the party initiating the deposit and providing the funds.
    * **treasury:** This `SystemAccount` represents the account that will receive the deposited lamports.
    * **system\_program:** This `Program` account represents the Solana system program, which provides functionalities like transferring lamports between accounts.
  * **DepositData data:** Contains the deposit details:
    * **amount:** The amount of lamports to deposit (u64).
    * **address\_icp:** The ICP address to receive Chain-key Sol(String).

  **Event Emission:**

  * Emit a `DepositEvent` after a successful deposit.
  * This event provides information about the transaction to interested parties, enabling integration with other applications or monitoring systems.

    **Fields within DepositEvent:**

    * **address\_icp:** This field stores the receiver's ICP address obtained from the `data.address_icp` input.
    * **amount:** This field holds the deposited amount (`transfer_amount`) transferred from the payer to the treasury.

  **Outputs:**

  * **Result<()>:** Indicates success (Ok()) or an error (Err(DepositError)).
  * **DepositEvent:** An emitted event containing:
    * **address\_icp:** The ICP address to receive Chain-key Sol.
    * **amount:** The deposited amount.

  **Algorithm Flow:**

  1. **Validation:**
     * Checks if the payer is a signer. If not, returns `DepositError::PayerNotSigner`.
     * Verifies if the payer has enough lamports to cover the transfer. If not, returns `DepositError::PayerInsufficientAmount`.
  2. **Transfer:**
     * Uses the `transfer` instruction from the system program to transfer lamports from the payer's account to the treasury account.
  3. **Event Emission:**
     * Emits a `DepositEvent` with the receiver's ICP address and the deposited amount.
  4. **Success:**
     * Returns `Ok(())` to signal successful deposit.

**Withdrawing SOL:**

* Users can withdraw SOL from the treasury by calling `withdraw` function providing a signed message containing the withdrawal amount, receiver Solana address, a valid signature, and a valid data hash.

  **Inputs:**

  * **Context ctx:** Provides access to relevant accounts and program information.
  * **WithdrawData data:** Contains data for withdrawal:
    * **message:** A hashed message for verification (Vec).
    * **signature:** A signature over the message (\[u8; 64]).
    * **verify\_data:** Information for verification:
      * **address:** The recipient's address (String).
      * **amount:** The withdrawal amount in Ethereum format (u64).

  **Outputs:**

  * **Result<()>:** Indicates success (Ok()) or errors:
    * WithdrawError: Treasury-related issues.
    * ValidationError: Data or signature validation failures.

  **Algorithm Flow:**

  1. **Validation:**
     * Checks if the treasury has enough lamports for the withdrawal.
     * Calls `utils::verify` to verify:
       * Message hash matches the generated hash from verify\_data.
       * Signature validity using provided Ethereum public key.
  2. **Signer Seeds:**
     * Prepares seeds for treasury PDA (Program Derived Account).
  3. **Transfer:**
     * Uses `transfer` with signer seeds to transfer lamports from treasury to receiver.
  4. **Success:**
     * Returns `Ok(())` if successful.

**Signature verification**

* This function `utils::verify` which is used in `withdraw` before transfering lamports, verifies the integrity and authenticity of a withdrawal request in a Solana program.

  **Inputs:**

  * `eth_pubkey`: Ethereum public key which is hardcoded in the Treasury program, associated with the withdrawal request (\[u8; 64]).
  * `msg`: The message bytes representing the withdrawal information (Vec).
  * `sig`: The signature over the message (\[u8; 64]).
  * `msg_address`: The recipient's address for the withdrawal (String).
  * `msg_amount`: The withdrawal amount in Ethereum format (u64).

  **Outputs:**

  * `Result<()>`: Indicates success (Ok()) or error (Err(ValidationError)):
    * `InvalidDataHash`: The message hash doesn't match the data derived from `msg_address` and `msg_amount`.
    * `InvalidSignature`: The signature doesn't match the provided Ethereum public key.

  **Algorithm Flow:**

  1. **Message Construction:**
     * Creates a formatted string message containing `msg_address` and `msg_amount`.
  2. **Hashing:**
     * Calculates the hash of the constructed message.
  3. **Data Hash Validation:**
     * Compares the provided message bytes (`msg`) with the hash of the constructed message. If they don't match, it throws an `InvalidDataHash` error, indicating a mismatch between the signed data and the claimed withdrawal details.
  4. **Signature Verification:**
     * Attempts to recover the public key from the signature (`sig`) using `solana_program::secp256k1_recover::secp256k1_recover` function.
     * If the recovered public key matches the pubkey embeded in the program, it signifies a valid signature.
  5. **Validation Result:**

     * If no match is found for the recovered public key and the pubkey embeded in the program, it throws an `InvalidSignature` error, indicating the signature doesn't correspond to the provided public key.
     * If data and signature verification are successful, the function returns `Ok(())`.

### Frontend Application

Simplified UI that enables seamless wallet connection and Mint/Burn of ICP Chain-key Sol tokens.

<figure><img src="https://2514621625-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fay34DYG6V6TRhLBwuDSv%2Fuploads%2FrlfT9JqUNRSdp2RsXK3R%2FScreenshot%202024-03-07%20at%2016.42.56.png?alt=media&#x26;token=ef8fd2a7-7ca6-4985-bfc5-a304e71b8141" alt=""><figcaption><p>Figure 1 (Main Page)</p></figcaption></figure>

<figure><img src="https://2514621625-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fay34DYG6V6TRhLBwuDSv%2Fuploads%2Fnp2UfRF7Vg0x0ygSHzaJ%2FScreenshot%202024-03-07%20at%2016.43.13.png?alt=media&#x26;token=65bcfb24-eeff-4db1-9aee-449ccc5e543c" alt=""><figcaption><p>Figure 2 (Connect Wallet)</p></figcaption></figure>

<figure><img src="https://2514621625-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fay34DYG6V6TRhLBwuDSv%2Fuploads%2FehqKmw4GvIbyhQprWkll%2FScreenshot%202024-03-07%20at%2016.43.54.png?alt=media&#x26;token=462b855b-3bd2-4450-930c-52bf7d68cea0" alt=""><figcaption><p>Figure 3 (Mint Chain-key Sol)</p></figcaption></figure>

## Novelty and Algorithms

There are 2 main user flows in the protocol:

* **Deposit Solana tokens and Mint Chain-key Sol**
* **Burn Chain-key** **Sol and Withdraw Solana**

### Deposit Solana Tokens and Mint Chain-key Sol

<figure><img src="https://2514621625-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fay34DYG6V6TRhLBwuDSv%2Fuploads%2FYtQ3pd49GOc3GHWoSXEw%2FScreenshot%202024-03-07%20at%2016.51.11.png?alt=media&#x26;token=1497755a-277f-4d6e-9fc4-490375eec0d2" alt=""><figcaption><p>Figure 4 Deposit and Mint</p></figcaption></figure>

Deposit Algorithm is straight forward:

* User A deposits Solana tokens in Solana Treasury Program using `deposit function`
* Deposit data contains **`amount`**` ``and`` `**`address_icp`**
* Solana Program emits  **`DepositEvent`**
* ICP Minter canister fetches **`DepositEvent`**
* ICP Minter **`mint`** **Chain-key Sol** `to`` `**`address_icp`**

### Burn Chain-key Sol and Withdraw Solana

<figure><img src="https://2514621625-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fay34DYG6V6TRhLBwuDSv%2Fuploads%2FGp3o0h0kLSYY4vDBb973%2FScreenshot%202024-03-07%20at%2016.51.17.png?alt=media&#x26;token=e5297490-9311-44b3-a3d9-e1eda4dfaacb" alt=""><figcaption><p>Figure 5 Burn and Withdraw</p></figcaption></figure>

Burn and Withdaw algorithm is the novel part that we have researched and developed. Verifying the tECDSA signature on the Solana Treasury program side is allowing us to control the treasury funds. This approach is universal and can be used for EVM and non-EVM chains that support `Secp256k1.`

* User A gives **icrc2\_approve** to Ledger Canister&#x20;
* User A executed **burn** transaction
* Canister  coupon with **`sign_with_ecdsa`**

```
let coupon = Coupon {
        address: "9gVndQ5SdugdFfGzyuKmePLRJZkCreKZ2iUTEg4agR5g".to_string(),
        amount: 10_000_000,
    };
returns 
        1 coupon in json format
        2 hex of coupon
        3 signature
```

* User A uses the returned data to invoke `withdraw in Solana Treasury Program`

**Withdraw Algorithm Solana**

**Algorithm Flow:**

1. **Validation:**
   * Checks if the treasury has enough lamports for the withdrawal.
   * Calls `utils::verify` to verify:
     * Message hash matches the generated hash from verify\_data.
     * Signature validity using provided Ethereum public key.
2. **Signer Seeds:**
   * Prepares seeds for treasury PDA (Program Derived Account).
3. **Transfer:**
   * Uses `transfer` with signer seeds to transfer lamports from treasury to receiver.
4. **Success:**
   * Returns `Ok(())` if successful.

**Signature Verification Solana**

**Algorithm Flow:**

1. **Message Construction:**
   * Creates a formatted string message containing `msg_address` and `msg_amount`.
2. **Hashing:**
   * Calculates the hash of the constructed message.
3. **Data Hash Validation:**
   * Compares the provided message bytes (`msg`) with the hash of the constructed message. If they don't match, it throws an `InvalidDataHash` error, indicating a mismatch between the signed data and the claimed withdrawal details.
4. **Signature Verification:**
   * Attempts to recover the public key from the signature (`sig`) using `solana_program::secp256k1_recover::secp256k1_recover` function.
   * If the recovered public key matches the pubkey embeded in the program, it signifies a valid signature.
5. **Validation Result:**
   * If no match is found for the recovered public key and the pubkey embeded in the program, it throws an `InvalidSignature` error, indicating the signature doesn't correspond to the provided public key.
   * If data and signature verification are successful, the function returns `Ok(())`.

## Useful Links

* <https://github.com/weichain/galactic-bridge-icp>
* <https://github.com/weichain/galactic-bridge-sol>
* [https://github.com/weichain/galactic-bridge-fe](https://github.com/weichain/galactic-bridge-solhttps://github.com/weichain/galactic-bridge-fe)
* [https://drive.google.com/file/d/17Ut0TwhQCojSzX-v7KZFdxLC6Ak7DDxg/view?usp=sharing ](https://drive.google.com/file/d/17Ut0TwhQCojSzX-v7KZFdxLC6Ak7DDxg/view?usp=sharing)
* <https://internetcomputer.org/docs/current/developer-docs/getting-started/overview-of-icp>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://weichain.gitbook.io/galactic-bridge/galactic-bridge.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
