@theqrl/qrl-contracts 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,389 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // QRL Contracts (last updated v0.1.0) (token/SQRCTB1/SQRCTB1.hyp)
3
+
4
+ pragma hyperion >=0.0;
5
+
6
+ import {ISQRCTB1} from "./ISQRCTB1.hyp";
7
+ import {ISQRCTB1MetadataURI} from "./extensions/ISQRCTB1MetadataURI.hyp";
8
+ import {SQRCTB1Utils} from "./utils/SQRCTB1Utils.hyp";
9
+ import {Context} from "../../utils/Context.hyp";
10
+ import {IZRC165, ZRC165} from "../../utils/introspection/ZRC165.hyp";
11
+ import {Arrays} from "../../utils/Arrays.hyp";
12
+ import {ISQRCTB1Errors} from "../../interfaces/draft-IZRC6093.hyp";
13
+
14
+ /**
15
+ * @dev Implementation of the basic standard multi-token.
16
+ * See https://eips.ethereum.org/EIPS/eip-1155
17
+ * Originally based on code by Enjin: https://github.com/enjin/erc-1155
18
+ */
19
+ abstract contract SQRCTB1 is Context, ZRC165, ISQRCTB1, ISQRCTB1MetadataURI, ISQRCTB1Errors {
20
+ using Arrays for uint256[];
21
+ using Arrays for address[];
22
+
23
+ mapping(uint256 id => mapping(address account => uint256)) private _balances;
24
+
25
+ mapping(address account => mapping(address operator => bool)) private _operatorApprovals;
26
+
27
+ // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
28
+ string private _uri;
29
+
30
+ /**
31
+ * @dev See {_setURI}.
32
+ */
33
+ constructor(string memory uri_) {
34
+ _setURI(uri_);
35
+ }
36
+
37
+ /// @inheritdoc IZRC165
38
+ function supportsInterface(bytes4 interfaceId) public view virtual override(ZRC165, IZRC165) returns (bool) {
39
+ return
40
+ interfaceId == type(ISQRCTB1).interfaceId ||
41
+ interfaceId == type(ISQRCTB1MetadataURI).interfaceId ||
42
+ super.supportsInterface(interfaceId);
43
+ }
44
+
45
+ /**
46
+ * @dev See {ISQRCTB1MetadataURI-uri}.
47
+ *
48
+ * This implementation returns the same URI for *all* token types. It relies
49
+ * on the token type ID substitution mechanism
50
+ * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the ZRC].
51
+ *
52
+ * Clients calling this function must replace the `\{id\}` substring with the
53
+ * actual token type ID.
54
+ */
55
+ function uri(uint256 /* id */) public view virtual returns (string memory) {
56
+ return _uri;
57
+ }
58
+
59
+ /// @inheritdoc ISQRCTB1
60
+ function balanceOf(address account, uint256 id) public view virtual returns (uint256) {
61
+ return _balances[id][account];
62
+ }
63
+
64
+ /**
65
+ * @dev See {ISQRCTB1-balanceOfBatch}.
66
+ *
67
+ * Requirements:
68
+ *
69
+ * - `accounts` and `ids` must have the same length.
70
+ */
71
+ function balanceOfBatch(
72
+ address[] memory accounts,
73
+ uint256[] memory ids
74
+ ) public view virtual returns (uint256[] memory) {
75
+ if (accounts.length != ids.length) {
76
+ revert SQRCTB1InvalidArrayLength(ids.length, accounts.length);
77
+ }
78
+
79
+ uint256[] memory batchBalances = new uint256[](accounts.length);
80
+
81
+ for (uint256 i = 0; i < accounts.length; ++i) {
82
+ batchBalances[i] = balanceOf(accounts.unsafeMemoryAccess(i), ids.unsafeMemoryAccess(i));
83
+ }
84
+
85
+ return batchBalances;
86
+ }
87
+
88
+ /// @inheritdoc ISQRCTB1
89
+ function setApprovalForAll(address operator, bool approved) public virtual {
90
+ _setApprovalForAll(_msgSender(), operator, approved);
91
+ }
92
+
93
+ /// @inheritdoc ISQRCTB1
94
+ function isApprovedForAll(address account, address operator) public view virtual returns (bool) {
95
+ return _operatorApprovals[account][operator];
96
+ }
97
+
98
+ /// @inheritdoc ISQRCTB1
99
+ function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) public virtual {
100
+ address sender = _msgSender();
101
+ if (from != sender && !isApprovedForAll(from, sender)) {
102
+ revert SQRCTB1MissingApprovalForAll(sender, from);
103
+ }
104
+ _safeTransferFrom(from, to, id, value, data);
105
+ }
106
+
107
+ /// @inheritdoc ISQRCTB1
108
+ function safeBatchTransferFrom(
109
+ address from,
110
+ address to,
111
+ uint256[] memory ids,
112
+ uint256[] memory values,
113
+ bytes memory data
114
+ ) public virtual {
115
+ address sender = _msgSender();
116
+ if (from != sender && !isApprovedForAll(from, sender)) {
117
+ revert SQRCTB1MissingApprovalForAll(sender, from);
118
+ }
119
+ _safeBatchTransferFrom(from, to, ids, values, data);
120
+ }
121
+
122
+ /**
123
+ * @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`. Will mint (or burn) if `from`
124
+ * (or `to`) is the zero address.
125
+ *
126
+ * Emits a {TransferSingle} event if the arrays contain one element, and {TransferBatch} otherwise.
127
+ *
128
+ * Requirements:
129
+ *
130
+ * - If `to` refers to a smart contract, it must implement either {ISQRCTB1Receiver-onSQRCTB1Received}
131
+ * or {ISQRCTB1Receiver-onSQRCTB1BatchReceived} and return the acceptance magic value.
132
+ * - `ids` and `values` must have the same length.
133
+ *
134
+ * NOTE: The SQRC-TB1 acceptance check is not performed in this function. See {_updateWithAcceptanceCheck} instead.
135
+ */
136
+ function _update(address from, address to, uint256[] memory ids, uint256[] memory values) internal virtual {
137
+ if (ids.length != values.length) {
138
+ revert SQRCTB1InvalidArrayLength(ids.length, values.length);
139
+ }
140
+
141
+ address operator = _msgSender();
142
+
143
+ for (uint256 i = 0; i < ids.length; ++i) {
144
+ uint256 id = ids.unsafeMemoryAccess(i);
145
+ uint256 value = values.unsafeMemoryAccess(i);
146
+
147
+ if (from != address(0)) {
148
+ uint256 fromBalance = _balances[id][from];
149
+ if (fromBalance < value) {
150
+ revert SQRCTB1InsufficientBalance(from, fromBalance, value, id);
151
+ }
152
+ unchecked {
153
+ // Overflow not possible: value <= fromBalance
154
+ _balances[id][from] = fromBalance - value;
155
+ }
156
+ }
157
+
158
+ if (to != address(0)) {
159
+ _balances[id][to] += value;
160
+ }
161
+ }
162
+
163
+ if (ids.length == 1) {
164
+ uint256 id = ids.unsafeMemoryAccess(0);
165
+ uint256 value = values.unsafeMemoryAccess(0);
166
+ emit TransferSingle(operator, from, to, id, value);
167
+ } else {
168
+ emit TransferBatch(operator, from, to, ids, values);
169
+ }
170
+ }
171
+
172
+ /**
173
+ * @dev Version of {_update} that performs the token acceptance check by calling
174
+ * {ISQRCTB1Receiver-onSQRCTB1Received} or {ISQRCTB1Receiver-onSQRCTB1BatchReceived} on the receiver address if it
175
+ * contains code (eg. is a smart contract at the moment of execution).
176
+ *
177
+ * IMPORTANT: Overriding this function is discouraged because it poses a reentrancy risk from the receiver. So any
178
+ * update to the contract state after this function would break the check-effect-interaction pattern. Consider
179
+ * overriding {_update} instead.
180
+ */
181
+ function _updateWithAcceptanceCheck(
182
+ address from,
183
+ address to,
184
+ uint256[] memory ids,
185
+ uint256[] memory values,
186
+ bytes memory data
187
+ ) internal virtual {
188
+ _update(from, to, ids, values);
189
+ if (to != address(0)) {
190
+ address operator = _msgSender();
191
+ if (ids.length == 1) {
192
+ uint256 id = ids.unsafeMemoryAccess(0);
193
+ uint256 value = values.unsafeMemoryAccess(0);
194
+ SQRCTB1Utils.checkOnSQRCTB1Received(operator, from, to, id, value, data);
195
+ } else {
196
+ SQRCTB1Utils.checkOnSQRCTB1BatchReceived(operator, from, to, ids, values, data);
197
+ }
198
+ }
199
+ }
200
+
201
+ /**
202
+ * @dev Transfers a `value` tokens of token type `id` from `from` to `to`.
203
+ *
204
+ * Emits a {TransferSingle} event.
205
+ *
206
+ * Requirements:
207
+ *
208
+ * - `to` cannot be the zero address.
209
+ * - `from` must have a balance of tokens of type `id` of at least `value` amount.
210
+ * - If `to` refers to a smart contract, it must implement {ISQRCTB1Receiver-onSQRCTB1Received} and return the
211
+ * acceptance magic value.
212
+ */
213
+ function _safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) internal {
214
+ if (to == address(0)) {
215
+ revert SQRCTB1InvalidReceiver(address(0));
216
+ }
217
+ if (from == address(0)) {
218
+ revert SQRCTB1InvalidSender(address(0));
219
+ }
220
+ (uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
221
+ _updateWithAcceptanceCheck(from, to, ids, values, data);
222
+ }
223
+
224
+ /**
225
+ * @dev xref:ROOT:zrc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.
226
+ *
227
+ * Emits a {TransferBatch} event.
228
+ *
229
+ * Requirements:
230
+ *
231
+ * - If `to` refers to a smart contract, it must implement {ISQRCTB1Receiver-onSQRCTB1BatchReceived} and return the
232
+ * acceptance magic value.
233
+ * - `ids` and `values` must have the same length.
234
+ */
235
+ function _safeBatchTransferFrom(
236
+ address from,
237
+ address to,
238
+ uint256[] memory ids,
239
+ uint256[] memory values,
240
+ bytes memory data
241
+ ) internal {
242
+ if (to == address(0)) {
243
+ revert SQRCTB1InvalidReceiver(address(0));
244
+ }
245
+ if (from == address(0)) {
246
+ revert SQRCTB1InvalidSender(address(0));
247
+ }
248
+ _updateWithAcceptanceCheck(from, to, ids, values, data);
249
+ }
250
+
251
+ /**
252
+ * @dev Sets a new URI for all token types, by relying on the token type ID
253
+ * substitution mechanism
254
+ * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the ZRC].
255
+ *
256
+ * By this mechanism, any occurrence of the `\{id\}` substring in either the
257
+ * URI or any of the values in the JSON file at said URI will be replaced by
258
+ * clients with the token type ID.
259
+ *
260
+ * For example, the `https://token-cdn-domain/\{id\}.json` URI would be
261
+ * interpreted by clients as
262
+ * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
263
+ * for token type ID 0x4cce0.
264
+ *
265
+ * See {uri}.
266
+ *
267
+ * Because these URIs cannot be meaningfully represented by the {URI} event,
268
+ * this function emits no events.
269
+ */
270
+ function _setURI(string memory newuri) internal virtual {
271
+ _uri = newuri;
272
+ }
273
+
274
+ /**
275
+ * @dev Creates a `value` amount of tokens of type `id`, and assigns them to `to`.
276
+ *
277
+ * Emits a {TransferSingle} event.
278
+ *
279
+ * Requirements:
280
+ *
281
+ * - `to` cannot be the zero address.
282
+ * - If `to` refers to a smart contract, it must implement {ISQRCTB1Receiver-onSQRCTB1Received} and return the
283
+ * acceptance magic value.
284
+ */
285
+ function _mint(address to, uint256 id, uint256 value, bytes memory data) internal {
286
+ if (to == address(0)) {
287
+ revert SQRCTB1InvalidReceiver(address(0));
288
+ }
289
+ (uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
290
+ _updateWithAcceptanceCheck(address(0), to, ids, values, data);
291
+ }
292
+
293
+ /**
294
+ * @dev xref:ROOT:zrc1155.adoc#batch-operations[Batched] version of {_mint}.
295
+ *
296
+ * Emits a {TransferBatch} event.
297
+ *
298
+ * Requirements:
299
+ *
300
+ * - `ids` and `values` must have the same length.
301
+ * - `to` cannot be the zero address.
302
+ * - If `to` refers to a smart contract, it must implement {ISQRCTB1Receiver-onSQRCTB1BatchReceived} and return the
303
+ * acceptance magic value.
304
+ */
305
+ function _mintBatch(address to, uint256[] memory ids, uint256[] memory values, bytes memory data) internal {
306
+ if (to == address(0)) {
307
+ revert SQRCTB1InvalidReceiver(address(0));
308
+ }
309
+ _updateWithAcceptanceCheck(address(0), to, ids, values, data);
310
+ }
311
+
312
+ /**
313
+ * @dev Destroys a `value` amount of tokens of type `id` from `from`
314
+ *
315
+ * Emits a {TransferSingle} event.
316
+ *
317
+ * Requirements:
318
+ *
319
+ * - `from` cannot be the zero address.
320
+ * - `from` must have at least `value` amount of tokens of type `id`.
321
+ */
322
+ function _burn(address from, uint256 id, uint256 value) internal {
323
+ if (from == address(0)) {
324
+ revert SQRCTB1InvalidSender(address(0));
325
+ }
326
+ (uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
327
+ _updateWithAcceptanceCheck(from, address(0), ids, values, "");
328
+ }
329
+
330
+ /**
331
+ * @dev xref:ROOT:zrc1155.adoc#batch-operations[Batched] version of {_burn}.
332
+ *
333
+ * Emits a {TransferBatch} event.
334
+ *
335
+ * Requirements:
336
+ *
337
+ * - `from` cannot be the zero address.
338
+ * - `from` must have at least `value` amount of tokens of type `id`.
339
+ * - `ids` and `values` must have the same length.
340
+ */
341
+ function _burnBatch(address from, uint256[] memory ids, uint256[] memory values) internal {
342
+ if (from == address(0)) {
343
+ revert SQRCTB1InvalidSender(address(0));
344
+ }
345
+ _updateWithAcceptanceCheck(from, address(0), ids, values, "");
346
+ }
347
+
348
+ /**
349
+ * @dev Approve `operator` to operate on all of `owner` tokens
350
+ *
351
+ * Emits an {ApprovalForAll} event.
352
+ *
353
+ * Requirements:
354
+ *
355
+ * - `operator` cannot be the zero address.
356
+ */
357
+ function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
358
+ if (operator == address(0)) {
359
+ revert SQRCTB1InvalidOperator(address(0));
360
+ }
361
+ _operatorApprovals[owner][operator] = approved;
362
+ emit ApprovalForAll(owner, operator, approved);
363
+ }
364
+
365
+ /**
366
+ * @dev Creates an array in memory with only one value for each of the elements provided.
367
+ */
368
+ function _asSingletonArrays(
369
+ uint256 element1,
370
+ uint256 element2
371
+ ) private pure returns (uint256[] memory array1, uint256[] memory array2) {
372
+ assembly ("memory-safe") {
373
+ // Load the free memory pointer
374
+ array1 := mload(0x40)
375
+ // Set array length to 1
376
+ mstore(array1, 1)
377
+ // Store the single element at the next word after the length (where content starts)
378
+ mstore(add(array1, 0x20), element1)
379
+
380
+ // Repeat for next array locating it right after the first array
381
+ array2 := add(array1, 0x40)
382
+ mstore(array2, 1)
383
+ mstore(add(array2, 0x20), element2)
384
+
385
+ // Update the free memory pointer by pointing after the second array
386
+ mstore(0x40, add(array2, 0x40))
387
+ }
388
+ }
389
+ }
@@ -0,0 +1,20 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // QRL Contracts (last updated v0.1.0) (token/SQRCTB1/extensions/ISQRCTB1MetadataURI.hyp)
3
+
4
+ pragma hyperion >=0.0;
5
+
6
+ import {ISQRCTB1} from "../ISQRCTB1.hyp";
7
+
8
+ /**
9
+ * @dev Interface of the optional SQRCTB1MetadataExtension interface, as defined
10
+ * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[ZRC].
11
+ */
12
+ interface ISQRCTB1MetadataURI is ISQRCTB1 {
13
+ /**
14
+ * @dev Returns the URI for token type `id`.
15
+ *
16
+ * If the `\{id\}` substring is present in the URI, it must be replaced by
17
+ * clients with the actual token type ID.
18
+ */
19
+ function uri(uint256 id) external view returns (string memory);
20
+ }
@@ -0,0 +1,88 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // QRL Contracts (last updated v0.1.0) (token/SQRCTB1/utils/SQRCTB1Utils.hyp)
3
+
4
+ pragma hyperion >=0.0;
5
+
6
+ import {ISQRCTB1Receiver} from "../ISQRCTB1Receiver.hyp";
7
+ import {ISQRCTB1Errors} from "../../../interfaces/draft-IZRC6093.hyp";
8
+
9
+ /**
10
+ * @dev Library that provide common SQRC-TB1 utility functions.
11
+ *
12
+ * See https://eips.ethereum.org/EIPS/eip-1155[SQRC-TB1].
13
+ *
14
+ * _Available since v5.1._
15
+ */
16
+ library SQRCTB1Utils {
17
+ /**
18
+ * @dev Performs an acceptance check for the provided `operator` by calling {ISQRCTB1Receiver-onSQRCTB1Received}
19
+ * on the `to` address. The `operator` is generally the address that initiated the token transfer (i.e. `msg.sender`).
20
+ *
21
+ * The acceptance call is not executed and treated as a no-op if the target address doesn't contain code (i.e. an EOA).
22
+ * Otherwise, the recipient must implement {ISQRCTB1Receiver-onSQRCTB1Received} and return the acceptance magic value to accept
23
+ * the transfer.
24
+ */
25
+ function checkOnSQRCTB1Received(
26
+ address operator,
27
+ address from,
28
+ address to,
29
+ uint256 id,
30
+ uint256 value,
31
+ bytes memory data
32
+ ) internal {
33
+ if (to.code.length > 0) {
34
+ try ISQRCTB1Receiver(to).onSQRCTB1Received(operator, from, id, value, data) returns (bytes4 response) {
35
+ if (response != ISQRCTB1Receiver.onSQRCTB1Received.selector) {
36
+ // Tokens rejected
37
+ revert ISQRCTB1Errors.SQRCTB1InvalidReceiver(to);
38
+ }
39
+ } catch (bytes memory reason) {
40
+ if (reason.length == 0) {
41
+ // non-ISQRCTB1Receiver implementer
42
+ revert ISQRCTB1Errors.SQRCTB1InvalidReceiver(to);
43
+ } else {
44
+ assembly ("memory-safe") {
45
+ revert(add(32, reason), mload(reason))
46
+ }
47
+ }
48
+ }
49
+ }
50
+ }
51
+
52
+ /**
53
+ * @dev Performs a batch acceptance check for the provided `operator` by calling {ISQRCTB1Receiver-onSQRCTB1BatchReceived}
54
+ * on the `to` address. The `operator` is generally the address that initiated the token transfer (i.e. `msg.sender`).
55
+ *
56
+ * The acceptance call is not executed and treated as a no-op if the target address doesn't contain code (i.e. an EOA).
57
+ * Otherwise, the recipient must implement {ISQRCTB1Receiver-onSQRCTB1Received} and return the acceptance magic value to accept
58
+ * the transfer.
59
+ */
60
+ function checkOnSQRCTB1BatchReceived(
61
+ address operator,
62
+ address from,
63
+ address to,
64
+ uint256[] memory ids,
65
+ uint256[] memory values,
66
+ bytes memory data
67
+ ) internal {
68
+ if (to.code.length > 0) {
69
+ try ISQRCTB1Receiver(to).onSQRCTB1BatchReceived(operator, from, ids, values, data) returns (
70
+ bytes4 response
71
+ ) {
72
+ if (response != ISQRCTB1Receiver.onSQRCTB1BatchReceived.selector) {
73
+ // Tokens rejected
74
+ revert ISQRCTB1Errors.SQRCTB1InvalidReceiver(to);
75
+ }
76
+ } catch (bytes memory reason) {
77
+ if (reason.length == 0) {
78
+ // non-ISQRCTB1Receiver implementer
79
+ revert ISQRCTB1Errors.SQRCTB1InvalidReceiver(to);
80
+ } else {
81
+ assembly ("memory-safe") {
82
+ revert(add(32, reason), mload(reason))
83
+ }
84
+ }
85
+ }
86
+ }
87
+ }
88
+ }
@@ -0,0 +1,79 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // QRL Contracts (last updated v0.1.0) (token/SQRCTF1/ISQRCTF1.hyp)
3
+
4
+ pragma hyperion >=0.0;
5
+
6
+ /**
7
+ * @dev Interface of the SQRC-TF1 standard as defined in the ZRC.
8
+ */
9
+ interface ISQRCTF1 {
10
+ /**
11
+ * @dev Emitted when `value` tokens are moved from one account (`from`) to
12
+ * another (`to`).
13
+ *
14
+ * Note that `value` may be zero.
15
+ */
16
+ event Transfer(address indexed from, address indexed to, uint256 value);
17
+
18
+ /**
19
+ * @dev Emitted when the allowance of a `spender` for an `owner` is set by
20
+ * a call to {approve}. `value` is the new allowance.
21
+ */
22
+ event Approval(address indexed owner, address indexed spender, uint256 value);
23
+
24
+ /**
25
+ * @dev Returns the value of tokens in existence.
26
+ */
27
+ function totalSupply() external view returns (uint256);
28
+
29
+ /**
30
+ * @dev Returns the value of tokens owned by `account`.
31
+ */
32
+ function balanceOf(address account) external view returns (uint256);
33
+
34
+ /**
35
+ * @dev Moves a `value` amount of tokens from the caller's account to `to`.
36
+ *
37
+ * Returns a boolean value indicating whether the operation succeeded.
38
+ *
39
+ * Emits a {Transfer} event.
40
+ */
41
+ function transfer(address to, uint256 value) external returns (bool);
42
+
43
+ /**
44
+ * @dev Returns the remaining number of tokens that `spender` will be
45
+ * allowed to spend on behalf of `owner` through {transferFrom}. This is
46
+ * zero by default.
47
+ *
48
+ * This value changes when {approve} or {transferFrom} are called.
49
+ */
50
+ function allowance(address owner, address spender) external view returns (uint256);
51
+
52
+ /**
53
+ * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
54
+ * caller's tokens.
55
+ *
56
+ * Returns a boolean value indicating whether the operation succeeded.
57
+ *
58
+ * IMPORTANT: Beware that changing an allowance with this method brings the risk
59
+ * that someone may use both the old and the new allowance by unfortunate
60
+ * transaction ordering. One possible solution to mitigate this race
61
+ * condition is to first reduce the spender's allowance to 0 and set the
62
+ * desired value afterwards:
63
+ * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
64
+ *
65
+ * Emits an {Approval} event.
66
+ */
67
+ function approve(address spender, uint256 value) external returns (bool);
68
+
69
+ /**
70
+ * @dev Moves a `value` amount of tokens from `from` to `to` using the
71
+ * allowance mechanism. `value` is then deducted from the caller's
72
+ * allowance.
73
+ *
74
+ * Returns a boolean value indicating whether the operation succeeded.
75
+ *
76
+ * Emits a {Transfer} event.
77
+ */
78
+ function transferFrom(address from, address to, uint256 value) external returns (bool);
79
+ }