-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: add workspace for axelar gas service * feat: add refund impl and set up tests * feat: add impl for pay_native_gas_for_contract_call * feat: implement collect_fees chore: add back contract_id as output to the setup_emv test chore: update tests to pass in correct token address into refund chore: WIP - adding auth for refund methods and tests for emitted events chore: unwrapping index value * feat: update gas service unit tests * chore: remove vec from and add emitted event to collect_fees api * chore: cargo fmt * Update contracts/axelar-gas-service/Cargo.toml Co-authored-by: Milap Sheth <[email protected]> * Update contracts/axelar-gas-service/Cargo.toml Co-authored-by: Milap Sheth <[email protected]> * Update contracts/axelar-gas-service/src/contract.rs Co-authored-by: Milap Sheth <[email protected]> * Update contracts/axelar-gas-service/src/test.rs Co-authored-by: Milap Sheth <[email protected]> * Update contracts/axelar-gas-service/src/error.rs Co-authored-by: Milap Sheth <[email protected]> * Update contracts/axelar-gas-service/src/event.rs Co-authored-by: Milap Sheth <[email protected]> * Update contracts/axelar-gas-service/src/event.rs Co-authored-by: Milap Sheth <[email protected]> * Update contracts/axelar-gas-service/src/event.rs Co-authored-by: Milap Sheth <[email protected]> * Update contracts/axelar-gas-service/src/event.rs Co-authored-by: Milap Sheth <[email protected]> * Update contracts/axelar-gas-service/src/interface.rs Co-authored-by: Milap Sheth <[email protected]> * Update contracts/axelar-gas-service/src/lib.rs Co-authored-by: Milap Sheth <[email protected]> * chore: addressing latest comments on gas-service PR * chore: fmt code chore: fmt code chore: run cargo sort * chore: reduce parameter list size in pay_gas_for_contract_call * Update contracts/axelar-soroban-interfaces/src/axelar_gas_service.rs Co-authored-by: Milap Sheth <[email protected]> * Update contracts/axelar-soroban-interfaces/src/axelar_gas_service.rs Co-authored-by: Milap Sheth <[email protected]> * Update contracts/axelar-gas-service/src/contract.rs Co-authored-by: Milap Sheth <[email protected]> * Update contracts/axelar-soroban-interfaces/src/axelar_gas_service.rs Co-authored-by: Milap Sheth <[email protected]> * Update contracts/axelar-gas-service/src/contract.rs Co-authored-by: Milap Sheth <[email protected]> * Update packages/axelar-soroban-std/src/types.rs Co-authored-by: Milap Sheth <[email protected]> * Update contracts/axelar-soroban-interfaces/src/axelar_gas_service.rs Co-authored-by: Milap Sheth <[email protected]> * chore: refactor gas service chore: incorporate add'l comments * chore: update pay_gas_for_contract_call to use tranfer_from * Update contracts/axelar-gas-service/src/event.rs Co-authored-by: Milap Sheth <[email protected]> * Update contracts/axelar-gas-service/src/contract.rs Co-authored-by: Milap Sheth <[email protected]> * Update contracts/axelar-gas-service/src/contract.rs Co-authored-by: Milap Sheth <[email protected]> * Update contracts/axelar-gas-service/src/test.rs Co-authored-by: Milap Sheth <[email protected]> * Update contracts/axelar-gas-service/src/test.rs Co-authored-by: Milap Sheth <[email protected]> * chore: fix tests with variable name change --------- Co-authored-by: Milap Sheth <[email protected]> Co-authored-by: Milap Sheth <[email protected]>
- Loading branch information
1 parent
65a0891
commit 64fdccf
Showing
12 changed files
with
376 additions
and
1 deletion.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
[package] | ||
name = "axelar-gas-service" | ||
version = "0.1.0" | ||
edition = { workspace = true } | ||
|
||
[lib] | ||
crate-type = ["cdylib"] | ||
|
||
[dependencies] | ||
axelar-soroban-interfaces = { workspace = true } | ||
axelar-soroban-std = { workspace = true } | ||
soroban-sdk = { workspace = true } | ||
|
||
[dev_dependencies] | ||
soroban-sdk = { workspace = true, features = ["testutils"] } | ||
axelar-soroban-std = { workspace = true, features = ["testutils"] } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
use soroban_sdk::{contract, contractimpl, panic_with_error, token, Address, Bytes, Env, String}; | ||
|
||
use axelar_soroban_std::types::Token; | ||
|
||
use crate::storage_types::DataKey; | ||
use crate::{error::Error, event}; | ||
use axelar_soroban_interfaces::axelar_gas_service::AxelarGasServiceInterface; | ||
|
||
#[contract] | ||
pub struct AxelarGasService; | ||
|
||
#[contractimpl] | ||
impl AxelarGasServiceInterface for AxelarGasService { | ||
fn initialize(env: Env, gas_collector: Address) { | ||
if env | ||
.storage() | ||
.instance() | ||
.get(&DataKey::Initialized) | ||
.unwrap_or(false) | ||
{ | ||
panic!("Already initialized"); | ||
} | ||
|
||
env.storage().instance().set(&DataKey::Initialized, &true); | ||
|
||
env.storage() | ||
.instance() | ||
.set(&DataKey::GasCollector, &gas_collector); | ||
} | ||
|
||
fn pay_gas_for_contract_call( | ||
env: Env, | ||
sender: Address, | ||
destination_chain: String, | ||
destination_address: String, | ||
payload: Bytes, | ||
refund_address: Address, | ||
token: Token, | ||
) { | ||
sender.require_auth(); | ||
|
||
if token.amount <= 0 { | ||
panic_with_error!(env, Error::InvalidAmount); | ||
} | ||
|
||
token::Client::new(&env, &token.address).transfer_from( | ||
&env.current_contract_address(), | ||
&sender, | ||
&env.current_contract_address(), | ||
&token.amount, | ||
); | ||
|
||
event::gas_paid_for_contract_call( | ||
&env, | ||
sender, | ||
destination_chain, | ||
destination_address, | ||
payload, | ||
refund_address, | ||
token, | ||
); | ||
} | ||
|
||
fn collect_fees(env: Env, receiver: Address, token: Token) { | ||
let gas_collector: Address = env | ||
.storage() | ||
.instance() | ||
.get(&DataKey::GasCollector) | ||
.unwrap(); | ||
|
||
gas_collector.require_auth(); | ||
|
||
if token.amount <= 0 { | ||
panic_with_error!(env, Error::InvalidAmount); | ||
} | ||
|
||
let token_client = token::Client::new(&env, &token.address); | ||
|
||
let contract_token_balance = token_client.balance(&env.current_contract_address()); | ||
|
||
if contract_token_balance >= token.amount { | ||
token_client.transfer(&env.current_contract_address(), &receiver, &token.amount) | ||
} else { | ||
panic_with_error!(env, Error::InsufficientBalance); | ||
} | ||
|
||
event::fee_collected(&env, gas_collector, token); | ||
} | ||
|
||
fn refund(env: Env, message_id: String, receiver: Address, token: Token) { | ||
let gas_collector: Address = env | ||
.storage() | ||
.instance() | ||
.get(&DataKey::GasCollector) | ||
.unwrap(); | ||
|
||
gas_collector.require_auth(); | ||
|
||
token::Client::new(&env, &token.address).transfer( | ||
&env.current_contract_address(), | ||
&receiver, | ||
&token.amount, | ||
); | ||
|
||
event::refunded(&env, message_id, receiver, token); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
use soroban_sdk::contracterror; | ||
|
||
#[contracterror] | ||
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] | ||
#[repr(u32)] | ||
pub enum Error { | ||
InvalidAddress = 1, | ||
InvalidAmount = 2, | ||
InsufficientBalance = 3, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
use axelar_soroban_std::types::Token; | ||
use soroban_sdk::{symbol_short, Address, Bytes, Env, String}; | ||
|
||
pub(crate) fn gas_paid_for_contract_call( | ||
env: &Env, | ||
sender: Address, | ||
destination_chain: String, | ||
destination_address: String, | ||
payload: Bytes, | ||
refund_address: Address, | ||
token: Token, | ||
) { | ||
let topics = ( | ||
symbol_short!("gas_paid"), | ||
env.crypto().keccak256(&payload), | ||
sender, | ||
destination_chain, | ||
); | ||
env.events().publish( | ||
topics, | ||
(destination_address, payload, refund_address, token), | ||
); | ||
} | ||
|
||
pub(crate) fn refunded(env: &Env, message_id: String, receiver: Address, token: Token) { | ||
let topics = (symbol_short!("refunded"), message_id, receiver, token); | ||
env.events().publish(topics, ()); | ||
} | ||
|
||
pub(crate) fn fee_collected(env: &Env, receiver: Address, token: Token) { | ||
let topics = (symbol_short!("collected"), receiver, token); | ||
env.events().publish(topics, ()); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
#![no_std] | ||
|
||
pub mod contract; | ||
mod error; | ||
mod event; | ||
mod storage_types; | ||
|
||
#[cfg(test)] | ||
mod test; | ||
|
||
pub use contract::AxelarGasServiceClient; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
use soroban_sdk::contracttype; | ||
|
||
#[contracttype] | ||
#[derive(Clone, Debug)] | ||
pub enum DataKey { | ||
Initialized, | ||
GasCollector, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
#![cfg(test)] | ||
extern crate std; | ||
|
||
use std::format; | ||
|
||
use axelar_soroban_std::{assert_emitted_event, types::Token}; | ||
|
||
use crate::contract::{AxelarGasService, AxelarGasServiceClient}; | ||
use soroban_sdk::{ | ||
bytes, symbol_short, | ||
testutils::Address as _, | ||
token::{StellarAssetClient, TokenClient}, | ||
Address, Env, String, | ||
}; | ||
|
||
fn setup_env<'a>() -> (Env, Address, Address, AxelarGasServiceClient<'a>) { | ||
let env = Env::default(); | ||
|
||
env.mock_all_auths(); | ||
|
||
let contract_id = env.register_contract(None, AxelarGasService); | ||
|
||
let client = AxelarGasServiceClient::new(&env, &contract_id); | ||
let gas_collector: Address = Address::generate(&env); | ||
client.initialize(&gas_collector); | ||
|
||
(env, contract_id, gas_collector, client) | ||
} | ||
|
||
#[test] | ||
fn pay_gas_for_contract_call() { | ||
let (env, contract_id, _, client) = setup_env(); | ||
|
||
let token_address: Address = env.register_stellar_asset_contract(Address::generate(&env)); | ||
let sender: Address = Address::generate(&env); | ||
let gas_amount: i128 = 1; | ||
let token = Token { | ||
address: token_address.clone(), | ||
amount: gas_amount, | ||
}; | ||
let refund_address: Address = Address::generate(&env); | ||
let payload = bytes!(&env, 0x1234); | ||
let destination_chain: String = String::from_str(&env, "ethereum"); | ||
let destination_address: String = | ||
String::from_str(&env, "0x4EFE356BEDeCC817cb89B4E9b796dB8bC188DC59"); | ||
|
||
let token_client = TokenClient::new(&env, &token_address); | ||
StellarAssetClient::new(&env, &token_address).mint(&sender, &gas_amount); | ||
|
||
let expiration_ledger = &env.ledger().sequence() + 200; | ||
|
||
// approve token spend before invoking `pay_gas_for_contract_call` | ||
token_client.approve(&sender, &contract_id, &gas_amount, &expiration_ledger); | ||
|
||
assert_eq!(token_client.allowance(&sender, &contract_id), gas_amount); | ||
|
||
client.pay_gas_for_contract_call( | ||
&sender, | ||
&destination_chain, | ||
&destination_address, | ||
&payload, | ||
&refund_address, | ||
&token, | ||
); | ||
|
||
assert_eq!(0, token_client.balance(&sender)); | ||
assert_eq!(gas_amount, token_client.balance(&contract_id)); | ||
assert_eq!(token_client.allowance(&sender, &contract_id), 0); | ||
|
||
assert_emitted_event( | ||
&env, | ||
-1, | ||
&contract_id, | ||
( | ||
symbol_short!("gas_paid"), | ||
env.crypto().keccak256(&payload), | ||
sender, | ||
destination_chain, | ||
), | ||
(destination_address, payload, refund_address, token), | ||
); | ||
} | ||
|
||
#[test] | ||
fn collect_fees() { | ||
let (env, contract_id, gas_collector, client) = setup_env(); | ||
let token_address: Address = env.register_stellar_asset_contract(Address::generate(&env)); | ||
let token_client = TokenClient::new(&env, &token_address); | ||
let supply: i128 = 1000; | ||
let refund_amount = 1; | ||
let token = Token { | ||
address: token_address.clone(), | ||
amount: refund_amount, | ||
}; | ||
StellarAssetClient::new(&env, &token.address).mint(&contract_id, &supply); | ||
|
||
client.collect_fees(&gas_collector, &token); | ||
|
||
assert_eq!(refund_amount, token_client.balance(&gas_collector)); | ||
assert_eq!(supply - refund_amount, token_client.balance(&contract_id)); | ||
|
||
assert_emitted_event( | ||
&env, | ||
-1, | ||
&contract_id, | ||
(symbol_short!("collected"), gas_collector, token), | ||
(), | ||
); | ||
} | ||
|
||
#[test] | ||
fn refund() { | ||
let (env, contract_id, _, client) = setup_env(); | ||
let token_address: Address = env.register_stellar_asset_contract(Address::generate(&env)); | ||
let token_client = TokenClient::new(&env, &token_address); | ||
let supply: i128 = 1000; | ||
StellarAssetClient::new(&env, &token_address).mint(&contract_id, &supply); | ||
|
||
let receiver: Address = Address::generate(&env); | ||
let refund_amount: i128 = 1; | ||
let token = Token { | ||
address: token_address.clone(), | ||
amount: refund_amount, | ||
}; | ||
|
||
let message_id = String::from_str( | ||
&env, | ||
&format!( | ||
"{}-{}", | ||
"0xfded3f55dec47250a52a8c0bb7038e72fa6ffaae33562f77cd2b629ef7fd424d", 0 | ||
), | ||
); | ||
|
||
client.refund(&message_id, &receiver, &token); | ||
|
||
assert_eq!(refund_amount, token_client.balance(&receiver)); | ||
assert_eq!(supply - refund_amount, token_client.balance(&contract_id)); | ||
|
||
assert_emitted_event( | ||
&env, | ||
-1, | ||
&contract_id, | ||
(symbol_short!("refunded"), message_id, receiver, token), | ||
(), | ||
); | ||
} |
26 changes: 26 additions & 0 deletions
26
contracts/axelar-soroban-interfaces/src/axelar_gas_service.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
use axelar_soroban_std::types::Token; | ||
use soroban_sdk::{contractclient, Address, Bytes, Env, String}; | ||
|
||
/// Interface for the Axelar Gas Service. | ||
#[contractclient(name = "AxelarGasServiceClient")] | ||
pub trait AxelarGasServiceInterface { | ||
/// Initialize the gas service contract with a gas_collector address. | ||
fn initialize(env: Env, gas_collector: Address); | ||
|
||
/// Pay for gas using a token for a contract call on a destination chain. This function is called on the source chain before calling the gateway to execute a remote contract. | ||
fn pay_gas_for_contract_call( | ||
env: Env, | ||
sender: Address, | ||
destination_chain: String, | ||
destination_address: String, | ||
payload: Bytes, | ||
refund_address: Address, | ||
token: Token, | ||
); | ||
|
||
/// Allows the `gas_collector` to collect accumulated fees from the contract. Only callable by the gas_collector. | ||
fn collect_fees(env: Env, receiver: Address, token: Token); | ||
|
||
/// Refunds gas payment to the receiver in relation to a specific cross-chain transaction. Only callable by the gas_collector. | ||
fn refund(env: Env, message_id: String, receiver: Address, token: Token); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,4 +2,5 @@ | |
|
||
pub mod axelar_auth_verifier; | ||
pub mod axelar_executable; | ||
pub mod axelar_gas_service; | ||
pub mod axelar_gateway; |
Oops, something went wrong.