pallet_chain_extension_assets/
lib.rs

1// This file is part of Astar.
2
3// Copyright (C) Stake Technologies Pte.Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later
5
6// Astar is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// Astar is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with Astar. If not, see <http://www.gnu.org/licenses/>.
18
19#![cfg_attr(not(feature = "std"), no_std)]
20
21#[cfg(test)]
22mod mock;
23#[cfg(test)]
24mod tests;
25
26pub use assets_chain_extension_types::Command::{self, *};
27use assets_chain_extension_types::{handle_result, Outcome, LOG_TARGET};
28use frame_support::traits::fungibles::{
29    approvals::Inspect as AllowanceInspect, metadata::Inspect as MetadataInspect, Inspect,
30};
31use frame_support::DefaultNoBound;
32use frame_system::RawOrigin;
33use pallet_assets::WeightInfo;
34use pallet_contracts::chain_extension::{
35    ChainExtension, Environment, Ext, InitState, RetVal, SysConfig,
36};
37use parity_scale_codec::Encode;
38use sp_runtime::traits::{Get, StaticLookup};
39use sp_runtime::DispatchError;
40use sp_std::marker::PhantomData;
41type Weight<T> = <T as pallet_assets::Config>::WeightInfo;
42
43/// Pallet Assets chain extension.
44#[derive(DefaultNoBound)]
45pub struct AssetsExtension<T>(PhantomData<T>);
46
47impl<T> ChainExtension<T> for AssetsExtension<T>
48where
49    T: pallet_assets::Config + pallet_contracts::Config,
50    <T as pallet_assets::Config>::AssetId: Copy,
51    <<T as SysConfig>::Lookup as StaticLookup>::Source: From<<T as SysConfig>::AccountId>,
52{
53    fn call<E: Ext>(&mut self, env: Environment<E, InitState>) -> Result<RetVal, DispatchError>
54    where
55        E: Ext<T = T>,
56    {
57        let mut env = env.buf_in_buf_out();
58        match env.func_id().try_into().map_err(|_| {
59            DispatchError::Other("Unsupported func id in Pallet Assets Chain Extension")
60        })? {
61            Transfer => {
62                env.charge_weight(Weight::<T>::transfer())?;
63
64                let (id, target, amount): (
65                    <T as pallet_assets::Config>::AssetId,
66                    T::AccountId,
67                    T::Balance,
68                ) = env.read_as()?;
69
70                log::trace!(
71                    target: LOG_TARGET,
72                    "transfer: raw arguments: id: {:?}, to: {:?}, amount: {:?}",
73                    id,
74                    target,
75                    amount
76                );
77
78                let call_result = pallet_assets::Pallet::<T>::transfer(
79                    RawOrigin::Signed(env.ext().address().clone()).into(),
80                    id.into(),
81                    target.into(),
82                    amount,
83                );
84                handle_result!(call_result);
85            }
86            TransferApproved => {
87                env.charge_weight(Weight::<T>::transfer_approved())?;
88
89                let (id, owner, destination, amount): (
90                    <T as pallet_assets::Config>::AssetId,
91                    T::AccountId,
92                    T::AccountId,
93                    T::Balance,
94                ) = env.read_as()?;
95
96                log::trace!(target: LOG_TARGET,
97                    "transfer_approved: raw arguments: id: {:?}, owner: {:?}, destination: {:?}, amount: {:?}",
98                      id, owner, destination, amount);
99
100                let call_result = pallet_assets::Pallet::<T>::transfer_approved(
101                    RawOrigin::Signed(env.ext().address().clone()).into(),
102                    id.into(),
103                    owner.into(),
104                    destination.into(),
105                    amount,
106                );
107                handle_result!(call_result);
108            }
109            Mint => {
110                env.charge_weight(Weight::<T>::mint())?;
111
112                let (id, beneficiary, amount): (
113                    <T as pallet_assets::Config>::AssetId,
114                    T::AccountId,
115                    T::Balance,
116                ) = env.read_as()?;
117
118                log::trace!(
119                    target: LOG_TARGET,
120                    "mint: raw arguments: id: {:?}, beneficiary: {:?}, amount: {:?}",
121                    id,
122                    beneficiary,
123                    amount
124                );
125
126                let call_result = pallet_assets::Pallet::<T>::mint(
127                    RawOrigin::Signed(env.ext().address().clone()).into(),
128                    id.into(),
129                    beneficiary.into(),
130                    amount,
131                );
132                handle_result!(call_result);
133            }
134            Burn => {
135                env.charge_weight(Weight::<T>::burn())?;
136
137                let (id, who, amount): (
138                    <T as pallet_assets::Config>::AssetId,
139                    T::AccountId,
140                    T::Balance,
141                ) = env.read_as()?;
142
143                log::trace!(
144                    target: LOG_TARGET,
145                    "burn: raw arguments: id: {:?}, who: {:?}, amount: {:?}",
146                    id,
147                    who,
148                    amount
149                );
150
151                let call_result = pallet_assets::Pallet::<T>::burn(
152                    RawOrigin::Signed(env.ext().address().clone()).into(),
153                    id.into(),
154                    who.into(),
155                    amount,
156                );
157                handle_result!(call_result);
158            }
159            ApproveTransfer => {
160                env.charge_weight(Weight::<T>::approve_transfer())?;
161
162                let (id, delegate, amount): (
163                    <T as pallet_assets::Config>::AssetId,
164                    T::AccountId,
165                    T::Balance,
166                ) = env.read_as()?;
167
168                log::trace!(
169                    target: LOG_TARGET,
170                    "approve_transfer: raw arguments: id: {id:?}, delegate: {delegate:?}, amount: {amount:?}",
171                );
172
173                let call_result = pallet_assets::Pallet::<T>::approve_transfer(
174                    RawOrigin::Signed(env.ext().address().clone()).into(),
175                    id.into(),
176                    delegate.into(),
177                    amount,
178                );
179                handle_result!(call_result);
180            }
181            BalanceOf => {
182                env.charge_weight(T::DbWeight::get().reads(1_u64))?;
183
184                let (id, who): (<T as pallet_assets::Config>::AssetId, T::AccountId) =
185                    env.read_as()?;
186
187                pallet_assets::Pallet::<T>::balance(id, who)
188                    .using_encoded(|r| env.write(r, false, None))?;
189            }
190            TotalSupply => {
191                env.charge_weight(T::DbWeight::get().reads(1_u64))?;
192
193                let id: <T as pallet_assets::Config>::AssetId = env.read_as()?;
194
195                pallet_assets::Pallet::<T>::total_supply(id)
196                    .using_encoded(|r| env.write(r, false, None))?;
197            }
198            Allowance => {
199                env.charge_weight(T::DbWeight::get().reads(1_u64))?;
200
201                let (id, owner, delegate): (
202                    <T as pallet_assets::Config>::AssetId,
203                    T::AccountId,
204                    T::AccountId,
205                ) = env.read_as()?;
206
207                <pallet_assets::Pallet<T> as AllowanceInspect<T::AccountId>>::allowance(
208                    id, &owner, &delegate,
209                )
210                .using_encoded(|r| env.write(r, false, None))?;
211            }
212            MetadataName => {
213                env.charge_weight(T::DbWeight::get().reads(1_u64))?;
214
215                let id: <T as pallet_assets::Config>::AssetId = env.read_as()?;
216
217                <pallet_assets::Pallet<T> as MetadataInspect<T::AccountId>>::name(id)
218                    .using_encoded(|r| env.write(r, false, None))?;
219            }
220            MetadataSymbol => {
221                env.charge_weight(T::DbWeight::get().reads(1_u64))?;
222
223                let id: <T as pallet_assets::Config>::AssetId = env.read_as()?;
224
225                <pallet_assets::Pallet<T> as MetadataInspect<T::AccountId>>::symbol(id)
226                    .using_encoded(|r| env.write(r, false, None))?;
227            }
228            MetadataDecimals => {
229                env.charge_weight(T::DbWeight::get().reads(1_u64))?;
230
231                let id: <T as pallet_assets::Config>::AssetId = env.read_as()?;
232
233                <pallet_assets::Pallet<T> as MetadataInspect<T::AccountId>>::decimals(id)
234                    .using_encoded(|r| env.write(r, false, None))?;
235            }
236            MinimumBalance => {
237                env.charge_weight(T::DbWeight::get().reads(1_u64))?;
238
239                let id: <T as pallet_assets::Config>::AssetId = env.read_as()?;
240
241                <pallet_assets::Pallet<T> as Inspect<T::AccountId>>::minimum_balance(id)
242                    .using_encoded(|r| env.write(r, false, None))?;
243            }
244        }
245
246        Ok(RetVal::Converging(Outcome::Success as u32))
247    }
248}