Skip to content

Conversation

@zaryab2000
Copy link
Collaborator

@zaryab2000 zaryab2000 commented Oct 20, 2025

List of Important Changes in this PR

UniversalGatewayPC has now been added - a dedicated gateway for outbound flows from Push Chain.

1. New Vault Contract for ERC20 Custody

Separation of Concerns: Introduced dedicated Vault.sol contract for ERC20 token custody
Key Features:

  • TSS-controlled withdrawals and payload executions
  • Token support gated by UniversalGateway.isSupportedToken() (single source of truth)
    Three main operations:
    withdraw(): Simple ERC20 transfers
    withdrawAndExecute(): Transfers tokens to Gateway, then triggers execution
    revertWithdraw(): Refund path for failed operations

UniversalGateway Refactor: Vault Integration

  • Added address public VAULT and bytes32 public constant VAULT_ROLE

Function Changes
Removed: withdrawFunds() (replaced by Vault delegation)
Added:

  • updateVault(): Admin function to update Vault address (only when paused)
  • revertTokens(): ERC20 refund path (VAULT_ROLE only)
  • revertNative(): Native token refund path (TSS_ROLE, requires msg.value)
  • executeUniversalTx(): Two overloaded versions for ERC20 and native payload execution
    Token Flow Changes
    _handleTokenDeposit(): Now transfers tokens directly to VAULT instead of address(this)
    ERC20 custody responsibility fully delegated to Vault contract

ExecutePayloadd

  • executePayload now has to functions:
    1. For payload execution with Native Tokens ( msg.value )
    1. For payload execution with ERC20 Tokens

Test cases and interfaces have been updated accordingly.

@zaryab2000 zaryab2000 self-assigned this Oct 20, 2025
@zaryab2000 zaryab2000 requested a review from Copilot October 20, 2025 10:56
@zaryab2000 zaryab2000 added the enhancement New feature or request label Oct 20, 2025
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Adds Push Chain outbound gateway (UniversalGatewayPC) with supporting interfaces, errors, mocks, and extensive test coverage, plus a new “universal tx execution” path on the legacy UniversalGateway.

  • Introduces UniversalGatewayPC with withdraw and withdraw+execute flows, fee calculation via UniversalCore, and event emission.
  • Extends UniversalGateway with executeUniversalTx, approval handling, and replay protection.
  • Adds comprehensive tests and mocks for PRC20, UniversalCore, ERC20 approval variants, targets, and reentrancy scenarios.

Reviewed Changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
contracts/evm-gateway/src/UniversalGatewayPC.sol New gateway for Push Chain outbound flows; fee handling, burning, events
contracts/evm-gateway/src/interfaces/IUniversalGatewayPC.sol Interface for UniversalGatewayPC, including event and admin/user APIs
contracts/evm-gateway/src/libraries/Errors.sol Adds new specific errors used by PC gateway and universal execution path
contracts/evm-gateway/src/interfaces/IUniversalCore.sol Minimal interface for UniversalCore (UEM, gas token, gas price)
contracts/evm-gateway/src/interfaces/IPRC20.sol Minimal PRC20 interface required by gateway logic
contracts/evm-gateway/src/UniversalGateway.sol Adds executeUniversalTx path, approval reset/safe approve helpers, and replay guard
contracts/evm-gateway/test/gateway/8_GatewayPC.t.sol Comprehensive tests for UniversalGatewayPC withdraw flows, edge cases, and reentrancy
contracts/evm-gateway/test/gateway/7_GatewayExecuteUniversalTx.t.sol Tests for executeUniversalTx: native/ERC20 paths, approvals, and failures
contracts/evm-gateway/test/mocks/MockPRC20.sol Accurate PRC20 mock used by gateway tests
contracts/evm-gateway/test/mocks/MockUniversalCoreReal.sol Core mock with gas price/token config and autoswap placeholders
contracts/evm-gateway/test/mocks/MockReentrantContract.sol Reentrancy test helper calling gateway functions
contracts/evm-gateway/test/mocks/MockTarget.sol Target mock receiving ETH or tokens via transferFrom
contracts/evm-gateway/test/mocks/MockRevertingTarget.sol Target mock with revert/gas-heavy behaviors
contracts/evm-gateway/test/mocks/MockUSDTToken.sol USDT-like approve-zero-first behavior
contracts/evm-gateway/test/mocks/MockTokenApprovalVariants.sol Configurable token approve behavior for negative-path tests
contracts/evm-gateway/.env.sample Removed sample env file (non-code)

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@zaryab2000 zaryab2000 changed the title Feat gateway pc UniversalGateway PC + Vault Inclusion Oct 22, 2025
msg.sender, chainId, token, target, amount, gasToken, gasFee, gasLimitUsed, payload, protocolFee, revertInstruction
);
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

execute() fn is missing
If a user only wants to execute an outbound payload without withdrawal, then execute fn needs to be there

/// @param target target contract address to execute call
/// @param amount amount of token to send along
/// @param payload calldata to be executed on target
function executeUniversalTx(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it only supports arbitrary payload execution, but not the onCall/onExecute feature, which is crucial for any universal app development

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBD internally.

@zaryab2000
Copy link
Collaborator Author

zaryab2000 commented Oct 30, 2025

Second Set of Changes Made

  1. All suggested changes ( except the ones under discussion ) have now been pushed.
  2. VaultPC is now its own minimal contract , tests added in VaultPC.t.sol
  3. UniversalCore now has isSupportedToken() function.
  4. Vault Contract changes: vault now sends token to gateway for withdraw and revert of tokens that involve ERC20 ( and not native )
  • VaultPC is now recipient of all FEES in UniversalGatewayPC outflow of tokens.
  • Universal Core Module has completely been removed as recipient of any FEES now.
  1. UniversalGateway Changes:
  • revert functions name changed
  • revert event name changed
  • withdrawToken function added fro pure ERC20 token.

cc: @Zartaj0 @0xNilesh

whenNotPaused
onlyRole(FUND_MANAGER_ROLE)
{
_enforceSupportedToken(token);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we want to enforce supported token restriction here?
and what's the diff between sweep and withdraw in this pc vault?

isn't this supposed to be a protocol fees only contract, then why not just two functions

  1. withdraw for erc20
  2. withdraw for native pc

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. _enforceSupportedToken acts an additional layer of security to ensure fees collected are supported PRC20 tokens themselves
  2. withdraw vs sweep:
  • with withdraw(), admin takes fees out by legit PRC20 tokens.
  • with sweep() , it acts as a security mechanism to remove/transfer any unwanted tokens that are sent to this contract.
  1. Do you think we need withdraw for native PC function? Just to be sure, which chain's outbound flow will charge fees in native PC token?


/// @inheritdoc IUniversalGateway
function withdrawFunds(address recipient, address token, uint256 amount)
function revertUniversalTxToken(address token, uint256 amount, RevertInstructions calldata revertInstruction)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can also apply replay protection in revert functions
similar to withdraw by taking txId

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

works - but just to understand: every revert tx will also be a universal TX with txID?? I was not expecting txID for revert specific txs but wanted to double check this on this.

/// @inheritdoc IUniversalGateway
function revertWithdrawFunds(address token, uint256 amount, RevertInstructions calldata revertInstruction)
function revertUniversalTx(uint256 amount, RevertInstructions calldata revertInstruction)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same replay protection comment here

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

works - but just to understand: every revert tx will also be a universal TX with txID?? I was not expecting txID for revert specific txs but wanted to double check this on this.

/// @inheritdoc IUniversalGateway
function revertWithdrawFunds(address token, uint256 amount, RevertInstructions calldata revertInstruction)
function revertUniversalTx(uint256 amount, RevertInstructions calldata revertInstruction)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

even though I supported having a revert native token in gateway for a proper record :)

there are two things:

  1. there is no withdraw native tokens fn, TSS directly transfers it. We should make it standardised, either have both withdraw and revert for native or both should be handled by tss only without a gateway interaction
  2. having a fn for native withdraw and revert has benefit of proper record and all, but it unnecessarily opens up a route for re-entrancy (even tho, I don't see any issue now)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you still consider THIS a issue, after I responded on slack on the reason behind this? Are you suggesting we have a withdrawNative() function in gateway?

@zaryab2000 zaryab2000 merged commit 5973697 into universalGateway_dev Nov 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants