[PAXG] ERC20 Token Smart Contract Domain Community Assessment

General Information

Risk Summary

  • Does the contract implement the ERC20 token standards?
    Yes, the contract implements all the required ERC20 functions.
    PAXG is a pausable erc20 token with burn and mint controlled by a central SupplyController.
    The contract also has additional asset protection functions.
  • Risk analysis: Medium

Technical Information

  • Compiler version: v0.4.24+commit.e67f0147
  • Decimals: 18
  • Overflow checks: Yes, the contract uses a SafeMath library.
  • Mitigation against allowance race-condition:
    No, the approve function does have a race condition
  • Upgradeable contract patterns: yes, contract provides UpgradeabilityProxy
  • Access control or restriction lists: ability to freeze/pause wallets, seize tokens from wallets
  • Non-standard features or behaviors: upgradeability, admin proxy, pausing and freezing,
    minting and burning, asset protection functions, BetaDelegateTransfer allowing end user to pay gas for token transfers.

Formal Verification Considerations:

  • Does transfer have simple semantics? Yes, seems standard
  • Does transferFrom have simple semantics? Yes, seems standard
  • Can balances be arbitrarily modified by some actor?
    AssetProtectionRole can freeze/unfreeze wallets and seize tokens
  • Are there any external calls?
    Only the Proxy which can change the contract implementation.
    There is also an external function β€œonlyOwner” which uses the AssetProtectionRole
    to seize PAXG

Testnet Information

No Testnet Information available

Contract Logic Summary

The token uses a Proxy contract which links to an implementation contract. The implementation
contract is an upgradeable, freezable, contract with special asset protection functions. At its core the
implementation is a standard erc20 contract which uses the SafeMath contract. But these additional
functions are added to comply with regulation, and due to being a physical asset custodial token.

The contract is upgraded by pointing the Proxy contract to a new implementation contract. This is done
by actors with administrative permissions.

Administrative Addresses

Below is a list of several addresses related to token management:

feeRecipient: 0x611479ce1d3d457ffe9fb2abbaf8d3fe2ad8fffb
feeController: 0x5195427ca88df768c298721da791b93ad11eca65
owner: 0xb87cec7baa2ce4a055f8563e9cc5a210cedc329f
supplyController: 0x5195427ca88df768c298721da791b93ad11eca65
assetProtectionRole: 0xb87cec7baa2ce4a055f8563e9cc5a210cedc329f
All of these addresses are EOAs with private keys, and no associated code. This presents more risk because there is no way to know who holds these keys and how the security is being handled.

Contract Risk Summary

This is a medium risk contract. The ERC20 functions are implemented to the industry standard and uses upgradeable design patterns. The ERC20 allowance race condition is noted in their code and not mitigated. The contract makes use of a SafeMath library to prevent overflows & underflows. The contract also has pausable, freezable features, and the ability for an administrator to seize funds
from wallets. These features are similar to other real asset and custodial tokens.

Supporting Materials

BetaDelegateTransfer function: https://github.com/paxosglobal/paxos-gold-contract#betadelegatetransfer

Contracts Description Table

Proxy Contract:

Contract Type Bases
β”” Function Name Visibility Mutability Modifiers
Proxy Implementation
β”” External :exclamation: :dollar: NO❗️
β”” _implementation Internal :lock:
β”” _delegate Internal :lock: :stop_sign:
β”” _willFallback Internal :lock: :stop_sign:
β”” _fallback Internal :lock: :stop_sign:
AddressUtils Library
β”” isContract Internal :lock:
UpgradeabilityProxy Implementation Proxy
β”” Public :exclamation: :stop_sign: NO❗️
β”” _implementation Internal :lock:
β”” _upgradeTo Internal :lock: :stop_sign:
β”” _setImplementation Private :closed_lock_with_key: :stop_sign:
AdminUpgradeabilityProxy Implementation UpgradeabilityProxy
β”” Public :exclamation: :stop_sign: UpgradeabilityProxy
β”” admin External :exclamation: ifAdmin
β”” implementation External :exclamation: ifAdmin
β”” changeAdmin External :exclamation: :stop_sign: ifAdmin
β”” upgradeTo External :exclamation: :stop_sign: ifAdmin
β”” upgradeToAndCall External :exclamation: :dollar: ifAdmin
β”” _admin Internal :lock:
β”” _setAdmin Internal :lock: :stop_sign:
β”” _willFallback Internal :lock: :stop_sign:

Implementation Contract:

Contract Type Bases
β”” Function Name Visibility Mutability Modifiers
SafeMath Library
β”” sub Internal :lock:
β”” add Internal :lock:
β”” mul Internal :lock:
β”” div Internal :lock:
PAXGImplementation Implementation
β”” initialize Public :exclamation: :stop_sign: NO❗️
β”” Public :exclamation: :stop_sign: NO❗️
β”” initializeDomainSeparator Public :exclamation: :stop_sign: NO❗️
β”” totalSupply Public :exclamation: NO❗️
β”” transfer Public :exclamation: :stop_sign: whenNotPaused
β”” balanceOf Public :exclamation: NO❗️
β”” transferFrom Public :exclamation: :stop_sign: whenNotPaused
β”” approve Public :exclamation: :stop_sign: whenNotPaused
β”” allowance Public :exclamation: NO❗️
β”” _transfer Internal :lock: :stop_sign:
β”” proposeOwner Public :exclamation: :stop_sign: onlyOwner
β”” disregardProposeOwner Public :exclamation: :stop_sign: NO❗️
β”” claimOwnership Public :exclamation: :stop_sign: NO❗️
β”” reclaimPAXG External :exclamation: :stop_sign: onlyOwner
β”” pause Public :exclamation: :stop_sign: onlyOwner
β”” unpause Public :exclamation: :stop_sign: onlyOwner
β”” setAssetProtectionRole Public :exclamation: :stop_sign: NO❗️
β”” freeze Public :exclamation: :stop_sign: onlyAssetProtectionRole
β”” unfreeze Public :exclamation: :stop_sign: onlyAssetProtectionRole
β”” wipeFrozenAddress Public :exclamation: :stop_sign: onlyAssetProtectionRole
β”” isFrozen Public :exclamation: NO❗️
β”” setSupplyController Public :exclamation: :stop_sign: NO❗️
β”” increaseSupply Public :exclamation: :stop_sign: onlySupplyController
β”” decreaseSupply Public :exclamation: :stop_sign: onlySupplyController
β”” nextSeqOf Public :exclamation: NO❗️
β”” betaDelegatedTransfer Public :exclamation: :stop_sign: NO❗️
β”” _betaDelegatedTransfer Internal :lock: :stop_sign: whenNotPaused
β”” betaDelegatedTransferBatch Public :exclamation: :stop_sign: NO❗️
β”” isWhitelistedBetaDelegate Public :exclamation: NO❗️
β”” setBetaDelegateWhitelister Public :exclamation: :stop_sign: NO❗️
β”” whitelistBetaDelegate Public :exclamation: :stop_sign: onlyBetaDelegateWhitelister
β”” unwhitelistBetaDelegate Public :exclamation: :stop_sign: onlyBetaDelegateWhitelister
β”” setFeeController Public :exclamation: :stop_sign: NO❗️
β”” setFeeRecipient Public :exclamation: :stop_sign: onlyFeeController
β”” setFeeRate Public :exclamation: :stop_sign: onlyFeeController
β”” getFeeFor Public :exclamation: NO❗️


Symbol Meaning
:stop_sign: Function can modify state
:dollar: Function is payable

How difficult would it be to get PAXG included in the next governance cycle?


Btw if anyone wants to get involved in writing these smart contract assessments, and has some technical knowledge of the erc20 standard and a bit of solidity, reach out to me and/or @wil

see this post here: Discussion of collateral onboarding process

1 Like

Thanks for the review @befitsandpiper. Happy to answer any questions about these findings

1 Like