05-erc721-contract.rs 8.52 KB
Newer Older
1
use ink_lang as ink;
2

3
#[ink::contract]
4
mod erc721 {
5
    use ink_core::storage::collections::HashMap as StorageHashMap;
6

7
8
9
10
    /// A token ID.
    pub type TokenId = u32;

    #[derive(scale::Encode, scale::Decode)]
11
    #[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
    pub enum Error {
        SpecifiedTokenHasNoOwner,
        ApprovalToCurrentOwner,
        ApproveCallerNotLegitimate,
        ApprovedQueryForNonexistentToken,
        ApproveToCaller,
        TransferCallerIsNotOwnerOrApproved,
        OperatorQueryForNonexistentToken,
        TransferOfTokenThatIsNotOwned,
        TokenAlreadyMinted,
        CannotBurnNonexistentToken,
    }

    pub type Result<T> = core::result::Result<T, Error>;

    /// The storage items for a typical ERC721 token implementation.
    #[ink(storage)]
29
    #[derive(Default)]
30
    pub struct Erc721 {
31
        /// Stores one owner for every token.
32
        token_owner: StorageHashMap<TokenId, AccountId>,
33
        /// Mapping from token ID to approved address.
34
        token_approvals: StorageHashMap<TokenId, AccountId>,
35
        /// Mapping from owner to number of owned tokens.
36
        owned_tokens_count: StorageHashMap<AccountId, u32>,
37
        /// Mapping from owner to operator approval.
38
        operator_approvals: StorageHashMap<(AccountId, AccountId), bool>,
39
40
41
42
    }

    /// Notifies about token approvals.
    #[ink(event)]
43
    pub struct Approval {
44
45
46
47
48
49
50
51
52
53
        /// The owner of the token.
        owner: AccountId,
        /// The approved account.
        to: AccountId,
        /// The approved token.
        token: TokenId,
    }

    /// Notifies about approval for all tokens.
    #[ink(event)]
54
    pub struct ApprovalForAll {
55
56
57
58
59
60
61
62
63
64
        /// The source.
        from: AccountId,
        /// The destination.
        to: AccountId,
        /// If it was approved.
        approved: bool,
    }

    /// Notifies about token transfers.
    #[ink(event)]
65
    pub struct Transfer {
66
67
68
69
70
71
72
73
74
75
76
        /// The source of the transfered token.
        from: Option<AccountId>,
        /// The destination of the transfered token.
        to: Option<AccountId>,
        /// The transfered token.
        token: TokenId,
    }

    impl Erc721 {
        /// Nothing to do for initialization.
        #[ink(constructor)]
77
        pub fn new() -> Self {
78
79
            Default::default()
        }
80
81
82
83
84
85
86

        /// Returns the balance of the specified address.
        ///
        /// # Note
        ///
        /// The returned amount represents the number of owned tokens by the address.
        #[ink(message)]
87
        pub fn balance_of(&self, owner: AccountId) -> u32 {
88
89
90
91
92
            *self.owned_tokens_count.get(&owner).unwrap_or(&0)
        }

        /// Returns the owner of the specified token ID if any.
        #[ink(message)]
93
        pub fn owner_of(&self, token: TokenId) -> Option<AccountId> {
94
95
96
97
98
99
100
101
            self.token_owner.get(&token).cloned()
        }

        /// Approves another address to transfer the given token ID.
        ///
        /// There can only be one approved address per token at a given time.
        /// Can only be called by the token owner or an approved operator.
        #[ink(message)]
102
        pub fn approve(&mut self, to: AccountId, token: TokenId) -> Result<()> {
103
104
105
            let owner = self
                .owner_of(token)
                .ok_or(Error::SpecifiedTokenHasNoOwner)?;
106
107
108
109
110
111
112
113
            if to == owner {
                return Err(Error::ApprovalToCurrentOwner)
            }
            let caller = self.env().caller();
            if caller == owner || self.is_approved_for_all(owner, caller) {
                return Err(Error::ApproveCallerNotLegitimate)
            }
            self.token_approvals.insert(token, to);
114
            self.env().emit_event(Approval { owner, to, token });
115
116
117
118
119
120
121
            Ok(())
        }

        /// Returns the approved address for the token ID if any.
        ///
        /// Reverts if the token ID does not exist.
        #[ink(message)]
122
        pub fn get_approved(&self, token: TokenId) -> Result<AccountId> {
123
124
            self.token_owner
                .get(&token)
125
126
127
128
129
130
131
132
                .ok_or(Error::ApprovedQueryForNonexistentToken)
                .map(Clone::clone)
        }

        /// Sets of unsets the approval of a given operator.
        ///
        /// An operator is allowed to transfer all tokens of the sender on their behalf.
        #[ink(message)]
133
        pub fn set_approval_for_all(&mut self, to: AccountId, approved: bool) -> Result<()> {
134
135
136
137
138
            let caller = self.env().caller();
            if to == caller {
                return Err(Error::ApproveToCaller)
            }
            self.operator_approvals.insert((caller, to), approved);
139
140
141
142
143
            self.env().emit_event(ApprovalForAll {
                from: caller,
                to,
                approved,
            });
144
145
146
147
148
            Ok(())
        }

        /// Returns `true` if an operator is approved by a given owner.
        #[ink(message)]
149
        pub fn is_approved_for_all(&self, owner: AccountId, operator: AccountId) -> bool {
150
151
152
153
            *self
                .operator_approvals
                .get(&(owner, operator))
                .unwrap_or(&false)
154
155
156
157
158
159
160
161
162
163
164
165
        }

        /// Transfers the ownership of a given token ID to another address.
        ///
        /// # Note
        ///
        /// Usage of this method is discouraged, use `safe_transfer_from` whenever possible.
        ///
        /// # Errors
        ///
        /// If the caller is not the owner, approved or operator.
        #[ink(message)]
166
        pub fn transfer_from(
167
168
169
170
171
            &mut self,
            from: AccountId,
            to: AccountId,
            token: TokenId,
        ) -> Result<()> {
172
173
174
175
176
177
178
179
180
181
            let caller = self.env().caller();
            if !self.is_approved_or_owner(&caller, token) {
                return Err(Error::TransferCallerIsNotOwnerOrApproved)
            }
            self.transfer_from_impl(from, to, token)?;
            Ok(())
        }

        /// Returns `true` if the given spender can transfer the given token.
        fn is_approved_or_owner(&self, spender: &AccountId, token: TokenId) -> bool {
182
183
            self.token_owner
                .get(&token)
184
185
186
                .ok_or(Error::OperatorQueryForNonexistentToken)
                .map(|&owner| {
                    let approved = self.get_approved(token).unwrap_or(owner);
187
188
189
                    *spender == owner
                        || approved == *spender
                        || self.is_approved_for_all(owner, *spender)
190
191
192
193
194
195
196
197
198
                })
                .unwrap_or(false)
        }

        /// Transfers ownership of the token to another address.
        ///
        /// # Safety
        ///
        /// As opposed to `transfer_from` this imposes no restructions on the `caller`.
199
200
201
202
203
204
        fn transfer_from_impl(
            &mut self,
            from: AccountId,
            to: AccountId,
            token: TokenId,
        ) -> Result<()> {
205
206
207
208
209
210
211
            if self.owner_of(token).unwrap_or(from) != from {
                return Err(Error::TransferOfTokenThatIsNotOwned)
            }
            self.clear_approval(token);
            self.owned_tokens_count[&from] -= 1; // TODO: are these calls safe here?
            self.owned_tokens_count[&to] += 1;
            self.token_owner[&token] = to;
212
213
214
215
216
            self.env().emit_event(Transfer {
                from: Some(from),
                to: Some(to),
                token,
            });
217
218
219
220
221
            Ok(())
        }

        /// Clears the current approval of a given token.
        fn clear_approval(&mut self, token: TokenId) {
222
            self.token_approvals.take(&token);
223
224
225
226
        }

        /// Mints a new token.
        fn mint(&mut self, to: AccountId, token: TokenId) -> Result<()> {
227
228
229
            let _ = self
                .token_owner
                .get(&token)
230
231
232
                .ok_or(Error::TokenAlreadyMinted)?;
            self.token_owner[&token] = to;
            self.owned_tokens_count[&to] += 1;
233
234
235
236
237
            self.env().emit_event(Transfer {
                from: None,
                to: Some(to),
                token,
            });
238
239
240
241
242
            Ok(())
        }

        // Burns the token.
        fn burn(&mut self, token: TokenId) -> Result<()> {
243
244
245
            let owner = *self
                .token_owner
                .get(&token)
246
247
248
                .ok_or(Error::CannotBurnNonexistentToken)?;
            self.clear_approval(token);
            self.owned_tokens_count[&owner] -= 1;
249
250
251
252
253
254
            self.token_owner.take(&token);
            self.env().emit_event(Transfer {
                from: Some(owner),
                to: None,
                token,
            });
255
256
257
258
259
260
            Ok(())
        }
    }
}

fn main() {}