[PAXUSD] ERC20 Token Smart Contract Technical Assessment
- Symbol: PAX
- Proxy (entry point):
- Current Implementation:
- Proxy (entry point):
- Deployment Date:
- Total supply: 0
- Developers allotment: N/A
- Project website: https://www.paxos.com/pax/
- Github repository:
- Can use existing MCD collateral type adapter? Yes, GemJoin or GemJoin6 (to pro
- Does the contract implement the ERC20 token standards? Yes.
- Risk analysis: MEDIUM.
- Decimals: 18
- Overflow checks: Yes, the contract uses a SafeMath uint256 library.
Mitigation against allowance race-condition: No, the contract does not mitigate this with the proposed fix. It does make not of it within the code comments above the
Upgradeable contract patterns: Yes, the contract is upgradeable. And is currently on the second implementation:
- Access control or restriction lists: Yes.
Non-standard features or behaviors: Yes.
- Ability to control the token supply.
- Ability to pause the contract.
- Ability to freeze and unfreeze the balance of any on-chain address.
- Ability to BetaDelegateTransfer (gas-less transactions).
- Ability to upgrade the contract.
Formal Verification Considerations:
- Does transfer have simple semantics? Yes.
- Does transferFrom have simple semantics? Yes.
- Can balances be arbitrarily modified by some actor? Yes, the contract can freeze/unfreeze any on-chain address.
- Are there any external calls? No.
- N/A or an inactive testnet, the below addresses were found:
Contract Logic Summary
PAX uses OpenZeppelin’s
AdminUpgradeabilityProxy upgradeability pattern. This pattern uses two contracts: a proxy contract and an implementation contract. The proxy contract receives calls and delegatecalls onward to the implementation contract. The proxy contract address doesn’t change, and should PAX need to change (“upgrade”) the underlying implementation contract, they can do so without having to point external users to a new contract address.
PAX briefly documents their usage of the pattern here.
The contract includes a beta implementation variation of EIP-865 that allows for gas-less transactions. This allows a user to delegate a token transfer to a third party, which will pay for the transaction using native Ether, and takes the commensurate fee in tokens. PAX’s implementation is such that only approved parties are allowed to transfer PAXUSD on behalf of a user. There is an additional
betaDelegatedTransferBatch() function that allows for the aforementioned action to be done in batches.
betaDelegateTransfer() functionality can be found in the code beginning here.
- NOTE: the address above is NOT a multisig, it is an externally owned address (EOA)!
ownercan pause the contract (pausing transfers and approvals of the
PAXtoken) – this functionality is implemented in the contract following OpenZeppelin’s
supplyControllercan mint and burn tokens, and per PAXUSD documentation, this functionality is “based on teh actual movement of cash in and out of the reserve based on requests for the purchase and redemption of PAX.”
It’s important to note that these are currently set to same address but occupy two different
address variables within the implementation smart contract. When calling
initialize() (a one-time use function) these two address variables are set to
msg.sender. These two addresses could be different in the future.
PAXUSD’s contract logic, excluding the upgradeability patterns, is all encompassed within the
PAXImplementationV2.sol contract. The contract inherits no other contracts.
Contract Risk Summary
This is a medium risk contract. The ERC20 function are implemented to industry standard, it uses a SafeMath library to prevent over/underflows, and there is no inheritance. However, the non-standard features outlined in the technical information section of this assessment introduce additional risk.
Sūrya’s Description Report (tool: Surya)
Files Description Table
|File Name||SHA-1 Hash|
Contracts Description Table
|Function can modify state|
|Function is payable|
totalSupply() returns 0