Skip to content

Commit e06032c

Browse files
feat(interchain-token-service): add message routing (#90)
Co-authored-by: Milap Sheth <milap@interoplabs.io>
1 parent d0edee0 commit e06032c

File tree

12 files changed

+652
-377
lines changed

12 files changed

+652
-377
lines changed

contracts/interchain-token-service/Cargo.toml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,5 @@ goldie = { workspace = true }
2626
hex = "0.4"
2727
soroban-sdk = { workspace = true, features = ["testutils", "alloc"] }
2828

29-
[features]
30-
testutils = ["soroban-sdk/testutils", "axelar-soroban-std/testutils"]
31-
3229
[lints]
3330
workspace = true

contracts/interchain-token-service/src/abi.rs

Lines changed: 41 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,16 @@
11
use alloy_primitives::{FixedBytes, Uint, U256};
22
use alloy_sol_types::{sol, SolValue};
33
use axelar_soroban_std::ensure;
4-
use soroban_sdk::{contracterror, Bytes, BytesN, Env, String};
4+
use soroban_sdk::{Bytes, BytesN, Env, String};
55

6+
// alloc needed for converting to alloy types
7+
use crate::abi::alloc::{string::String as StdString, vec};
8+
use crate::error::ContractError;
69
use crate::types::{self, HubMessage, Message};
710
extern crate alloc;
8-
use crate::abi::alloc::{string::String as StdString, vec};
9-
10-
#[contracterror]
11-
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
12-
#[repr(u32)]
13-
pub enum MessageError {
14-
InsufficientMessageLength = 0,
15-
InvalidMessageType = 1,
16-
AbiDecodeFailed = 2,
17-
InvalidAmount = 3,
18-
InvalidUtf8 = 4,
19-
}
2011

2112
sol! {
13+
#[derive(PartialEq, Eq)]
2214
enum MessageType {
2315
InterchainTransfer,
2416
DeployInterchainToken,
@@ -59,7 +51,7 @@ sol! {
5951
}
6052

6153
impl Message {
62-
pub fn abi_encode(self, env: &Env) -> Result<Bytes, MessageError> {
54+
pub fn abi_encode(self, env: &Env) -> Result<Bytes, ContractError> {
6355
let msg = match self {
6456
Self::InterchainTransfer(types::InterchainTransfer {
6557
token_id,
@@ -95,18 +87,15 @@ impl Message {
9587
Ok(Bytes::from_slice(env, &msg))
9688
}
9789

98-
pub fn abi_decode(env: &Env, payload: &Bytes) -> Result<Self, MessageError> {
99-
ensure!(payload.len() >= 32, MessageError::InsufficientMessageLength);
100-
90+
pub fn abi_decode(env: &Env, payload: &Bytes) -> Result<Self, ContractError> {
10191
let payload = payload.to_alloc_vec();
10292

103-
let message_type = MessageType::abi_decode(&payload[0..32], true)
104-
.map_err(|_| MessageError::InvalidMessageType)?;
93+
let message_type = get_message_type(&payload)?;
10594

10695
match message_type {
10796
MessageType::InterchainTransfer => {
10897
let decoded = InterchainTransfer::abi_decode_params(&payload, true)
109-
.map_err(|_| MessageError::AbiDecodeFailed)?;
98+
.map_err(|_| ContractError::AbiDecodeFailed)?;
11099

111100
Ok(Self::InterchainTransfer(types::InterchainTransfer {
112101
token_id: BytesN::from_array(env, &decoded.tokenId.into()),
@@ -121,7 +110,7 @@ impl Message {
121110
}
122111
MessageType::DeployInterchainToken => {
123112
let decoded = DeployInterchainToken::abi_decode_params(&payload, true)
124-
.map_err(|_| MessageError::AbiDecodeFailed)?;
113+
.map_err(|_| ContractError::AbiDecodeFailed)?;
125114

126115
Ok(Self::DeployInterchainToken(types::DeployInterchainToken {
127116
token_id: BytesN::from_array(env, &decoded.tokenId.into()),
@@ -131,14 +120,13 @@ impl Message {
131120
minter: from_vec(env, decoded.minter.as_ref()),
132121
}))
133122
}
134-
_ => Err(MessageError::InvalidMessageType),
123+
_ => Err(ContractError::InvalidMessageType),
135124
}
136125
}
137126
}
138127

139-
#[allow(dead_code)]
140128
impl HubMessage {
141-
pub fn abi_encode(self, env: &Env) -> Result<Bytes, MessageError> {
129+
pub fn abi_encode(self, env: &Env) -> Result<Bytes, ContractError> {
142130
let msg = match self {
143131
Self::SendToHub {
144132
destination_chain,
@@ -162,18 +150,15 @@ impl HubMessage {
162150
Ok(Bytes::from_slice(env, &msg))
163151
}
164152

165-
pub fn abi_decode(env: &Env, payload: &Bytes) -> Result<Self, MessageError> {
166-
ensure!(payload.len() >= 32, MessageError::InsufficientMessageLength);
167-
153+
pub fn abi_decode(env: &Env, payload: &Bytes) -> Result<Self, ContractError> {
168154
let payload = payload.to_alloc_vec();
169155

170-
let message_type = MessageType::abi_decode(&payload[0..32], true)
171-
.map_err(|_| MessageError::InvalidMessageType)?;
156+
let message_type = get_message_type(&payload)?;
172157

173158
match message_type {
174159
MessageType::SendToHub => {
175160
let decoded = SendToHub::abi_decode_params(&payload, true)
176-
.map_err(|_| MessageError::AbiDecodeFailed)?;
161+
.map_err(|_| ContractError::AbiDecodeFailed)?;
177162

178163
Ok(Self::SendToHub {
179164
destination_chain: String::from_str(env, &decoded.destination_chain),
@@ -185,7 +170,7 @@ impl HubMessage {
185170
}
186171
MessageType::ReceiveFromHub => {
187172
let decoded = ReceiveFromHub::abi_decode_params(&payload, true)
188-
.map_err(|_| MessageError::AbiDecodeFailed)?;
173+
.map_err(|_| ContractError::AbiDecodeFailed)?;
189174

190175
Ok(Self::ReceiveFromHub {
191176
source_chain: String::from_str(env, &decoded.source_chain),
@@ -195,19 +180,31 @@ impl HubMessage {
195180
)?,
196181
})
197182
}
198-
_ => Err(MessageError::InvalidMessageType),
183+
_ => Err(ContractError::InvalidMessageType),
199184
}
200185
}
201186
}
202187

203-
fn to_std_string(soroban_string: String) -> Result<StdString, MessageError> {
188+
pub fn get_message_type(payload: &[u8]) -> Result<MessageType, ContractError> {
189+
ensure!(
190+
payload.len() >= 32,
191+
ContractError::InsufficientMessageLength
192+
);
193+
194+
let message_type = MessageType::abi_decode(&payload[0..32], true)
195+
.map_err(|_| ContractError::InvalidMessageType)?;
196+
197+
Ok(message_type)
198+
}
199+
200+
fn to_std_string(soroban_string: String) -> Result<StdString, ContractError> {
204201
let length = soroban_string.len() as usize;
205202
let mut bytes = vec![0u8; length];
206203
soroban_string.copy_into_slice(&mut bytes);
207-
StdString::from_utf8(bytes).map_err(|_| MessageError::InvalidUtf8)
204+
StdString::from_utf8(bytes).map_err(|_| ContractError::InvalidUtf8)
208205
}
209206

210-
fn to_i128(value: Uint<256, 4>) -> Result<i128, MessageError> {
207+
fn to_i128(value: Uint<256, 4>) -> Result<i128, ContractError> {
211208
let slice = value.as_le_slice();
212209

213210
let mut bytes_to_remove = [0; 16];
@@ -217,12 +214,12 @@ fn to_i128(value: Uint<256, 4>) -> Result<i128, MessageError> {
217214

218215
ensure!(
219216
i128::from_le_bytes(bytes_to_remove) == 0,
220-
MessageError::InvalidAmount
217+
ContractError::InvalidAmount
221218
);
222219

223220
let i128_value = i128::from_le_bytes(bytes_to_convert);
224221

225-
ensure!(i128_value >= 0, MessageError::InvalidAmount);
222+
ensure!(i128_value >= 0, ContractError::InvalidAmount);
226223

227224
Ok(i128_value)
228225
}
@@ -253,7 +250,7 @@ mod tests {
253250
use soroban_sdk::{Bytes, BytesN, Env, String};
254251
use std::vec::Vec;
255252

256-
fn bytes_from_hex(env: &Env, hex_string: &str) -> Bytes {
253+
pub fn bytes_from_hex(env: &Env, hex_string: &str) -> Bytes {
257254
let bytes_vec: Vec<u8> = hex::decode(hex_string).unwrap();
258255
Bytes::from_slice(env, &bytes_vec)
259256
}
@@ -305,7 +302,7 @@ mod tests {
305302

306303
for sequence in invalid_sequences {
307304
let result = to_std_string(sequence);
308-
assert!(matches!(result, Err(MessageError::InvalidUtf8)));
305+
assert!(matches!(result, Err(ContractError::InvalidUtf8)));
309306
}
310307
}
311308

@@ -340,18 +337,18 @@ mod tests {
340337

341338
let result = to_i128(bad_uint);
342339

343-
assert!(matches!(result, Err(MessageError::InvalidAmount)));
340+
assert!(matches!(result, Err(ContractError::InvalidAmount)));
344341
}
345342

346343
#[test]
347344
fn to_i128_fails_overflow() {
348345
let overflow: Uint<256, 4> = Uint::from(i128::MAX) + Uint::from(1);
349346
let result = to_i128(overflow);
350-
assert!(matches!(result, Err(MessageError::InvalidAmount)));
347+
assert!(matches!(result, Err(ContractError::InvalidAmount)));
351348

352349
let overflow: Uint<256, 4> = Uint::from(u128::MAX);
353350
let result = to_i128(overflow);
354-
assert!(matches!(result, Err(MessageError::InvalidAmount)));
351+
assert!(matches!(result, Err(ContractError::InvalidAmount)));
355352
}
356353

357354
#[test]
@@ -529,7 +526,7 @@ mod tests {
529526
let invalid_payload = Bytes::from_slice(&env, &bytes);
530527

531528
let result = HubMessage::abi_decode(&env, &invalid_payload);
532-
assert!(matches!(result, Err(MessageError::InvalidMessageType)));
529+
assert!(matches!(result, Err(ContractError::InvalidMessageType)));
533530

534531
let invalid_hub_message_type = assert_ok!(types::Message::InterchainTransfer(
535532
types::InterchainTransfer {
@@ -543,6 +540,6 @@ mod tests {
543540
.abi_encode(&env));
544541

545542
let result = HubMessage::abi_decode(&env, &invalid_hub_message_type);
546-
assert!(matches!(result, Err(MessageError::InvalidMessageType)));
543+
assert!(matches!(result, Err(ContractError::InvalidMessageType)));
547544
}
548545
}

0 commit comments

Comments
 (0)