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

            
41
pub struct NativeAssetReserve;
42
impl frame_support::traits::ContainsPair<Asset, Location> for NativeAssetReserve {
43
1326
    fn contains(asset: &Asset, origin: &Location) -> bool {
44
1326
        log::trace!(target: "xcm::contains", "NativeAssetReserve asset: {:?}, origin: {:?}", asset, origin);
45
1326
        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
1144
            asset.id.0.chain_part()
51
        };
52

            
53
1326
        if let Some(ref reserve) = reserve {
54
1326
            if reserve == origin {
55
260
                return true;
56
1066
            }
57
        }
58
1066
        false
59
1326
    }
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
72
    fn contains(asset: &Asset, origin: &Location) -> bool {
73
72
        log::trace!(target: "xcm::contains", "EthereumAssetReserve asset: {:?}, origin: {:?}", asset, origin);
74
72
        if *origin != EthereumLocation::get() {
75
4
            return false;
76
68
        }
77
68
        matches!((asset.id.0.parents, asset.id.0.first_interior()), (1, Some(GlobalConsensus(network))) if *network == EthereumNetwork::get())
78
72
    }
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
18
    fn contains(asset: &Asset, origin: &Location) -> bool {
92
18
        log::trace!(target: "xcm::contains", "EthereumAssetReserveFromPara asset: {:?}, origin: {:?}, eth_network: {:?}", asset, origin, EthereumLocation::get());
93
18
        if *origin == EthereumLocation::get() || *origin == Location::parent() {
94
16
            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
18
    }
98
}
99

            
100
/// Filter to ensure that Ethereum can be recongnized as a reserve for Tanssi asset.
101
/// Used in containers to allow sending tokens to Ethereum and paying fees with Tanssi.
102
pub struct EthereumAssetReserveForTanssi<EthereumLocation>(
103
    core::marker::PhantomData<EthereumLocation>,
104
);
105
impl<EthereumLocation> frame_support::traits::ContainsPair<Asset, Location>
106
    for EthereumAssetReserveForTanssi<EthereumLocation>
107
where
108
    EthereumLocation: Get<Location>,
109
{
110
20
    fn contains(asset: &Asset, origin: &Location) -> bool {
111
20
        log::trace!(target: "xcm::contains", "EthereumAssetReserveForTanssi asset: {:?}, origin: {:?}, eth_network: {:?}", asset, origin, EthereumLocation::get());
112
20
        if *origin == EthereumLocation::get() {
113
6
            return matches!((asset.id.0.parents, asset.id.0.first_interior()), (1, None));
114
14
        }
115
14
        return false;
116
20
    }
117
}