Galactic Bridge
Intro to Galactic Bridge project
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.
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
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.
Burn
Mint method manually removes Chain-key Sol asset. This functionality will become part of the withdraw flow.
Key Functions
get_address
Returns Threshold ECDSA address ("ecdsa_public_key") in 3 formats:
compressed public key (size: 33 bytes, generated from icp)
uncompressed public key (size: 64 bytes, generated from compressed version via "libsecp256k1" library)
ethereum address (size: 20 bytes)
sign message
Signs a predefined message with "sign_with_ecdsa":
Returns:
coupon in json format
hex of coupon
signature
verify
Input:
signature
message
compressed key pair (via "k256" library)
Return: true/false
Example:
y_parity / recovery id
Input:
signature
message
compressed public key (via "k256" library)
Return: Recovery id -> 0/1
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:
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
.
Transfer:
Uses the
transfer
instruction from the system program to transfer lamports from the payer's account to the treasury account.
Event Emission:
Emits a
DepositEvent
with the receiver's ICP address and the deposited amount.
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:
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.
Signer Seeds:
Prepares seeds for treasury PDA (Program Derived Account).
Transfer:
Uses
transfer
with signer seeds to transfer lamports from treasury to receiver.
Success:
Returns
Ok(())
if successful.
Signature verification
This function
utils::verify
which is used inwithdraw
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 frommsg_address
andmsg_amount
.InvalidSignature
: The signature doesn't match the provided Ethereum public key.
Algorithm Flow:
Message Construction:
Creates a formatted string message containing
msg_address
andmsg_amount
.
Hashing:
Calculates the hash of the constructed message.
Data Hash Validation:
Compares the provided message bytes (
msg
) with the hash of the constructed message. If they don't match, it throws anInvalidDataHash
error, indicating a mismatch between the signed data and the claimed withdrawal details.
Signature Verification:
Attempts to recover the public key from the signature (
sig
) usingsolana_program::secp256k1_recover::secp256k1_recover
function.If the recovered public key matches the pubkey embeded in the program, it signifies a valid signature.
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.
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
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
to
address_icp
Burn Chain-key Sol and Withdraw Solana
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
User A executed burn transaction
Canister coupon with
sign_with_ecdsa
User A uses the returned data to invoke
withdraw in Solana Treasury Program
Withdraw Algorithm Solana
Algorithm Flow:
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.
Signer Seeds:
Prepares seeds for treasury PDA (Program Derived Account).
Transfer:
Uses
transfer
with signer seeds to transfer lamports from treasury to receiver.
Success:
Returns
Ok(())
if successful.
Signature Verification Solana
Algorithm Flow:
Message Construction:
Creates a formatted string message containing
msg_address
andmsg_amount
.
Hashing:
Calculates the hash of the constructed message.
Data Hash Validation:
Compares the provided message bytes (
msg
) with the hash of the constructed message. If they don't match, it throws anInvalidDataHash
error, indicating a mismatch between the signed data and the claimed withdrawal details.
Signature Verification:
Attempts to recover the public key from the signature (
sig
) usingsolana_program::secp256k1_recover::secp256k1_recover
function.If the recovered public key matches the pubkey embeded in the program, it signifies a valid signature.
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
Last updated