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

feat: mayan integration #322

Open
wants to merge 21 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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ lazy_static = "1.4.0"
futures-util = "0.3.30"
uuid = { version = "1.8.0", features = ["v4"] }
rand = { version = "0.8.5" }
rand_core = { version = "0.6.4" }

# db
diesel = { version = "2.2.3", features = ["postgres", "chrono", "serde_json"] }
Expand Down
4 changes: 4 additions & 0 deletions crates/gem_evm/src/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ impl FromStr for EthereumAddress {
impl EthereumAddress {
pub const LEN: usize = 20;

pub fn zero() -> Self {
Self { bytes: vec![0u8; Self::LEN] }
}

pub fn parse(str: &str) -> Option<EthereumAddress> {
Self::from_str(str).ok()
}
Expand Down
1 change: 1 addition & 0 deletions crates/gem_evm/src/erc20.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ use alloy_core::sol;
sol! {
interface IERC20 {
function allowance(address owner, address spender) external view returns (uint256);
function decimals() external view returns (uint8);
}
}
16 changes: 16 additions & 0 deletions crates/gem_evm/src/jsonrpc.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use alloy_primitives::U256;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
Expand Down Expand Up @@ -35,6 +36,17 @@ impl TransactionObject {
data: format!("0x{}", hex::encode(data)),
}
}

pub fn new_call_with_value(from: &str, to: &str, data: Vec<u8>, value: &str) -> Self {
Self {
from: Some(from.to_string()),
to: to.to_string(),
gas: None,
gas_price: None,
value: Some(value.to_string()),
data: format!("0x{}", hex::encode(data)),
}
}
}

#[derive(Debug, Clone, Serialize, Deserialize)]
Expand Down Expand Up @@ -73,6 +85,8 @@ pub enum EthereumRpc {
GasPrice,
GetBalance(&'static str),
Call(TransactionObject, BlockParameter),
GetTransactionReceipt(String),
EstimateGas(TransactionObject),
}

impl EthereumRpc {
Expand All @@ -81,6 +95,8 @@ impl EthereumRpc {
EthereumRpc::GasPrice => "eth_gasPrice",
EthereumRpc::GetBalance(_) => "eth_getBalance",
EthereumRpc::Call(_, _) => "eth_call",
EthereumRpc::GetTransactionReceipt(_) => "eth_getTransactionReceipt",
EthereumRpc::EstimateGas(_) => "eth_estimateGas",
}
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/gem_evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ pub mod erc20;
pub mod erc2612;
pub mod jsonrpc;
pub mod lido;
pub mod mayan;
pub mod permit2;
pub mod uniswap;
53 changes: 53 additions & 0 deletions crates/gem_evm/src/mayan/forwarder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use alloy_core::sol;

sol! {
/// @title MayanForwarder Interface
#[derive(Debug, PartialEq)]
interface IMayanForwarder {

/// @notice Forward ETH to Mayan protocol
function forwardEth(address mayanProtocol, bytes calldata protocolData) external payable;

/// @notice Forward ERC20 tokens to Mayan protocol
function forwardERC20(
address tokenIn,
uint256 amountIn,
PermitParams calldata permitParams,
address mayanProtocol,
bytes calldata protocolData
) external payable;

/// @notice Swap ETH to token and forward to Mayan protocol
function swapAndForwardEth(
uint256 amountIn,
address swapProtocol,
bytes calldata swapData,
address middleToken,
uint256 minMiddleAmount,
address mayanProtocol,
bytes calldata mayanData
) external payable;

/// @notice Swap ERC20 token and forward to Mayan protocol
function swapAndForwardERC20(
address tokenIn,
uint256 amountIn,
PermitParams calldata permitParams,
address swapProtocol,
bytes calldata swapData,
address middleToken,
uint256 minMiddleAmount,
address mayanProtocol,
bytes calldata mayanData
) external payable;

/// Structs
struct PermitParams {
uint256 value;
uint256 deadline;
uint8 v;
bytes32 r;
bytes32 s;
}
}
}
2 changes: 2 additions & 0 deletions crates/gem_evm/src/mayan/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod forwarder;
pub mod swift;
144 changes: 144 additions & 0 deletions crates/gem_evm/src/mayan/swift/deployment.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
use std::collections::HashMap;

use primitives::Chain;

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum MayanSwiftDeploymentWormholeId {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick, this is really long, let's just call it WormholdChainId?

Solana = 1,
Ethereum = 2,
SmartChain = 4,
Polygon = 5,
Arbitrum = 23,
Optimism = 24,
Base = 30,
}

#[derive(Debug, Clone, PartialEq)]
pub struct MayanSwiftDeployment {
pub address: String,
pub wormhole_id: MayanSwiftDeploymentWormholeId,
}

pub fn get_swift_providers() -> HashMap<Chain, MayanSwiftDeployment> {
HashMap::from([
(
Chain::Solana,
MayanSwiftDeployment {
address: "BLZRi6frs4X4DNLw56V4EXai1b6QVESN1BhHBTYM9VcY".to_string(),
wormhole_id: MayanSwiftDeploymentWormholeId::Solana,
},
),
(
Chain::Ethereum,
MayanSwiftDeployment {
address: "0xC38e4e6A15593f908255214653d3D947CA1c2338".to_string(),
wormhole_id: MayanSwiftDeploymentWormholeId::Ethereum,
},
),
(
Chain::SmartChain,
MayanSwiftDeployment {
address: "0xC38e4e6A15593f908255214653d3D947CA1c2338".to_string(),
wormhole_id: MayanSwiftDeploymentWormholeId::SmartChain,
},
),
(
Chain::Polygon,
MayanSwiftDeployment {
address: "0xC38e4e6A15593f908255214653d3D947CA1c2338".to_string(),
wormhole_id: MayanSwiftDeploymentWormholeId::Polygon,
},
),
(
Chain::Arbitrum,
MayanSwiftDeployment {
address: "0xC38e4e6A15593f908255214653d3D947CA1c2338".to_string(),
wormhole_id: MayanSwiftDeploymentWormholeId::Arbitrum,
},
),
(
Chain::Optimism,
MayanSwiftDeployment {
address: "0xC38e4e6A15593f908255214653d3D947CA1c2338".to_string(),
wormhole_id: MayanSwiftDeploymentWormholeId::Optimism,
},
),
(
Chain::Base,
MayanSwiftDeployment {
address: "0xC38e4e6A15593f908255214653d3D947CA1c2338".to_string(),
wormhole_id: MayanSwiftDeploymentWormholeId::Base,
},
),
])
}

pub fn get_swift_deployment_chains() -> Vec<Chain> {
get_swift_providers().keys().cloned().collect()
}

pub fn get_swift_deployment_by_chain(chain: Chain) -> Option<MayanSwiftDeployment> {
get_swift_providers().get(&chain).cloned()
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_get_swift_provider_address() {
// Test all supported chains
assert_eq!(
get_swift_deployment_by_chain(Chain::Solana),
Some(MayanSwiftDeployment {
address: "BLZRi6frs4X4DNLw56V4EXai1b6QVESN1BhHBTYM9VcY".to_string(),
wormhole_id: MayanSwiftDeploymentWormholeId::Solana,
})
);

let evm_address = "0xC38e4e6A15593f908255214653d3D947CA1c2338";

assert_eq!(get_swift_deployment_by_chain(Chain::Ethereum).map(|x| x.address), Some(evm_address.to_string()));
assert_eq!(
get_swift_deployment_by_chain(Chain::SmartChain).map(|x| x.address),
Some(evm_address.to_string())
);
assert_eq!(get_swift_deployment_by_chain(Chain::Polygon).map(|x| x.address), Some(evm_address.to_string()));
// assert_eq!(get_swift_deployment_by_chain(Chain::Avalanche).map(|x| x.address), Some(evm_address.to_string()));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// assert_eq!(get_swift_deployment_by_chain(Chain::Avalanche).map(|x| x.address), Some(evm_address.to_string()));

assert_eq!(get_swift_deployment_by_chain(Chain::Arbitrum).map(|x| x.address), Some(evm_address.to_string()));
assert_eq!(get_swift_deployment_by_chain(Chain::Optimism).map(|x| x.address), Some(evm_address.to_string()));

// Test unsupported chain
assert_eq!(get_swift_deployment_by_chain(Chain::Sui), None);
}

#[test]
fn test_chain_ids() {
// Verify chain IDs match the provided table, and that they are in order
assert_eq!(
get_swift_deployment_by_chain(Chain::Solana).map(|x| x.wormhole_id),
Some(MayanSwiftDeploymentWormholeId::Solana)
);
assert_eq!(
get_swift_deployment_by_chain(Chain::Ethereum).map(|x| x.wormhole_id),
Some(MayanSwiftDeploymentWormholeId::Ethereum)
);
assert_eq!(
get_swift_deployment_by_chain(Chain::SmartChain).map(|x| x.wormhole_id),
Some(MayanSwiftDeploymentWormholeId::SmartChain)
);
assert_eq!(
get_swift_deployment_by_chain(Chain::Polygon).map(|x| x.wormhole_id),
Some(MayanSwiftDeploymentWormholeId::Polygon)
);
// assert_eq!(get_swift_deployment_by_chain(Chain::Avalanche).map(|x| x.wormhole_id), Some(6));
assert_eq!(
get_swift_deployment_by_chain(Chain::Arbitrum).map(|x| x.wormhole_id),
Some(MayanSwiftDeploymentWormholeId::Arbitrum)
);
assert_eq!(
get_swift_deployment_by_chain(Chain::Optimism).map(|x| x.wormhole_id),
Some(MayanSwiftDeploymentWormholeId::Optimism)
);
}
}
2 changes: 2 additions & 0 deletions crates/gem_evm/src/mayan/swift/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod deployment;
pub mod swift;
34 changes: 34 additions & 0 deletions crates/gem_evm/src/mayan/swift/swift.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use alloy_core::sol;

sol! {
/// @title MayanSwift Cross-Chain Swap Contract
#[derive(Debug)]
contract IMayanSwift{
struct OrderParams {
bytes32 trader;
bytes32 tokenOut;
uint64 minAmountOut;
uint64 gasDrop;
uint64 cancelFee;
uint64 refundFee;
uint64 deadline;
bytes32 destAddr;
uint16 destChainId;
bytes32 referrerAddr;
uint8 referrerBps;
uint8 auctionMode;
bytes32 random;
}

struct PermitParams {
uint256 value;
uint256 deadline;
uint8 v;
bytes32 r;
bytes32 s;
}

function createOrderWithEth(OrderParams memory params) external payable returns (bytes32 orderHash);
function createOrderWithToken(address tokenIn, uint256 amountIn, OrderParams memory params) external returns (bytes32 orderHash);
}
}
1 change: 1 addition & 0 deletions gemstone/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ num-bigint.workspace = true
num-traits.workspace = true
futures.workspace = true
borsh.workspace = true
rand.workspace = true
orca_whirlpools_core = "1.0.0"

[build-dependencies]
Expand Down
3 changes: 2 additions & 1 deletion gemstone/src/network/mock.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::{AlienError, AlienProvider, AlienTarget, Data};
use async_trait::async_trait;
use primitives::Chain;

use super::{AlienError, AlienProvider, AlienTarget, Data};
use std::{fmt::Debug, sync::Arc, time::Duration};

#[derive(Debug, uniffi::Object)]
Expand Down
3 changes: 3 additions & 0 deletions gemstone/src/swapper/mayan/constants.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub const MAYAN_PROGRAM_ID: &str = "FC4eXxkyrMPTjiYUpp4EAnkmwMbQyZ6NDCh1kfLn6vsf";
pub const MAYAN_FORWARDER_CONTRACT: &str = "0x0654874eb7F59C6f5b39931FC45dC45337c967c3";
pub const MAYAN_ZERO_ADDRESS: &str = "0x0000000000000000000000000000000000000000";
Loading