Skip to content

Commit 421b1ea

Browse files
authored
feat(minor-interchain-token-service): fix amount scaling (#686)
1 parent 19fa978 commit 421b1ea

File tree

6 files changed

+136
-66
lines changed

6 files changed

+136
-66
lines changed

contracts/interchain-token-service/src/contract/execute/interceptors.rs

+75-38
Original file line numberDiff line numberDiff line change
@@ -197,22 +197,24 @@ fn destination_token_decimals(
197197
storage: &dyn Storage,
198198
source_chain: &ChainNameRaw,
199199
destination_chain: &ChainNameRaw,
200-
source_chain_decimals: u8,
200+
source_token_decimals: u8,
201201
) -> Result<u8, Error> {
202202
let source_chain_config =
203203
state::load_chain_config(storage, source_chain).change_context(Error::State)?;
204204
let destination_chain_config =
205205
state::load_chain_config(storage, destination_chain).change_context(Error::State)?;
206206

207207
if source_chain_config
208+
.truncation
208209
.max_uint
209-
.le(&destination_chain_config.max_uint)
210+
.le(&destination_chain_config.truncation.max_uint)
210211
{
211-
source_chain_decimals
212+
source_token_decimals
212213
} else {
213-
source_chain_config
214-
.max_target_decimals
215-
.min(source_chain_decimals)
214+
destination_chain_config
215+
.truncation
216+
.max_decimals_when_truncating
217+
.min(source_token_decimals)
216218
}
217219
.then(Result::Ok)
218220
}
@@ -244,6 +246,7 @@ fn destination_amount(
244246

245247
let destination_max_uint = state::load_chain_config(storage, destination_chain)
246248
.change_context(Error::State)?
249+
.truncation
247250
.max_uint;
248251

249252
// It's intentionally written in this way since the end result may still be fine even if
@@ -311,6 +314,7 @@ mod test {
311314

312315
use super::Error;
313316
use crate::contract::execute::interceptors;
317+
use crate::msg::TruncationConfig;
314318
use crate::state::{self, TokenDeploymentType};
315319
use crate::{msg, DeployInterchainToken, InterchainTransfer, TokenInstance};
316320

@@ -347,8 +351,10 @@ mod test {
347351
msg::ChainConfig {
348352
chain: destination_chain.clone(),
349353
its_edge_contract: "itsedgecontract".to_string().try_into().unwrap(),
350-
max_uint: Uint256::from(1_000_000_000u128).try_into().unwrap(),
351-
max_target_decimals: 6,
354+
truncation: TruncationConfig {
355+
max_uint: Uint256::from(1_000_000_000u128).try_into().unwrap(),
356+
max_decimals_when_truncating: 6,
357+
},
352358
},
353359
)
354360
.unwrap();
@@ -398,8 +404,10 @@ mod test {
398404
msg::ChainConfig {
399405
chain: destination_chain.clone(),
400406
its_edge_contract: "itsedgecontract".to_string().try_into().unwrap(),
401-
max_uint: Uint256::from(1_000_000_000_000_000u128).try_into().unwrap(),
402-
max_target_decimals: 6,
407+
truncation: TruncationConfig {
408+
max_uint: Uint256::from(1_000_000_000_000_000u128).try_into().unwrap(),
409+
max_decimals_when_truncating: 6,
410+
},
403411
},
404412
)
405413
.unwrap();
@@ -449,8 +457,10 @@ mod test {
449457
msg::ChainConfig {
450458
chain: destination_chain.clone(),
451459
its_edge_contract: "itsedgecontract".to_string().try_into().unwrap(),
452-
max_uint: Uint256::from(1_000_000_000_000_000u128).try_into().unwrap(),
453-
max_target_decimals: 6,
460+
truncation: TruncationConfig {
461+
max_uint: Uint256::from(1_000_000_000_000_000u128).try_into().unwrap(),
462+
max_decimals_when_truncating: 6,
463+
},
454464
},
455465
)
456466
.unwrap();
@@ -500,8 +510,10 @@ mod test {
500510
msg::ChainConfig {
501511
chain: destination_chain.clone(),
502512
its_edge_contract: "itsedgecontract".to_string().try_into().unwrap(),
503-
max_uint: Uint256::from(100_000u128).try_into().unwrap(),
504-
max_target_decimals: 6,
513+
truncation: TruncationConfig {
514+
max_uint: Uint256::from(100_000u128).try_into().unwrap(),
515+
max_decimals_when_truncating: 6,
516+
},
505517
},
506518
)
507519
.unwrap();
@@ -551,8 +563,10 @@ mod test {
551563
msg::ChainConfig {
552564
chain: destination_chain.clone(),
553565
its_edge_contract: "itsedgecontract".to_string().try_into().unwrap(),
554-
max_uint: Uint256::from(100_000u128).try_into().unwrap(),
555-
max_target_decimals: 6,
566+
truncation: TruncationConfig {
567+
max_uint: Uint256::from(100_000u128).try_into().unwrap(),
568+
max_decimals_when_truncating: 6,
569+
},
556570
},
557571
)
558572
.unwrap();
@@ -574,22 +588,17 @@ mod test {
574588
let mut storage = MockStorage::new();
575589
let source_chain: ChainNameRaw = "sourcechain".try_into().unwrap();
576590
let destination_chain: ChainNameRaw = "destinationchain".try_into().unwrap();
577-
let deploy_token = DeployInterchainToken {
578-
token_id: [1u8; 32].into(),
579-
name: "token".to_string().try_into().unwrap(),
580-
symbol: "TKN".to_string().try_into().unwrap(),
581-
decimals: 9,
582-
minter: None,
583-
};
584591

585592
state::save_chain_config(
586593
&mut storage,
587594
&source_chain,
588595
msg::ChainConfig {
589596
chain: source_chain.clone(),
590597
its_edge_contract: "itsedgecontract".to_string().try_into().unwrap(),
591-
max_uint: Uint256::from(1_000_000_000_000_000u128).try_into().unwrap(),
592-
max_target_decimals: 6,
598+
truncation: TruncationConfig {
599+
max_uint: Uint256::from(1_000_000_000_000_000u128).try_into().unwrap(),
600+
max_decimals_when_truncating: 12,
601+
},
593602
},
594603
)
595604
.unwrap();
@@ -599,11 +608,20 @@ mod test {
599608
msg::ChainConfig {
600609
chain: destination_chain.clone(),
601610
its_edge_contract: "itsedgecontract".to_string().try_into().unwrap(),
602-
max_uint: Uint256::from(1_000_000_000u128).try_into().unwrap(),
603-
max_target_decimals: 6,
611+
truncation: TruncationConfig {
612+
max_uint: Uint256::from(1_000_000_000u128).try_into().unwrap(),
613+
max_decimals_when_truncating: 6,
614+
},
604615
},
605616
)
606617
.unwrap();
618+
let deploy_token = DeployInterchainToken {
619+
token_id: [1u8; 32].into(),
620+
name: "token".to_string().try_into().unwrap(),
621+
symbol: "TKN".to_string().try_into().unwrap(),
622+
decimals: 9,
623+
minter: None,
624+
};
607625

608626
let deploy_token = assert_ok!(interceptors::calculate_scaling_factor(
609627
&storage,
@@ -634,22 +652,17 @@ mod test {
634652
let mut storage = MockStorage::new();
635653
let source_chain: ChainNameRaw = "sourcechain".try_into().unwrap();
636654
let destination_chain: ChainNameRaw = "destinationchain".try_into().unwrap();
637-
let deploy_token = DeployInterchainToken {
638-
token_id: [1u8; 32].into(),
639-
name: "token".to_string().try_into().unwrap(),
640-
symbol: "TKN".to_string().try_into().unwrap(),
641-
decimals: 9,
642-
minter: None,
643-
};
644655

645656
state::save_chain_config(
646657
&mut storage,
647658
&source_chain,
648659
msg::ChainConfig {
649660
chain: source_chain.clone(),
650661
its_edge_contract: "itsedgecontract".to_string().try_into().unwrap(),
651-
max_uint: Uint256::from(1_000_000_000u128).try_into().unwrap(),
652-
max_target_decimals: 6,
662+
truncation: TruncationConfig {
663+
max_uint: Uint256::from(1_000_000_000u128).try_into().unwrap(),
664+
max_decimals_when_truncating: 6,
665+
},
653666
},
654667
)
655668
.unwrap();
@@ -659,18 +672,42 @@ mod test {
659672
msg::ChainConfig {
660673
chain: destination_chain.clone(),
661674
its_edge_contract: "itsedgecontract".to_string().try_into().unwrap(),
662-
max_uint: Uint256::from(1_000_000_000_000_000u128).try_into().unwrap(),
663-
max_target_decimals: 6,
675+
truncation: TruncationConfig {
676+
max_uint: Uint256::from(1_000_000_000_000_000u128).try_into().unwrap(),
677+
max_decimals_when_truncating: 6,
678+
},
664679
},
665680
)
666681
.unwrap();
667682

683+
let deploy_token = DeployInterchainToken {
684+
token_id: [1u8; 32].into(),
685+
name: "token".to_string().try_into().unwrap(),
686+
symbol: "TKN".to_string().try_into().unwrap(),
687+
decimals: 9,
688+
minter: None,
689+
};
668690
let deploy_token = assert_ok!(interceptors::calculate_scaling_factor(
669691
&storage,
670692
&source_chain,
671693
&destination_chain,
672694
deploy_token,
673695
));
674696
assert_eq!(deploy_token.decimals, 9);
697+
698+
let deploy_token = DeployInterchainToken {
699+
token_id: [1u8; 32].into(),
700+
name: "token".to_string().try_into().unwrap(),
701+
symbol: "TKN".to_string().try_into().unwrap(),
702+
decimals: 3,
703+
minter: None,
704+
};
705+
let deploy_token = assert_ok!(interceptors::calculate_scaling_factor(
706+
&storage,
707+
&source_chain,
708+
&destination_chain,
709+
deploy_token,
710+
));
711+
assert_eq!(deploy_token.decimals, 3);
675712
}
676713
}

contracts/interchain-token-service/src/contract/execute/mod.rs

+21-10
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@ mod tests {
300300
disable_execution, enable_execution, execute_message, freeze_chain, register_chain,
301301
register_chains, unfreeze_chain, update_chain, Error,
302302
};
303+
use crate::msg::TruncationConfig;
303304
use crate::state::{self, Config};
304305
use crate::{msg, DeployInterchainToken, HubMessage, InterchainTransfer};
305306

@@ -536,8 +537,10 @@ mod tests {
536537
msg::ChainConfig {
537538
chain: SOLANA.parse().unwrap(),
538539
its_edge_contract: ITS_ADDRESS.to_string().try_into().unwrap(),
539-
max_uint: Uint256::one().try_into().unwrap(),
540-
max_target_decimals: 16u8
540+
truncation: TruncationConfig {
541+
max_uint: Uint256::one().try_into().unwrap(),
542+
max_decimals_when_truncating: 16u8
543+
}
541544
}
542545
));
543546
assert_err_contains!(
@@ -546,8 +549,10 @@ mod tests {
546549
msg::ChainConfig {
547550
chain: SOLANA.parse().unwrap(),
548551
its_edge_contract: ITS_ADDRESS.to_string().try_into().unwrap(),
549-
max_uint: Uint256::one().try_into().unwrap(),
550-
max_target_decimals: 16u8
552+
truncation: TruncationConfig {
553+
max_uint: Uint256::one().try_into().unwrap(),
554+
max_decimals_when_truncating: 16u8
555+
}
551556
}
552557
),
553558
Error,
@@ -562,14 +567,18 @@ mod tests {
562567
msg::ChainConfig {
563568
chain: SOLANA.parse().unwrap(),
564569
its_edge_contract: ITS_ADDRESS.to_string().try_into().unwrap(),
565-
max_uint: Uint256::MAX.try_into().unwrap(),
566-
max_target_decimals: 16u8,
570+
truncation: TruncationConfig {
571+
max_uint: Uint256::MAX.try_into().unwrap(),
572+
max_decimals_when_truncating: 16u8,
573+
},
567574
},
568575
msg::ChainConfig {
569576
chain: XRPL.parse().unwrap(),
570577
its_edge_contract: ITS_ADDRESS.to_string().try_into().unwrap(),
571-
max_uint: Uint256::MAX.try_into().unwrap(),
572-
max_target_decimals: 16u8,
578+
truncation: TruncationConfig {
579+
max_uint: Uint256::MAX.try_into().unwrap(),
580+
max_decimals_when_truncating: 16u8,
581+
},
573582
},
574583
];
575584
assert_ok!(register_chains(deps.as_mut(), chains[0..1].to_vec()));
@@ -623,8 +632,10 @@ mod tests {
623632
msg::ChainConfig {
624633
chain: chain.clone(),
625634
its_edge_contract: ITS_ADDRESS.to_string().try_into().unwrap(),
626-
max_uint: Uint256::one().try_into().unwrap(),
627-
max_target_decimals: 16u8
635+
truncation: TruncationConfig {
636+
max_uint: Uint256::one().try_into().unwrap(),
637+
max_decimals_when_truncating: 16u8
638+
}
628639
}
629640
));
630641
}

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

+6-1
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,13 @@ pub enum ExecuteMsg {
5757
pub struct ChainConfig {
5858
pub chain: ChainNameRaw,
5959
pub its_edge_contract: Address,
60+
pub truncation: TruncationConfig,
61+
}
62+
63+
#[cw_serde]
64+
pub struct TruncationConfig {
6065
pub max_uint: nonempty::Uint256, // The maximum uint value that is supported by the chain's token standard
61-
pub max_target_decimals: u8, // The maximum number of decimals that is preserved when deploying a token to another chain where smaller uint values are used
66+
pub max_decimals_when_truncating: u8, // The maximum number of decimals that is preserved when deploying from a chain with a larger max_uint
6267
}
6368

6469
#[cw_serde]

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

+19-8
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,24 @@ pub struct Config {
3434

3535
#[cw_serde]
3636
pub struct ChainConfig {
37-
pub max_uint: nonempty::Uint256,
38-
pub max_target_decimals: u8,
37+
pub truncation: TruncationConfig,
3938
pub its_address: Address,
4039
frozen: bool,
4140
}
4241

42+
#[cw_serde]
43+
pub struct TruncationConfig {
44+
pub max_uint: nonempty::Uint256, // The maximum uint value that is supported by the chain's token standard
45+
pub max_decimals_when_truncating: u8, // The maximum number of decimals that is preserved when deploying from a chain with a larger max_uint
46+
}
47+
4348
impl From<msg::ChainConfig> for ChainConfig {
4449
fn from(value: msg::ChainConfig) -> Self {
4550
Self {
46-
max_uint: value.max_uint,
47-
max_target_decimals: value.max_target_decimals,
51+
truncation: TruncationConfig {
52+
max_uint: value.truncation.max_uint,
53+
max_decimals_when_truncating: value.truncation.max_decimals_when_truncating,
54+
},
4855
its_address: value.its_edge_contract,
4956
frozen: false,
5057
}
@@ -326,8 +333,10 @@ mod tests {
326333
msg::ChainConfig {
327334
chain: chain1.clone(),
328335
its_edge_contract: address1.clone(),
329-
max_uint: Uint256::MAX.try_into().unwrap(),
330-
max_target_decimals: 16u8
336+
truncation: msg::TruncationConfig {
337+
max_uint: Uint256::MAX.try_into().unwrap(),
338+
max_decimals_when_truncating: 16u8
339+
}
331340
}
332341
));
333342
assert_ok!(save_chain_config(
@@ -336,8 +345,10 @@ mod tests {
336345
msg::ChainConfig {
337346
chain: chain2.clone(),
338347
its_edge_contract: address2.clone(),
339-
max_uint: Uint256::MAX.try_into().unwrap(),
340-
max_target_decimals: 16u8
348+
truncation: msg::TruncationConfig {
349+
max_uint: Uint256::MAX.try_into().unwrap(),
350+
max_decimals_when_truncating: 16u8
351+
}
341352
}
342353
));
343354
assert_eq!(

0 commit comments

Comments
 (0)