1
- use axelar_wasm_std:: IntoContractError ;
1
+ use axelar_wasm_std:: { nonempty , FnExt , IntoContractError } ;
2
2
use cosmwasm_std:: { DepsMut , HexBinary , QuerierWrapper , Response , Storage } ;
3
3
use error_stack:: { bail, ensure, report, Result , ResultExt } ;
4
4
use router_api:: { Address , ChainName , ChainNameRaw , CrossChainId } ;
5
+ use sha3:: { Digest , Keccak256 } ;
5
6
6
7
use crate :: events:: Event ;
7
8
use crate :: primitives:: HubMessage ;
8
9
use crate :: state:: { self , load_config, load_its_contract} ;
10
+ use crate :: TokenId ;
11
+
12
+ // this is just keccak256("its-interchain-token-id-gateway")
13
+ const GATEWAY_TOKEN_PREFIX : [ u8 ; 32 ] = [
14
+ 106 , 80 , 188 , 250 , 12 , 170 , 167 , 223 , 94 , 185 , 52 , 185 , 146 , 147 , 21 , 23 , 145 , 36 , 97 , 146 ,
15
+ 215 , 72 , 32 , 167 , 6 , 16 , 83 , 155 , 176 , 213 , 112 , 44 ,
16
+ ] ;
9
17
10
18
#[ derive( thiserror:: Error , Debug , IntoContractError ) ]
11
19
pub enum Error {
@@ -21,6 +29,10 @@ pub enum Error {
21
29
FailedItsContractRegistration ( ChainNameRaw ) ,
22
30
#[ error( "failed to deregister its contract for chain {0}" ) ]
23
31
FailedItsContractDeregistration ( ChainNameRaw ) ,
32
+ #[ error( "failed to register gateway token" ) ]
33
+ FailedGatewayTokenRegistration ,
34
+ #[ error( "failed to generate token id" ) ]
35
+ FailedTokenIdGeneration ,
24
36
}
25
37
26
38
/// Executes an incoming ITS message.
@@ -126,3 +138,116 @@ pub fn deregister_its_contract(deps: DepsMut, chain: ChainNameRaw) -> Result<Res
126
138
127
139
Ok ( Response :: new ( ) . add_event ( Event :: ItsContractDeregistered { chain } . into ( ) ) )
128
140
}
141
+
142
+ pub fn register_gateway_token (
143
+ deps : DepsMut ,
144
+ denom : nonempty:: String ,
145
+ _chain : ChainNameRaw ,
146
+ ) -> Result < Response , Error > {
147
+ let token_id = gateway_token_id ( & deps, & denom) ?;
148
+ state:: save_gateway_token_denom ( deps. storage , token_id, denom)
149
+ . change_context ( Error :: FailedGatewayTokenRegistration ) ?;
150
+ Ok ( Response :: new ( ) )
151
+ }
152
+
153
+ pub fn gateway_token_id ( deps : & DepsMut , denom : & str ) -> Result < TokenId , Error > {
154
+ let config = state:: load_config ( deps. storage ) ;
155
+ let gateway: axelarnet_gateway:: Client =
156
+ client:: ContractClient :: new ( deps. querier , & config. axelarnet_gateway ) . into ( ) ;
157
+ let chain_name = gateway
158
+ . chain_name ( )
159
+ . change_context ( Error :: FailedTokenIdGeneration ) ?;
160
+ let chain_name_hash: [ u8 ; 32 ] = Keccak256 :: digest ( chain_name. to_string ( ) . as_bytes ( ) ) . into ( ) ;
161
+
162
+ Keccak256 :: digest ( [ & GATEWAY_TOKEN_PREFIX , & chain_name_hash, denom. as_bytes ( ) ] . concat ( ) )
163
+ . then ( <[ u8 ; 32 ] >:: from)
164
+ . then ( TokenId :: new)
165
+ . then ( Ok )
166
+ }
167
+
168
+ #[ cfg( test) ]
169
+ mod tests {
170
+ use assert_ok:: assert_ok;
171
+ use axelar_wasm_std:: assert_err_contains;
172
+ use axelarnet_gateway:: msg:: QueryMsg ;
173
+ use cosmwasm_std:: testing:: { mock_dependencies, MockApi , MockQuerier } ;
174
+ use cosmwasm_std:: { from_json, to_json_binary, Addr , MemoryStorage , OwnedDeps , WasmQuery } ;
175
+ use router_api:: { ChainName , ChainNameRaw } ;
176
+
177
+ use super :: { gateway_token_id, register_gateway_token, Error } ;
178
+ use crate :: state:: { self , Config } ;
179
+
180
+ #[ test]
181
+ fn gateway_token_id_should_be_idempotent ( ) {
182
+ let mut deps = init ( ) ;
183
+ let denom = "uaxl" ;
184
+ let token_id = assert_ok ! ( gateway_token_id( & deps. as_mut( ) , denom) ) ;
185
+ let token_id_2 = assert_ok ! ( gateway_token_id( & deps. as_mut( ) , denom) ) ;
186
+ assert_eq ! ( token_id, token_id_2) ;
187
+ }
188
+
189
+ #[ test]
190
+ fn gateway_token_id_should_differ_for_different_denoms ( ) {
191
+ let mut deps = init ( ) ;
192
+ let axl_denom = "uaxl" ;
193
+ let eth_denom = "eth" ;
194
+ let token_id_axl = assert_ok ! ( gateway_token_id( & deps. as_mut( ) , axl_denom) ) ;
195
+ let token_id_eth = assert_ok ! ( gateway_token_id( & deps. as_mut( ) , eth_denom) ) ;
196
+ assert_ne ! ( token_id_axl, token_id_eth) ;
197
+ }
198
+
199
+ #[ test]
200
+ fn gateway_token_id_should_not_change ( ) {
201
+ let mut deps = init ( ) ;
202
+ let denom = "uaxl" ;
203
+ let token_id = assert_ok ! ( gateway_token_id( & deps. as_mut( ) , denom) ) ;
204
+ goldie:: assert_json!( token_id) ;
205
+ }
206
+
207
+ #[ test]
208
+ fn register_token_id_should_not_overwrite ( ) {
209
+ let mut deps = init ( ) ;
210
+ let denom = "uaxl" ;
211
+ let chain = ChainNameRaw :: try_from ( "ethereum" ) . unwrap ( ) ;
212
+ assert_ok ! ( register_gateway_token(
213
+ deps. as_mut( ) ,
214
+ denom. try_into( ) . unwrap( ) ,
215
+ chain. clone( )
216
+ ) ) ;
217
+ // calling again should fail
218
+ assert_err_contains ! (
219
+ register_gateway_token( deps. as_mut( ) , denom. try_into( ) . unwrap( ) , chain) ,
220
+ Error ,
221
+ Error :: FailedGatewayTokenRegistration
222
+ ) ;
223
+ }
224
+
225
+ fn init ( ) -> OwnedDeps < MemoryStorage , MockApi , MockQuerier > {
226
+ let addr = Addr :: unchecked ( "axelar-gateway" ) ;
227
+ let mut deps = mock_dependencies ( ) ;
228
+ state:: save_config (
229
+ deps. as_mut ( ) . storage ,
230
+ & Config {
231
+ axelarnet_gateway : addr. clone ( ) ,
232
+ } ,
233
+ )
234
+ . unwrap ( ) ;
235
+
236
+ let mut querier = MockQuerier :: default ( ) ;
237
+ querier. update_wasm ( move |msg| match msg {
238
+ WasmQuery :: Smart { contract_addr, msg } if contract_addr == & addr. to_string ( ) => {
239
+ let msg = from_json :: < QueryMsg > ( msg) . unwrap ( ) ;
240
+ match msg {
241
+ QueryMsg :: ChainName { } => {
242
+ Ok ( to_json_binary ( & ChainName :: try_from ( "axelar" ) . unwrap ( ) ) . into ( ) ) . into ( )
243
+ }
244
+ _ => panic ! ( "unsupported query" ) ,
245
+ }
246
+ }
247
+ _ => panic ! ( "unexpected query: {:?}" , msg) ,
248
+ } ) ;
249
+
250
+ deps. querier = querier;
251
+ deps
252
+ }
253
+ }
0 commit comments