1
// Copyright (C) Moondance Labs Ltd.
2
// This file is part of Tanssi.
3

            
4
// Tanssi is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8

            
9
// Tanssi is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13

            
14
// You should have received a copy of the GNU General Public License
15
// along with Tanssi.  If not, see <http://www.gnu.org/licenses/>
16

            
17
#![cfg_attr(not(feature = "std"), no_std)]
18

            
19
use frame_support::traits::Get;
20
use xcm::latest::prelude::*;
21
trait Parse {
22
    /// Returns the "chain" location part. It could be parent, sibling
23
    /// parachain, or child parachain.
24
    fn chain_part(&self) -> Option<Location>;
25
}
26

            
27
impl Parse for Location {
28
1040
    fn chain_part(&self) -> Option<Location> {
29
1040
        match (self.parents, self.first_interior()) {
30
            // sibling parachain
31
104
            (1, Some(Parachain(id))) => Some(Location::new(1, [Parachain(*id)])),
32
            // parent
33
936
            (1, _) => Some(Location::parent()),
34
            // children parachain
35
            (0, Some(Parachain(id))) => Some(Location::new(0, [Parachain(*id)])),
36
            _ => None,
37
        }
38
1040
    }
39
}
40

            
41
pub struct NativeAssetReserve;
42
impl frame_support::traits::ContainsPair<Asset, Location> for NativeAssetReserve {
43
1222
    fn contains(asset: &Asset, origin: &Location) -> bool {
44
1222
        log::trace!(target: "xcm::contains", "NativeAssetReserve asset: {:?}, origin: {:?}", asset, origin);
45
1222
        let reserve = if asset.id.0.parents == 0
46
182
            && !matches!(asset.id.0.first_interior(), Some(Parachain(_)))
47
        {
48
182
            Some(Location::here())
49
        } else {
50
1040
            asset.id.0.chain_part()
51
        };
52

            
53
1222
        if let Some(ref reserve) = reserve {
54
1222
            if reserve == origin {
55
260
                return true;
56
962
            }
57
        }
58
962
        false
59
1222
    }
60
}
61

            
62
/// Filter to ensure an ETH asset is coming from a trusted Ethereum location.
63
pub struct EthereumAssetReserve<EthereumLocation, EthereumNetwork>(
64
    core::marker::PhantomData<(EthereumLocation, EthereumNetwork)>,
65
);
66
impl<EthereumLocation, EthereumNetwork> frame_support::traits::ContainsPair<Asset, Location>
67
    for EthereumAssetReserve<EthereumLocation, EthereumNetwork>
68
where
69
    EthereumLocation: Get<Location>,
70
    EthereumNetwork: Get<NetworkId>,
71
{
72
48
    fn contains(asset: &Asset, origin: &Location) -> bool {
73
48
        log::trace!(target: "xcm::contains", "EthereumAssetReserve asset: {:?}, origin: {:?}", asset, origin);
74
48
        if *origin != EthereumLocation::get() {
75
4
            return false;
76
44
        }
77
44
        matches!((asset.id.0.parents, asset.id.0.first_interior()), (1, Some(GlobalConsensus(network))) if *network == EthereumNetwork::get())
78
48
    }
79
}
80

            
81
/// Filter to ensure an ETH asset is coming from a parent.
82
pub struct EthereumAssetReserveFromParent<EthereumLocation, EthereumNetwork>(
83
    core::marker::PhantomData<(EthereumLocation, EthereumNetwork)>,
84
);
85
impl<EthereumLocation, EthereumNetwork> frame_support::traits::ContainsPair<Asset, Location>
86
    for EthereumAssetReserveFromParent<EthereumLocation, EthereumNetwork>
87
where
88
    EthereumLocation: Get<Location>,
89
    EthereumNetwork: Get<NetworkId>,
90
{
91
10
    fn contains(asset: &Asset, origin: &Location) -> bool {
92
10
        log::trace!(target: "xcm::contains", "EthereumAssetReserveFromPara asset: {:?}, origin: {:?}, eth_network: {:?}", asset, origin, EthereumLocation::get());
93
10
        if *origin == EthereumLocation::get() || *origin == Location::parent() {
94
8
            return matches!((asset.id.0.parents, asset.id.0.first_interior()), (2, Some(GlobalConsensus(network))) if *network == EthereumNetwork::get());
95
2
        }
96
2
        return false;
97
10
    }
98
}