Developer Docs
AppGitHub
  • Welcome!
  • Smart contracts
    • Core
      • Introduction
      • Deep Dive
      • Smart Contract Reference
        • PWN Hub
          • Tags
        • PWN Config
        • PWN Vault
        • Loan Types
          • Simple Loan
        • Proposals
          • Simple Loan Proposal
            • Simple Proposal
            • List Proposal
            • Elastic Proposal
            • Elastic Chainlink Proposal
            • Dutch Proposal
        • PWN Utilized Credit
        • PWN LOAN
        • PWN Revoked Nonce
        • Peripheral Contracts
          • Acceptor Controller
            • World ID
          • State Fingerprint Computer
            • UniV3
            • Chicken Bonds
          • Pool Adapter
            • Aave
            • Compound
            • ERC4626
        • Miscellaneous
          • PWN Fee Calculator
          • PWN Signature Checker
          • PWN Errors
          • PWN Periphery
          • Timelock
    • PWN DAO
      • Governance
        • Optimistic
        • Token
      • Tokens
        • PWN
        • stPWN
        • vePWN
          • Stake
          • Power
          • Metadata
      • Epoch Clock
      • Miscellaneous
        • Errors
        • EpochPowerLib
    • Tools
      • PWN Safe
        • Architecture
        • Security considerations
        • Smart Contract Reference
          • PWN Safe Factory
          • ATR Module
            • Tokenized Asset Manager
            • Recipient Permission Manager
          • Whitelist
          • ATR Guard
            • Operators context
      • Token Bundler
      • PWN Deployer
    • Libraries
      • MultiToken
    • Contract Addresses
  • More documentation
    • PWN Docs
    • FAQ
    • Audits
    • Using PWN without front-end
  • Deprecated
    • PWN Beta
      • Architecture
      • PWN
        • Off-chain signed offer
        • Offer types
      • PWN Vault
      • PWN LOAN
Powered by GitBook
On this page
  • 1. Summary
  • 2. Contract details
  • Features
  • Functions
  • Recipient Permission Struct
  • Events
Edit on GitHub
  1. Smart contracts
  2. Tools
  3. PWN Safe
  4. Smart Contract Reference
  5. ATR Module

Recipient Permission Manager

PreviousTokenized Asset ManagerNextWhitelist

Last updated 2 years ago

1. Summary

This contract is responsible for checking valid recipient permissions and tracking granted and revoked permissions. It is necessary to prevent the .

2. Contract details

  • RecipientPermissionManager.sol is written in Solidity version 0.8.15

Features

  • Checks for valid recipient permissions

  • Tracks granted and revoked permissions

  • Provides a function to hash the struct

Functions

grantRecipientPermission

Overview

A function to grant an on-chain recipient permission.

This function takes one argument supplied by the caller:

  • RecipientPermission calldatapermission - The

Implementation

function grantRecipientPermission(RecipientPermission calldata permission) external {
	// Check that caller is permission signer
	require(msg.sender == permission.recipient, "Sender is not permission recipient");

	bytes32 permissionHash = recipientPermissionHash(permission);

	// Check that permission is not have been granted
	require(grantedPermissions[permissionHash] == false, "Recipient permission is granted");

	// Check that permission is not have been revoked
	require(revokedPermissionNonces[msg.sender][permission.nonce] == false, "Recipient permission nonce is revoked");

	// Grant permission
	grantedPermissions[permissionHash] = true;

	// Emit event
	emit RecipientPermissionGranted(permissionHash);
}
revokeRecipientPermission

Overview

A function to revoke permissions.

This function takes one argument supplied by the caller:

  • bytes32permissionNonce - A of the permission being revoked for the caller

Implementation

function revokeRecipientPermission(bytes32 permissionNonce) external {
	// Check that permission is has not been revoked
	require(
		revokedPermissionNonces[msg.sender][permissionNonce] == false,
		"Recipient permission nonce is revoked"
	);

	// Revoke permission
	revokedPermissionNonces[msg.sender][permissionNonce] = true;

	// Emit event
	emit RecipientPermissionNonceRevoked(msg.sender, permissionNonce);
}
recipientPermissionHash

Overview

A function to hash a permission struct using keccak256.

This function takes one argument supplied by the caller:

Implementation

function recipientPermissionHash(RecipientPermission memory permission) public view returns (bytes32) {
	return keccak256(abi.encodePacked(
		"\x19\x01",
		// Domain separator is composing to prevent replay attack in case of an Ethereum fork
		keccak256(abi.encode(
			keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
			keccak256(bytes("AssetTransferRights")),
			keccak256(bytes("0.1")),
			block.chainid,
			address(this)
		)),
		keccak256(abi.encode(
			RECIPIENT_PERMISSION_TYPEHASH,
			permission.assetCategory,
			permission.assetAddress,
			permission.assetId,
			permission.assetAmount,
			permission.ignoreAssetIdAndAmount,
			permission.recipient,
			permission.expiration,
			permission.isPersistent,
			permission.nonce
		))
	));
}
_checkValidPermission

Overview

An internal function that verifies the validity of supplied permission and marks it as used.

This function takes four arguments supplied by the ATR Module:

  • addresssender - Address of the account that is sending the asset

Implementation

function _useValidPermission(
	address sender,
	MultiToken.Asset memory asset,
	RecipientPermission memory permission,
	bytes calldata permissionSignature
) internal {
	// Check that permission is not expired
	uint40 expiration = permission.expiration;
	require(expiration == 0 || block.timestamp < expiration, "Recipient permission is expired");

	// Check permitted agent
	address agent = permission.agent;
	require(agent == address(0) || sender == agent, "Caller is not permitted agent");

	// Check correct asset
	require(permission.assetCategory == asset.category, "Invalid permitted asset");
	require(permission.assetAddress == asset.assetAddress, "Invalid permitted asset");
	// Check id and amount if ignore flag is false
	if (permission.ignoreAssetIdAndAmount == false) {
		require(permission.assetId == asset.id, "Invalid permitted asset");
		require(permission.assetAmount == asset.amount, "Invalid permitted asset");
	} // Skip id and amount check if ignore flag is true

	// Check that permission nonce is not revoked
	address recipient = permission.recipient;
	bytes32 nonce = permission.nonce;
	require(revokedPermissionNonces[recipient][nonce] == false, "Recipient permission nonce is revoked");

	// Compute EIP-712 structured data hash
	bytes32 permissionHash = recipientPermissionHash(permission);

	// Check that permission is granted
	// Via on-chain tx, EIP-1271 or off-chain signature
	if (grantedPermissions[permissionHash] == true) {
		// Permission is granted on-chain, no need to check signature
	} else if (recipient.code.length > 0) {
		// Check that permission is valid
		require(IERC1271(recipient).isValidSignature(permissionHash, permissionSignature) == EIP1271_VALID_SIGNATURE, "Signature on behalf of contract is invalid");
	} else {
		// Check that permission signature is valid
		require(ECDSA.recover(permissionHash, permissionSignature) == recipient, "Permission signer is not stated as recipient");
	}

	// Mark used permission nonce as revoked if not persistent
	if (permission.isPersistent == false) {
		revokedPermissionNonces[recipient][nonce] = true;

		emit RecipientPermissionNonceRevoked(recipient, nonce);
	}

}

Recipient Permission Struct

Type
Name
Comment

assetCategory

address

assetAddress

Contract address of the asset that is permitted to transfer

uint256

assetId

ID of the asset that is permitted to transfer

uint256

assetAmount

Amount of the asset that is permitted to transfer

bool

ignoreAssetIdAndAmount

Flag stating if asset ID and amount are ignored when checking the permissioned asset

address

recipient

Address of the recipient and permission signer

address

agent

Optional address of a permitted agent that can process the permission. If this value is zero, any agent can process the permission

uint40

expiration

Optional permission expiration timestamp in seconds. If this value is zero, the permission doesn't have an expiration

bool

isPersistent

Flag stating if a permission is valid for more than one use

bytes32

nonce

Additional value to distinguish otherwise identical permissions

Events

The Recipient Permission Manager contract defines two events and no custom errors.

event RecipientPermissionGranted(bytes32 indexed permissionHash);
event RecipientPermissionNonceRevoked(address indexed recipient, bytes32 indexed permissionNonce);
RecipientPermissionGranted

RecipientPermissionGranted event is emitted when on-chain recipient permission is granted.

This event has one parameter:

  • bytes32 indexedpermissionHash - Hash of the recipient permission struct returned by the recipientPermissionHash function

RecipientPermissionNonceRevoked

RecipientPermissionNonceRevoked event is emitted when a recipient revokes previously granted permission.

This event has two parameters:

  • address indexedrecipient - Address of the recipient who revoked the permission

  • bytes32 indexedpermissionNonce - Nonce of the revoked permission (see RecipientPermission struct for more information)

RecipientPermission memorypermission - The

MultiToken.Asset memoryasset - An asset struct (see )

RecipientPermission memorypermission - The

bytes calldatapermissionSignature - of the recipient permission struct. This signature is not required if the permission was granted on-chain

Category of the asset that is permitted to transfer (see for more information)

MultiToken
EIP-712
raw signature
recipient permission struct
recipient permission struct
MultiToken
RecipientPermission
recipient permission struct
nonce
stalking attack
MultiToken.Category