-
Notifications
You must be signed in to change notification settings - Fork 6
/
ERC6909.fe
174 lines (158 loc) · 5.86 KB
/
ERC6909.fe
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
// SPDX-License-Identifier: MIT
/// @title ERC6909 Multi-Token
/// @author jtriley.eth
//! > NOTE: At the time of writing, Fe does not support `bytes4`, therefore compliance with a
//! > required dependency ERC (165), is not possible, as `bytes4` is a required method argument.
//! > A temporary workaround is implemented by using the `Array<u8, 4>` type as the argument.
/// @notice The event emitted when a transfer occurs.
/// @param sender The address of the sender.
/// @param receiver The address of the receiver.
/// @param id The id of the token.
/// @param amount The amount of the token.
struct Transfer {
#indexed
pub sender: address
#indexed
pub receiver: address
#indexed
pub id: u256
pub amount: u256
}
/// @notice The event emitted when an operator is set.
/// @param owner The address of the owner.
/// @param spender The address of the spender.
/// @param approved The approval status.
struct OperatorSet {
#indexed
pub owner: address
#indexed
pub spender: address
pub approved: bool
}
/// @notice The event emitted when an approval occurs.
/// @param owner The address of the owner.
/// @param spender The address of the spender.
/// @param id The id of the token.
/// @param amount The amount of the token.
struct Approval {
#indexed
pub owner: address
#indexed
pub spender: address
#indexed
pub id: u256
pub amount: u256
}
contract ERCN {
// --- Storage Layout ---
totalSupply: Map<u256, u256>
balanceOf: Map<address, Map<u256, u256>>
allowance: Map<address, Map<address, Map<u256, u256>>>
isOperator: Map<address, Map<address, bool>>
// --- External Interface ---
/// @notice The total supply of each id.
/// @param id The id of the token.
/// @return amount The total supply of the token.
pub fn totalSupply(self, id: u256) -> u256 {
return self.totalSupply[id]
}
/// @notice Owner balance of an id.
/// @param owner The address of the owner.
/// @param id The id of the token.
/// @return amount The balance of the token.
pub fn balanceOf(self, owner: address, id: u256) -> u256 {
return self.balanceOf[owner][id]
}
/// @notice Spender allowance of an id.
/// @param owner The address of the owner.
/// @param spender The address of the spender.
/// @param id The id of the token.
/// @return amount The allowance of the token.
pub fn allowance(self, owner: address, spender: address, id: u256) -> u256 {
return self.allowance[owner][spender][id]
}
/// @notice Checks if a spender is approved by an owner as an operator
/// @param owner The address of the owner.
/// @param spender The address of the spender.
/// @return approved The approval status.
pub fn isOperator(self, owner: address, operator: address) -> bool {
return self.isOperator[owner][operator]
}
/// @notice Transfers an amount of an id from the caller to a receiver.
/// @param receiver The address of the receiver.
/// @param id The id of the token.
/// @param amount The amount of the token.
pub fn transfer(
mut self,
mut ctx: Context,
receiver: address,
id: u256,
amount: u256
) {
assert self.balanceOf[ctx.msg_sender()][id] >= amount
self.balanceOf[ctx.msg_sender()][id] -= amount
self.balanceOf[receiver][id] += amount
ctx.emit(Transfer(sender: ctx.msg_sender(), receiver, id, amount))
return
}
/// @notice Transfers an amount of an id from a sender to a receiver.
/// @param sender The address of the sender.
/// @param receiver The address of the receiver.
/// @param id The id of the token.
/// @param amount The amount of the token.
pub fn transferFrom(
mut self,
mut ctx: Context,
sender: address,
receiver: address,
id: u256,
amount: u256
) {
if ctx.msg_sender() != sender and self.isOperator[sender][ctx.msg_sender()] {
assert self.allowance[sender][ctx.msg_sender()][id] >= amount
self.allowance[sender][ctx.msg_sender()][id] -= amount
}
assert self.balanceOf[sender][id] >= amount
self.balanceOf[sender][id] -= amount
self.balanceOf[receiver][id] += amount
ctx.emit(Transfer(sender, receiver, id, amount))
return
}
/// @notice Approves an amount of an id to a spender.
/// @param spender The address of the spender.
/// @param id The id of the token.
/// @param amount The amount of the token.
pub fn approve(
mut self,
mut ctx: Context,
spender: address,
id: u256,
amount: u256
) {
self.allowance[ctx.msg_sender()][spender][id] = amount
ctx.emit(Approval(owner: ctx.msg_sender(), spender, id, amount))
return
}
/// @notice Sets or removes a spender as an operator for the caller.
/// @param spender The address of the spender.
/// @param approved The approval status.
pub fn setOperator(
mut self,
mut ctx: Context,
spender: address,
approved: bool
) {
self.isOperator[ctx.msg_sender()][spender] = approved;
ctx.emit(OperatorSet(owner: ctx.msg_sender(), spender, approved))
return
}
/// @notice Checks if a contract implements an interface.
/// @dev NOT ERC-165 COMPLIANT UNTIL FE IMPLEMENTS `bytes4` TYPE.
/// @param interfaceId The interface identifier, as specified in ERC-165.
/// @return supported True if the contract implements `interfaceId` and
/// `interfaceId` is not 0xffffffff, false otherwise.
pub fn supportsInterface(interfaceId: Array<u8, 4>) -> bool {
let numericInterfaceId: u32 = interfaceId[0] | (interfaceId[1] << 8) | (interfaceId[2] << 16) | (interfaceId[3] << 24)
return numericInterfaceId == 0x01ffc9a7 or numericInterfaceId == 0x8da179e8
}
}