@@ -31,12 +31,34 @@ where
3131 pub env : Env ,
3232 pub info : MessageInfo ,
3333
34+ // royalty info
35+ pub royalty : RoyaltyInfo ,
36+
3437 /// The response being built up by the plugins.
3538 pub response : Response < TCustomResponseMsg > ,
3639
3740 pub data : Context ,
3841}
3942
43+ pub struct RoyaltyInfo {
44+ pub collection_royalty_bps : Option < u16 > ,
45+ pub collection_royalty_recipient : Option < Addr > ,
46+ pub collection_royalty_on_primary : Option < bool > ,
47+
48+ pub primary_complete : bool ,
49+ }
50+
51+ impl Default for RoyaltyInfo {
52+ fn default ( ) -> Self {
53+ RoyaltyInfo {
54+ collection_royalty_bps : None ,
55+ collection_royalty_recipient : None ,
56+ collection_royalty_on_primary : None ,
57+ primary_complete : false ,
58+ }
59+ }
60+ }
61+
4062pub struct DefaultXionAssetContext {
4163 pub token_id : String ,
4264 pub seller : Option < Addr > ,
@@ -50,16 +72,6 @@ pub struct DefaultXionAssetContext {
5072 pub reservation : Option < Reserve > ,
5173 pub time_lock : Option < Duration > ,
5274
53- pub collection_royalty_bps : Option < u16 > ,
54- pub collection_royalty_recipient : Option < Addr > ,
55- pub collection_royalty_on_primary : Option < bool > ,
56-
57- pub nft_royalty_bps : Option < u16 > ,
58- pub nft_royalty_recipient : Option < Addr > ,
59- pub nft_royalty_on_primary : Option < bool > ,
60-
61- pub primary_complete : bool ,
62-
6375 pub allowed_marketplaces : Option < Vec < Addr > > ,
6476 pub allowed_currencies : Option < Vec < Coin > > ,
6577}
@@ -75,13 +87,6 @@ impl Default for DefaultXionAssetContext {
7587 not_before : Expiration :: Never { } ,
7688 not_after : Expiration :: Never { } ,
7789 reservation : None ,
78- collection_royalty_bps : None ,
79- collection_royalty_recipient : None ,
80- collection_royalty_on_primary : None ,
81- nft_royalty_bps : None ,
82- nft_royalty_recipient : None ,
83- nft_royalty_on_primary : None ,
84- primary_complete : false ,
8590 allowed_marketplaces : None ,
8691 allowed_currencies : None ,
8792 time_lock : None ,
@@ -155,9 +160,9 @@ impl Plugin {
155160 recipient,
156161 on_primary,
157162 } => {
158- ctx. data . collection_royalty_bps = Some ( * bps) ;
159- ctx. data . collection_royalty_recipient = Some ( ( * recipient) . clone ( ) ) ;
160- ctx. data . collection_royalty_on_primary = Some ( * on_primary) ;
163+ ctx. royalty . collection_royalty_bps = Some ( * bps) ;
164+ ctx. royalty . collection_royalty_recipient = Some ( ( * recipient) . clone ( ) ) ;
165+ ctx. royalty . collection_royalty_on_primary = Some ( * on_primary) ;
161166 default_plugins:: royalty_plugin ( ctx) ?;
162167 }
163168 Plugin :: AllowedMarketplaces { marketplaces } => {
@@ -175,6 +180,23 @@ impl Plugin {
175180 }
176181 Ok ( true )
177182 }
183+
184+ pub fn run_raw_transfer_plugin < T , U : CustomMsg > ( & self , ctx : & mut PluginCtx < T , U > ) -> StdResult < bool > {
185+ match self {
186+ Plugin :: Royalty {
187+ bps,
188+ recipient,
189+ on_primary,
190+ } => {
191+ ctx. royalty . collection_royalty_bps = Some ( * bps) ;
192+ ctx. royalty . collection_royalty_recipient = Some ( ( * recipient) . clone ( ) ) ;
193+ ctx. royalty . collection_royalty_on_primary = Some ( * on_primary) ;
194+ default_plugins:: is_transfer_enabled_plugin ( ctx) ?;
195+ }
196+ _ => { }
197+ }
198+ Ok ( true )
199+ }
178200}
179201
180202/// The concept of a plugin is to be able to hook into the execution flow when a certain action
@@ -263,8 +285,15 @@ pub trait PluggableAsset<
263285 & self ,
264286 _recipient : & String ,
265287 _token_id : & String ,
266- _ctx : & mut PluginCtx < Context , TCustomResponseMsg > ,
288+ ctx : & mut PluginCtx < Context , TCustomResponseMsg > ,
267289 ) -> StdResult < bool > {
290+ // for transfers we run the royalty plugin if set
291+ let royalty_plugin = AssetConfig :: < TNftExtension > :: default ( )
292+ . collection_plugins
293+ . may_load ( ctx. deps . storage , "Royalty" ) ?;
294+ if let Some ( plugin) = royalty_plugin {
295+ plugin. run_raw_transfer_plugin ( ctx) ?;
296+ }
268297 Ok ( true )
269298 }
270299
@@ -343,25 +372,6 @@ where
343372 TNftExtensionMsg : Cw721CustomMsg ,
344373 TNftExtensionMsg : StateFactory < TNftExtension > ,
345374{
346- fn on_transfer_plugin (
347- & self ,
348- recipient : & String ,
349- token_id : & String ,
350- ctx : & mut DefaultPluginCtx ,
351- ) -> StdResult < bool > {
352- // for transfers we run the royalty plugin if set
353- let royalty_plugin = AssetConfig :: < TNftExtension > :: default ( )
354- . collection_plugins
355- . may_load ( ctx. deps . storage , "Royalty" ) ?;
356- ctx. data . token_id = token_id. to_string ( ) ;
357- ctx. data . buyer = Some ( ctx. deps . api . addr_validate ( & recipient) ?) ;
358- ctx. data . seller = Some ( ctx. info . sender . clone ( ) ) ;
359- if let Some ( plugin) = royalty_plugin {
360- plugin. run_asset_plugin ( ctx) ?;
361- }
362- Ok ( true )
363- }
364-
365375 fn on_update_extension_plugin < ' a > (
366376 & self ,
367377 msg : & AssetExtensionExecuteMsg ,
@@ -509,6 +519,7 @@ where
509519 env : env. clone ( ) ,
510520 info : info. clone ( ) ,
511521 response : Response :: default ( ) ,
522+ royalty : RoyaltyInfo :: default ( ) ,
512523 data : DefaultXionAssetContext :: default ( ) ,
513524 }
514525 }
@@ -626,33 +637,35 @@ pub mod default_plugins {
626637
627638 pub fn royalty_plugin ( ctx : & mut PluginCtx < DefaultXionAssetContext , Empty > ) -> StdResult < bool > {
628639 let ( recipient, bps, on_primary) = match (
629- ctx. data . nft_royalty_recipient . clone ( ) ,
630- ctx. data . nft_royalty_bps ,
631- ctx. data . nft_royalty_on_primary ,
640+ ctx. royalty . collection_royalty_recipient . clone ( ) ,
641+ ctx. royalty . collection_royalty_bps ,
642+ ctx. royalty . collection_royalty_on_primary ,
632643 ) {
633644 ( Some ( recipient) , Some ( bps) , on_primary) => ( recipient, bps, on_primary) ,
634- _ => match (
635- ctx. data . collection_royalty_recipient . clone ( ) ,
636- ctx. data . collection_royalty_bps ,
637- ctx. data . collection_royalty_on_primary ,
638- ) {
639- ( Some ( recipient) , Some ( bps) , on_primary) => ( recipient, bps, on_primary) ,
640- _ => return Ok ( true ) ,
641- } ,
645+ _ => return Ok ( true ) ,
642646 } ;
643647
644648 if bps == 0 {
645649 return Ok ( true ) ;
646650 }
647651
648- let is_primary_sale = !ctx. data . primary_complete ;
652+ let is_primary_sale = !ctx. royalty . primary_complete ;
649653 let collect_on_primary = on_primary. unwrap_or ( false ) ;
650654 let should_collect = !is_primary_sale || collect_on_primary;
651655
652656 if !should_collect {
653657 return Ok ( true ) ;
654658 }
655659
660+ if let Some ( ask_price) = & ctx. data . ask_price {
661+ if ask_price. amount . is_zero ( ) {
662+ return Ok ( true ) ;
663+ }
664+ } else {
665+ return Err ( cosmwasm_std:: StdError :: generic_err (
666+ "No ask price set for royalty calculation" . to_string ( ) ,
667+ ) ) ?;
668+ }
656669 let fund = ctx
657670 . info
658671 . funds
@@ -754,6 +767,18 @@ pub mod default_plugins {
754767 ) ) ) ;
755768 }
756769 }
770+ Ok ( true )
771+ }
772+ /// This plugin checks that raw transfers are enabled. If royalty info is set,
773+ /// transfers are disabled and all transfers must go through the buy flow.
774+ pub fn is_transfer_enabled_plugin < T , U : CustomMsg > ( ctx : & mut PluginCtx < T , U > ) -> StdResult < bool > {
775+ if ctx. royalty . collection_royalty_bps . is_some ( )
776+ && ctx. royalty . collection_royalty_recipient . is_some ( )
777+ {
778+ return Err ( cosmwasm_std:: StdError :: generic_err (
779+ "raw transfers are disabled when royalty info is set" ,
780+ ) ) ;
781+ }
757782
758783 Ok ( true )
759784 }
0 commit comments