1
+ se scrypto:: prelude:: * ;
2
+
3
+ blueprint! {
4
+ struct CadiTeamEscrow {
5
+ vaults: BTreeMap <ResourceSpecifier , Vault >,
6
+ obligation_non_fungible_resource: ResourceAddress ,
7
+ is_escrow_fulfilled: bool
8
+ }
9
+
10
+ impl CadiTeamEscrow {
11
+ pub fn instantiate_escrow(
12
+ to_be_paid_by_party_1: ResourceSpecifier ,
13
+ to_be_paid_by_party_2: ResourceSpecifier ,
14
+ ) -> ( ComponentAddress , Bucket ) {
15
+ assert!(
16
+ to_be_paid_by_party_1. validate( ) . is_ok( ) ,
17
+ "First resource is invalid"
18
+ ) ;
19
+ assert!(
20
+ to_be_paid_by_party_1. validate( ) . is_ok( ) ,
21
+ "Second resource is invalid"
22
+ ) ;
23
+ assert_ne!(
24
+ to_be_paid_by_party_1, to_be_paid_by_party_2,
25
+ "they are not equal"
26
+ ) ;
27
+
28
+ let party_1_obligation: EscrowObligation = EscrowObligation {
29
+ amount_to_pay: to_be_paid_by_party_1. clone( ) ,
30
+ amount_to_get: to_be_paid_by_party_2. clone( )
31
+ } ;
32
+
33
+ let party_2_obligation: EscrowObligation = EscrowObligation {
34
+ amount_to_pay: to_be_paid_by_party_2. clone( ) ,
35
+ amount_to_get: to_be_paid_by_party_1. clone( )
36
+ } ;
37
+
38
+ let escrow_obligations: Bucket = ResourceBuilder :: new_non_fungible( )
39
+ . metadata( "name" , "Escrow Obligation" )
40
+ . metadata( "symbol" , "ESCROW" )
41
+ . metadata( "description" , "This resource describes the obligation of the two parties involved in the exchange" )
42
+ . metadata( "team-member-1-github-username" , "andrealupini" )
43
+ . metadata( "team-member-2-github-username" , "gitpck" )
44
+ . metadata( "team-member-1-github-username" , "diogosequeira94" )
45
+ . metadata( "team-member-2-github-username" , "ianmac2" )
46
+ . initial_supply( [
47
+ (
48
+ NonFungibleId :: from_u32( 1 ) ,
49
+ party_1_obligation
50
+ ) ,
51
+ (
52
+ NonFungibleId :: from_u32( 2 ) ,
53
+ party_2_obligation
54
+ ) ,
55
+ ] ) ;
56
+
57
+
58
+ let mut vaults: BTreeMap <ResourceSpecifier , Vault > = BTreeMap :: new( ) ;
59
+ vaults. insert(
60
+ to_be_paid_by_party_1. clone( ) ,
61
+ Vault :: new( to_be_paid_by_party_1. resource_address( ) )
62
+ ) ;
63
+ vaults. insert(
64
+ to_be_paid_by_party_2. clone( ) ,
65
+ Vault :: new( to_be_paid_by_party_2. resource_address( ) )
66
+ ) ;
67
+
68
+ let component_address: ComponentAddress = Self {
69
+ vaults,
70
+ obligation_non_fungible_resource: escrow_obligations. resource_address( ) ,
71
+ is_escrow_fulfilled: false
72
+ }
73
+ . instantiate( )
74
+ . globalize( ) ;
75
+
76
+ ( component_address, escrow_obligations)
77
+
78
+ }
79
+
80
+ pub fn deposit( & mut self , obligation_badge: Proof , mut funds: Bucket ) -> Bucket {
81
+ /// First we need to make sure if the person passed the proper obligation badge (we have created)
82
+ let obligation_badge: ValidatedProof = obligation_badge
83
+ . validate_proof( self . obligation_non_fungible_resource)
84
+ . expect( "Invalid badge" ) ;
85
+ /// After this lets get the data on the badge
86
+ let obligation: EscrowObligation = obligation_badge. non_fungible( ) . data( ) ;
87
+ let vault: & mut Vault = self . vaults. get_mut( & obligation. amount_to_pay) . unwrap( ) ;
88
+
89
+ let funds_to_deposit: Bucket = match obligation. amount_to_pay {
90
+ ResourceSpecifier :: Fungible { amount, .. } => funds. take( amount) ,
91
+ ResourceSpecifier :: NonFungible { non_fungible_ids, .. } => funds. take_non_fungibles( & non_fungible_ids) ,
92
+ } ;
93
+
94
+ vault. put( funds_to_deposit) ;
95
+ funds
96
+ }
97
+
98
+ pub fn withdraw( & mut self , obligation_badge: Proof ) -> Bucket {
99
+ assert!(
100
+ self . is_escrow_fulfilled( ) ,
101
+ "You can not withdraw your funds unless the escrow is not concluded" ,
102
+ ) ;
103
+
104
+ let obligation_badge: ValidatedProof = obligation_badge
105
+ . validate_proof( self . obligation_non_fungible_resource)
106
+ . expect( "invalid badge provider" ) ;
107
+
108
+ let obligation: EscrowObligation = obligation_badge. non_fungible( ) . data( ) ;
109
+ let vault: & mut Vault = self . vaults. get_mut( & obligation. amount_to_get) . unwrap( ) ;
110
+ vault. take_all( )
111
+ }
112
+
113
+ pub fn is_escrow_fulfilled( & mut self ) -> bool {
114
+ if self . is_escrow_fulfilled {
115
+ self . is_escrow_fulfilled
116
+ } else {
117
+ self . is_escrow_fulfilled = self . vaults
118
+ . iter( )
119
+ . map( |( resource_specifier, vault) | {
120
+ match resource_specifier {
121
+ ResourceSpecifier :: Fungible {
122
+ resource_address,
123
+ amount,
124
+ } => {
125
+ vault. resource_address( ) == * resource_address
126
+ && vault. amount( ) >= * amount
127
+ }
128
+
129
+ ResourceSpecifier :: NonFungible {
130
+ resource_address,
131
+ non_fungible_ids,
132
+ } => {
133
+ vault. resource_address( ) == * resource_address
134
+ && vault
135
+ . non_fungible_ids( )
136
+ . iter( )
137
+ . all( |x| non_fungible_ids. contains( x) )
138
+ }
139
+ }
140
+ } )
141
+ . all( |x| x) ;
142
+ self . is_escrow_fulfilled
143
+ }
144
+
145
+ }
146
+ }
147
+ }
148
+
149
+ #[ derive( Debug , NonFungibleData ) ]
150
+ pub struct EscrowObligation {
151
+ /// The amount of tokens which this party needs to pay to the other party.
152
+ amount_to_pay : ResourceSpecifier ,
153
+ /// The amount of tokens paid by the other party to this party.
154
+ amount_to_get : ResourceSpecifier ,
155
+ }
156
+
157
+ #[ derive( Debug , TypeId , Encode , Decode , Describe , Ord , PartialOrd , Eq , PartialEq , Clone ) ]
158
+ pub enum ResourceSpecifier {
159
+ /// A variant used to specify the amount of a fungible resource through the [`ResourceAddress`]
160
+ /// of the resource the amount of that resource as a [`Decimal`].
161
+ Fungible {
162
+ resource_address : ResourceAddress ,
163
+ amount : Decimal ,
164
+ } ,
165
+ /// A variant used to specify non-fungible of that resource based on the [`ResourceAddress`] of
166
+ /// the resource and a set of the [`NonFungibleId`]s being specified by the enum.
167
+ NonFungible {
168
+ resource_address : ResourceAddress ,
169
+ non_fungible_ids : BTreeSet < NonFungibleId > ,
170
+ } ,
171
+ }
172
+
173
+ impl ResourceSpecifier {
174
+ pub fn validate ( & self ) -> Result < ( ) , ( ) > {
175
+ match self {
176
+ Self :: Fungible { amount, .. } => {
177
+ if * amount <= Decimal :: zero ( ) {
178
+ Err ( ( ) )
179
+ } else {
180
+ Ok ( ( ) )
181
+ }
182
+ }
183
+ Self :: NonFungible {
184
+ non_fungible_ids, ..
185
+ } => {
186
+ if non_fungible_ids. is_empty ( ) {
187
+ Err ( ( ) )
188
+ } else {
189
+ Ok ( ( ) )
190
+ }
191
+ }
192
+ }
193
+ }
194
+
195
+ pub fn resource_address ( & self ) -> ResourceAddress {
196
+ match self {
197
+ Self :: Fungible {
198
+ resource_address, ..
199
+ }
200
+ | Self :: NonFungible {
201
+ resource_address, ..
202
+ } => * resource_address,
203
+ }
204
+ }
205
+ }
0 commit comments