@lukso/lsp8-contracts 0.15.0-rc.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.
Files changed (43) hide show
  1. package/README.md +3 -0
  2. package/artifacts/LSP8CappedSupply.json +959 -0
  3. package/artifacts/LSP8CappedSupplyInitAbstract.json +972 -0
  4. package/artifacts/LSP8IdentifiableDigitalAsset.json +936 -0
  5. package/artifacts/LSP8IdentifiableDigitalAssetInitAbstract.json +949 -0
  6. package/artifacts/LSP8Mintable.json +1006 -0
  7. package/artifacts/LSP8MintableInit.json +1026 -0
  8. package/contracts/ILSP8IdentifiableDigitalAsset.sol +328 -0
  9. package/contracts/LSP8Constants.sol +41 -0
  10. package/contracts/LSP8Errors.sol +118 -0
  11. package/contracts/LSP8IdentifiableDigitalAsset.sol +241 -0
  12. package/contracts/LSP8IdentifiableDigitalAssetCore.sol +806 -0
  13. package/contracts/LSP8IdentifiableDigitalAssetInitAbstract.sol +248 -0
  14. package/contracts/extensions/LSP8Burnable.sol +30 -0
  15. package/contracts/extensions/LSP8BurnableInitAbstract.sol +24 -0
  16. package/contracts/extensions/LSP8CappedSupply.sol +85 -0
  17. package/contracts/extensions/LSP8CappedSupplyInitAbstract.sol +88 -0
  18. package/contracts/extensions/LSP8Enumerable.sol +69 -0
  19. package/contracts/extensions/LSP8EnumerableInitAbstract.sol +64 -0
  20. package/contracts/presets/ILSP8Mintable.sol +33 -0
  21. package/contracts/presets/LSP8Mintable.sol +60 -0
  22. package/contracts/presets/LSP8MintableInit.sol +43 -0
  23. package/contracts/presets/LSP8MintableInitAbstract.sol +62 -0
  24. package/dist/index.cjs +33 -0
  25. package/dist/index.d.cts +29 -0
  26. package/dist/index.d.mts +29 -0
  27. package/dist/index.d.ts +29 -0
  28. package/dist/index.mjs +28 -0
  29. package/package.json +56 -0
  30. package/types/LSP8CappedSupply.ts +792 -0
  31. package/types/LSP8CappedSupplyInitAbstract.ts +824 -0
  32. package/types/LSP8IdentifiableDigitalAsset.ts +778 -0
  33. package/types/LSP8IdentifiableDigitalAssetInitAbstract.ts +813 -0
  34. package/types/LSP8Mintable.ts +797 -0
  35. package/types/LSP8MintableInit.ts +860 -0
  36. package/types/common.ts +131 -0
  37. package/types/contracts/LSP8IdentifiableDigitalAsset.ts +778 -0
  38. package/types/contracts/LSP8IdentifiableDigitalAssetInitAbstract.ts +813 -0
  39. package/types/contracts/extensions/LSP8CappedSupply.ts +792 -0
  40. package/types/contracts/extensions/LSP8CappedSupplyInitAbstract.ts +824 -0
  41. package/types/contracts/presets/LSP8Mintable.ts +797 -0
  42. package/types/contracts/presets/LSP8MintableInit.ts +860 -0
  43. package/types/index.ts +16 -0
@@ -0,0 +1,241 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.12;
3
+
4
+ // interfaces
5
+ import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
6
+
7
+ // modules
8
+ import {ERC725YCore} from "@erc725/smart-contracts/contracts/ERC725YCore.sol";
9
+ import {
10
+ LSP8IdentifiableDigitalAssetCore
11
+ } from "./LSP8IdentifiableDigitalAssetCore.sol";
12
+ import {
13
+ LSP4DigitalAssetMetadata
14
+ } from "@lukso/lsp4-contracts/contracts/LSP4DigitalAssetMetadata.sol";
15
+
16
+ import {
17
+ LSP4DigitalAssetMetadataCore
18
+ } from "@lukso/lsp4-contracts/contracts/LSP4DigitalAssetMetadataCore.sol";
19
+
20
+ import {
21
+ LSP17Extendable
22
+ } from "@lukso/lsp17contractextension-contracts/contracts/LSP17Extendable.sol";
23
+
24
+ // libraries
25
+ import {LSP2Utils} from "@lukso/lsp2-contracts/contracts/LSP2Utils.sol";
26
+
27
+ // constants
28
+ import {_INTERFACEID_LSP8, _LSP8_TOKENID_FORMAT_KEY} from "./LSP8Constants.sol";
29
+
30
+ // errors
31
+ import {
32
+ LSP8TokenContractCannotHoldValue,
33
+ LSP8TokenIdFormatNotEditable
34
+ } from "./LSP8Errors.sol";
35
+
36
+ import {
37
+ _LSP17_EXTENSION_PREFIX
38
+ } from "@lukso/lsp17contractextension-contracts/contracts/LSP17Constants.sol";
39
+
40
+ // errors
41
+
42
+ import {
43
+ NoExtensionFoundForFunctionSelector,
44
+ InvalidFunctionSelector,
45
+ InvalidExtensionAddress
46
+ } from "@lukso/lsp17contractextension-contracts/contracts/LSP17Errors.sol";
47
+
48
+ /**
49
+ * @title Implementation of a LSP8 Identifiable Digital Asset, a contract that represents a non-fungible token.
50
+ * @author Matthew Stevens
51
+ *
52
+ * @dev Standard implementation contract of the LSP8 standard.
53
+ *
54
+ * Minting and transferring are done by providing a unique `tokenId`.
55
+ * This implementation is agnostic to the way tokens are created.
56
+ * A supply mechanism has to be added in a derived contract using {_mint}
57
+ * For a generic mechanism, see {LSP7Mintable}.
58
+ */
59
+ abstract contract LSP8IdentifiableDigitalAsset is
60
+ LSP4DigitalAssetMetadata,
61
+ LSP8IdentifiableDigitalAssetCore,
62
+ LSP17Extendable
63
+ {
64
+ /**
65
+ * @notice Deploying a LSP8IdentifiableDigitalAsset with name `name_`, symbol `symbol_`, owned by address `newOwner_`
66
+ * with tokenId format `lsp8TokenIdFormat_`.
67
+ *
68
+ * @dev Deploy a `LSP8IdentifiableDigitalAsset` contract and set the tokenId format inside the ERC725Y storage of the contract.
69
+ * This will also set the token `name_` and `symbol_` under the ERC725Y data keys `LSP4TokenName` and `LSP4TokenSymbol`.
70
+ *
71
+ * @param name_ The name of the token
72
+ * @param symbol_ The symbol of the token
73
+ * @param newOwner_ The owner of the the token-Metadata
74
+ * @param lsp4TokenType_ The type of token this digital asset contract represents (`0` = Token, `1` = NFT, `2` = Collection).
75
+ * @param lsp8TokenIdFormat_ The format of tokenIds (= NFTs) that this contract will create.
76
+ *
77
+ * @custom:warning Make sure the tokenId format provided on deployment is correct, as it can only be set once
78
+ * and cannot be changed in the ERC725Y storage after the contract has been deployed.
79
+ */
80
+ constructor(
81
+ string memory name_,
82
+ string memory symbol_,
83
+ address newOwner_,
84
+ uint256 lsp4TokenType_,
85
+ uint256 lsp8TokenIdFormat_
86
+ ) LSP4DigitalAssetMetadata(name_, symbol_, newOwner_, lsp4TokenType_) {
87
+ LSP4DigitalAssetMetadata._setData(
88
+ _LSP8_TOKENID_FORMAT_KEY,
89
+ abi.encode(lsp8TokenIdFormat_)
90
+ );
91
+ }
92
+
93
+ // fallback function
94
+
95
+ /**
96
+ * @notice The `fallback` function was called with the following amount of native tokens: `msg.value`; and the following calldata: `callData`.
97
+ *
98
+ * @dev Achieves the goal of [LSP-17-ContractExtension] standard by extending the contract to handle calls of functions that do not exist natively,
99
+ * forwarding the function call to the extension address mapped to the function being called.
100
+ *
101
+ * This function is executed when:
102
+ * - Sending data of length less than 4 bytes to the contract.
103
+ * - The first 4 bytes of the calldata do not match any publicly callable functions from the contract ABI.
104
+ * - Receiving native tokens
105
+ *
106
+ * 1. If the data is equal or longer than 4 bytes, the [ERC-725Y] storage is queried with the following data key: [_LSP17_EXTENSION_PREFIX] + `bytes4(msg.sig)` (Check [LSP-2-ERC725YJSONSchema] for encoding the data key)
107
+ *
108
+ * - If there is no address stored under the following data key, revert with {NoExtensionFoundForFunctionSelector(bytes4)}. The data key relative to `bytes4(0)` is an exception, where no reverts occurs if there is no extension address stored under. This exception is made to allow users to send random data (graffiti) to the account and to be able to react on it.
109
+ *
110
+ * - If there is an address, forward the `msg.data` to the extension using the CALL opcode, appending 52 bytes (20 bytes of `msg.sender` and 32 bytes of `msg.value`). Return what the calls returns, or revert if the call failed.
111
+ *
112
+ * 2. If the data sent to this function is of length less than 4 bytes (not a function selector), revert.
113
+ */
114
+ // solhint-disable-next-line no-complex-fallback
115
+ fallback(
116
+ bytes calldata callData
117
+ ) external payable virtual returns (bytes memory) {
118
+ if (msg.data.length < 4) {
119
+ revert InvalidFunctionSelector(callData);
120
+ }
121
+ return _fallbackLSP17Extendable(callData);
122
+ }
123
+
124
+ /**
125
+ * @dev Reverts whenever someone tries to send native tokens to a LSP8 contract.
126
+ * @notice LSP8 contract cannot receive native tokens.
127
+ */
128
+ receive() external payable virtual {
129
+ // revert on empty calls with no value
130
+ if (msg.value == 0) {
131
+ revert InvalidFunctionSelector(hex"00000000");
132
+ }
133
+
134
+ revert LSP8TokenContractCannotHoldValue();
135
+ }
136
+
137
+ /**
138
+ * @dev Forwards the call with the received value to an extension mapped to a function selector.
139
+ *
140
+ * Calls {_getExtensionAndForwardValue} to get the address of the extension mapped to the function selector being
141
+ * called on the account. If there is no extension, the address(0) will be returned.
142
+ * We will always forward the value to the extension, as the LSP8 contract is not supposed to hold any native tokens.
143
+ *
144
+ * Reverts if there is no extension for the function being called.
145
+ *
146
+ * If there is an extension for the function selector being called, it calls the extension with the
147
+ * CALL opcode, passing the {msg.data} appended with the 20 bytes of the {msg.sender} and
148
+ * 32 bytes of the {msg.value}
149
+ *
150
+ * @custom:info The LSP8 Token contract should not hold any native tokens. Any native tokens received by the contract
151
+ * will be forwarded to the extension address mapped to the selector from `msg.sig`.
152
+ */
153
+ function _fallbackLSP17Extendable(
154
+ bytes calldata callData
155
+ ) internal virtual override returns (bytes memory) {
156
+ // If there is a function selector
157
+ (address extension, ) = _getExtensionAndForwardValue(msg.sig);
158
+
159
+ // if no extension was found, revert
160
+ if (extension == address(0))
161
+ revert NoExtensionFoundForFunctionSelector(msg.sig);
162
+
163
+ (bool success, bytes memory result) = extension.call{value: msg.value}(
164
+ abi.encodePacked(callData, msg.sender, msg.value)
165
+ );
166
+
167
+ if (success) {
168
+ return result;
169
+ } else {
170
+ // `mload(result)` -> offset in memory where `result.length` is located
171
+ // `add(result, 32)` -> offset in memory where `result` data starts
172
+ // solhint-disable no-inline-assembly
173
+ /// @solidity memory-safe-assembly
174
+ assembly {
175
+ let resultdata_size := mload(result)
176
+ revert(add(result, 32), resultdata_size)
177
+ }
178
+ }
179
+ }
180
+
181
+ /**
182
+ * @dev Returns the extension address stored under the following data key:
183
+ * - {_LSP17_EXTENSION_PREFIX} + `<bytes4>` (Check [LSP2-ERC725YJSONSchema] for encoding the data key).
184
+ * - If no extension is stored, returns the address(0).
185
+ */
186
+ function _getExtensionAndForwardValue(
187
+ bytes4 functionSelector
188
+ ) internal view virtual override returns (address, bool) {
189
+ // Generate the data key relevant for the functionSelector being called
190
+ bytes32 mappedExtensionDataKey = LSP2Utils.generateMappingKey(
191
+ _LSP17_EXTENSION_PREFIX,
192
+ functionSelector
193
+ );
194
+
195
+ // Check if there is an extension stored under the generated data key
196
+ bytes memory extensionAddress = ERC725YCore._getData(
197
+ mappedExtensionDataKey
198
+ );
199
+ if (extensionAddress.length != 20 && extensionAddress.length != 0)
200
+ revert InvalidExtensionAddress(extensionAddress);
201
+
202
+ return (address(bytes20(extensionAddress)), true);
203
+ }
204
+
205
+ /**
206
+ * @inheritdoc IERC165
207
+ */
208
+ function supportsInterface(
209
+ bytes4 interfaceId
210
+ )
211
+ public
212
+ view
213
+ virtual
214
+ override(IERC165, ERC725YCore, LSP17Extendable)
215
+ returns (bool)
216
+ {
217
+ return
218
+ interfaceId == _INTERFACEID_LSP8 ||
219
+ super.supportsInterface(interfaceId) ||
220
+ LSP17Extendable._supportsInterfaceInERC165Extension(interfaceId);
221
+ }
222
+
223
+ /**
224
+ * @inheritdoc LSP4DigitalAssetMetadata
225
+ * @dev The ERC725Y data key `_LSP8_TOKENID_FORMAT_KEY` cannot be changed
226
+ * once the identifiable digital asset contract has been deployed.
227
+ */
228
+ function _setData(
229
+ bytes32 dataKey,
230
+ bytes memory dataValue
231
+ )
232
+ internal
233
+ virtual
234
+ override(LSP4DigitalAssetMetadata, LSP4DigitalAssetMetadataCore)
235
+ {
236
+ if (dataKey == _LSP8_TOKENID_FORMAT_KEY) {
237
+ revert LSP8TokenIdFormatNotEditable();
238
+ }
239
+ LSP4DigitalAssetMetadata._setData(dataKey, dataValue);
240
+ }
241
+ }