Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions contracts/BackedAutoFeeTokenImplementation.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pragma solidity 0.8.9;

import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "./BackedTokenImplementation.sol";
import "./interfaces/IBackedAutoFeeToken.sol";

/**
* @dev
Expand All @@ -51,7 +52,7 @@ import "./BackedTokenImplementation.sol";
*
*/

contract BackedAutoFeeTokenImplementation is BackedTokenImplementation {
contract BackedAutoFeeTokenImplementation is BackedTokenImplementation, IBackedAutoFeeToken {
// Calculating the Delegated Transfer Shares typehash:
bytes32 constant public DELEGATED_TRANSFER_SHARES_TYPEHASH =
keccak256(
Expand Down Expand Up @@ -164,7 +165,7 @@ contract BackedAutoFeeTokenImplementation is BackedTokenImplementation {
function initialize(
string memory name_,
string memory symbol_
) public virtual override {
) public virtual override(BackedTokenImplementation, IBackedToken) {
super.initialize(name_, symbol_);
_initialize_auto_fee(24 * 3600, block.timestamp, 0);
}
Expand Down Expand Up @@ -215,6 +216,13 @@ contract BackedAutoFeeTokenImplementation is BackedTokenImplementation {
feePerPeriod = _feePerPeriod;
}

/**
* @inheritdoc IERC20MetadataUpgradeable
*/
function decimals() public view virtual override(BackedTokenImplementation, IBackedToken) returns (uint8) {
return ERC20Upgradeable.decimals();
}

/**
* @dev See {IERC20-totalSupply}.
*/
Expand Down
17 changes: 6 additions & 11 deletions contracts/BackedTokenImplementation.sol
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pragma solidity 0.8.9;
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "./ERC20PermitDelegateTransfer.sol";
import "./SanctionsList.sol";
import "./interfaces/IBackedToken.sol";

/**
* @dev
Expand All @@ -55,7 +56,7 @@ import "./SanctionsList.sol";
*
*/

contract BackedTokenImplementation is OwnableUpgradeable, ERC20PermitDelegateTransfer {
contract BackedTokenImplementation is OwnableUpgradeable, ERC20PermitDelegateTransfer, IBackedToken {
string constant public VERSION = "1.1.0";

// Roles:
Expand All @@ -76,16 +77,6 @@ contract BackedTokenImplementation is OwnableUpgradeable, ERC20PermitDelegateTra
// Terms:
string public terms;

// Events:
event NewMinter(address indexed newMinter);
event NewBurner(address indexed newBurner);
event NewPauser(address indexed newPauser);
event NewSanctionsList(address indexed newSanctionsList);
event DelegateWhitelistChange(address indexed whitelistAddress, bool status);
event DelegateModeChange(bool delegateMode);
event PauseModeChange(bool pauseMode);
event NewTerms(string newTerms);

modifier allowedDelegate {
require(delegateMode || delegateWhitelist[_msgSender()], "BackedToken: Unauthorized delegate");
_;
Expand Down Expand Up @@ -153,6 +144,10 @@ contract BackedTokenImplementation is OwnableUpgradeable, ERC20PermitDelegateTra
super.delegatedTransfer(owner, to, value, deadline, v, r, s);
}

function decimals() public view virtual override(ERC20Upgradeable, IBackedToken) returns (uint8) {
return super.decimals();
}

/**
* @dev Function to mint tokens. Allowed only for minter
*
Expand Down
2 changes: 0 additions & 2 deletions contracts/WrappedBackedTokenFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ contract WrappedBackedTokenFactory is Ownable {
address underlying; // The address of the wrapped token underlying
address tokenOwner; // The address of the account to which the owner role will be assigned
address pauser; // The address of the account to which the pauser role will be assigned
address sanctionsList; // The address of sanctions list contract
}

/**
Expand Down Expand Up @@ -125,7 +124,6 @@ contract WrappedBackedTokenFactory is Ownable {
);

newToken.setPauser(configuration.pauser);
newToken.setSanctionsList(configuration.sanctionsList);
newToken.transferOwnership(configuration.tokenOwner);

emit NewToken(
Expand Down
32 changes: 6 additions & 26 deletions contracts/WrappedBackedTokenImplementation.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@

pragma solidity 0.8.9;

import "./interfaces/IBackedAutoFeeToken.sol";
import "./interfaces/IBackedToken.sol";
import "@openzeppelin/contracts-upgradeable-new/token/ERC20/extensions/ERC4626Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable-new/token/ERC20/extensions/ERC20PermitUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable-new/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable-new/utils/math/MathUpgradeable.sol";
import "./SanctionsList.sol";
import "./interfaces/IBackedAutoFeeToken.sol";

/**
* @dev
Expand All @@ -55,7 +55,6 @@ import "./interfaces/IBackedAutoFeeToken.sol";
* Enforces Sanctions List via the Chainalysis standard interface.
* The contract contains one role:
* - A pauser, that can pause or restore all transfers in the contract.
* - An owner, that can set the above, and also the sanctionsList pointer.
*
*/

Expand All @@ -78,22 +77,18 @@ contract WrappedBackedTokenImplementation is OwnableUpgradeable, ERC4626Upgradea
// Pause:
bool public isPaused;

// SanctionsList:
SanctionsList public sanctionsList;

// Terms:
string public terms;

// Events:
event NewPauser(address indexed newPauser);
event NewSanctionsList(address indexed newSanctionsList);
event PauseModeChange(bool pauseMode);
event NewTerms(string newTerms);


// constructor, call initializer to lock the implementation instance.
constructor () {
initialize("Wrapped Backed Token Implementation", "wBTI", address(0x0000000000000000000000000000000000000000));
_disableInitializers();
}

function initialize(string memory name_, string memory symbol_, address underlying_) public initializer {
Expand Down Expand Up @@ -162,21 +157,6 @@ contract WrappedBackedTokenImplementation is OwnableUpgradeable, ERC4626Upgradea
emit NewPauser(newPauser);
}

/**
* @dev Function to change the contract Senctions List. Allowed only for owner
*
* Emits a { NewSanctionsList } event
*
* @param newSanctionsList The address of the new Senctions List following the Chainalysis standard
*/
function setSanctionsList(address newSanctionsList) external onlyOwner {
// Check the proposed sanctions list contract has the right interface:
require(!SanctionsList(newSanctionsList).isSanctioned(address(this)), "WrappedBackedToken: Wrong List interface");

sanctionsList = SanctionsList(newSanctionsList);
emit NewSanctionsList(newSanctionsList);
}

/**
* @dev Function to change the contract terms. Allowed only for owner
*
Expand Down Expand Up @@ -204,10 +184,10 @@ contract WrappedBackedTokenImplementation is OwnableUpgradeable, ERC4626Upgradea
require(!isPaused, "WrappedBackedToken: token transfer while paused");

if (from != address(0)) {
require(!sanctionsList.isSanctioned(from), "WrappedBackedToken: sender is sanctioned");
require(!IBackedToken(asset()).sanctionsList().isSanctioned(from), "WrappedBackedToken: sender is sanctioned");
}
if (to != address(0)) {
require(!sanctionsList.isSanctioned(to), "WrappedBackedToken: receiver is sanctioned");
require(!IBackedToken(asset()).sanctionsList().isSanctioned(to), "WrappedBackedToken: receiver is sanctioned");
}

super._beforeTokenTransfer(from, to, amount);
Expand All @@ -219,7 +199,7 @@ contract WrappedBackedTokenImplementation is OwnableUpgradeable, ERC4626Upgradea
address spender,
uint256 amount
) internal virtual override {
require(!sanctionsList.isSanctioned(spender), "WrappedBackedToken: spender is sanctioned");
require(!IBackedToken(asset()).sanctionsList().isSanctioned(spender), "WrappedBackedToken: spender is sanctioned");

super._spendAllowance(owner, spender, amount);
}
Expand Down
12 changes: 5 additions & 7 deletions contracts/interfaces/IBackedAutoFeeToken.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

import "../SanctionsList.sol";
import "./IBackedToken.sol";

/**
* @title IBackedAutoFeeToken
* @dev Interface for the BackedAutoFeeToken, a rebasing ERC20 token with automatic fee accrual
Expand All @@ -11,14 +14,9 @@ pragma solidity 0.8.9;
* - Fees are automatically applied by decreasing the multiplier over time
* - The multiplier can be updated by an authorized multiplierUpdater address
*/
interface IBackedAutoFeeToken {
// View functions - EIP-712 and Roles
interface IBackedAutoFeeToken is IBackedToken {

/**
* @dev Returns the EIP-712 typehash for delegated share transfers
* @return The keccak256 hash of the DELEGATED_TRANSFER_SHARES type string
*/
function DELEGATED_TRANSFER_SHARES_TYPEHASH() external view returns (bytes32);
// View functions - EIP-712 and Roles

/**
* @dev Returns the address authorized to update the multiplier
Expand Down
172 changes: 172 additions & 0 deletions contracts/interfaces/IBackedToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

import "../SanctionsList.sol";

/**
* @title IBackedToken
* @dev Interface for BackedTokenImplementation, an ERC20 token with EIP-712
* permit and delegated-transfer support, role-based mint/burn/pause
* controls, a Chainalysis-compatible sanctions list, and a settable
* terms-of-service link.
*
* The contract exposes four roles:
* - minter: can mint new tokens.
* - burner: can burn its own tokens or tokens held by the contract itself.
* - pauser: can pause or unpause all transfers.
* - owner: can configure the three roles above, the sanctions list, the
* delegate-mode flags, and the terms string.
*/
interface IBackedToken {
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);

// View functions - Roles

/**
* @dev Returns the address authorized to mint tokens.
*/
function minter() external view returns (address);

/**
* @dev Returns the address authorized to burn tokens.
*/
function burner() external view returns (address);

/**
* @dev Returns the address authorized to pause/unpause transfers.
*/
function pauser() external view returns (address);

// View functions - Delegate Mode

/**
* @dev Returns whether anyone is allowed to relay `permit` and
* `delegatedTransfer` calls. When false, only addresses present in
* `delegateWhitelist` are allowed.
*/
function delegateMode() external view returns (bool);

/**
* @dev Returns whether `account` is whitelisted to relay `permit` and
* `delegatedTransfer` calls.
* @param account The address to query.
*/
function delegateWhitelist(address account) external view returns (bool);

// View functions - Pause

/**
* @dev Returns whether all token transfers are currently paused.
*/
function isPaused() external view returns (bool);

// View functions - Sanctions List and Terms

/**
* @dev Returns the sanctions list contract used to gate transfers and
* allowance spends. Follows the Chainalysis interface.
*/
function sanctionsList() external view returns (SanctionsList);

/**
* @dev Returns the current terms-of-service string (typically a web or
* IPFS link).
*/
function terms() external view returns (string memory);

// State-changing functions - Initialization

/**
* @dev Initializes the token. Can only be called once per proxy.
* @param name_ The ERC20 token name.
* @param symbol_ The ERC20 token symbol.
*/
function initialize(string memory name_, string memory symbol_) external;

// State-changing functions - Mint and Burn

/**
* @dev Mint new tokens. Callable only by `minter`.
* @param account Recipient of the minted tokens.
* @param amount Amount to mint.
*/
function mint(address account, uint256 amount) external;

/**
* @dev Burn tokens. Callable only by `burner`. The burned tokens must
* come from the burner itself or from this contract.
* @param account Account from which the tokens will be burned.
* @param amount Amount to burn.
*/
function burn(address account, uint256 amount) external;

// State-changing functions - Pause

/**
* @dev Pause or unpause all token transfers. Callable only by `pauser`.
* @param newPauseMode True to pause, false to resume.
*/
function setPause(bool newPauseMode) external;

// State-changing functions - Owner Configuration

/**
* @dev Set the address authorized to mint tokens. Owner only.
* @param newMinter The new minter address.
*/
function setMinter(address newMinter) external;

/**
* @dev Set the address authorized to burn tokens. Owner only.
* @param newBurner The new burner address.
*/
function setBurner(address newBurner) external;

/**
* @dev Set the address authorized to pause transfers. Owner only.
* @param newPauser The new pauser address.
*/
function setPauser(address newPauser) external;

/**
* @dev Point the contract at a new sanctions-list contract. Owner only.
* The new contract must implement the Chainalysis interface; the
* call probes `isSanctioned(address(this))` to verify.
* @param newSanctionsList The new sanctions list address.
*/
function setSanctionsList(address newSanctionsList) external;

/**
* @dev Toggle the delegate-relay whitelist status of an address. Owner only.
* @param whitelistAddress The address whose status is changing.
* @param status True to whitelist, false to remove.
*/
function setDelegateWhitelist(address whitelistAddress, bool status) external;

/**
* @dev Toggle global delegate mode. When true, anyone may relay `permit`
* and `delegatedTransfer` calls. Owner only.
* @param _delegateMode The new delegate-mode flag.
*/
function setDelegateMode(bool _delegateMode) external;

/**
* @dev Set the terms-of-service string. Owner only.
* @param newTerms The new terms (typically a web or IPFS link).
*/
function setTerms(string memory newTerms) external;

// Events

event NewMinter(address indexed newMinter);
event NewBurner(address indexed newBurner);
event NewPauser(address indexed newPauser);
event NewSanctionsList(address indexed newSanctionsList);
event DelegateWhitelistChange(address indexed whitelistAddress, bool status);
event DelegateModeChange(bool delegateMode);
event PauseModeChange(bool pauseMode);
event NewTerms(string newTerms);
}
Loading
Loading