@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.
- package/README.md +3 -0
- package/artifacts/LSP8CappedSupply.json +959 -0
- package/artifacts/LSP8CappedSupplyInitAbstract.json +972 -0
- package/artifacts/LSP8IdentifiableDigitalAsset.json +936 -0
- package/artifacts/LSP8IdentifiableDigitalAssetInitAbstract.json +949 -0
- package/artifacts/LSP8Mintable.json +1006 -0
- package/artifacts/LSP8MintableInit.json +1026 -0
- package/contracts/ILSP8IdentifiableDigitalAsset.sol +328 -0
- package/contracts/LSP8Constants.sol +41 -0
- package/contracts/LSP8Errors.sol +118 -0
- package/contracts/LSP8IdentifiableDigitalAsset.sol +241 -0
- package/contracts/LSP8IdentifiableDigitalAssetCore.sol +806 -0
- package/contracts/LSP8IdentifiableDigitalAssetInitAbstract.sol +248 -0
- package/contracts/extensions/LSP8Burnable.sol +30 -0
- package/contracts/extensions/LSP8BurnableInitAbstract.sol +24 -0
- package/contracts/extensions/LSP8CappedSupply.sol +85 -0
- package/contracts/extensions/LSP8CappedSupplyInitAbstract.sol +88 -0
- package/contracts/extensions/LSP8Enumerable.sol +69 -0
- package/contracts/extensions/LSP8EnumerableInitAbstract.sol +64 -0
- package/contracts/presets/ILSP8Mintable.sol +33 -0
- package/contracts/presets/LSP8Mintable.sol +60 -0
- package/contracts/presets/LSP8MintableInit.sol +43 -0
- package/contracts/presets/LSP8MintableInitAbstract.sol +62 -0
- package/dist/index.cjs +33 -0
- package/dist/index.d.cts +29 -0
- package/dist/index.d.mts +29 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.mjs +28 -0
- package/package.json +56 -0
- package/types/LSP8CappedSupply.ts +792 -0
- package/types/LSP8CappedSupplyInitAbstract.ts +824 -0
- package/types/LSP8IdentifiableDigitalAsset.ts +778 -0
- package/types/LSP8IdentifiableDigitalAssetInitAbstract.ts +813 -0
- package/types/LSP8Mintable.ts +797 -0
- package/types/LSP8MintableInit.ts +860 -0
- package/types/common.ts +131 -0
- package/types/contracts/LSP8IdentifiableDigitalAsset.ts +778 -0
- package/types/contracts/LSP8IdentifiableDigitalAssetInitAbstract.ts +813 -0
- package/types/contracts/extensions/LSP8CappedSupply.ts +792 -0
- package/types/contracts/extensions/LSP8CappedSupplyInitAbstract.ts +824 -0
- package/types/contracts/presets/LSP8Mintable.ts +797 -0
- package/types/contracts/presets/LSP8MintableInit.ts +860 -0
- 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
|
+
}
|