Unable to compile Solidity contracts which require external libraries
Closed this issue · 1 comments
stranger80 commented
As per thread zkSync-Community-Hub/zksync-developers#217
...it is impossible to compile a file which imports external libraries:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import {IPaymaster, ExecutionResult, PAYMASTER_VALIDATION_SUCCESS_MAGIC} from "@matterlabs/zksync-contracts/l2/system-contracts/interfaces/IPaymaster.sol";
import {IPaymasterFlow} from "@matterlabs/zksync-contracts/l2/system-contracts/interfaces/IPaymasterFlow.sol";
import {TransactionHelper, Transaction} from "@matterlabs/zksync-contracts/l2/system-contracts/libraries/TransactionHelper.sol";
import "@matterlabs/zksync-contracts/l2/system-contracts/Constants.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract NftGatedPaymaster is IPaymaster, Ownable {
// NFT to for paymaster validation
IERC721 private immutable nft_asset;
modifier onlyBootloader() {
require(
msg.sender == BOOTLOADER_FORMAL_ADDRESS,
"Only bootloader can call this method"
);
// Continue execution if called from the bootloader.
_;
}
// The constructor takes the address of the NFT as an argument.
constructor(address _erc721) Ownable(msg.sender) {
nft_asset = IERC721(_erc721);
}
// The gas fees will be paid for by the paymaster if the user is the owner of the required NFT asset.
function validateAndPayForPaymasterTransaction(
bytes32,
bytes32,
Transaction calldata _transaction
)
external
payable
onlyBootloader
returns (bytes4 magic, bytes memory context)
{
// By default we consider the transaction as accepted.
magic = PAYMASTER_VALIDATION_SUCCESS_MAGIC;
require(
_transaction.paymasterInput.length >= 4,
"The standard paymaster input must be at least 4 bytes long"
);
bytes4 paymasterInputSelector = bytes4(
_transaction.paymasterInput[0:4]
);
// Use the general paymaster flow
if (paymasterInputSelector == IPaymasterFlow.general.selector) {
address userAddress = address(uint160(_transaction.from));
// Verify if user has the required NFT asset in order to use paymaster
require(
nft_asset.balanceOf(userAddress) > 0,
"User does not hold the required NFT asset and therefore must for their own gas!"
);
// Note, that while the minimal amount of ETH needed is tx.gasPrice * tx.gasLimit,
// neither paymaster nor account are allowed to access this context variable.
uint256 requiredETH = _transaction.gasLimit *
_transaction.maxFeePerGas;
// The bootloader never returns any data, so it can safely be ignored here.
(bool success, ) = payable(BOOTLOADER_FORMAL_ADDRESS).call{
value: requiredETH
}("");
} else {
revert("Invalid paymaster flow");
}
}
function postTransaction(
bytes calldata _context,
Transaction calldata _transaction,
bytes32,
bytes32,
ExecutionResult _txResult,
uint256 _maxRefundedGas
) external payable override onlyBootloader {
// Refunds are not supported yet.
}
function withdraw(address payable _to) external onlyOwner {
// send paymaster funds to the owner
uint256 balance = address(this).balance;
(bool success, ) = _to.call{value: balance}("");
require(success, "Failed to withdraw funds from paymaster.");
}
receive() external payable {}
}
stranger80 commented
Tactical solution:
- Preload the compilation backend with a set of included libraries
Strategic solution:
- Maintain a list of included packages
- Add note in readme saying that if anyone wants to add a package to the list - they need to raise it with plugin owners