Skip to content

Commit

Permalink
fix: restrict owner change in _beforeTokenTransfer
Browse files Browse the repository at this point in the history
  • Loading branch information
skimaharvey committed Jan 11, 2024
1 parent 8006a04 commit 35ddbd5
Show file tree
Hide file tree
Showing 11 changed files with 329 additions and 14 deletions.
5 changes: 5 additions & 0 deletions contracts/LSP8IdentifiableDigitalAsset/LSP8Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,8 @@ error LSP8TokenIdsDataEmptyArray();
* @notice Batch call failed.
*/
error LSP8BatchCallFailed(uint256 callIndex);

/**
* @dev Reverts when the token owner changed inside the {_beforeTokenTransfer} hook.
*/
error LSP8TokenOwnerChanged(bytes32 tokenId, address oldOwner, address newOwner);
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ import {
LSP8NotifyTokenReceiverIsEOA,
LSP8TokenIdsDataLengthMismatch,
LSP8TokenIdsDataEmptyArray,
LSP8BatchCallFailed
LSP8BatchCallFailed,
LSP8TokenOwnerChanged
} from "./LSP8Errors.sol";

// constants
Expand Down Expand Up @@ -634,9 +635,11 @@ abstract contract LSP8IdentifiableDigitalAssetCore is

_beforeTokenTransfer(from, to, tokenId, data);

// Re-fetch and update `tokenOwner` in case `tokenId`
// was transferred inside the `_beforeTokenTransfer` hook
tokenOwner = tokenOwnerOf(tokenId);
// Check that `tokenId`'s owner was not changed inside the `_beforeTokenTransfer` hook
address currentTokenOwner = tokenOwnerOf(tokenId);
if (tokenOwner != currentTokenOwner) {
revert LSP8TokenOwnerChanged(tokenId, tokenOwner, currentTokenOwner);
}

_clearOperators(from, tokenId);

Expand Down Expand Up @@ -721,8 +724,8 @@ abstract contract LSP8IdentifiableDigitalAssetCore is
* @dev Attempt to notify the operator `operator` about the `tokenId` being authorized.
* This is done by calling its {universalReceiver} function with the `_TYPEID_LSP8_TOKENOPERATOR` as typeId, if `operator` is a contract that supports the LSP1 interface.
* If `operator` is an EOA or a contract that does not support the LSP1 interface, nothing will happen and no notification will be sent.
* @param operator The address to call the {universalReceiver} function on.
* @param operator The address to call the {universalReceiver} function on.
* @param lsp1Data the data to be sent to the `operator` address in the `universalReceiver` call.
*/
function _notifyTokenOperator(
Expand All @@ -740,8 +743,8 @@ abstract contract LSP8IdentifiableDigitalAssetCore is
* @dev Attempt to notify the token sender `from` about the `tokenId` being transferred.
* This is done by calling its {universalReceiver} function with the `_TYPEID_LSP8_TOKENSSENDER` as typeId, if `from` is a contract that supports the LSP1 interface.
* If `from` is an EOA or a contract that does not support the LSP1 interface, nothing will happen and no notification will be sent.
* @param from The address to call the {universalReceiver} function on.
* @param from The address to call the {universalReceiver} function on.
* @param lsp1Data the data to be sent to the `from` address in the `universalReceiver` call.
*/
function _notifyTokenSender(
Expand Down
51 changes: 51 additions & 0 deletions contracts/Mocks/Tokens/LSP8TransferOwnerChange.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.4;

// modules
import {
LSP8IdentifiableDigitalAsset
} from "../../LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol";
import {
LSP8Burnable
} from "../../LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.sol";

contract LSP8TransferOwnerChange is LSP8IdentifiableDigitalAsset, LSP8Burnable {
// solhint-disable-next-line no-empty-blocks
constructor(
string memory name_,
string memory symbol_,
address newOwner_,
uint256 lsp4TokenType_,
uint256 lsp8TokenIdFormat_
)
LSP8IdentifiableDigitalAsset(
name_,
symbol_,
newOwner_,
lsp4TokenType_,
lsp8TokenIdFormat_
)
{}

function mint(
address to,
bytes32 tokenId,
bool force,
bytes memory data
) public {
_mint(to, tokenId, force, data);
}

function _beforeTokenTransfer(
address,
address,
bytes32 tokenId,
bytes memory
) internal override {
// if tokenID exist transfer token ownership to this contract
if (_exists(tokenId)) {
_tokenOwners[tokenId] = address(this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2066,6 +2066,37 @@ Reverts when trying to authorize or revoke the token's owner as an operator.

<br/>

### LSP8TokenOwnerChanged

:::note References

- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#lsp8tokenownerchanged)
- Solidity implementation: [`LSP8IdentifiableDigitalAsset.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol)
- Error signature: `LSP8TokenOwnerChanged(bytes32,address,address)`
- Error hash: `0x5a9c31d3`

:::

```solidity
error LSP8TokenOwnerChanged(
bytes32 tokenId,
address oldOwner,
address newOwner
);
```

Reverts when the token owner changed inside the [`_beforeTokenTransfer`](#_beforetokentransfer) hook.

#### Parameters

| Name | Type | Description |
| ---------- | :-------: | ----------- |
| `tokenId` | `bytes32` | - |
| `oldOwner` | `address` | - |
| `newOwner` | `address` | - |

<br/>

### NoExtensionFoundForFunctionSelector

:::note References
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2092,6 +2092,37 @@ Reverts when trying to authorize or revoke the token's owner as an operator.

<br/>

### LSP8TokenOwnerChanged

:::note References

- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#lsp8tokenownerchanged)
- Solidity implementation: [`LSP8Burnable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.sol)
- Error signature: `LSP8TokenOwnerChanged(bytes32,address,address)`
- Error hash: `0x5a9c31d3`

:::

```solidity
error LSP8TokenOwnerChanged(
bytes32 tokenId,
address oldOwner,
address newOwner
);
```

Reverts when the token owner changed inside the [`_beforeTokenTransfer`](#_beforetokentransfer) hook.

#### Parameters

| Name | Type | Description |
| ---------- | :-------: | ----------- |
| `tokenId` | `bytes32` | - |
| `oldOwner` | `address` | - |
| `newOwner` | `address` | - |

<br/>

### NoExtensionFoundForFunctionSelector

:::note References
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2108,6 +2108,37 @@ Reverts when trying to authorize or revoke the token's owner as an operator.

<br/>

### LSP8TokenOwnerChanged

:::note References

- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#lsp8tokenownerchanged)
- Solidity implementation: [`LSP8CappedSupply.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.sol)
- Error signature: `LSP8TokenOwnerChanged(bytes32,address,address)`
- Error hash: `0x5a9c31d3`

:::

```solidity
error LSP8TokenOwnerChanged(
bytes32 tokenId,
address oldOwner,
address newOwner
);
```

Reverts when the token owner changed inside the [`_beforeTokenTransfer`](#_beforetokentransfer) hook.

#### Parameters

| Name | Type | Description |
| ---------- | :-------: | ----------- |
| `tokenId` | `bytes32` | - |
| `oldOwner` | `address` | - |
| `newOwner` | `address` | - |

<br/>

### NoExtensionFoundForFunctionSelector

:::note References
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1677,7 +1677,7 @@ Approve `operator` to operate on all tokens of `tokensOwner`.
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
```

Emitted when the allowance of a `spender` for an `owner` is set by a call to [`approve`](#approve). `value` is the new allowance.
Emitted when `owner` enables `approved` to manage the `tokenId` token.

#### Parameters

Expand All @@ -1704,7 +1704,7 @@ Emitted when the allowance of a `spender` for an `owner` is set by a call to [`a
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
```

Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to `approved`.
Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.

#### Parameters

Expand Down Expand Up @@ -1897,7 +1897,7 @@ Emitted when `tokenId` token is transferred from the `from` to the `to` address.
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
```

Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero.
Emitted when `tokenId` token is transferred from `from` to `to`.

#### Parameters

Expand Down Expand Up @@ -2457,6 +2457,37 @@ Reverts when trying to authorize or revoke the token's owner as an operator.

<br/>

### LSP8TokenOwnerChanged

:::note References

- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#lsp8tokenownerchanged)
- Solidity implementation: [`LSP8CompatibleERC721.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol)
- Error signature: `LSP8TokenOwnerChanged(bytes32,address,address)`
- Error hash: `0x5a9c31d3`

:::

```solidity
error LSP8TokenOwnerChanged(
bytes32 tokenId,
address oldOwner,
address newOwner
);
```

Reverts when the token owner changed inside the [`_beforeTokenTransfer`](#_beforetokentransfer) hook.

#### Parameters

| Name | Type | Description |
| ---------- | :-------: | ----------- |
| `tokenId` | `bytes32` | - |
| `oldOwner` | `address` | - |
| `newOwner` | `address` | - |

<br/>

### NoExtensionFoundForFunctionSelector

:::note References
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2094,6 +2094,37 @@ Reverts when trying to authorize or revoke the token's owner as an operator.

<br/>

### LSP8TokenOwnerChanged

:::note References

- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#lsp8tokenownerchanged)
- Solidity implementation: [`LSP8Enumerable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.sol)
- Error signature: `LSP8TokenOwnerChanged(bytes32,address,address)`
- Error hash: `0x5a9c31d3`

:::

```solidity
error LSP8TokenOwnerChanged(
bytes32 tokenId,
address oldOwner,
address newOwner
);
```

Reverts when the token owner changed inside the [`_beforeTokenTransfer`](#_beforetokentransfer) hook.

#### Parameters

| Name | Type | Description |
| ---------- | :-------: | ----------- |
| `tokenId` | `bytes32` | - |
| `oldOwner` | `address` | - |
| `newOwner` | `address` | - |

<br/>

### NoExtensionFoundForFunctionSelector

:::note References
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1721,7 +1721,7 @@ Approve `operator` to operate on all tokens of `tokensOwner`.
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
```

Emitted when the allowance of a `spender` for an `owner` is set by a call to [`approve`](#approve). `value` is the new allowance.
Emitted when `owner` enables `approved` to manage the `tokenId` token.

#### Parameters

Expand All @@ -1748,7 +1748,7 @@ Emitted when the allowance of a `spender` for an `owner` is set by a call to [`a
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
```

Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to `approved`.
Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.

#### Parameters

Expand Down Expand Up @@ -1941,7 +1941,7 @@ Emitted when `tokenId` token is transferred from the `from` to the `to` address.
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
```

Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero.
Emitted when `tokenId` token is transferred from `from` to `to`.

#### Parameters

Expand Down Expand Up @@ -2526,6 +2526,37 @@ Reverts when trying to authorize or revoke the token's owner as an operator.

<br/>

### LSP8TokenOwnerChanged

:::note References

- Specification details: [**LSP-8-IdentifiableDigitalAsset**](https://github.com/lukso-network/lips/tree/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#lsp8tokenownerchanged)
- Solidity implementation: [`LSP8CompatibleERC721Mintable.sol`](https://github.com/lukso-network/lsp-smart-contracts/blob/develop/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.sol)
- Error signature: `LSP8TokenOwnerChanged(bytes32,address,address)`
- Error hash: `0x5a9c31d3`

:::

```solidity
error LSP8TokenOwnerChanged(
bytes32 tokenId,
address oldOwner,
address newOwner
);
```

Reverts when the token owner changed inside the [`_beforeTokenTransfer`](#_beforetokentransfer) hook.

#### Parameters

| Name | Type | Description |
| ---------- | :-------: | ----------- |
| `tokenId` | `bytes32` | - |
| `oldOwner` | `address` | - |
| `newOwner` | `address` | - |

<br/>

### NoExtensionFoundForFunctionSelector

:::note References
Expand Down
Loading

0 comments on commit 35ddbd5

Please sign in to comment.