Skip to content
This repository was archived by the owner on Jun 1, 2026. It is now read-only.

Commit e113141

Browse files
authored
Move Cetus Aggregator to Rust (#1123)
1 parent 6297425 commit e113141

42 files changed

Lines changed: 1615 additions & 156 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/gem_client/src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,14 @@ pub trait Client: Send + Sync + Debug {
5151
R: DeserializeOwned;
5252
}
5353

54+
pub trait ClientBounds: Client + Clone + Send + Sync + 'static {}
55+
56+
impl<T> ClientBounds for T where T: Client + Clone + Send + Sync + 'static {}
57+
58+
pub trait DebugClientBounds: ClientBounds + Debug {}
59+
60+
impl<T> DebugClientBounds for T where T: ClientBounds + Debug {}
61+
5462
#[async_trait]
5563
pub trait ClientExt: Client {
5664
async fn get<R>(&self, path: &str) -> Result<R, ClientError>

crates/gem_sui/src/coin_type.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
use crate::{SUI_COIN_TYPE, SUI_COIN_TYPE_FULL};
2+
use primitives::hex::decode_hex;
3+
4+
const SUI_ADDRESS_LENGTH: usize = 32;
5+
6+
pub fn full_coin_type(coin_type: &str) -> String {
7+
let Some((prefix, rest)) = coin_type.split_once("::") else {
8+
return coin_type.to_string();
9+
};
10+
match decode_hex(prefix) {
11+
Ok(bytes) if bytes.len() <= SUI_ADDRESS_LENGTH => {
12+
let mut padded = [0u8; SUI_ADDRESS_LENGTH];
13+
padded[SUI_ADDRESS_LENGTH - bytes.len()..].copy_from_slice(&bytes);
14+
format!("0x{}::{rest}", hex::encode(padded))
15+
}
16+
_ => coin_type.to_string(),
17+
}
18+
}
19+
20+
pub fn coin_type_matches(a: &str, b: &str) -> bool {
21+
full_coin_type(a) == full_coin_type(b)
22+
}
23+
24+
pub fn is_sui_coin(coin_type: &str) -> bool {
25+
coin_type == SUI_COIN_TYPE || coin_type == SUI_COIN_TYPE_FULL
26+
}
27+
28+
#[cfg(test)]
29+
mod tests {
30+
use super::*;
31+
32+
#[test]
33+
fn test_full_coin_type() {
34+
assert_eq!(
35+
full_coin_type("0x2::sui::SUI"),
36+
"0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI"
37+
);
38+
assert_eq!(
39+
full_coin_type("2::sui::SUI"),
40+
"0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI"
41+
);
42+
assert_eq!(
43+
full_coin_type("0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI"),
44+
"0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI"
45+
);
46+
assert_eq!(full_coin_type("0xabc"), "0xabc");
47+
assert_eq!(full_coin_type("not-a-type::coin::COIN"), "not-a-type::coin::COIN");
48+
}
49+
50+
#[test]
51+
fn test_coin_type_matches() {
52+
assert!(coin_type_matches("0x2::sui::SUI", "0x2::sui::SUI"));
53+
assert!(coin_type_matches("0x2::sui::SUI", "2::sui::SUI"));
54+
assert!(coin_type_matches("2::sui::SUI", "0x2::sui::SUI"));
55+
assert!(coin_type_matches(
56+
"0x2::sui::SUI",
57+
"0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI"
58+
));
59+
assert!(!coin_type_matches("0x2::sui::SUI", "0x3::token::TOKEN"));
60+
}
61+
62+
#[test]
63+
fn test_is_sui_coin() {
64+
assert!(is_sui_coin(SUI_COIN_TYPE));
65+
assert!(is_sui_coin(SUI_COIN_TYPE_FULL));
66+
assert!(!is_sui_coin("0x3::token::TOKEN"));
67+
}
68+
}

crates/gem_sui/src/error.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use std::{
2+
error::Error,
3+
fmt::{Display, Formatter},
4+
};
5+
6+
#[derive(Debug)]
7+
pub enum SuiError {
8+
InvalidInput(String),
9+
InsufficientBalance,
10+
NoGasCoins,
11+
}
12+
13+
impl Display for SuiError {
14+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
15+
match self {
16+
Self::InvalidInput(message) => write!(f, "{message}"),
17+
Self::InsufficientBalance => write!(f, "insufficient Sui coin balance"),
18+
Self::NoGasCoins => write!(f, "No SUI coins available for gas"),
19+
}
20+
}
21+
}
22+
23+
impl Error for SuiError {}
24+
25+
impl SuiError {
26+
pub fn invalid_input(message: impl Into<String>) -> Self {
27+
Self::InvalidInput(message.into())
28+
}
29+
}

crates/gem_sui/src/jsonrpc.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,18 @@ impl Default for ObjectDataOptions {
9696
}
9797
}
9898

99+
impl ObjectDataOptions {
100+
pub fn owner_only() -> Self {
101+
Self {
102+
show_type: false,
103+
show_owner: true,
104+
show_display: false,
105+
show_content: false,
106+
show_bcs: false,
107+
}
108+
}
109+
}
110+
99111
#[derive(Debug, Clone, Serialize, Deserialize)]
100112
#[serde(rename_all = "camelCase")]
101113
pub struct SuiData<T> {

crates/gem_sui/src/lib.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
pub mod address;
22
pub use address::validate_address;
3+
pub mod coin_type;
4+
pub use coin_type::{coin_type_matches, full_coin_type, is_sui_coin};
35
#[cfg(feature = "rpc")]
46
pub mod rpc;
57
#[cfg(feature = "rpc")]
@@ -15,18 +17,21 @@ pub mod transfer_builder;
1517
#[cfg(feature = "rpc")]
1618
pub use transfer_builder::*;
1719

20+
pub mod error;
1821
pub mod gas_budget;
1922
pub mod jsonrpc;
20-
pub mod operations;
23+
pub mod tx_builder;
2124

2225
#[cfg(feature = "signer")]
2326
pub mod signer;
2427

28+
pub use error::SuiError;
2529
use models::Coin;
2630
pub use models::ObjectId;
27-
pub use operations::*;
2831
use std::error::Error;
2932
use sui_transaction_builder::ObjectInput;
33+
pub use tx_builder::{decode_transaction, stake::*, transfer::*, validate_and_hash};
34+
pub use tx_builder::{stake, transfer};
3035

3136
pub const SUI_SYSTEM_ID: &str = "sui_system";
3237

crates/gem_sui/src/models/coin_asset.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
use num_bigint::BigInt;
22
use serde::{Deserialize, Serialize};
33
use serde_serializers::{deserialize_bigint_from_str, deserialize_u64_from_str, serialize_bigint, serialize_u64};
4+
#[cfg(feature = "rpc")]
5+
use std::{error::Error, str::FromStr};
46
use sui_transaction_builder::ObjectInput;
57
use sui_types::{Address, Digest};
68

9+
#[cfg(feature = "rpc")]
10+
use super::SuiCoin;
11+
712
#[derive(Debug, Clone, Serialize, Deserialize)]
813
#[serde(rename_all = "camelCase")]
914
pub struct CoinAsset {
@@ -22,6 +27,21 @@ impl CoinAsset {
2227
}
2328
}
2429

30+
#[cfg(feature = "rpc")]
31+
impl TryFrom<SuiCoin> for CoinAsset {
32+
type Error = Box<dyn Error + Send + Sync>;
33+
34+
fn try_from(coin: SuiCoin) -> Result<Self, Self::Error> {
35+
Ok(Self {
36+
coin_object_id: Address::from_str(&coin.coin_object_id)?,
37+
coin_type: coin.coin_type,
38+
digest: Digest::from_str(&coin.digest)?,
39+
balance: coin.balance,
40+
version: coin.version.parse()?,
41+
})
42+
}
43+
}
44+
2545
#[derive(Debug, Clone, Serialize, Deserialize)]
2646
#[serde(rename_all = "camelCase")]
2747
pub struct CoinResponse {

crates/gem_sui/src/models/transaction.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ pub struct SuiTransaction {
2424
#[serde(rename_all = "camelCase")]
2525
pub struct SuiStatus {
2626
pub status: String,
27+
pub error: Option<String>,
2728
}
2829

2930
#[derive(Debug, Clone, Serialize, Deserialize)]

crates/gem_sui/src/operations/mod.rs

Lines changed: 0 additions & 7 deletions
This file was deleted.

crates/gem_sui/src/operations/tx.rs

Lines changed: 0 additions & 52 deletions
This file was deleted.

0 commit comments

Comments
 (0)