1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
use core::time::Duration;
use ibc_relayer::event::IbcEventWithHeight;
use ibc_relayer_types::applications::ics29_fee::packet_fee::IdentifiedPacketFees;
use ibc_relayer_types::core::ics04_channel::packet::Sequence;

use crate::chain::driver::ChainDriver;
use crate::chain::tagged::TaggedChainDriverExt;
use crate::error::Error;
use crate::ibc::token::TaggedTokenRef;
use crate::relayer::fee::{
    ibc_token_transfer_with_fee, pay_packet_fee, query_counterparty_payee,
    query_incentivized_packets, register_counterparty_payee, register_payee,
};
use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef};
use crate::types::tagged::*;
use crate::types::wallet::{Wallet, WalletAddress};

pub trait ChainFeeMethodsExt<Chain> {
    fn ibc_token_transfer_with_fee<Counterparty>(
        &self,
        port_id: &TaggedPortIdRef<'_, Chain, Counterparty>,
        channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>,
        sender: &MonoTagged<Chain, &Wallet>,
        recipient: &MonoTagged<Counterparty, &WalletAddress>,
        send_amount: &TaggedTokenRef<'_, Chain>,
        receive_fee: &TaggedTokenRef<'_, Chain>,
        ack_fee: &TaggedTokenRef<'_, Chain>,
        timeout_fee: &TaggedTokenRef<'_, Chain>,
        timeout: Duration,
    ) -> Result<Vec<IbcEventWithHeight>, Error>;

    fn pay_packet_fee<Counterparty>(
        &self,
        port_id: &TaggedPortIdRef<'_, Chain, Counterparty>,
        channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>,
        sequence: &DualTagged<Chain, Counterparty, Sequence>,
        payer: &MonoTagged<Chain, &Wallet>,
        receive_fee: &TaggedTokenRef<'_, Chain>,
        ack_fee: &TaggedTokenRef<'_, Chain>,
        timeout_fee: &TaggedTokenRef<'_, Chain>,
    ) -> Result<Vec<IbcEventWithHeight>, Error>;

    fn register_counterparty_payee<Counterparty>(
        &self,
        wallet: &MonoTagged<Chain, &Wallet>,
        counterparty_payee: &MonoTagged<Counterparty, &WalletAddress>,
        channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>,
        port_id: &TaggedPortIdRef<'_, Chain, Counterparty>,
    ) -> Result<(), Error>;

    fn register_payee<Counterparty>(
        &self,
        wallet: &MonoTagged<Chain, &Wallet>,
        payee: &MonoTagged<Chain, &WalletAddress>,
        channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>,
        port_id: &TaggedPortIdRef<'_, Chain, Counterparty>,
    ) -> Result<(), Error>;

    fn query_counterparty_payee<Counterparty>(
        &self,
        channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>,
        address: &MonoTagged<Chain, &WalletAddress>,
    ) -> Result<Option<MonoTagged<Counterparty, WalletAddress>>, Error>;

    fn query_incentivized_packets<Counterparty>(
        &self,
        channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>,
        port_id: &TaggedPortIdRef<'_, Chain, Counterparty>,
    ) -> Result<Vec<IdentifiedPacketFees>, Error>;
}

impl<'a, Chain: Send> ChainFeeMethodsExt<Chain> for MonoTagged<Chain, &'a ChainDriver> {
    fn ibc_token_transfer_with_fee<Counterparty>(
        &self,
        port_id: &TaggedPortIdRef<'_, Chain, Counterparty>,
        channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>,
        sender: &MonoTagged<Chain, &Wallet>,
        recipient: &MonoTagged<Counterparty, &WalletAddress>,
        send_amount: &TaggedTokenRef<'_, Chain>,
        receive_fee: &TaggedTokenRef<'_, Chain>,
        ack_fee: &TaggedTokenRef<'_, Chain>,
        timeout_fee: &TaggedTokenRef<'_, Chain>,
        timeout: Duration,
    ) -> Result<Vec<IbcEventWithHeight>, Error> {
        let rpc_client = self.rpc_client()?;
        self.value().runtime.block_on(ibc_token_transfer_with_fee(
            rpc_client.as_ref(),
            &self.tx_config(),
            port_id,
            channel_id,
            sender,
            recipient,
            send_amount,
            receive_fee,
            ack_fee,
            timeout_fee,
            timeout,
        ))
    }

    fn pay_packet_fee<Counterparty>(
        &self,
        port_id: &TaggedPortIdRef<'_, Chain, Counterparty>,
        channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>,
        sequence: &DualTagged<Chain, Counterparty, Sequence>,
        payer: &MonoTagged<Chain, &Wallet>,
        receive_fee: &TaggedTokenRef<'_, Chain>,
        ack_fee: &TaggedTokenRef<'_, Chain>,
        timeout_fee: &TaggedTokenRef<'_, Chain>,
    ) -> Result<Vec<IbcEventWithHeight>, Error> {
        let rpc_client = self.rpc_client()?;
        self.value().runtime.block_on(pay_packet_fee(
            rpc_client.as_ref(),
            &self.tx_config(),
            port_id,
            channel_id,
            sequence,
            payer,
            receive_fee,
            ack_fee,
            timeout_fee,
        ))
    }

    fn register_counterparty_payee<Counterparty>(
        &self,
        wallet: &MonoTagged<Chain, &Wallet>,
        counterparty_payee: &MonoTagged<Counterparty, &WalletAddress>,
        channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>,
        port_id: &TaggedPortIdRef<'_, Chain, Counterparty>,
    ) -> Result<(), Error> {
        let rpc_client = self.rpc_client()?;
        self.value().runtime.block_on(register_counterparty_payee(
            rpc_client.as_ref(),
            &self.tx_config(),
            wallet,
            counterparty_payee,
            channel_id,
            port_id,
        ))
    }

    fn register_payee<Counterparty>(
        &self,
        wallet: &MonoTagged<Chain, &Wallet>,
        payee: &MonoTagged<Chain, &WalletAddress>,
        channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>,
        port_id: &TaggedPortIdRef<'_, Chain, Counterparty>,
    ) -> Result<(), Error> {
        let rpc_client = self.rpc_client()?;
        self.value().runtime.block_on(register_payee(
            rpc_client.as_ref(),
            &self.tx_config(),
            wallet,
            payee,
            channel_id,
            port_id,
        ))
    }

    fn query_counterparty_payee<Counterparty>(
        &self,
        channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>,
        address: &MonoTagged<Chain, &WalletAddress>,
    ) -> Result<Option<MonoTagged<Counterparty, WalletAddress>>, Error> {
        self.value().runtime.block_on(query_counterparty_payee(
            &self.tx_config().value().grpc_address,
            channel_id,
            address,
        ))
    }

    fn query_incentivized_packets<Counterparty>(
        &self,
        channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>,
        port_id: &TaggedPortIdRef<'_, Chain, Counterparty>,
    ) -> Result<Vec<IdentifiedPacketFees>, Error> {
        self.value().runtime.block_on(query_incentivized_packets(
            &self.tx_config().value().grpc_address,
            channel_id,
            port_id,
        ))
    }
}