Skip to content
Snippets Groups Projects
Commit c4d3bf89 authored by Pat Hourigan's avatar Pat Hourigan :shamrock:
Browse files

The max fx fee must be set on the TokenFee, so it is recorded based on the...

The max fx fee must be set on the TokenFee, so it is recorded based on the calculation in that denominated currency
parents 0c6ed546 f56576ae
No related branches found
No related tags found
1 merge request!51Ability to FXSwap FrictionlessFundDepositTokens in a single contract IFrictionlessFXSwap
Pipeline #1114670516 passed
[bumpversion]
current_version = 2.0.0
current_version = 2.1.0-rc1
tag_name = {new_version}
commit = True
tag = True
......
......@@ -17,10 +17,9 @@ export CONTRACT_ADDR_FRICTIONLESS_PERMISSIONS_MANAGER=0xa33248a6A76B54Dc915128E8
export CONTRACT_ADDR_FRICTIONLESS_TREASURY_MANAGER=0x8D71eA5f06b30394Ef9894258002E5Ee80CBbd2F
export CONTRACT_ADDR_FRICTIONLESS_TRANSFER_MANAGER=0x1615C73e5689e95c8F99959b0D782693ef89fca7
export CONTRACT_ADDR_FRICTIONLESS_FX_SWAP=0x1273A29346bcf89A38edfA2E0fA5FdE12becB5cA
# FX Desk Custodians
export PERMISSIONED_FX_DESK=0x1df9f80af2ef7bac6af47d84c30de118538f9acc
export PERMISSIONED_FX_DESK_FEE_RECIPIENT=0x965980eC98E9986Dd86F424B6cE592f454718075
export PERMISSIONED_INVESTOR=0xb7061725d7654850254e650F302C0027F5c61e4A
......@@ -30,5 +29,5 @@ export FRICTIONLESS_DEPOSIT_TOKEN_FX_SELL_ADDR=0xeb52471e1958A0A41f6591679fb48b3
export FRICTIONLESS_DEPOSIT_TOKEN_FX_BUY_ADDR=0xD010a894A744b26C4cc2484810940bE98e08988F
export FRICTIONLESS_DEPOSIT_TOKEN_FX_BUY_AMOUNT=10000000000
#Precision 6 swap rate - The rate to used when buying
export FRICTIONLESS_DEPOSIT_TOKEN_FX_RATE=1160800
#Precision 18 swap rate - The rate to used when buying
export FRICTIONLESS_DEPOSIT_TOKEN_FX_RATE=1160800000000000000
# ================ Base Configuration for Deployment ================
# Avalanche TestNet - Fuji RPC URL
export RPC_URL=https://api.avax-test.network/ext/bc/C/rpc
......@@ -8,6 +9,23 @@ export PROTOCOL_ADMIN_PK=0x93402139724e3f6a99af8bd32b7bd239f9f8e3f39be6b8995eb55
# The key for EtherScan
export SCAN_KEY=BU7BBUHTT27RYUHBBXY3P4ST9EBUK9JNIT
export PERMISSIONED_FX_DESK_FEE_RECIPIENT=0x965980eC98E9986Dd86F424B6cE592f454718075
# ================ Deployment of Contract Upgrades ================
# Address of the Protocol Treasury
export PROTOCOL_TREASURY=0x241C1d0dE7A5FE02C08499116949Cc82C73cEdb5
# Address of the previously deployed FrictionlessPermissionsManager
export CONTRACT_ADDR_FRICTIONLESS_PERMISSIONS_MANAGER=0xa33248a6A76B54Dc915128E8211C5e772e1F9187
# Address of the previously deployed FrictionlessTreasuryManager
export CONTRACT_ADDR_FRICTIONLESS_TREASURY_MANAGER=0x8D71eA5f06b30394Ef9894258002E5Ee80CBbd2F
# FX Desk Custodians
export PERMISSIONED_FX_DESK_FEE_RECIPIENT=0x965980eC98E9986Dd86F424B6cE592f454718075
# ================ Deployment of PROTOCOL_TREASURY ================
# Address of the Protocol Treasury
export PROTOCOL_TREASURY=0x241C1d0dE7A5FE02C08499116949Cc82C73cEdb5
......
......@@ -3,9 +3,11 @@
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
- [Change Log](#change-log)
- [[1.0.0]](#100)
- [[2.1.0]](#210)
- [Features](#features)
- [Fixes](#fixes)
- [New Features](#new-features)
- [Existing Features](#existing-features)
- [Fixes](#fixes)
- [Security Vulnerabilities](#security-vulnerabilities)
- [Upgrades](#upgrades)
- [Incompatibilities](#incompatibilities)
......@@ -15,10 +17,14 @@
# Change Log
All notable changes to this project will be documented in this file.
## [1.0.0]
## [2.1.0]
### Features
#### New Features
- Frictionless FX Swap based on FX spot and forward rates between denominated FricitonlessFundDepositTokens
#### Existing Features
- Issuance of permissioned, secure, transferrable, digital securites and programmable cash waterfalls for a variety of OnChainAssets such as private credit & infrastructure funds, ETF's Treasuries, AMCs, Tracker Certificates, etc
- Issuance of permissioned, secure, transferrable, deposit tokens in multiple FIAT currencies.
- Payment & Settlement of digital securities using deposit tokens
......@@ -26,13 +32,13 @@ All notable changes to this project will be documented in this file.
- Ability to automatically collect fees trsutures for payment, settlement and conversion of digital securities, deposit tokens and ERC20 stablecoins.
### Fixes
#### Fixes
- n/a
### Security Vulnerabilities
- n/a
- None - Existing audit remains applicable https://hacken.io/audits/frictionless-protocol/
### Upgrades
......
......@@ -23,6 +23,7 @@
- [FrictionlessDigitalSecurityToken Payment & Atomic Settlement Flows](#frictionlessdigitalsecuritytoken-payment--atomic-settlement-flows)
- [FrictionlessTransferManager](#frictionlesstransfermanager)
- [FrictionlessERC20ConverterManager](#frictionlesserc20convertermanager)
- [FrictionlessFXSwap](#frictionlessfxswap)
- [FrictionlessFundDepositToken Delivery versus Payment](#frictionlessfunddeposittoken-delivery-versus-payment)
- [FrictionlessDigitalSecurityToken Atomic Settlement at Maturity](#frictionlessdigitalsecuritytoken-atomic-settlement-at-maturity)
- [FrictionlessDigitalSecurityToken Atomic Settlement in Secondaries](#frictionlessdigitalsecuritytoken-atomic-settlement-in-secondaries)
......@@ -354,7 +355,20 @@ The overview (non-exhaustive, please see the docs for that) of this IFrictionles
| convertToERC20 | Executes a directional exchange of the tokens in the pair, converting FrictionlessFundDepositToken to the ERC20, where the fees are collected by a defined recipient by a token owner. The FrictionlessFundDepositToken is burned in the conversion and the ERC20 is sent to the convertedTokensRecipient_ from the treasuryAddress. | PROTOCOL_TREASURY, PERMISSIONED_INVESTOR |
##### FrictionlessFXSwap
The [contracts/interface/IFrictionlessFXSwap.sol](contracts/interface/IFrictionlessFXSwap.sol) is the contract which enables the Frictionless FX Swap based on FX spot and forward rates between denominated FricitonlessFundDepositTokens
- Defining the frictionless conversion and atomic swapping of any FrictionlessFundDepositToken currency pair on the Frictionless protocol.
- SetFX rates are set from the live spot & forward FX partners on the protocol.
- Enable the collection of FX fees (in bps with a hard cap per transaction) which are transferred to a defined FX Desk recipient on the protocol.
The overview (non-exhaustive, please see the docs for that) of this IFrictionlessFXSwap is as follows:
| Function | Use Case | Applicable Role |
| :------- | :---------- | :-------------- |
| setFXDeskFeeAddr | Sets the address of the FXDesk fee recipient | PROTOCOL_ADMIN |
| setSwapFees | Set the swap fees for the swaps of a token pair. The fees can be any combination of zero (0%) or up to 10000 bps (100%) on any directional transfer. | PROTOCOL_ADMIN |
| swapTokens | Swaps tokens between addresses at a specified exchange rate. The exchange rates are taken from our FX providers and are configured based on either the spot or forward rate at the transaction time. | PROTOCOL_TREASURY |
......@@ -851,4 +865,4 @@ Similar to the TestNet deployment a .env-mainnet file is created and deployed us
```bash
pnpm run deploy:mainnet
```
\ No newline at end of file
```
......@@ -32,10 +32,12 @@ interface IFrictionlessFXSwap is IAbstractFeeModule {
/**
* @dev Structure representing token fee information including the token address and fee information
* @param tokenAddr The address of the token
* @param feeAbsoluteLimit The absolute limit of fees to be paid in the FX
* @param feeInfo The fee information associated with the token
*/
struct TokenFeeInfo {
struct FrictionlessTokenFXFeeInfo {
address tokenAddr;
uint256 feeAbsoluteLimit;
FeeInfo feeInfo;
}
......@@ -49,7 +51,7 @@ interface IFrictionlessFXSwap is IAbstractFeeModule {
* @param buyingTokensAmount The amount of tokens being bought
* @param buyingTokenExchangeRate The exchange rate of the token being bought to the token being sold
*/
event TokensSwapped(
event FrictionlessFXTokensSwapped(
address sellingTokenAddr,
address buyingTokenAddr,
address tokenSender,
......@@ -75,13 +77,6 @@ interface IFrictionlessFXSwap is IAbstractFeeModule {
*/
function setFXDeskFeeAddr(address newFXDeskFeeAddr_) external;
/**
* @dev Sets the maximum tokens fee amount
* Only Owner (PROTOCOL_ADMIN) can call this function
* @param newMaxTokensFeeAmount_ The new maximum tokens fee amount to be set
*/
function setMaxTokensFeeAmount(uint256 newMaxTokensFeeAmount_) external;
/**
* @dev Set the swap fees for the swaps of a token pair. The fees can be any combination of zero (0%) or upto 10000 bps (100%) on any directional transfer.
* Fees can only be set by the Owner (PROTOCOL_ADMIN).
......@@ -93,7 +88,10 @@ interface IFrictionlessFXSwap is IAbstractFeeModule {
* throws `AbstractFeeModuleInvalidFee` if the feeInBps is not in the valid range (ZERO_FEES_IN_BPS to MAX_FEES_IN_BPS)
* emits `FrictionlessFeeSet` upon completion of the setting of the fee info for the token in either set of fees
*/
function setSwapFees(TokenFeeInfo calldata token0FeeInfo_, TokenFeeInfo calldata token1FeeInfo_) external;
function setSwapFees(
FrictionlessTokenFXFeeInfo calldata token0FeeInfo_,
FrictionlessTokenFXFeeInfo calldata token1FeeInfo_
) external;
/**
* @dev Set the fee associated with the swap of a Token and manages the mapping of the key to this set of Fees.
......@@ -106,7 +104,7 @@ interface IFrictionlessFXSwap is IAbstractFeeModule {
* throws `AbstractFeeModuleInvalidFee` if the feeInBps is not in the valid range (ZERO_FEES_IN_BPS to MAX_FEES_IN_BPS)
* emits `FrictionlessTokenFeeSet` upon completion of the setting of the fee info for the token
*/
function setTokenFee(bytes32 tokenFeeKey_, TokenFeeInfo calldata tokenFeeInfo_) external;
function setTokenFee(bytes32 tokenFeeKey_, FrictionlessTokenFXFeeInfo calldata tokenFeeInfo_) external;
/**
* @dev Swaps tokens between addresses at a specified exchange rate
......@@ -133,12 +131,6 @@ interface IFrictionlessFXSwap is IAbstractFeeModule {
*/
function fxDeskFeeAddr() external view returns (address);
/**
* @dev Retrieves the maximum tokens fee amount
* @return The maximum tokens fee amount
*/
function maxTokensFeeAmount() external view returns (uint256);
/**
* @dev Retrieves the Frictionless Treasury Manager contract
* @return The address of the Frictionless Treasury Manager contract
......
......@@ -41,34 +41,27 @@ contract FrictionlessFXSwap is IFrictionlessFXSwap, OwnableUpgradeable, Abstract
/// @inheritdoc IFrictionlessFXSwap
address public override fxDeskFeeAddr;
/// @inheritdoc IFrictionlessFXSwap
uint256 public override maxTokensFeeAmount;
/// @inheritdoc IFrictionlessFXSwap
IFrictionlessTreasuryManager public override treasuryManager;
/// @inheritdoc IFrictionlessFXSwap
IFrictionlessPermissionsManager public override permissionManager;
/// @dev maintains the maximum set fee on a token FX SWap
mapping(bytes32 => uint256) private _maxAbsoluteFeesInfo;
modifier onlyTreasury() {
_onlyTreasury();
_;
}
function init(
address treasuryManager_,
address permissionManager_,
address fxDeskFeeAddr_,
uint256 maxTokensFeeAmount_
) external initializer {
function init(address treasuryManager_, address permissionManager_, address fxDeskFeeAddr_) external initializer {
__Ownable_init();
treasuryManager = IFrictionlessTreasuryManager(treasuryManager_);
permissionManager = IFrictionlessPermissionsManager(permissionManager_);
fxDeskFeeAddr = fxDeskFeeAddr_;
maxTokensFeeAmount = maxTokensFeeAmount_;
}
/// @inheritdoc IFrictionlessFXSwap
......@@ -76,15 +69,10 @@ contract FrictionlessFXSwap is IFrictionlessFXSwap, OwnableUpgradeable, Abstract
fxDeskFeeAddr = newFXDeskFeeAddr_;
}
/// @inheritdoc IFrictionlessFXSwap
function setMaxTokensFeeAmount(uint256 newMaxTokensFeeAmount_) external override onlyOwner {
maxTokensFeeAmount = newMaxTokensFeeAmount_;
}
/// @inheritdoc IFrictionlessFXSwap
function setSwapFees(
TokenFeeInfo calldata token0FeeInfo_,
TokenFeeInfo calldata token1FeeInfo_
FrictionlessTokenFXFeeInfo calldata token0FeeInfo_,
FrictionlessTokenFXFeeInfo calldata token1FeeInfo_
) external override onlyOwner {
(bytes32 tokenFeeKey0_, bytes32 tokenFeeKey1_) = getSwapFeeKeys(
token0FeeInfo_.tokenAddr,
......@@ -95,12 +83,18 @@ contract FrictionlessFXSwap is IFrictionlessFXSwap, OwnableUpgradeable, Abstract
revert FrictionlessFXSwapInvalidTokenAddresses(token0FeeInfo_.tokenAddr, token1FeeInfo_.tokenAddr);
}
_maxAbsoluteFeesInfo[tokenFeeKey0_] = token0FeeInfo_.feeAbsoluteLimit;
_maxAbsoluteFeesInfo[tokenFeeKey1_] = token1FeeInfo_.feeAbsoluteLimit;
_setTokenFee(tokenFeeKey0_, token0FeeInfo_.feeInfo);
_setTokenFee(tokenFeeKey1_, token1FeeInfo_.feeInfo);
}
/// @inheritdoc IFrictionlessFXSwap
function setTokenFee(bytes32 tokenFeeKey_, TokenFeeInfo calldata tokenFeeInfo_) external override onlyOwner {
function setTokenFee(
bytes32 tokenFeeKey_,
FrictionlessTokenFXFeeInfo calldata tokenFeeInfo_
) external override onlyOwner {
_setTokenFee(tokenFeeKey_, tokenFeeInfo_.feeInfo);
}
......@@ -115,10 +109,15 @@ contract FrictionlessFXSwap is IFrictionlessFXSwap, OwnableUpgradeable, Abstract
) external override onlyTreasury {
uint256 sellingTokensAmount_ = getSellingTokensAmount(buyingTokensAmount_, buyingTokenExchangeRate_);
FeeInfo memory tokenFeeInfo_ = getFeeInfo(getTokenFeeKey(sellingTokenAddr_, buyingTokenAddr_));
bytes32 tokenFeeKey0_ = getTokenFeeKey(sellingTokenAddr_, buyingTokenAddr_);
FeeInfo memory tokenFeeInfo_ = getFeeInfo(tokenFeeKey0_);
uint256 feeAmount_ = calculateFeeAmount(sellingTokensAmount_, tokenFeeInfo_.feeInBps);
feeAmount_ = Math.min(feeAmount_, maxTokensFeeAmount);
uint256 maxFeeAmount_ = _maxAbsoluteFeesInfo[tokenFeeKey0_];
if (maxFeeAmount_ > 0) {
feeAmount_ = Math.min(feeAmount_, maxFeeAmount_);
}
if (feeAmount_ > 0) {
_validateFeeRecipientAddr(tokenFeeInfo_);
......@@ -129,7 +128,7 @@ contract FrictionlessFXSwap is IFrictionlessFXSwap, OwnableUpgradeable, Abstract
treasuryManager.burnToken(sellingTokenAddr_, tokenSender_, sellingTokensAmount_ - feeAmount_);
treasuryManager.mintTokenForUser(buyingTokenAddr_, tokenRecipient_, buyingTokensAmount_);
emit TokensSwapped(
emit FrictionlessFXTokensSwapped(
sellingTokenAddr_,
buyingTokenAddr_,
tokenSender_,
......
......@@ -12,10 +12,12 @@
"build": "forge build",
"clean": "rm -rf out & rm -rf broadcast & rm -rf node_modules",
"deploy:testnet": ". ./.env-testnet && forge script script/DeployContracts.s.sol --fork-url $RPC_URL --private-key $PROTOCOL_ADMIN_PK --verify --etherscan-api-key $SCAN_KEY -vvvv --broadcast ",
"deploy:testnet:upgrade": ". ./.env-testnet && forge script script/DeployUpgradeContracts.s.sol --fork-url $RPC_URL --private-key $PROTOCOL_ADMIN_PK --verify --etherscan-api-key $SCAN_KEY -vvvv --broadcast ",
"deploy:testnet:treasury": ". ./.env-testnet && forge script script/DeployTreasury.s.sol --fork-url $RPC_URL --private-key $PROTOCOL_ADMIN_PK --verify --etherscan-api-key $SCAN_KEY -vvvv --broadcast ",
"deploy:testnet:depositToken": ". ./.env-testnet && forge script script/DeployDepositToken.s.sol --fork-url $RPC_URL --private-key $PROTOCOL_ADMIN_PK --verify --etherscan-api-key $SCAN_KEY -vvvv --broadcast ",
"deploy:testnet:litmusTransaction": ". ./.env-testnet && forge script script/DeployLitmus.s.sol --fork-url $RPC_URL --private-key $PROTOCOL_ADMIN_PK --verify --etherscan-api-key $SCAN_KEY -vvvv --broadcast ",
"deploy:mainnet": ". ./.env-mainnet && forge script script/DeployContracts.s.sol --fork-url $RPC_URL --private-key $PROTOCOL_ADMIN_PK --verify --etherscan-api-key $SCAN_KEY -vvvv --broadcast ",
"deploy:mainnet:upgrade": ". ./.env-mainnet && forge script script/DeployUpgradeContracts.s.sol --fork-url $RPC_URL --private-key $PROTOCOL_ADMIN_PK --verify --etherscan-api-key $SCAN_KEY -vvvv --broadcast ",
"deploy:mainnet:treasury": ". ./.env-mainnet && forge script script/DeployTreasury.s.sol --fork-url $RPC_URL --private-key $PROTOCOL_ADMIN_PK --verify --etherscan-api-key $SCAN_KEY -vvvv --broadcast ",
"deploy:mainnet:depositToken": ". ./.env-mainnet && forge script script/DeployDepositToken.s.sol --fork-url $RPC_URL --private-key $PROTOCOL_ADMIN_PK --verify --etherscan-api-key $SCAN_KEY -vvvv --broadcast ",
"deploy:local": ". ./.env-local && forge script script/DeployContracts.s.sol --fork-url $RPC_URL --private-key $PROTOCOL_ADMIN_PK -vvvv --broadcast ",
......
......@@ -88,7 +88,7 @@ contract DeployContracts is Script {
uint256 private immutable _protocolAdminPK = vm.envUint("PROTOCOL_ADMIN_PK");
/// @dev The address of the FX_DESK_FEE_RECIPIENT
address private immutable _fxDeskFeeRecipient = vm.envAddress("FX_DESK_FEE_RECIPIENT");
address private immutable _fxDeskFeeRecipient = vm.envAddress("PERMISSIONED_FX_DESK_FEE_RECIPIENT");
FrictionlessPermissionsManager public permissionsManager;
FrictionlessTreasuryManager public treasuryManager;
......@@ -105,7 +105,6 @@ contract DeployContracts is Script {
uint256 public defaultMinRedeemAmount = 10 ** 6;
uint256 public defaultMaxModulesCount = 25;
uint256 public defaultMaxTokensFeeAmount = 1000 * (10 ** 6);
ClaimIssuer private _claimIssuer;
......@@ -292,12 +291,7 @@ contract DeployContracts is Script {
fxSwap = FrictionlessFXSwap(_fxSwapProxyAddr);
fxSwap.init(
address(treasuryManager),
address(permissionsManager),
_fxDeskFeeRecipient,
defaultMaxTokensFeeAmount
);
fxSwap.init(address(treasuryManager), address(permissionsManager), _fxDeskFeeRecipient);
complianceFactory = _deployComplianceFactory(address(treasuryManager), address(permissionsManager));
......@@ -362,7 +356,7 @@ contract DeployContracts is Script {
console.log("FrictionlessTransferManager address", address(transferManager));
console.log("FrictionlessERC20ConverterManager address", address(erc20ConverterManager));
console.log("FrictionlessAttestationManager address", address(attestationManager));
console.log("FrictionlessFXSwap address", address(fxSwap));
console.log("FrictionlessFXSwap proxy address", _fxSwapProxyAddr);
}
/// @dev Deploy the PROTOCOL_ADMIN, create the relevant claim topics, establishes the TrustIssuer for claims
......
// SPDX-License-Identifier: MIT
/**
* Copyright © 2023 DEFYCA Labs S.à.r.l
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of the Frictionless protocol smart contracts
* (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies
* or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL DEFYCA LABS
* S.à.r.l BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
pragma solidity ^0.8.16;
import { TypeCaster } from "@solidity-lib/libs/utils/TypeCaster.sol";
import { Script } from "@forge-std/Script.sol";
import { console } from "@forge-std/console.sol";
import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import { IdentityProxy } from "@onchain-id/solidity/contracts/proxy/IdentityProxy.sol";
import { ImplementationAuthority } from "@onchain-id/solidity/contracts/proxy/ImplementationAuthority.sol";
import { ClaimIssuer } from "@onchain-id/solidity/contracts/ClaimIssuer.sol";
import { Identity } from "@onchain-id/solidity/contracts/Identity.sol";
import { AgentManager } from "@ERC-3643/roles/permissioning/agent/AgentManager.sol";
import { ClaimTopicsRegistry } from "@ERC-3643/registry/implementation/ClaimTopicsRegistry.sol";
import { ClaimTopicsRegistryProxy } from "@ERC-3643/proxy/ClaimTopicsRegistryProxy.sol";
import { IdentityRegistryStorage } from "@ERC-3643/registry/implementation/IdentityRegistryStorage.sol";
import { IdentityRegistry } from "@ERC-3643/registry/implementation/IdentityRegistry.sol";
import { IdentityRegistryStorageProxy } from "@ERC-3643/proxy/IdentityRegistryStorageProxy.sol";
import { IdentityRegistryProxy } from "@ERC-3643/proxy/IdentityRegistryProxy.sol";
import { ITREXImplementationAuthority } from "@ERC-3643/proxy/authority/ITREXImplementationAuthority.sol";
import { Token } from "@ERC-3643/token/Token.sol";
import { TokenProxy } from "@ERC-3643/proxy/TokenProxy.sol";
import { TREXImplementationAuthority } from "@ERC-3643/proxy/authority/TREXImplementationAuthority.sol";
import { TrustedIssuersRegistry } from "@ERC-3643/registry/implementation/TrustedIssuersRegistry.sol";
import { TrustedIssuersRegistryProxy } from "@ERC-3643/proxy/TrustedIssuersRegistryProxy.sol";
import { FrictionlessDigitalSecurity } from "@modules/FrictionlessDigitalSecurity.sol";
import { FrictionlessDigitalSecurityToken } from "@core/FrictionlessDigitalSecurityToken.sol";
import { FrictionlessFundDeposit } from "@modules/FrictionlessFundDeposit.sol";
import { FrictionlessFundDepositToken } from "@core/FrictionlessFundDepositToken.sol";
import { FrictionlessOnChainAsset } from "@modules/FrictionlessOnChainAsset.sol";
import { FrictionlessOnChainAssetToken } from "@core/FrictionlessOnChainAssetToken.sol";
import { IBasicFrictionlessToken } from "@interface/IBasicFrictionlessToken.sol";
import { IFrictionlessPermissionsManager } from "@interface/IFrictionlessPermissionsManager.sol";
import { IFrictionlessTreasuryManager } from "@interface/IFrictionlessTreasuryManager.sol";
import { IFrictionlessERC20ConverterManager } from "@interface/IFrictionlessERC20ConverterManager.sol";
import { IFrictionlessComplianceFactory } from "@interface/IFrictionlessComplianceFactory.sol";
import { IFrictionlessTokensFactory } from "@interface/IFrictionlessTokensFactory.sol";
import { FrictionlessPermissionsManager } from "@modules/FrictionlessPermissionsManager.sol";
import { FrictionlessTreasuryManager } from "@modules/FrictionlessTreasuryManager.sol";
import { FrictionlessERC20ConverterManager } from "@modules/FrictionlessERC20ConverterManager.sol";
import { FrictionlessComplianceFactory } from "@modules/FrictionlessComplianceFactory.sol";
import { FrictionlessAttestationManager } from "@modules/FrictionlessAttestationManager.sol";
import { FrictionlessTokensFactory } from "@modules/FrictionlessTokensFactory.sol";
import { FrictionlessFXSwap } from "@modules/FrictionlessFXSwap.sol";
import { FundDepositComplianceModule } from "@rules/FundDepositComplianceModule.sol";
import { DigitalSecurityComplianceModule } from "@rules/DigitalSecurityComplianceModule.sol";
import { OnChainAssetComplianceModule } from "@rules/OnChainAssetComplianceModule.sol";
import { FrictionlessModularCompliance } from "@rules/FrictionlessModularCompliance.sol";
import { AgentManager } from "@ERC-3643/roles/permissioning/agent/AgentManager.sol";
import { FrictionlessTransferManager } from "@modules/FrictionlessTransferManager.sol";
/**
* @title DeployUgradeContracts - Deploys upgrades or new smart contracts required to operate the Frictionless protocol
* @author DEFYCA Labs S.à.r.l
*/
//solhint-disable max-states-count
contract DeployUgradeContracts is Script {
using TypeCaster for *;
/// @dev The address of the PROTOCOL_ADMIN
address private immutable _protocolAdmin = vm.envAddress("PROTOCOL_ADMIN");
/// @dev The private_key of the Protocol Admin required for signing.
uint256 private immutable _protocolAdminPK = vm.envUint("PROTOCOL_ADMIN_PK");
/// @dev The address of the previously deployed FrictionlessPermissionsManager
address private immutable permissionsManagerAddr = vm.envAddress("CONTRACT_ADDR_FRICTIONLESS_PERMISSIONS_MANAGER");
/// @dev The address of the previously deployed FrictionlessTreasuryManager
address private immutable treasuryManagerAddr = vm.envAddress("CONTRACT_ADDR_FRICTIONLESS_TREASURY_MANAGER");
/// @dev The address of the Protocol Treasury, the agent permitted to mint OnChain Asset & FCD's
address private immutable _protocolTreasury = vm.envAddress("PROTOCOL_TREASURY");
/// @dev The address of the FX_DESK_FEE_RECIPIENT
address private immutable _fxDeskFeeRecipient = vm.envAddress("PERMISSIONED_FX_DESK_FEE_RECIPIENT");
FrictionlessPermissionsManager public permissionsManager;
FrictionlessTreasuryManager public treasuryManager;
FrictionlessFXSwap public fxSwap;
/// @dev Load the Frictionless contracts for Treasury Management, Permission and Transfers/Settlement/DvD/DvP by address
function _loadFrictionlessContracts() internal {
permissionsManager = FrictionlessPermissionsManager(permissionsManagerAddr);
console.log("Loaded FrictionlessPermissionsManager by address", address(permissionsManager));
if (!permissionsManager.isAgent(_protocolTreasury)) {
permissionsManager.addAgent(_protocolTreasury);
}
treasuryManager = FrictionlessTreasuryManager(treasuryManagerAddr);
console.log("Loaded FrictionlessTreasuryManager by address", address(treasuryManager));
// Add the Treasury as an Agent
if (!treasuryManager.isAgent(_protocolTreasury)) {
treasuryManager.addAgent(_protocolTreasury);
}
}
/// @dev Deploy any new Frictionless contracts in this version.
function _deployNewFrictionlessContracts() internal {
FrictionlessFXSwap _fxSwapImpl = new FrictionlessFXSwap();
address _fxSwapProxyAddr = address(new ERC1967Proxy(address(_fxSwapImpl), ""));
fxSwap = FrictionlessFXSwap(_fxSwapProxyAddr);
fxSwap.init(address(treasuryManager), address(permissionsManager), _fxDeskFeeRecipient);
console.log("FrictionlessFXSwap proxy address", _fxSwapProxyAddr);
// Add the FrictionlessFXSwap as an Agent
if (!treasuryManager.isAgent(address(fxSwap))) {
treasuryManager.addAgent(address(fxSwap));
}
}
/**
* @dev Executes the deployment of upgrades or new Frictionless protocol contracts on the existing protocol deployment.
*/
function run() external {
vm.startBroadcast();
_loadFrictionlessContracts();
// Deploy the Frictionless contracts
_deployNewFrictionlessContracts();
vm.stopBroadcast();
}
}
......@@ -57,7 +57,7 @@ contract RunFXSwap is Script {
uint256 private immutable _protocolTreasuryPK = vm.envUint("PROTOCOL_TREASURY_PK");
/// @dev The address of the previously deployed FrictionlessFXSwap
address private immutable fxSwapAddr = vm.envAddress("CONTRACT_ADDR_FX_SWAP");
address private immutable fxSwapAddr = vm.envAddress("CONTRACT_ADDR_FRICTIONLESS_FX_SWAP");
/// @dev The address of the previously deployed FrictionlessPermissionsManager
address private immutable permissionsManagerAddr = vm.envAddress("CONTRACT_ADDR_FRICTIONLESS_PERMISSIONS_MANAGER");
......@@ -172,15 +172,11 @@ contract RunFXSwap is Script {
}
// Setup the Transfer Manager to exchange Selling and Buying Token, take N basis point either side of the FX Swap
IFrictionlessFXSwap.TokenFeeInfo memory sellingTokenFee = IFrictionlessFXSwap.TokenFeeInfo(
_sellDepositTokenAddr,
IAbstractFeeModule.FeeInfo(1, _fxDeskFeeAddr)
);
IFrictionlessFXSwap.FrictionlessTokenFXFeeInfo memory sellingTokenFee = IFrictionlessFXSwap
.FrictionlessTokenFXFeeInfo(_sellDepositTokenAddr, 0, IAbstractFeeModule.FeeInfo(1, _fxDeskFeeAddr));
// No buying fee as the FX Desk does't pay fees to itself.
IFrictionlessFXSwap.TokenFeeInfo memory buyingTokenFee = IFrictionlessFXSwap.TokenFeeInfo(
_buyDepositTokenAddr,
IAbstractFeeModule.FeeInfo(0, _fxDeskFeeAddr)
);
IFrictionlessFXSwap.FrictionlessTokenFXFeeInfo memory buyingTokenFee = IFrictionlessFXSwap
.FrictionlessTokenFXFeeInfo(_buyDepositTokenAddr, 0, IAbstractFeeModule.FeeInfo(1, _fxDeskFeeAddr));
// Set the token fee, so there is a fee associated with the conversion is each direction
fxSwap.setSwapFees(sellingTokenFee, buyingTokenFee);
......
......@@ -36,8 +36,6 @@ contract FXSwapTestsBase is CommonDeploy, TokenHelper {
uint256 public investor1Amount;
uint256 public investor2Amount;
uint256 public defMaxTokensFeeAmount;
address internal _fxDeskFeeRecipient;
FrictionlessFundDepositToken internal _eurToken;
......@@ -50,8 +48,6 @@ contract FXSwapTestsBase is CommonDeploy, TokenHelper {
vm.startPrank(_protocolAdmin);
defMaxTokensFeeAmount = _getTokensAmount(1_000, 6);
(_fxDeskFeeRecipient, ) = _randomSigner();
initialFundDepositAmount = _getTokensAmount(100_000, 6);
......@@ -79,7 +75,7 @@ contract FXSwapTestsBase is CommonDeploy, TokenHelper {
fxSwap = FrictionlessFXSwap(address(new ERC1967Proxy(address(new FrictionlessFXSwap()), "")));
fxSwap.init(address(treasuryManager), address(permissionsManager), _fxDeskFeeRecipient, defMaxTokensFeeAmount);
fxSwap.init(address(treasuryManager), address(permissionsManager), _fxDeskFeeRecipient);
// Deploy tokens
_eurToken = _deployValidFundDepositToken("EUR", initialFundDepositAmount);
......
......@@ -33,17 +33,12 @@ contract FXSwapTestsOwner is FXSwapTestsBase {
function test_invalid_init() public {
FrictionlessFXSwap newFrictionlessFXSwap = new FrictionlessFXSwap();
newFrictionlessFXSwap.init(
address(treasuryManager),
address(permissionsManager),
_fxDeskFeeRecipient,
defMaxTokensFeeAmount
);
newFrictionlessFXSwap.init(address(treasuryManager), address(permissionsManager), _fxDeskFeeRecipient);
vm.expectRevert(bytes("Initializable: contract is already initialized"));
vm.prank(_protocolAdmin);
newFrictionlessFXSwap.init(address(treasuryManager), address(permissionsManager), _fxDeskFeeRecipient, 0);
newFrictionlessFXSwap.init(address(treasuryManager), address(permissionsManager), _fxDeskFeeRecipient);
}
function test_set_fee_desk_addr() public {
......@@ -70,40 +65,22 @@ contract FXSwapTestsOwner is FXSwapTestsBase {
vm.stopPrank();
}
function test_set_max_tokens_fee_amount() public {
vm.startPrank(_protocolAdmin);
fxSwap.setMaxTokensFeeAmount(defMaxTokensFeeAmount * 2);
assertEq(fxSwap.maxTokensFeeAmount(), defMaxTokensFeeAmount * 2);
vm.stopPrank();
}
function test_invalid_set_max_tokens_fee_amount_not_an_owner() public {
vm.startPrank(_approvedInvestor1);
vm.expectRevert(bytes("Ownable: caller is not the owner"));
fxSwap.setMaxTokensFeeAmount(0);
assertEq(fxSwap.maxTokensFeeAmount(), defMaxTokensFeeAmount);
vm.stopPrank();
}
function test_set_swap_fees() public {
uint256 eurFeeInBps = 100;
uint256 usdFeeInBps = 200;
IFrictionlessFXSwap.TokenFeeInfo memory usdTokenInfo = IFrictionlessFXSwap.TokenFeeInfo(
address(_usdToken),
IAbstractFeeModule.FeeInfo(usdFeeInBps, _fxDeskFeeRecipient)
);
IFrictionlessFXSwap.TokenFeeInfo memory eurTokenInfo = IFrictionlessFXSwap.TokenFeeInfo(
address(_eurToken),
IAbstractFeeModule.FeeInfo(eurFeeInBps, _fxDeskFeeRecipient)
);
IFrictionlessFXSwap.FrictionlessTokenFXFeeInfo memory usdTokenInfo = IFrictionlessFXSwap
.FrictionlessTokenFXFeeInfo(
address(_usdToken),
0,
IAbstractFeeModule.FeeInfo(usdFeeInBps, _fxDeskFeeRecipient)
);
IFrictionlessFXSwap.FrictionlessTokenFXFeeInfo memory eurTokenInfo = IFrictionlessFXSwap
.FrictionlessTokenFXFeeInfo(
address(_eurToken),
0,
IAbstractFeeModule.FeeInfo(eurFeeInBps, _fxDeskFeeRecipient)
);
(bytes32 usdTokenFeeKey, bytes32 eurTokenFeeKey) = fxSwap.getSwapFeeKeys(
address(_usdToken),
......@@ -137,10 +114,12 @@ contract FXSwapTestsOwner is FXSwapTestsBase {
function test_invalid_set_swap_fee() public {
uint256 usdFeeInBps = 200;
IFrictionlessFXSwap.TokenFeeInfo memory usdTokenInfo = IFrictionlessFXSwap.TokenFeeInfo(
address(_usdToken),
IAbstractFeeModule.FeeInfo(usdFeeInBps, _fxDeskFeeRecipient)
);
IFrictionlessFXSwap.FrictionlessTokenFXFeeInfo memory usdTokenInfo = IFrictionlessFXSwap
.FrictionlessTokenFXFeeInfo(
address(_usdToken),
0,
IAbstractFeeModule.FeeInfo(usdFeeInBps, _fxDeskFeeRecipient)
);
vm.expectRevert(
abi.encodeWithSelector(
......@@ -161,14 +140,14 @@ contract FXSwapTestsOwner is FXSwapTestsBase {
uint256 eurFeeInBps = 100;
uint256 usdFeeInBps = 200;
IFrictionlessFXSwap.TokenFeeInfo memory usdTokenInfo = IFrictionlessFXSwap.TokenFeeInfo(
address(_usdToken),
IAbstractFeeModule.FeeInfo(usdFeeInBps, address(0))
);
IFrictionlessFXSwap.TokenFeeInfo memory eurTokenInfo = IFrictionlessFXSwap.TokenFeeInfo(
address(_eurToken),
IAbstractFeeModule.FeeInfo(eurFeeInBps, _fxDeskFeeRecipient)
);
IFrictionlessFXSwap.FrictionlessTokenFXFeeInfo memory usdTokenInfo = IFrictionlessFXSwap
.FrictionlessTokenFXFeeInfo(address(_usdToken), 0, IAbstractFeeModule.FeeInfo(usdFeeInBps, address(0)));
IFrictionlessFXSwap.FrictionlessTokenFXFeeInfo memory eurTokenInfo = IFrictionlessFXSwap
.FrictionlessTokenFXFeeInfo(
address(_eurToken),
0,
IAbstractFeeModule.FeeInfo(eurFeeInBps, _fxDeskFeeRecipient)
);
vm.expectRevert(
abi.encodeWithSelector(IFrictionlessFXSwap.FrictionlessFXSwapInvalidFeeRecipientAddr.selector, address(0))
......
......@@ -28,7 +28,7 @@ import { FrictionlessFXSwap } from "@modules/FrictionlessFXSwap.sol";
import { FXSwapTestsBase } from "./FXSWap.base.t.sol";
contract FXSwapTestsSwap is FXSwapTestsBase {
event TokensSwapped(
event FrictionlessFXTokensSwapped(
address sellingTokenAddr,
address buyingTokenAddr,
address investorAddr,
......@@ -57,7 +57,7 @@ contract FXSwapTestsSwap is FXSwapTestsBase {
vm.expectEmit(true, false, false, true, address(fxSwap));
emit TokensSwapped(
emit FrictionlessFXTokensSwapped(
address(_eurToken),
address(_usdToken),
_approvedInvestor1,
......@@ -89,14 +89,10 @@ contract FXSwapTestsSwap is FXSwapTestsBase {
function test_swap_tokens_with_fees() public {
_transferToInvestors();
IFrictionlessFXSwap.TokenFeeInfo memory sellingTokenFee = IFrictionlessFXSwap.TokenFeeInfo(
address(_eurToken),
IAbstractFeeModule.FeeInfo(100, _fxDeskFeeRecipient)
);
IFrictionlessFXSwap.TokenFeeInfo memory buyingTokenFee = IFrictionlessFXSwap.TokenFeeInfo(
address(_usdToken),
IAbstractFeeModule.FeeInfo(200, _fxDeskFeeRecipient)
);
IFrictionlessFXSwap.FrictionlessTokenFXFeeInfo memory sellingTokenFee = IFrictionlessFXSwap
.FrictionlessTokenFXFeeInfo(address(_eurToken), 0, IAbstractFeeModule.FeeInfo(100, _fxDeskFeeRecipient));
IFrictionlessFXSwap.FrictionlessTokenFXFeeInfo memory buyingTokenFee = IFrictionlessFXSwap
.FrictionlessTokenFXFeeInfo(address(_usdToken), 0, IAbstractFeeModule.FeeInfo(200, _fxDeskFeeRecipient));
vm.prank(_protocolAdmin);
fxSwap.setSwapFees(sellingTokenFee, buyingTokenFee);
......@@ -112,7 +108,7 @@ contract FXSwapTestsSwap is FXSwapTestsBase {
vm.expectEmit(true, false, false, true, address(fxSwap));
emit TokensSwapped(
emit FrictionlessFXTokensSwapped(
address(_eurToken),
address(_usdToken),
_approvedInvestor1,
......@@ -146,14 +142,20 @@ contract FXSwapTestsSwap is FXSwapTestsBase {
function test_swap_tokens_with_max_fee_tokens_amount() public {
_transferToInvestors();
IFrictionlessFXSwap.TokenFeeInfo memory sellingTokenFee = IFrictionlessFXSwap.TokenFeeInfo(
address(_eurToken),
IAbstractFeeModule.FeeInfo(5000, _fxDeskFeeRecipient)
);
IFrictionlessFXSwap.TokenFeeInfo memory buyingTokenFee = IFrictionlessFXSwap.TokenFeeInfo(
address(_usdToken),
IAbstractFeeModule.FeeInfo(200, _fxDeskFeeRecipient)
);
uint256 defMaxTokensFeeAmount = 1000;
IFrictionlessFXSwap.FrictionlessTokenFXFeeInfo memory sellingTokenFee = IFrictionlessFXSwap
.FrictionlessTokenFXFeeInfo(
address(_eurToken),
defMaxTokensFeeAmount,
IAbstractFeeModule.FeeInfo(5000, _fxDeskFeeRecipient)
);
IFrictionlessFXSwap.FrictionlessTokenFXFeeInfo memory buyingTokenFee = IFrictionlessFXSwap
.FrictionlessTokenFXFeeInfo(
address(_usdToken),
defMaxTokensFeeAmount,
IAbstractFeeModule.FeeInfo(200, _fxDeskFeeRecipient)
);
vm.prank(_protocolAdmin);
fxSwap.setSwapFees(sellingTokenFee, buyingTokenFee);
......@@ -185,14 +187,10 @@ contract FXSwapTestsSwap is FXSwapTestsBase {
function test_invalid_swap_tokens_invalid_fee_recipient() public {
_transferToInvestors();
IFrictionlessFXSwap.TokenFeeInfo memory sellingTokenFee = IFrictionlessFXSwap.TokenFeeInfo(
address(_eurToken),
IAbstractFeeModule.FeeInfo(100, _fxDeskFeeRecipient)
);
IFrictionlessFXSwap.TokenFeeInfo memory buyingTokenFee = IFrictionlessFXSwap.TokenFeeInfo(
address(_usdToken),
IAbstractFeeModule.FeeInfo(200, _fxDeskFeeRecipient)
);
IFrictionlessFXSwap.FrictionlessTokenFXFeeInfo memory sellingTokenFee = IFrictionlessFXSwap
.FrictionlessTokenFXFeeInfo(address(_eurToken), 0, IAbstractFeeModule.FeeInfo(100, _fxDeskFeeRecipient));
IFrictionlessFXSwap.FrictionlessTokenFXFeeInfo memory buyingTokenFee = IFrictionlessFXSwap
.FrictionlessTokenFXFeeInfo(address(_usdToken), 0, IAbstractFeeModule.FeeInfo(200, _fxDeskFeeRecipient));
vm.startPrank(_protocolAdmin);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment