Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: allow Operator to revoke himself #893

Merged
merged 6 commits into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const INTERFACE_IDS = {
LSP1UniversalReceiver: '0x6bb56a14',
LSP1UniversalReceiverDelegate: '0xa245bbda',
LSP6KeyManager: '0x23f34c62',
LSP7DigitalAsset: '0xb3c4928f',
LSP7DigitalAsset: '0xc52d6008',
LSP8IdentifiableDigitalAsset: '0x3a271706',
LSP9Vault: '0x28af17e6',
LSP11BasicSocialRecovery: '0x049a28f1',
Expand Down
10 changes: 7 additions & 3 deletions contracts/LSP7DigitalAsset/ILSP7DigitalAsset.sol
Original file line number Diff line number Diff line change
Expand Up @@ -122,21 +122,23 @@ interface ILSP7DigitalAsset is IERC165, IERC725Y {
) external;

/**
* @dev Removes the `operator` address as an operator of callers tokens, disallowing it to send any amount of tokens
* on behalf of the token owner (the caller of the function `msg.sender`). See also {authorizedAmountFor}.
* @dev Enables `tokenOwner` to remove `operator` for its tokens, disallowing it to send any amount of tokens on its behalf.
* This function also allows the `operator` to remove itself if it is the caller of this function
*
* @param operator The address to revoke as an operator.
* @param tokenOwner The address of the token owner.
YamenMerhi marked this conversation as resolved.
Show resolved Hide resolved
* @param notify Boolean indicating whether to notify the operator or not.
* @param operatorNotificationData The data to notify the operator about via LSP1.
*
YamenMerhi marked this conversation as resolved.
Show resolved Hide resolved
* @custom:requirements
* - `operator` cannot be calling address.
* - caller MUST be `operator` or `tokenOwner`
* - `operator` cannot be the zero address.
*
* @custom:events {OperatorRevoked} event with address of the operator being revoked for the caller (token holder).
*/
function revokeOperator(
address operator,
address tokenOwner,
bool notify,
bytes memory operatorNotificationData
) external;
Expand Down Expand Up @@ -184,6 +186,7 @@ interface ILSP7DigitalAsset is IERC165, IERC725Y {
* indicating `operator` does not have any alauthorizedAmountForlowance left for `msg.sender`.
*
* @param operator The operator to decrease allowance for `msg.sender`
* @param tokenOwner The address of the token owner.
* @param subtractedAmount The amount to decrease by in the operator's allowance.
*
* @custom:requirements
Expand All @@ -192,6 +195,7 @@ interface ILSP7DigitalAsset is IERC165, IERC725Y {
*/
function decreaseAllowance(
address operator,
address tokenOwner,
uint256 subtractedAmount,
bytes memory operatorNotificationData
) external;
Expand Down
2 changes: 1 addition & 1 deletion contracts/LSP7DigitalAsset/LSP7Constants.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
pragma solidity ^0.8.4;

// --- ERC165 interface ids
bytes4 constant _INTERFACEID_LSP7 = 0xb3c4928f;
bytes4 constant _INTERFACEID_LSP7 = 0xc52d6008;

// --- Token Hooks

Expand Down
35 changes: 26 additions & 9 deletions contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import {LSP1Utils} from "../LSP1UniversalReceiver/LSP1Utils.sol";

// errors
import {
LSP7CannotSendToSelf,
LSP7AmountExceedsAuthorizedAmount,
LSP7InvalidTransferBatch,
LSP7AmountExceedsBalance,
Expand All @@ -31,7 +30,9 @@ import {
LSP7NotifyTokenReceiverContractMissingLSP1Interface,
LSP7NotifyTokenReceiverIsEOA,
OperatorAllowanceCannotBeIncreasedFromZero,
LSP7BatchCallFailed
LSP7BatchCallFailed,
LSP7RevokeOperatorNotAuthorized,
LSP7DecreaseAllowanceNotAuthorized
} from "./LSP7Errors.sol";

// constants
Expand Down Expand Up @@ -173,11 +174,20 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset {
*/
function revokeOperator(
address operator,
address tokenOwner,
bool notify,
bytes memory operatorNotificationData
) public virtual override {
if (msg.sender != tokenOwner && msg.sender != operator) {
revert LSP7RevokeOperatorNotAuthorized(
msg.sender,
tokenOwner,
operator
);
}

_updateOperator(
msg.sender,
tokenOwner,
operator,
0,
notify,
Expand All @@ -186,7 +196,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset {

if (notify) {
bytes memory lsp1Data = abi.encode(
msg.sender,
tokenOwner,
0,
operatorNotificationData
);
Expand Down Expand Up @@ -254,10 +264,19 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset {
*/
function decreaseAllowance(
address operator,
address tokenOwner,
uint256 subtractedAmount,
bytes memory operatorNotificationData
) public virtual override {
uint256 currentAllowance = authorizedAmountFor(operator, msg.sender);
if (msg.sender != tokenOwner && msg.sender != operator) {
revert LSP7DecreaseAllowanceNotAuthorized(
YamenMerhi marked this conversation as resolved.
Show resolved Hide resolved
msg.sender,
tokenOwner,
operator
);
}

uint256 currentAllowance = authorizedAmountFor(operator, tokenOwner);
if (currentAllowance < subtractedAmount) {
revert LSP7DecreasedAllowanceBelowZero();
}
Expand All @@ -266,7 +285,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset {
unchecked {
newAllowance = currentAllowance - subtractedAmount;
_updateOperator(
msg.sender,
tokenOwner,
operator,
newAllowance,
true,
Expand All @@ -275,7 +294,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset {
}

bytes memory lsp1Data = abi.encode(
msg.sender,
tokenOwner,
newAllowance,
operatorNotificationData
);
Expand All @@ -295,8 +314,6 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset {
bool force,
bytes memory data
) public virtual override {
if (from == to) revert LSP7CannotSendToSelf();

if (msg.sender != from) {
_spendAllowance({
operator: msg.sender,
Expand Down
23 changes: 18 additions & 5 deletions contracts/LSP7DigitalAsset/LSP7Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,6 @@ error LSP7CannotUseAddressZeroAsOperator();
*/
error LSP7CannotSendWithAddressZero();

/**
* @dev reverts when specifying the same address for `from` or `to` in a token transfer.
*/
error LSP7CannotSendToSelf();

/**
* @dev reverts when the array parameters used in {transferBatch} have different lengths.
*/
Expand Down Expand Up @@ -88,3 +83,21 @@ error OperatorAllowanceCannotBeIncreasedFromZero(address operator);
* @notice Batch call failed.
*/
error LSP7BatchCallFailed(uint256 callIndex);

/**
* @dev Reverts when the call to revoke operator is not authorized.
*/
error LSP7RevokeOperatorNotAuthorized(
address caller,
address tokenOwner,
address operator
);

/**
* @dev Reverts when the call to decrease allowance is not authorized.
*/
error LSP7DecreaseAllowanceNotAuthorized(
address caller,
address tokenOwner,
address operator
);
14 changes: 9 additions & 5 deletions contracts/LSP8IdentifiableDigitalAsset/LSP8Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,6 @@ error LSP8CannotUseAddressZeroAsOperator();
*/
error LSP8CannotSendToAddressZero();

/**
* @dev Reverts when specifying the same address for `from` and `to` in a token transfer.
*/
error LSP8CannotSendToSelf();

/**
* @dev Reverts when `operator` is not an operator for the `tokenId`.
*/
Expand Down Expand Up @@ -112,3 +107,12 @@ error LSP8TokenOwnerChanged(
address oldOwner,
address newOwner
);

/**
* @dev Reverts when the call to revoke operator is not authorized.
*/
error LSP8RevokeOperatorNotAuthorized(
address caller,
address tokenOwner,
bytes32 tokenId
);
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ import {
LSP8NonExistingOperator,
LSP8CannotSendToAddressZero,
LSP8TokenIdAlreadyMinted,
LSP8CannotSendToSelf,
LSP8NotifyTokenReceiverContractMissingLSP1Interface,
LSP8NotifyTokenReceiverIsEOA,
LSP8TokenIdsDataLengthMismatch,
LSP8TokenIdsDataEmptyArray,
LSP8BatchCallFailed,
LSP8TokenOwnerChanged
LSP8TokenOwnerChanged,
LSP8RevokeOperatorNotAuthorized
} from "./LSP8Errors.sol";

// constants
Expand Down Expand Up @@ -293,8 +293,14 @@ abstract contract LSP8IdentifiableDigitalAssetCore is
) public virtual override {
address tokenOwner = tokenOwnerOf(tokenId);

if (tokenOwner != msg.sender) {
revert LSP8NotTokenOwner(tokenOwner, tokenId, msg.sender);
if (msg.sender != tokenOwner) {
YamenMerhi marked this conversation as resolved.
Show resolved Hide resolved
if (operator != msg.sender) {
revert LSP8RevokeOperatorNotAuthorized(
msg.sender,
tokenOwner,
tokenId
);
}
}

if (operator == address(0)) {
Expand All @@ -315,7 +321,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is

if (notify) {
bytes memory lsp1Data = abi.encode(
msg.sender,
tokenOwner,
tokenId,
false, // unauthorized
operatorNotificationData
Expand Down Expand Up @@ -625,10 +631,6 @@ abstract contract LSP8IdentifiableDigitalAssetCore is
bool force,
bytes memory data
) internal virtual {
if (from == to) {
revert LSP8CannotSendToSelf();
}

address tokenOwner = tokenOwnerOf(tokenId);
if (tokenOwner != from) {
revert LSP8NotTokenOwner(tokenOwner, tokenId, from);
Expand Down
2 changes: 1 addition & 1 deletion docs/_interface_ids_table.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
| **LSP1UniversalReceiver** | `0x6bb56a14` | Interface of the LSP1 - Universal Receiver standard, an entry function for a contract to receive arbitrary information. |
| **LSP1UniversalReceiverDelegate** | `0xa245bbda` | Interface of the LSP1 - Universal Receiver Delegate standard. |
| **LSP6KeyManager** | `0x23f34c62` | Interface of the LSP6 - Key Manager standard, a contract acting as a controller of an ERC725 Account using predfined permissions. |
| **LSP7DigitalAsset** | `0xb3c4928f` | Interface of the LSP7 - Digital Asset standard, a fungible digital asset. |
| **LSP7DigitalAsset** | `0xc52d6008` | Interface of the LSP7 - Digital Asset standard, a fungible digital asset. |
| **LSP8IdentifiableDigitalAsset** | `0x3a271706` | Interface of the LSP8 - Identifiable Digital Asset standard, a non-fungible digital asset. |
| **LSP9Vault** | `0x28af17e6` | Interface of LSP9 - Vault standard, a blockchain vault that can hold assets and interact with other smart contracts. |
| **LSP11BasicSocialRecovery** | `0x049a28f1` | Interface of the LSP11 - Basic Social Recovery standard, a contract to recover access control into an account. |
Expand Down
Loading
Loading