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: connector native minting cap #248

Merged
merged 15 commits into from
Jul 25, 2024
30 changes: 26 additions & 4 deletions contracts/prototypes/evm/ZetaConnectorNonNative.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,38 @@ import "./IZetaNonEthNew.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";

contract ZetaConnectorNonNative is ZetaConnectorNewBase {
/// @notice Max supply for minting
uint256 public maxSupply = type(uint256).max;

/// @notice Event triggered when max supply is updated
/// @param maxSupply New max supply
event MaxSupplyUpdated(uint256 maxSupply);
error ExceedsMaxSupply();

constructor(address _gateway, address _zetaToken, address _tssAddress)
ZetaConnectorNewBase(_gateway, _zetaToken, _tssAddress)
{}

// @dev withdraw is called by TSS address, it mints zetaToken to the destination address
/// @notice Set max supply for minting
/// @param _maxSupply New max supply
/// @dev Caller must be TSS
function setMaxSupply(uint256 _maxSupply) external onlyTSS() {
Dismissed Show dismissed Hide dismissed
skosito marked this conversation as resolved.
Show resolved Hide resolved
maxSupply = _maxSupply;
emit MaxSupplyUpdated(_maxSupply);
}

/// @dev withdraw is called by TSS address, it mints zetaToken to the destination address
function withdraw(address to, uint256 amount, bytes32 internalSendHash) external override nonReentrant onlyTSS {
if (amount + IERC20(zetaToken).totalSupply() > maxSupply) revert ExceedsMaxSupply();

IZetaNonEthNew(zetaToken).mint(to, amount, internalSendHash);
emit Withdraw(to, amount);
}

// @dev withdrawAndCall is called by TSS address, it mints zetaToken and calls a contract
/// @dev withdrawAndCall is called by TSS address, it mints zetaToken and calls a contract
function withdrawAndCall(address to, uint256 amount, bytes calldata data, bytes32 internalSendHash) external override nonReentrant onlyTSS {
if (amount + IERC20(zetaToken).totalSupply() > maxSupply) revert ExceedsMaxSupply();

// Mint zetaToken to the Gateway contract
IZetaNonEthNew(zetaToken).mint(address(gateway), amount, internalSendHash);

Expand All @@ -27,8 +47,10 @@ contract ZetaConnectorNonNative is ZetaConnectorNewBase {
emit WithdrawAndCall(to, amount, data);
}

// @dev withdrawAndRevert is called by TSS address, it mints zetaToken to the gateway and calls onRevert on a contract
/// @dev withdrawAndRevert is called by TSS address, it mints zetaToken to the gateway and calls onRevert on a contract
function withdrawAndRevert(address to, uint256 amount, bytes calldata data, bytes32 internalSendHash) external override nonReentrant onlyTSS {
if (amount + IERC20(zetaToken).totalSupply() > maxSupply) revert ExceedsMaxSupply();

// Mint zetaToken to the Gateway contract
IZetaNonEthNew(zetaToken).mint(address(gateway), amount, internalSendHash);

Expand All @@ -38,7 +60,7 @@ contract ZetaConnectorNonNative is ZetaConnectorNewBase {
emit WithdrawAndRevert(to, amount, data);
}

// @dev receiveTokens handles token transfer and burn them
/// @dev receiveTokens handles token transfer and burn them
function receiveTokens(uint256 amount) external override {
IZetaNonEthNew(zetaToken).burnFrom(msg.sender, amount);
}
Expand Down

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions testFoundry/GatewayEVM.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ contract GatewayEVMTest is Test, IGatewayEVMErrors, IGatewayEVMEvents, IReceiver

token.mint(owner, 1000000);
token.transfer(address(custody), 500000);

vm.deal(tssAddress, 1 ether);
}

function testForwardCallToReceiveNonPayable() public {
Expand Down
2 changes: 2 additions & 0 deletions testFoundry/ZetaConnectorNative.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ contract ZetaConnectorNativeTest is Test, IGatewayEVMErrors, IGatewayEVMEvents,
vm.stopPrank();

zetaToken.mint(address(zetaConnector), 5000000);

vm.deal(tssAddress, 1 ether);
}

function testWithdraw() public {
Expand Down
56 changes: 55 additions & 1 deletion testFoundry/ZetaConnectorNonNative.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ contract ZetaConnectorNonNativeTest is Test, IGatewayEVMErrors, IGatewayEVMEvent
address destination;
address tssAddress;

error ExceedsMaxSupply();
event MaxSupplyUpdated(uint256 maxSupply);

function setUp() public {
owner = address(this);
destination = address(0x1234);
Expand All @@ -58,6 +61,8 @@ contract ZetaConnectorNonNativeTest is Test, IGatewayEVMErrors, IGatewayEVMEvent
gateway.setCustody(address(custody));
gateway.setConnector(address(zetaConnector));
vm.stopPrank();

vm.deal(tssAddress, 1 ether);
}

function testWithdraw() public {
Expand All @@ -76,6 +81,23 @@ contract ZetaConnectorNonNativeTest is Test, IGatewayEVMErrors, IGatewayEVMEvent
assertEq(balanceAfter, amount);
}

function testWithdrawFailsIfMaxSupplyReached() public {
uint256 amount = 100000;
uint256 balanceBefore = zetaToken.balanceOf(destination);
assertEq(balanceBefore, 0);
bytes32 internalSendHash = "";

uint256 maxSupply = 90000;
vm.expectEmit(true, true, true, true, address(zetaConnector));
emit MaxSupplyUpdated(maxSupply);
vm.prank(tssAddress);
zetaConnector.setMaxSupply(maxSupply);

vm.prank(tssAddress);
vm.expectRevert(ExceedsMaxSupply.selector);
zetaConnector.withdraw(destination, amount, internalSendHash);
}

function testWithdrawFailsIfSenderIsNotTSS() public {
uint256 amount = 100000;
bytes32 internalSendHash = "";
Expand Down Expand Up @@ -130,6 +152,22 @@ contract ZetaConnectorNonNativeTest is Test, IGatewayEVMErrors, IGatewayEVMEvent
zetaConnector.withdrawAndCall(address(receiver), amount, data, internalSendHash);
}

function testWithdrawAndCallReceiveERC20FailsIfMaxSupplyReached() public {
uint256 amount = 100000;
bytes32 internalSendHash = "";
bytes memory data = abi.encodeWithSignature("receiveERC20(uint256,address,address)", amount, address(zetaToken), destination);

uint256 maxSupply = 90000;
vm.expectEmit(true, true, true, true, address(zetaConnector));
emit MaxSupplyUpdated(maxSupply);
vm.prank(tssAddress);
zetaConnector.setMaxSupply(maxSupply);

vm.prank(tssAddress);
vm.expectRevert(ExceedsMaxSupply.selector);
zetaConnector.withdrawAndCall(address(receiver), amount, data, internalSendHash);
}

function testWithdrawAndCallReceiveNoParams() public {
uint256 amount = 100000;
bytes32 internalSendHash = "";
Expand Down Expand Up @@ -237,7 +275,7 @@ contract ZetaConnectorNonNativeTest is Test, IGatewayEVMErrors, IGatewayEVMEvent
assertEq(balanceGateway, 0);
}

function testWithdrawAndRevertFailsIfSenderIsNotTSS() public {
function testWithdrawAndRevertFailsIfSenderIsNotTSS() public {
uint256 amount = 100000;
bytes32 internalSendHash = "";
bytes memory data = abi.encodePacked("hello");
Expand All @@ -246,4 +284,20 @@ contract ZetaConnectorNonNativeTest is Test, IGatewayEVMErrors, IGatewayEVMEvent
vm.expectRevert(InvalidSender.selector);
zetaConnector.withdrawAndRevert(address(receiver), amount, data, internalSendHash);
}

function testWithdrawAndRevertFailsIfMaxSupplyReached() public {
uint256 amount = 100000;
bytes32 internalSendHash = "";
bytes memory data = abi.encodePacked("hello");

uint256 maxSupply = 90000;
vm.expectEmit(true, true, true, true, address(zetaConnector));
emit MaxSupplyUpdated(maxSupply);
vm.prank(tssAddress);
zetaConnector.setMaxSupply(maxSupply);

vm.prank(tssAddress);
vm.expectRevert(ExceedsMaxSupply.selector);
zetaConnector.withdrawAndRevert(address(receiver), amount, data, internalSendHash);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ import type {
export interface ZetaConnectorNonNativeInterface extends utils.Interface {
functions: {
"gateway()": FunctionFragment;
"maxSupply()": FunctionFragment;
"receiveTokens(uint256)": FunctionFragment;
"setMaxSupply(uint256)": FunctionFragment;
"tssAddress()": FunctionFragment;
"withdraw(address,uint256,bytes32)": FunctionFragment;
"withdrawAndCall(address,uint256,bytes,bytes32)": FunctionFragment;
Expand All @@ -41,7 +43,9 @@ export interface ZetaConnectorNonNativeInterface extends utils.Interface {
getFunction(
nameOrSignatureOrTopic:
| "gateway"
| "maxSupply"
| "receiveTokens"
| "setMaxSupply"
| "tssAddress"
| "withdraw"
| "withdrawAndCall"
Expand All @@ -50,10 +54,15 @@ export interface ZetaConnectorNonNativeInterface extends utils.Interface {
): FunctionFragment;

encodeFunctionData(functionFragment: "gateway", values?: undefined): string;
encodeFunctionData(functionFragment: "maxSupply", values?: undefined): string;
encodeFunctionData(
functionFragment: "receiveTokens",
values: [PromiseOrValue<BigNumberish>]
): string;
encodeFunctionData(
functionFragment: "setMaxSupply",
values: [PromiseOrValue<BigNumberish>]
): string;
encodeFunctionData(
functionFragment: "tssAddress",
values?: undefined
Expand Down Expand Up @@ -87,10 +96,15 @@ export interface ZetaConnectorNonNativeInterface extends utils.Interface {
encodeFunctionData(functionFragment: "zetaToken", values?: undefined): string;

decodeFunctionResult(functionFragment: "gateway", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "maxSupply", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "receiveTokens",
data: BytesLike
): Result;
decodeFunctionResult(
functionFragment: "setMaxSupply",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "tssAddress", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "withdraw", data: BytesLike): Result;
decodeFunctionResult(
Expand All @@ -104,16 +118,29 @@ export interface ZetaConnectorNonNativeInterface extends utils.Interface {
decodeFunctionResult(functionFragment: "zetaToken", data: BytesLike): Result;

events: {
"MaxSupplyUpdated(uint256)": EventFragment;
"Withdraw(address,uint256)": EventFragment;
"WithdrawAndCall(address,uint256,bytes)": EventFragment;
"WithdrawAndRevert(address,uint256,bytes)": EventFragment;
};

getEvent(nameOrSignatureOrTopic: "MaxSupplyUpdated"): EventFragment;
getEvent(nameOrSignatureOrTopic: "Withdraw"): EventFragment;
getEvent(nameOrSignatureOrTopic: "WithdrawAndCall"): EventFragment;
getEvent(nameOrSignatureOrTopic: "WithdrawAndRevert"): EventFragment;
}

export interface MaxSupplyUpdatedEventObject {
maxSupply: BigNumber;
}
export type MaxSupplyUpdatedEvent = TypedEvent<
[BigNumber],
MaxSupplyUpdatedEventObject
>;

export type MaxSupplyUpdatedEventFilter =
TypedEventFilter<MaxSupplyUpdatedEvent>;

export interface WithdrawEventObject {
to: string;
amount: BigNumber;
Expand Down Expand Up @@ -179,11 +206,18 @@ export interface ZetaConnectorNonNative extends BaseContract {
functions: {
gateway(overrides?: CallOverrides): Promise<[string]>;

maxSupply(overrides?: CallOverrides): Promise<[BigNumber]>;

receiveTokens(
amount: PromiseOrValue<BigNumberish>,
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<ContractTransaction>;

setMaxSupply(
_maxSupply: PromiseOrValue<BigNumberish>,
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<ContractTransaction>;

tssAddress(overrides?: CallOverrides): Promise<[string]>;

withdraw(
Expand Down Expand Up @@ -214,11 +248,18 @@ export interface ZetaConnectorNonNative extends BaseContract {

gateway(overrides?: CallOverrides): Promise<string>;

maxSupply(overrides?: CallOverrides): Promise<BigNumber>;

receiveTokens(
amount: PromiseOrValue<BigNumberish>,
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<ContractTransaction>;

setMaxSupply(
_maxSupply: PromiseOrValue<BigNumberish>,
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<ContractTransaction>;

tssAddress(overrides?: CallOverrides): Promise<string>;

withdraw(
Expand Down Expand Up @@ -249,11 +290,18 @@ export interface ZetaConnectorNonNative extends BaseContract {
callStatic: {
gateway(overrides?: CallOverrides): Promise<string>;

maxSupply(overrides?: CallOverrides): Promise<BigNumber>;

receiveTokens(
amount: PromiseOrValue<BigNumberish>,
overrides?: CallOverrides
): Promise<void>;

setMaxSupply(
_maxSupply: PromiseOrValue<BigNumberish>,
overrides?: CallOverrides
): Promise<void>;

tssAddress(overrides?: CallOverrides): Promise<string>;

withdraw(
Expand Down Expand Up @@ -283,6 +331,9 @@ export interface ZetaConnectorNonNative extends BaseContract {
};

filters: {
"MaxSupplyUpdated(uint256)"(maxSupply?: null): MaxSupplyUpdatedEventFilter;
MaxSupplyUpdated(maxSupply?: null): MaxSupplyUpdatedEventFilter;

"Withdraw(address,uint256)"(
to?: PromiseOrValue<string> | null,
amount?: null
Expand Down Expand Up @@ -318,11 +369,18 @@ export interface ZetaConnectorNonNative extends BaseContract {
estimateGas: {
gateway(overrides?: CallOverrides): Promise<BigNumber>;

maxSupply(overrides?: CallOverrides): Promise<BigNumber>;

receiveTokens(
amount: PromiseOrValue<BigNumberish>,
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<BigNumber>;

setMaxSupply(
_maxSupply: PromiseOrValue<BigNumberish>,
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<BigNumber>;

tssAddress(overrides?: CallOverrides): Promise<BigNumber>;

withdraw(
Expand Down Expand Up @@ -354,11 +412,18 @@ export interface ZetaConnectorNonNative extends BaseContract {
populateTransaction: {
gateway(overrides?: CallOverrides): Promise<PopulatedTransaction>;

maxSupply(overrides?: CallOverrides): Promise<PopulatedTransaction>;

receiveTokens(
amount: PromiseOrValue<BigNumberish>,
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<PopulatedTransaction>;

setMaxSupply(
_maxSupply: PromiseOrValue<BigNumberish>,
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<PopulatedTransaction>;

tssAddress(overrides?: CallOverrides): Promise<PopulatedTransaction>;

withdraw(
Expand Down
Loading
Loading