Skip to content

Commit 75e6387

Browse files
init: setup intial definitions and functions
1 parent 5d1855b commit 75e6387

Some content is hidden

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

47 files changed

+2532
-225
lines changed

crates/ibc/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,13 @@ serde = ["dep:serde", "dep:serde_derive", "serde_json", "erased-serde", "ics23/s
4646
# Depends on the `testgen` suite for generating Tendermint light blocks.
4747
mocks = ["tendermint-testgen", "tendermint/clock", "parking_lot"]
4848

49+
# This feature guards the unfinished implementation of the interchain accounts (ICS27) application.
50+
interchain-accounts = []
51+
4952
[dependencies]
5053
# Proto definitions for all IBC-related interfaces, e.g., connections or channels.
5154
ibc-proto = { version = "0.32.0", default-features = false }
55+
cosmrs = "0.14.0"
5256
ics23 = { version = "0.10.1", default-features = false, features = ["host-functions"] }
5357
time = { version = ">=0.3.0, <0.3.23", default-features = false }
5458
serde_derive = { version = "1.0.104", default-features = false, optional = true }
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
use alloc::string::{String, ToString};
2+
use alloc::vec;
3+
use cosmrs::AccountId;
4+
use prost::Message;
5+
6+
use ibc_proto::cosmos::auth::v1beta1::BaseAccount as RawBaseAccount;
7+
use ibc_proto::google::protobuf::Any;
8+
use ibc_proto::ibc::applications::interchain_accounts::v1::InterchainAccount as RawInterchainAccount;
9+
use ibc_proto::protobuf::Protobuf;
10+
use sha2::{Digest, Sha256};
11+
12+
use super::error::InterchainAccountError;
13+
use super::MODULE_ID_STR;
14+
use crate::core::ics24_host::identifier::PortId;
15+
use crate::Signer;
16+
17+
/// Defines an interchain account type with a generic base account.
18+
///
19+
/// TODO: to put a note that we currently only support Cosmos-SDK driven chains.
20+
#[derive(Clone, Debug)]
21+
pub struct InterchainAccount<A: BaseAccount> {
22+
/// The base account.
23+
base_account: A,
24+
/// The account owner.
25+
owner: PortId,
26+
}
27+
28+
impl<A: BaseAccount> InterchainAccount<A> {
29+
/// Constructs a new interchain account instance.
30+
pub fn new(base_account: A, owner: PortId) -> Self {
31+
Self {
32+
base_account,
33+
owner,
34+
}
35+
}
36+
37+
/// Constructs a new interchain account with a Cosmos-SDK base account.
38+
pub fn new_with_sdk_base_account(
39+
address: AccountId,
40+
owner: PortId,
41+
) -> InterchainAccount<SdkBaseAccount> {
42+
let acc = SdkBaseAccount {
43+
address,
44+
pub_key: Any {
45+
type_url: String::new(),
46+
value: vec![],
47+
},
48+
account_number: 0,
49+
sequence: 0,
50+
};
51+
InterchainAccount::new(acc, owner)
52+
}
53+
54+
pub fn address(&self) -> Signer {
55+
self.base_account.address()
56+
}
57+
}
58+
59+
impl BaseAccount for SdkBaseAccount {
60+
fn address(&self) -> Signer {
61+
Signer::from(self.address.to_string())
62+
}
63+
}
64+
65+
impl Protobuf<RawInterchainAccount> for InterchainAccount<SdkBaseAccount> {}
66+
67+
impl TryFrom<RawInterchainAccount> for InterchainAccount<SdkBaseAccount> {
68+
type Error = InterchainAccountError;
69+
70+
fn try_from(raw: RawInterchainAccount) -> Result<Self, Self::Error> {
71+
Ok(InterchainAccount {
72+
base_account: match raw.base_account {
73+
Some(base_account) => SdkBaseAccount::try_from(base_account)?,
74+
None => return Err(InterchainAccountError::not_found("base account")),
75+
},
76+
owner: raw.account_owner.parse().unwrap(),
77+
})
78+
}
79+
}
80+
81+
impl From<InterchainAccount<SdkBaseAccount>> for RawInterchainAccount {
82+
fn from(domain: InterchainAccount<SdkBaseAccount>) -> Self {
83+
RawInterchainAccount {
84+
base_account: Some(domain.base_account.into()),
85+
account_owner: domain.owner.to_string(),
86+
}
87+
}
88+
}
89+
90+
/// Defines the base account for Cosmos-SDK driven chains.
91+
#[derive(Clone, Debug)]
92+
pub struct SdkBaseAccount {
93+
/// The address of the account.
94+
pub address: AccountId,
95+
/// The public key of the account.
96+
pub pub_key: Any,
97+
/// The account number.
98+
pub account_number: u64,
99+
/// The sequence number.
100+
pub sequence: u64,
101+
}
102+
103+
impl Protobuf<RawBaseAccount> for SdkBaseAccount {}
104+
105+
impl TryFrom<RawBaseAccount> for SdkBaseAccount {
106+
type Error = InterchainAccountError;
107+
108+
fn try_from(raw: RawBaseAccount) -> Result<Self, Self::Error> {
109+
// TODO: should we check anything here? regarding number and sequence?
110+
Ok(SdkBaseAccount {
111+
address: raw
112+
.address
113+
.parse()
114+
.map_err(InterchainAccountError::source)?,
115+
pub_key: match raw.pub_key {
116+
Some(pub_key) => pub_key,
117+
None => return Err(InterchainAccountError::not_found("missing base account")),
118+
},
119+
account_number: raw.account_number,
120+
sequence: raw.sequence,
121+
})
122+
}
123+
}
124+
125+
impl From<SdkBaseAccount> for RawBaseAccount {
126+
fn from(domain: SdkBaseAccount) -> Self {
127+
RawBaseAccount {
128+
address: domain.address.to_string(),
129+
pub_key: Some(domain.pub_key),
130+
account_number: domain.account_number,
131+
sequence: domain.sequence,
132+
}
133+
}
134+
}
135+
136+
const TYPE_URL: &str = "/cosmos.auth.v1beta1.BaseAccount";
137+
138+
impl From<SdkBaseAccount> for Any {
139+
fn from(account: SdkBaseAccount) -> Self {
140+
let account = RawBaseAccount::from(account);
141+
Any {
142+
type_url: TYPE_URL.to_string(),
143+
value: account.encode_to_vec(),
144+
}
145+
}
146+
}
147+
148+
/// Enforces minimum definition requirement for a base account.
149+
pub trait BaseAccount {
150+
fn address(&self) -> Signer;
151+
}
152+
153+
pub fn get_sdk_controller_account() -> Result<AccountId, InterchainAccountError> {
154+
let mut hasher = Sha256::new();
155+
156+
hasher.update(MODULE_ID_STR.as_bytes());
157+
158+
let mut hash = hasher.finalize().to_vec();
159+
160+
hash.truncate(20);
161+
162+
let controller_account =
163+
AccountId::new(MODULE_ID_STR, &hash).map_err(InterchainAccountError::source)?;
164+
165+
Ok(controller_account)
166+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
use crate::core::ics24_host::identifier::ChannelId;
2+
use crate::core::ics24_host::identifier::ConnectionId;
3+
use crate::core::ics24_host::identifier::PortId;
4+
use crate::core::ExecutionContext;
5+
use crate::core::ValidationContext;
6+
use crate::Signer;
7+
8+
use super::account::BaseAccount;
9+
use super::account::InterchainAccount;
10+
use super::error::InterchainAccountError;
11+
use super::host::params::Params;
12+
13+
pub trait InterchainAccountValidationContext: ValidationContext {
14+
type AccountId: TryFrom<Signer>;
15+
16+
/// Returns true if the controller functionality is enabled on the chain
17+
fn is_controller_enabled(&self) -> bool;
18+
19+
/// Returns the active `ChannelId` from the store by the provided
20+
/// `ConnectionId` and `PortId`
21+
fn get_active_channel_id(
22+
&self,
23+
connection_id: &ConnectionId,
24+
port_id: &PortId,
25+
) -> Result<ChannelId, InterchainAccountError>;
26+
27+
/// Returns the parameters needed for functioning as a host chain
28+
fn get_params(&self) -> Result<Params, InterchainAccountError>;
29+
30+
/// Returns the `AccountId` for the given address
31+
fn get_interchain_account(
32+
&self,
33+
address: &Signer,
34+
) -> Result<Self::AccountId, InterchainAccountError>;
35+
36+
/// Returns the InterchainAccount address from the store associated with
37+
/// the provided ConnectionId and PortId
38+
fn get_ica_address(
39+
&self,
40+
connection_id: &ConnectionId,
41+
port_id: &PortId,
42+
) -> Result<Signer, InterchainAccountError>;
43+
}
44+
45+
pub trait InterchainAccountExecutionContext:
46+
ExecutionContext + InterchainAccountValidationContext
47+
{
48+
/// Stores the active `ChannelId` to the store by the provided
49+
/// `ConnectionId` and `PortId`
50+
fn store_active_channel_id(
51+
&mut self,
52+
connection_id: ConnectionId,
53+
port_id: PortId,
54+
channel_id: ChannelId,
55+
) -> Result<(), InterchainAccountError>;
56+
57+
/// Stores the parameters for functioning as a host chain
58+
fn store_params(&mut self, params: Params) -> Result<(), InterchainAccountError>;
59+
60+
/// Generates a new interchain account address.
61+
///
62+
/// It uses the host `ConnectionId`, the controller `PortId`, and may also
63+
/// (in case of Cosmos SDK chains) incorporate block dependent information.
64+
fn generate_ica_address(
65+
&self,
66+
connection_id: ConnectionId,
67+
port_id: PortId,
68+
) -> Result<Signer, InterchainAccountError>;
69+
70+
/// Stores the interchain account address
71+
fn store_ica_address(
72+
&mut self,
73+
connection_id: ConnectionId,
74+
port_id: PortId,
75+
interchain_account_address: Signer,
76+
) -> Result<(), InterchainAccountError>;
77+
78+
/// Creates a new interchain account with the provided account information
79+
fn new_interchain_account<A: BaseAccount>(
80+
&mut self,
81+
account: InterchainAccount<A>,
82+
) -> Result<Self::AccountId, InterchainAccountError>;
83+
84+
/// Stores the created interchain account to the store
85+
fn store_interchain_account(
86+
&mut self,
87+
account: Self::AccountId,
88+
) -> Result<(), InterchainAccountError>;
89+
}

0 commit comments

Comments
 (0)