Skip to content

Commit

Permalink
feat: add _afterTokenTransfer hook in LSP7 + LSP8
Browse files Browse the repository at this point in the history
  • Loading branch information
CJ42 committed Oct 10, 2023
1 parent abeac4f commit 4e3adc2
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 8 deletions.
32 changes: 30 additions & 2 deletions contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,10 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset {
/**
* @dev Mints `amount` of tokens and transfers it to `to`.
*
* @custom:info Any logic in the:
* - {_beforeTokenTransfer} function will run before updating the balances.
* - {_afterTokenTransfer} function will run after updating the balances, **but before notifying the recipient via LSP1**.
*
* @param to The address to mint tokens for.
* @param amount The amount of tokens to mint.
* @param force A boolean that describe if transfer to a `to` address that does not support LSP1 is allowed or not.
Expand Down Expand Up @@ -396,6 +400,8 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset {

emit Transfer(msg.sender, address(0), to, amount, force, data);

_afterTokenTransfer(address(0), to, amount);

bytes memory lsp1Data = abi.encode(address(0), to, amount, data);
_notifyTokenReceiver(to, force, lsp1Data);
}
Expand All @@ -407,7 +413,9 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset {
* function, if they are contracts that support the LSP1 interface. Their `universalReceiver` function will receive
* all the parameters in the calldata packed encoded.
*
* Any logic in the {_beforeTokenTransfer} function will run before updating the balances.
* @custom:info Any logic in the:
* - {_beforeTokenTransfer} function will run before updating the balances.
* - {_afterTokenTransfer} function will run after updating the balances, **but before notifying the sender via LSP1**.
*
* @param from The address to burn tokens from its balance.
* @param amount The amount of tokens to burn.
Expand Down Expand Up @@ -454,6 +462,8 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset {
data: data
});

_afterTokenTransfer(from, address(0), amount);

bytes memory lsp1Data = abi.encode(from, address(0), amount, data);
_notifyTokenSender(from, lsp1Data);
}
Expand Down Expand Up @@ -508,7 +518,9 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset {
* function, if they are contracts that support the LSP1 interface. Their `universalReceiver` function will receive
* all the parameters in the calldata packed encoded.
*
* Any logic in the {_beforeTokenTransfer} function will run before updating the balances.
* @custom:info Any logic in the:
* - {_beforeTokenTransfer} function will run before updating the balances.
* - {_afterTokenTransfer} function will run after updating the balances, **but before notifying the sender/recipient via LSP1**.
*
* @param from The address to decrease the balance.
* @param to The address to increase the balance.
Expand Down Expand Up @@ -546,6 +558,8 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset {

emit Transfer(msg.sender, from, to, amount, force, data);

_afterTokenTransfer(from, to, amount);

bytes memory lsp1Data = abi.encode(from, to, amount, data);

_notifyTokenSender(from, lsp1Data);
Expand All @@ -566,6 +580,20 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset {
uint256 amount // solhint-disable-next-line no-empty-blocks
) internal virtual {}

/**
* @dev Hook that is called after any token transfer, including minting and burning.
* Allows to run custom logic after updating balances, but **before notifiying sender/recipient** by overriding this function.
*
* @param from The sender address
* @param to The recipient address
* @param amount The amount of token to transfer
*/
function _afterTokenTransfer(
address from,
address to,
uint256 amount // solhint-disable-next-line no-empty-blocks
) internal virtual {}

/**
* @dev Attempt to notify the operator `operator` about the `amount` tokens being authorized with.
* This is done by calling its {universalReceiver} function with the `_TYPEID_LSP7_TOKENOPERATOR` as typeId, if `operator` is a contract that supports the LSP1 interface.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -348,15 +348,19 @@ abstract contract LSP8IdentifiableDigitalAssetCore is
/**
* @dev Create `tokenId` by minting it and transfers it to `to`.
*
* @custom:requirements
* - `tokenId` must not exist and not have been already minted.
* - `to` cannot be the zero address.
* @custom:info Any logic in the:
* - {_beforeTokenTransfer} function will run before updating the balances and ownership of `tokenId`s.
* - {_afterTokenTransfer} function will run after updating the balances and ownership of `tokenId`s, **but before notifying the recipient via LSP1**.
*
* @param to The address that will receive the minted `tokenId`.
* @param tokenId The token ID to create (= mint).
* @param force When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard.
* @param data Any additional data the caller wants included in the emitted event, and sent in the hook of the `to` address.
*
* @custom:requirements
* - `tokenId` must not exist and not have been already minted.
* - `to` cannot be the zero address.
* @custom:events {Transfer} event with `address(0)` as `from` address.
*/
function _mint(
Expand Down Expand Up @@ -384,6 +388,8 @@ abstract contract LSP8IdentifiableDigitalAssetCore is

emit Transfer(msg.sender, address(0), to, tokenId, force, data);

_afterTokenTransfer(address(0), to, tokenId);

bytes memory lsp1Data = abi.encode(address(0), to, tokenId, data);
_notifyTokenReceiver(to, force, lsp1Data);
}
Expand All @@ -396,7 +402,9 @@ abstract contract LSP8IdentifiableDigitalAssetCore is
* function, if it is a contract that supports the LSP1 interface. Its {universalReceiver} function will receive
* all the parameters in the calldata packed encoded.
*
* Any logic in the {_beforeTokenTransfer} function will run before burning `tokenId` and updating the balances.
* @custom:info Any logic in the:
* - {_beforeTokenTransfer} function will run before updating the balances and ownership of `tokenId`s.
* - {_afterTokenTransfer} function will run after updating the balances and ownership of `tokenId`s, **but before notifying the sender via LSP1**.
*
* @param tokenId The token to burn.
* @param data Any additional data the caller wants included in the emitted event, and sent in the LSP1 hook on the token owner's address.
Expand Down Expand Up @@ -427,6 +435,8 @@ abstract contract LSP8IdentifiableDigitalAssetCore is

emit Transfer(msg.sender, tokenOwner, address(0), tokenId, false, data);

_afterTokenTransfer(tokenOwner, address(0), tokenId);

bytes memory lsp1Data = abi.encode(
tokenOwner,
address(0),
Expand All @@ -443,7 +453,9 @@ abstract contract LSP8IdentifiableDigitalAssetCore is
* function, if they are contracts that support the LSP1 interface. Their `universalReceiver` function will receive
* all the parameters in the calldata packed encoded.
*
* Any logic in the {_beforeTokenTransfer} function will run before changing the owner of `tokenId`.
* @custom:info Any logic in the:
* - {_beforeTokenTransfer} function will run before updating the balances and ownership of `tokenId`s.
* - {_afterTokenTransfer} function will run after updating the balances and ownership of `tokenId`s, **but before notifying the sender/recipient via LSP1**.
*
* @param from The sender address.
* @param to The recipient address.
Expand Down Expand Up @@ -493,6 +505,8 @@ abstract contract LSP8IdentifiableDigitalAssetCore is

emit Transfer(msg.sender, from, to, tokenId, force, data);

_afterTokenTransfer(from, to, tokenId);

bytes memory lsp1Data = abi.encode(from, to, tokenId, data);

_notifyTokenSender(from, lsp1Data);
Expand All @@ -501,7 +515,7 @@ abstract contract LSP8IdentifiableDigitalAssetCore is

/**
* @dev Hook that is called before any token transfer, including minting and burning.
* * Allows to run custom logic before updating balances and notifiying sender/recipient by overriding this function.
* Allows to run custom logic before updating balances and notifiying sender/recipient by overriding this function.
*
* @param from The sender address
* @param to The recipient address
Expand All @@ -513,6 +527,20 @@ abstract contract LSP8IdentifiableDigitalAssetCore is
bytes32 tokenId // solhint-disable-next-line no-empty-blocks
) internal virtual {}

/**
* @dev Hook that is called after any token transfer, including minting and burning.
* Allows to run custom logic after updating balances, but **before notifiying sender/recipient via LSP1** by overriding this function.
*
* @param from The sender address
* @param to The recipient address
* @param tokenId The tokenId to transfer
*/
function _afterTokenTransfer(
address from,
address to,
bytes32 tokenId // solhint-disable-next-line no-empty-blocks
) internal virtual {}

/**
* @dev Attempt to notify the operator `operator` about the `tokenId` tokens 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.
Expand Down

0 comments on commit 4e3adc2

Please sign in to comment.