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: handle failed transfers inside onAbort #44

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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
4 changes: 2 additions & 2 deletions contracts/nft/contracts/evm/UniversalNFTCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ abstract contract UniversalNFTCore is
gateway.call(
universal,
message,
RevertOptions(address(this), false, address(0), message, 0)
RevertOptions(address(this), false, universal, message, 0)
);
} else {
gateway.depositAndCall{value: msg.value}(
Expand All @@ -137,7 +137,7 @@ abstract contract UniversalNFTCore is
RevertOptions(
address(this),
true,
address(0),
universal,
abi.encode(receiver, tokenId, uri, msg.sender),
gasLimitAmount
)
Expand Down
6 changes: 6 additions & 0 deletions contracts/nft/contracts/shared/UniversalNFTEvents.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ contract UniversalNFTEvents {
uint256 indexed tokenId,
string uri
);
event TokenTransferAborted(
address indexed sender,
uint256 indexed tokenId,
string uri,
bool outgoing
);
event TokenTransferToDestination(
address indexed destination,
address indexed sender,
Expand Down
39 changes: 33 additions & 6 deletions contracts/nft/contracts/zetachain/UniversalNFTCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ import "@zetachain/protocol-contracts/contracts/zevm/interfaces/IWZETA.sol";
import "@zetachain/protocol-contracts/contracts/zevm/GatewayZEVM.sol";
import {SwapHelperLib} from "@zetachain/toolkit/contracts/SwapHelperLib.sol";

struct AbortContext {
bytes sender;
address asset;
uint256 amount;
bool outgoing;
uint256 chainID;
bytes revertMessage;
}

/**
* @title UniversalNFTCore
* @dev This abstract contract provides the core logic for Universal NFTs. It is designed
Expand Down Expand Up @@ -167,8 +176,8 @@ abstract contract UniversalNFTCore is
RevertOptions memory revertOptions = RevertOptions(
address(this),
true,
address(0),
abi.encode(tokenId, uri, msg.sender),
address(this),
abi.encode(receiver, tokenId, uri, msg.sender),
gasLimitAmount
);

Expand Down Expand Up @@ -243,7 +252,7 @@ abstract contract UniversalNFTCore is
address(this),
true,
address(0),
abi.encode(tokenId, uri, sender),
abi.encode(receiver, tokenId, uri, sender),
0
)
);
Expand All @@ -256,16 +265,34 @@ abstract contract UniversalNFTCore is
* @param context Metadata about the failed call.
*/
function onRevert(RevertContext calldata context) external onlyGateway {
(uint256 tokenId, string memory uri, address sender) = abi.decode(
(, uint256 tokenId, string memory uri, address sender) = abi.decode(
context.revertMessage,
(uint256, string, address)
(address, uint256, string, address)
);

_safeMint(sender, tokenId);
_setTokenURI(tokenId, uri);
emit TokenTransferReverted(sender, tokenId, uri);
}

/**
* @notice onAbort is executed when a transfer from one connected chain to another
* fails inside onCall, for example, because the amount of tokens supplied is not
* sufficient to cover the withdraw gas fee to the destination and also not enough
* to cover withdraw gas fee to the source chain. In this scenario we don't have
* enough tokens to send NFT cross-chain, so the best thing we can do is to transfer
* the NFT to the original sender on ZetaChain.
* @param context Metadata about the failed call.
*/
function onAbort(AbortContext calldata context) external {
(, uint256 tokenId, string memory uri, address sender) = abi.decode(
context.revertMessage,
(address, uint256, string, address)
);
_safeMint(sender, tokenId);
_setTokenURI(tokenId, uri);
emit TokenTransferAborted(sender, tokenId, uri, context.outgoing);
}

/**
* @notice Returns the metadata URI for an NFT.
* @param tokenId The ID of the token.
Expand Down
2 changes: 1 addition & 1 deletion contracts/nft/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"@types/validator": "^13.12.2",
"@typescript-eslint/eslint-plugin": "^5.59.9",
"@typescript-eslint/parser": "^5.59.9",
"@zetachain/localnet": "4.0.0-rc6",
"@zetachain/localnet": "5.0.0-rc1",
"@zetachain/toolkit": "13.0.0-rc8",
"axios": "^1.3.6",
"chai": "^4.2.0",
Expand Down
20 changes: 15 additions & 5 deletions contracts/nft/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2564,15 +2564,15 @@
typescript "5.5.4"
zod "3.22.4"

"@zetachain/localnet@4.0.0-rc6":
version "4.0.0-rc6"
resolved "https://registry.yarnpkg.com/@zetachain/localnet/-/localnet-4.0.0-rc6.tgz#9b36f5ab0e8fac766d63cfca4b1cab6a263bdd5d"
integrity sha512-DGKspMAJZLUrgNirc3NzFYg9jRfaOyuF5ePj85D93qAA//f8lOsXpmh/6Bvq/MrEscCLpVavgVP7+ePy4KJ2Fw==
"@zetachain/localnet@5.0.0-rc1":
version "5.0.0-rc1"
resolved "https://registry.yarnpkg.com/@zetachain/localnet/-/localnet-5.0.0-rc1.tgz#920803084156a7b86fe763541b83a24833fb54d6"
integrity sha512-HHQ01dp9fxoA8WBBEXLmh5p/GMqVdd/0oYkdzzFZQ52UNXi+ucc4B/wdpBlKwub06r6Q8edPXiPfOjGPFthcMQ==
dependencies:
"@inquirer/prompts" "^5.5.0"
"@uniswap/v2-core" "^1.0.1"
"@uniswap/v2-periphery" "^1.1.0-beta.0"
"@zetachain/protocol-contracts" "11.0.0-rc3"
"@zetachain/protocol-contracts" "11.0.0-rc4"
ansis "^3.3.2"
concurrently "^8.2.2"
ethers "^6.13.2"
Expand All @@ -2596,6 +2596,16 @@
"@zetachain/networks" "^10.0.0"
ethers "5.6.8"

"@zetachain/[email protected]":
version "11.0.0-rc4"
resolved "https://registry.yarnpkg.com/@zetachain/protocol-contracts/-/protocol-contracts-11.0.0-rc4.tgz#2e2df98734793873e9c50629f6ec9f5eec6f9f54"
integrity sha512-7MJzEyUad7JgHucveIhtU8aaPkoMMzsfhKkh9MDMdxUzlaOmmxrQw2hi5B2b7UPxw2K9vFffkmIox6gd6c1+Yw==
dependencies:
"@openzeppelin/contracts" "^5.0.2"
"@openzeppelin/contracts-upgradeable" "^5.0.2"
"@zetachain/networks" "^10.0.0"
ethers "5.6.8"

"@zetachain/[email protected]":
version "9.0.0"
resolved "https://registry.yarnpkg.com/@zetachain/protocol-contracts/-/protocol-contracts-9.0.0.tgz#c20ad5da43f6f3676f31556b303d1cb4ea17357e"
Expand Down
4 changes: 2 additions & 2 deletions contracts/token/contracts/evm/UniversalTokenCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ abstract contract UniversalTokenCore is
gateway.call(
universal,
message,
RevertOptions(address(this), false, address(0), message, 0)
RevertOptions(address(this), false, universal, message, 0)
);
} else {
gateway.depositAndCall{value: msg.value}(
Expand All @@ -136,7 +136,7 @@ abstract contract UniversalTokenCore is
RevertOptions(
address(this),
true,
address(0),
universal,
abi.encode(amount, msg.sender),
gasLimitAmount
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ contract UniversalTokenEvents {
);
event TokenTransferReceived(address indexed receiver, uint256 amount);
event TokenTransferReverted(address indexed sender, uint256 amount);
event TokenTransferAborted(address indexed sender, uint256 amount);
event TokenTransferToDestination(
address indexed destination,
address indexed sender,
Expand Down
28 changes: 23 additions & 5 deletions contracts/token/contracts/zetachain/UniversalTokenCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ import {SwapHelperLib} from "@zetachain/toolkit/contracts/SwapHelperLib.sol";

import "../shared/UniversalTokenEvents.sol";

struct AbortContext {
bytes sender;
address asset;
uint256 amount;
bool outgoing;
uint256 chainID;
bytes revertMessage;
}

/**
* @title UniversalTokenCore
* @dev This abstract contract provides the core logic for Universal Tokens. It is designed
Expand Down Expand Up @@ -161,8 +170,8 @@ abstract contract UniversalTokenCore is
RevertOptions memory revertOptions = RevertOptions(
address(this),
true,
address(0),
abi.encode(amount, msg.sender),
address(this),
abi.encode(receiver, amount, msg.sender),
gasLimitAmount
);

Expand Down Expand Up @@ -230,7 +239,7 @@ abstract contract UniversalTokenCore is
address(this),
true,
address(0),
abi.encode(tokenAmount, sender),
abi.encode(receiver, tokenAmount, sender),
0
)
);
Expand All @@ -243,11 +252,20 @@ abstract contract UniversalTokenCore is
* @param context Metadata about the failed call.
*/
function onRevert(RevertContext calldata context) external onlyGateway {
(uint256 amount, address sender) = abi.decode(
(, uint256 amount, address sender) = abi.decode(
context.revertMessage,
(uint256, address)
(address, uint256, address)
);
_mint(sender, amount);
emit TokenTransferReverted(sender, amount);
}

function onAbort(AbortContext calldata context) external {
(, uint256 amount, address sender) = abi.decode(
context.revertMessage,
(address, uint256, address)
);
_mint(sender, amount);
emit TokenTransferAborted(sender, amount);
}
}
6 changes: 3 additions & 3 deletions contracts/token/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@
"@nomicfoundation/hardhat-toolbox": "^2.0.0",
"@nomiclabs/hardhat-ethers": "^2.0.0",
"@nomiclabs/hardhat-etherscan": "^3.0.0",
"@typechain/ethers-v5": "^10.1.0",
"@openzeppelin/hardhat-upgrades": "1.28.0",
"@typechain/ethers-v5": "^10.1.0",
"@typechain/hardhat": "^6.1.2",
"@types/chai": "^4.2.0",
"@types/mocha": ">=9.1.0",
"@types/node": ">=12.0.0",
"@typescript-eslint/eslint-plugin": "^5.59.9",
"@typescript-eslint/parser": "^5.59.9",
"@zetachain/localnet": "4.0.0-rc6",
"@zetachain/localnet": "5.0.0-rc1",
"@zetachain/toolkit": "13.0.0-rc8",
"axios": "^1.3.6",
"chai": "^4.2.0",
Expand Down Expand Up @@ -59,4 +59,4 @@
"@solana/web3.js": "^1.95.2",
"@zetachain/protocol-contracts": "11.0.0-rc3"
}
}
}
20 changes: 15 additions & 5 deletions contracts/token/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2536,15 +2536,15 @@
typescript "5.5.4"
zod "3.22.4"

"@zetachain/localnet@4.0.0-rc6":
version "4.0.0-rc6"
resolved "https://registry.yarnpkg.com/@zetachain/localnet/-/localnet-4.0.0-rc6.tgz#9b36f5ab0e8fac766d63cfca4b1cab6a263bdd5d"
integrity sha512-DGKspMAJZLUrgNirc3NzFYg9jRfaOyuF5ePj85D93qAA//f8lOsXpmh/6Bvq/MrEscCLpVavgVP7+ePy4KJ2Fw==
"@zetachain/localnet@5.0.0-rc1":
version "5.0.0-rc1"
resolved "https://registry.yarnpkg.com/@zetachain/localnet/-/localnet-5.0.0-rc1.tgz#920803084156a7b86fe763541b83a24833fb54d6"
integrity sha512-HHQ01dp9fxoA8WBBEXLmh5p/GMqVdd/0oYkdzzFZQ52UNXi+ucc4B/wdpBlKwub06r6Q8edPXiPfOjGPFthcMQ==
dependencies:
"@inquirer/prompts" "^5.5.0"
"@uniswap/v2-core" "^1.0.1"
"@uniswap/v2-periphery" "^1.1.0-beta.0"
"@zetachain/protocol-contracts" "11.0.0-rc3"
"@zetachain/protocol-contracts" "11.0.0-rc4"
ansis "^3.3.2"
concurrently "^8.2.2"
ethers "^6.13.2"
Expand All @@ -2568,6 +2568,16 @@
"@zetachain/networks" "^10.0.0"
ethers "5.6.8"

"@zetachain/[email protected]":
version "11.0.0-rc4"
resolved "https://registry.yarnpkg.com/@zetachain/protocol-contracts/-/protocol-contracts-11.0.0-rc4.tgz#2e2df98734793873e9c50629f6ec9f5eec6f9f54"
integrity sha512-7MJzEyUad7JgHucveIhtU8aaPkoMMzsfhKkh9MDMdxUzlaOmmxrQw2hi5B2b7UPxw2K9vFffkmIox6gd6c1+Yw==
dependencies:
"@openzeppelin/contracts" "^5.0.2"
"@openzeppelin/contracts-upgradeable" "^5.0.2"
"@zetachain/networks" "^10.0.0"
ethers "5.6.8"

"@zetachain/[email protected]":
version "9.0.0"
resolved "https://registry.yarnpkg.com/@zetachain/protocol-contracts/-/protocol-contracts-9.0.0.tgz#c20ad5da43f6f3676f31556b303d1cb4ea17357e"
Expand Down
Loading