Only this pageAll pages
Powered by GitBook
1 of 39

Frictionless Protocol

Loading...

Protocol Overview

Loading...

Loading...

Loading...

SMART CONTRACTS

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

API

Loading...

Loading...

Loading...

Loading...

Welcome to Frictionless Protocol

The Frictionless protocol is an institutional-grade venue built on EVM-compatible smart contracts for the issuance, distribution and settlement of digital securities in the private markets. The process involves dematerializing credit & infrastructure funds, ETFs or AMCs into risk-profiled future cash flow tokens, in the form of ERC-3643 digital securities which are aligned with the distribution schedule of the Manager.

Via strategies, Investors can invest in a diversified cross-section of funds using instant atomic settlement in attested 1:1 backed FIAT deposit tokens, which are banked with a in Luxembourg.

This tokenization lego-brick approach ensures digital securities can be instantly composed into secondary trades, semi-liquid & automatic structured products and distributed between Investors in a privacy-protected mode for a few cents. All tokens within the protocol are permissioned tokens built under to ensure that there is instant delivery versus payment, whilst ensuring the privacy of the Investor is protected. The Frictionless Markets APIs interact with these smart contracts to orchestrate the mint, transfer and burn of the various tokens in the protocol.

Join the community on Discord !

G-SIB
ERC-3643 specification for permissioned tokens
here

Audit & Security

10/10 - Security Score

10/10 - Code Quality Score

100% - Security Score

10/10 - Documentation Quality Score

Overview

Features

Smart Contract Architecture

The Frictionless protocol is essentially a decentralised system of privacy-protecting proofs and permissioned tokens that can only be transferred under tight controls in accordance with the regulatory rules of the underlying funds and securities which are tokenized.

  1. Identity Management - based on OnChainId all participants in the Frictionless protocol are permissioned with specific roles, defining the actions and token classes they can interact with.

  2. Compliance - based on the ERC-3643 specification, upgradable modules for compliance enable the compliant transfer of token classes in the protocol.

  3. Frictionless Tokens - based on the ERC-3643 specification, these are the tokens circulated in the protocol to represent securities, assets, cash contributions, cash distributions and settlements.

  4. Treasury Management - provides the smart contract functions to mint, transfer and burn token classes in the protocol.

  5. Proof-of-Reserve - provides independent attestations over the currencies underpinning FrictionlessFundDepositTokens.

  6. Transfer Agency - provides the controlled transfer of tokens between participants under strict compliance. This also includes the facility to swap tokens, such as stablecoins with FrictionlessFundDepositTokens or FX swaps of FrictionlessFundDepositTokens of various denominations.

The smart contracts powering the Frictionless protocol have undergone a meticulous audit by , a renowned name in blockchain audit and security.

The Frictionless Protocol smart contracts have achieved a perfect attesting to the robustness and security of our blockchain infrastructure. This accomplishment reflects our unwavering commitment to ensuring the safety and trustworthiness of our platform.

The comprehensive audit report conducted by Hacken.io is now available for review at We encourage anyone interacting with the Frictionless protocol to explore the detailed findings, recommendations, and security measures outlined in the report.

Throughout the auditing process, we maintained a transparent and collaborative tracking with the Hacken.io team. This approach allowed us to address potential vulnerabilities promptly and work together to enhance the overall security of our smart contracts.

We are proud to announce that the are released under the MIT license. This open-source licensing model reflects our dedication to transparency, collaboration, and community involvement. The MIT license allows developers and stakeholders to freely use, modify, and distribute our smart contracts while providing clear guidelines on attribution and liability.

The Frictionless smart contracts are an suite of available under the permissive which enable compliant digital securities transfer, payment and settlement on EVM-compatible blockchains, such as Avalance C-Chain, Ethereum or Polygon.

The Frictionless smart contracts extend the T-REX specification with specific features to operate private placements under MiFID II regulation.

The Frictionless protocol extends the specification with specific features to operate private placements under MiFID II regulation. The are six main pillars of the Frictionless protocol as illustrated in the diagram below.

The cover these topics in depth with visual explanations of how each contract functions along with its NATSPEC documentation.

Hacken.io
10/10 rating,
Frictionless Protocol Audit Results.
process
Frictionless Protocol smart contracts
audited
smart contracts
MIT license
ERC-3643
ERC-3643
Smart Contract Docs

Participants

The Frictionless protocol is a market infrastructure for the issuance, trade, and settlement of digital securities in the private markets. The protocol caters for various roles and responsibilities both within the smart contracts and the API systems, enabling the various market functions to be performed according to the regulatory posture of Frictionless Markets S.à r.l, the legal issuer of digital securities in Luxembourg under MiFID II and the broader E.U.

Frictionless Markets S.à r.l and its securitization fund (FRICTIONLESS MARKETS SECURITIES FT) is the legal issuer of digital securities in compliance with MiFID II (2014/65/EU) regulation. Frictionless Markets S.à r.l operates the PROTOCOL_ADMIN and PROTOCOL_TREASURY.

Where required and directed by a PERMISSIONED_MANAGER, Frictionless Markets S.à r.l provisions and/or operates a PERMISSIONED_CUSTODIAN on the protocol for the custody of securities or cash in accordance with the securitization laws of Luxembourg.

PROTOCOL_ADMIN

The protocol admin is the owner and deployer of the smart contracts. The Owner role is defined within the OpenZepplin context. The PROTOCOL_ADMIN is not permitted to custody any of the tokens within the protocol.

The ERC-3643 definition of the role is isOwner

PROTOCOL_TREASURY

Represents the treasury in the protocol. The PROTOCOL_TREASURY is an Agent under the definition of the ERC-3643 specification and is responsible for the lifecycle management of all tokens in the protocol. Frictionless Markets is the legal entity which is responsible for the treasury management of the non-co-mingled FIAT deposit & redemptions in multi-currency ledgers at G-SIB providers in Luxembourg under the role PROTOCOL_TREASURY.

The ERC-3643 definition of the role is isAgent

PERMISSIONED_CUSTODIAN

The Permissioned Custodian is the custodian address and OnChain Identity which can custody any of the Frictionless protocol tokens.

The ERC-3643 role is a Custom Compliance role.

PERMISSIONED_INVESTOR

A permissioned Investor in the protocol, is an investor who is compliant with the specification of the FrictionlessOnChainAssetToken and the private placement memorandum of the securitization structure and fund. The Frictionless protocol is open to accredited (professional client) investors only in compliance with (2014/65/EU) regulation, MiFID II. The onboarding of Investors is conducted off-chain, including KYC/AML, Subscription Agreement, etc, which are then added to the claim of the Investors' OnChainId.

The ERC-3643 role is a Custom Compliance role.

PERMISSIONED_MANAGER

A permissioned Manager in the protocol is a Manager or GP utilising both the technology protocol and the fund services of Frictionless Markets to issue their FrictionlessOnChainAssetToken. A PERMISSIONED_MANAGER may also interact with the FundDepositToken to accept & settle payments for Digital Securities.

The ERC-3643 role is a Custom Compliance role.

PERMISSIONED_FUND_ACCOUNTANT

A permissioned Fund Accountant in the protocol is an independent Fund Accountant with access to the underlying IBAN accounts for a FrictionlessFundDepositToken, so they can provide certified attestations for the balance of the accounts at regular intervals. A PERMISSIONED_FUND_ACCOUNTANT interacts with the IFrictionlessAttestationManager to provide this market feature.

The ERC-3643 role is a Custom Compliance role.

PERMISSIONED_CALCULATING_AGENT

A permissioned Calculating Agent in the protocol is an Agent who is permitted to calculate the market value of a FrictionlessOnChainAssetToken with the consent of the PERMISSIONED_MANAGER, so the cash waterfalls may be calculated for the Investors.

The role is not fully supported in the protocol yet.

The ERC-3643 role is a Custom Compliance role.

PERMISSIONED_TRANSFER_AGENT

A permissioned Transfer Agent in the protocol is an Agent who has the provision to transfer securities independently of the PROTOCOL_TREASURY.

The role is not fully supported in the protocol yet.

The ERC-3643 role is a Custom Compliance role.

Smart Contract Docs

For more information on the legal structure of the FRICTIONLESS MARKETS SECURITIES FT, consult our

The Frictionless protocol smart contracts are documented using the standard.

The Frictionless Tokens describe the tokens which are emitted by the Frictionless protocol to represent Asset, Securities and Deposits. These tokens are based on thespecification of IToken.

These contracts define the compliance layer for permissioned network participants (KYC/AML, Sanctions, PEP screening), the offering rules and the transfer rules for tokens, which ensures transfers are conducted in line with the legal and regulatory guardrails of MiFID II.

The Frictionless protocol is designed to automate cash operations across the lifecycle of a fund, part of this automation is the collection of contracted fee structures within a fund, such as management and/or performance fees. The smart contracts for transfer, ERC20 swap and FX swaps may be programmed to automatically collect fees for Managers, opening new revenue streams for Managers whilst ensuring the visibility of fees for Investors and Managers alike.

The Manager Contracts are the main entry points to the Frictionless protocol, they perform market functions such as permission management, treasury operations, issuance, transfer and settlement of securities, and attestations of deposits (proof-of-reserve) for the underlying of FrictionlessFundDepositTokens.

Frictionless FX Swaps enable Investors to invest instantly, securely and risk-free at super low cost in multiple currencies.

The FX Swap contracts in the Frictionless protocol provide an instant/atomic swap of a currency pair at a quoted spot of forward rate.

ERC20 Swaps were designed by the developers in the Frictionless protocol to risk off permissionless stablecoins such as USDC or USDT.

Permissionless are a great innovation from the crypto markets which were designed for permissionless crypto referencing to US Dollars, however handling stablecoins for traditional institutional partners is still a risky proposition.

Using the ERC20 Converter contracts, FrictionlessFundDepositTokens can be converted to/from stablecoins using the Frictionless protocol to help Managers accept stablecoins whilst off-loading their associated risks, such as de-peg events, underlying community bank reliance and liquidity risks.

legal & fund documentation
NATSPEC
Frictionless Tokens
ERC-3643
Compliance
Automated Fee Collection
Manager Contracts
Frictionless FX Swaps
ERC20 Swaps

Frictionless Tokens

The following diagram describes the high-level interaction and composition of a Frictionless token.

Protocol Roadmap

The Frictionless protocol is an upgradable and extensible market infrastructure. The protocol is developed by the IP company DEFYCA Labs S.à.r.l, which develops the smart contract suite under the permissive MIT license.

The roadmap for the Frictionless protocol smart contracts includes:

  1. Fundamental Analysis - Using the PERMISSIONED_CALCULATING_AGENT role to provide fundamental analysis on underlying portfolios via smart contracts in privacy-protecting mode.

  2. Qualified Transfer Agents - Opening access to 3rd party transfer agents to execute the transfer and settlement of securities issued on the Frictionless protocol in accordance with local regulatory posture.

  3. Portfolio Re-Balancers - A suite of smart contracts which enable PERMISSIONED_INVESTORS to automatically re-balance their portfolio of investments according to their specific investment goals.

IFrictionlessTokensFactory

Author: DEFYCA Labs S.à.r.l

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.

Interface defining the token factory for all tokens in the Frictionless protocol.

Functions

setTreasuryManager

Sets the Treasury Manager to be the specified address.

Parameters

deployFundDepositToken

Deploys the FrictionlessFundDepositToken contract as a proxy

Parameters

Returns

deployDigitalSecurityToken

Deploys the FrictionlessDigitalSecurityToken contract as a proxy

Parameters

Returns

deployOnChainAssetToken

Deploys the FrictionlessOnChainAssetToken contract as a proxy

Parameters

Returns

treasuryManager

returns the address of the treasuryManager

Returns

existingFrictionlessTokens

Checks whether a given token address is an existing frictionless token

Parameters

Returns

Events

FrictionlessTokenDeployed

Event emitted upon successful deployment of a compliance contract.

Errors

FrictionlessTokensFactoryZeroAddress

error thrown if an attempt to set a zero address contract during function setTreasuryManager

FrictionlessTokensFactoryNotATreasuryManager

error thrown if the msg.sender is not the treasury manager during the functions deployFundDepositToken, deployDigitalSecurityToken, or deployOnChainAssetToken

Structs

BaseTokenInitParams

Struct to represent the base contract data to deploy a Frictionless token contract.

The Frictionless Tokens describe the tokens which are emitted by the Frictionless protocol to represent Asset, Securities and Deposits. These tokens are based on thespecification of IToken.

To contribute or request features to the protocol, please consult the documentation for the smart contract suite.

The broader roadmap includes features which are commercially developed by Frictionless Markets S.à.r.l, which can be requested via the site.

Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
ERC-3643
CONTRIBUTING
https://www.frictionless.markets
function setTreasuryManager(address newTreasuryManager_) external;

newTreasuryManager_

address

the addresses of the treasury manager to set throws FrictionlessTokensFactoryZeroAddress if the newTreasuryManager_ is a zero address

function deployFundDepositToken(
    address tokenOwner_,
    BaseTokenInitParams calldata baseTokenInitParams_,
    IFrictionlessFundDepositToken.FFDImmutableData calldata initData_
) external returns (address tokenProxyAddr_);

tokenOwner_

address

The owner of the deployed contract

baseTokenInitParams_

BaseTokenInitParams

the base contract data to deploy a Frictionless token contract

initData_

IFrictionlessFundDepositToken.FFDImmutableData

the immutable data for the FrictionlessFundDepositToken

tokenProxyAddr_

address

the address of the deployed token contract FrictionlessFundDepositToken throws FrictionlessTokensFactoryNotATreasuryManager if the msg.sender is not the treasury manager emits FrictionlessTokenDeployed event upon successful deployment of the token contract.

function deployDigitalSecurityToken(
    address tokenOwner_,
    BaseTokenInitParams calldata baseTokenInitParams_,
    IFrictionlessDigitalSecurityToken.FDSImmutableData calldata initData_,
    IFrictionlessDigitalSecurityToken.FDSMutableData calldata updateData_
) external returns (address tokenProxyAddr_);

tokenOwner_

address

The owner of the deployed contract

baseTokenInitParams_

BaseTokenInitParams

the base contract data to deploy a Frictionless token contract

initData_

IFrictionlessDigitalSecurityToken.FDSImmutableData

the immutable data for the FrictionlessDigitalSecurityToken

updateData_

IFrictionlessDigitalSecurityToken.FDSMutableData

the mutable data for the FrictionlessDigitalSecurityToken

tokenProxyAddr_

address

the address of the deployed token contract FrictionlessDigitalSecurityToken throws FrictionlessTokensFactoryNotATreasuryManager if the msg.sender is not the treasury manager emits FrictionlessTokenDeployed event upon successful deployment of the token contract.

function deployOnChainAssetToken(
    address tokenOwner_,
    BaseTokenInitParams calldata baseTokenInitParams_,
    IFrictionlessOnChainAssetToken.FOCASpecData calldata specData_,
    IFrictionlessOnChainAssetToken.FOCAIssuanceData calldata issuanceData_,
    IFrictionlessOnChainAssetToken.FOCAUpdateData calldata updateData_
) external returns (address tokenProxyAddr_);

tokenOwner_

address

The owner of the deployed contract

baseTokenInitParams_

BaseTokenInitParams

the base contract data to deploy a Frictionless token contract

specData_

IFrictionlessOnChainAssetToken.FOCASpecData

the immutable specification data for the FrictionlessOnChainAssetToken

issuanceData_

IFrictionlessOnChainAssetToken.FOCAIssuanceData

the immutable issuance data for the FrictionlessOnChainAssetToken

updateData_

IFrictionlessOnChainAssetToken.FOCAUpdateData

the mutable update data for the FrictionlessOnChainAssetToken

tokenProxyAddr_

address

the address of the deployed token contract FrictionlessOnChainAssetToken throws FrictionlessTokensFactoryNotATreasuryManager if the msg.sender is not the treasury manager emits FrictionlessTokenDeployed event upon successful deployment of the token contract.

function treasuryManager() external view returns (address);

<none>

address

the address of the treasuryManager

function existingFrictionlessTokens(address tokenAddr_) external view returns (bool);

tokenAddr_

address

the address of the token to check

<none>

bool

A boolean indicating whether the token is an existing frictionless token

event FrictionlessTokenDeployed(
    IBasicFrictionlessToken.FrictionlessTokenTypes indexed tokenType, address newTokenContract
);
error FrictionlessTokensFactoryZeroAddress();
error FrictionlessTokensFactoryNotATreasuryManager(address);
struct BaseTokenInitParams {
    address implementationAuthority;
    address identityRegistry;
    address compliance;
    address onChainId;
    string tokenName;
    string tokenSymbol;
}
Git Source

How it works

The Frictionless protocol is the technology enabler which translates real-world investments into legal, compliant and transferrable tokenized securities through a Luxembourg structure, operated by Frictionless Markets S.à r.l and its securitization structures.

Frictionless Markets S.à.r.l and its securitization fund (FRICTIONLESS MARKETS SECURITIES FT) is the legal issuer of digital securities in compliance with MiFID II (2014/65/EU) regulation.

There are many tokenization offerings in the market place and the industry is witnessing new entrants each with its respective niche and focus. The Frictionless protocol focus is specifically on the private markets and specifically on providing the legally compliant market infrastructure to enable Managers and GPs to tokenize their funds and offerings, whilst offering Investors a frictionless, low minimum, and transparent access point to the private markets on a global basis.

Core Layers

As a market infrastructure, the Frictionless protocol provides the three core layers to enable Investors to invest in the best private markets offerings on a global basis. These sections cover the basics of securitization, tokenization and distribution.

1. Securitization

The Frictionless Markets team supports a wide variety of securitizations in Luxembourg. The securitizations can be "true sale" or "synthetic" securitizations and are issued from bankruptcy remote and orphan entity-protected structures.

A securitization transaction involves establishing a securitization entity in Luxembourg to assume the risk associated with future cash flows tied to receivables, assets, or activities conducted by third parties known as the Underlying Assets. Simultaneously, the entity issues securities, typically in the form of notes, whose yield and value are connected to the performance of the Underlying Assets. These securities are then offered to professional investors on the financial markets in a tokenized format using the Frictionless protocol.

The Frictionless Markets team establishes and operates the securitization structures, providing the fund administration, fund structuring, cash operations and fund reporting services under Luxembourg securitization law.

2. Tokenization

The Frictionless protocol includes:

  1. A suite of smart contracts to represent:

    1. Funds/Notes - Frictionless OnChain Assets: The FrictionlessOnChainAssetToken represents a listed fund with the informational and legal rights to the underlying. This includes all the informational rights on the underlying and its associated maturity. A FrictionlessOnChainAssetToken is issued as a digital twin for each specific note in a compartment within the Frictionless Markets fund structure.

  2. APIs and a Tokenization Engine to orchestrate and automate complex Manager workflows such as:

    1. Subscriptions

    2. Capital Calls

    3. Cash Distributions

    4. Portfolio Compositions

  3. Wallet Infrastructure enabling the custody of tokenized funds/notes, the collection of fees, custody of ERC20 stablecoins for the PROTOCOL_TREASURY and the wallet infrastructure required to sign and execute transactions on the blockchain.

The Frictionless Markets team operates the protocol, granting access to Managers to tokenize their funds and automate their fund administration services from the Frictionless Markets Manager Interface, API or smart contracts.

3. Distribution

Managers can onboard Investors directly or link into permissioned distribution agents on the Frictionless protocol to distribute their tokenized securities on a global basis., these include:

  1. Private Placement Agents

  2. Global Wealth Advisors

  3. Private Banks

  4. Digital Security Exchanges

Investors invest via subscriptions or subscription contracts to the tokenized fund/note in accordance with MiFID II regulation.

The investment and settlement of tokenized securities are carried out using Frictionless Deposit Tokens, which is a non-invasive and seamless conversion between FIAT contributions or settlement and their tokenized representation.

The Frictionless Markets team operates the protocol, granting access to Distribution Agents and their Investor base to a wide variety of tokenized funds from the world's best GPs and Managers.

Distribution Agents can manage:

  • Subscriptions to Funds for their Investor base.

  • Capital Calls and reporting for their Investor base.

  • Cash Distributions and reporting for their Investor base.

  • Portfolio Compositions for their Investor base.

Supported Securitizations

Securitization encompasses a wide range of asset types, including:

  1. Receivables such as loans

  2. Liquid assets like bonds or securities

  3. Illiquid assets including private equity and real estate

  4. Derivative instruments

  5. Intellectual property generating royalty streams

  6. Cash flow associated with risk or contractual agreements

  7. Shares in other entities, PE, Credit, Infrastructure funds, or deals

Frictionless Markets supports the issuance of Notes, Tracker Certificates, and Actively Managed Certificates in multiple currencies. In general, the Frictionless Markets team and the Frictionless protocol support the following securitization & tokenization use cases:

Lifecycle of a Transaction

The act of correctly securitizing an undertaking, legally and in compliance with the laws of Luxembourg, and thereafter tokenizing into legally compliant tokenized (digital) securities for distribution to permissioned Investors is a complex end-to-end transaction. This section covers the high-level details of the lifecycle of a transaction which holds true for any type of tokenized offering undertaken by Frictionless Markets.

  1. Establishment of the correct Luxembourg securitization structure.

    1. The Frictionless Markets team will create the PPM (private placement memorandum) and the Final Terms for the securitization undertaking.

    2. The Frictionless Markets team creates the compartment, bank accounts of the compartment and the permissioning/provisioning of the necessary wallet infrastructure to execute the tokenization.

    3. All relevant statutory reporting and regulatory obligations for the structure are handled by the Frictionless Markets team, including AML6, SARs, CRS, FATCA, FATF, ManCo Reporting, etc.

  2. Tokenization of the undertakings.

    1. The Manager is permissioned on the Frictionless protocol.

    2. Managers can onboard Investors via subscriptions or subscription contracts to the tokenized fund/note in accordance with MiFID II regulation.

    3. The Manager can issue notes, and capital calls*, and run cash distributions** from the Frictionless Markets UI, via integration with the Frictionless Markets API or directly via the smart contracts.

  3. Distribution of the tokenized securities.

    1. Managers can onboard Investors directly or link into permissioned distribution agents on the Frictionless protocol to distribute their tokenized securities on a global basis.

    2. Capital Calls* automatically execute upon Investors' subscriptions to a fund/funds, converting FIAT contributions to Frictionless Deposit Tokens and releasing Frictionless Digital Securities to record the transaction on-chain.

    3. Cash Distributions ** automatically distribute income and return of the underlying to the Investors, settling the Frictionless Digital Securities with Frictionless Deposit Tokens, thereafter handling the FIAT settlement in the securitization transaction.

For more information on the legal structure of the FRICTIONLESS MARKETS SECURITIES FT, consult our

Cash - Frictionless Deposit Tokens: A represents a permissioned Investors FIAT contribution to a specific fund IBAN in a denominated FIAT currency. The FrictionlessFundDepositToken is used as a means of payment and settlement record. The FrictionlessFundDepositToken can only be transferred between permissioned Investors and Managers in the fund as a record of FIAT transfers within the Fund. A daily attestation of the fund IBAN serves to prove the 1:1 backing with FIAT. Market participants holding a FrictionlessFundDepositToken have the legal claim to the FIAT value held in the fund IBAN account under the final terms of the financial instrument issued by the note tracking the FrictionlessFundDepositToken.

Securities - Frictionless Digital Security Tokens: This is the which represents the future cash flow from the FrictionlessOnChainAssetToken and is purchased by the Investor using FrictionlessFundDepositToken's. These digital securities are permissioned and transferable between permissioned Investors in a permissioned market. This token is linked to the FrictionlessOnChainAssetToken and denominated in a FIAT currency at a future date for settlement.

Smart contracts to execute the of Frictionless tokens in primary and secondary transactions

Smart contracts to ERC20 tokens (stablecoins) to/from Frictionless Deposit Tokens, enabling Managers to risk off stablecoin contributions to their respective funds/

Smart contracts to Frictionless Deposit Tokens of different FIAT denominations using spot and forward rates, enabling Investors to invest and settle in multiple currencies.

Smart contracts to manage the of market participants in accordance with regulation.

The distribution layer of the Frictionless protocol enables Investors to onboard into tokenized funds using their , direct KYC/AML subscription or via reliance letter.

For more information on the securitization benefits from Frictionless Markets and an in-depth understanding of our offerings, consult our .

legal & fund documentation
FrictionlessFundDepositToken
permissioned & transferrable digital security
swap
swap
OnChainId
legal & fund documentation
Securitization
Tokenization
Distribution
Frictionless protocol main smart contract pillars
Schematic relationship of Frictionless Tokens

IBasicFrictionlessToken

Inherits: IToken

Author: DEFYCA Labs S.à.r.l

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.

The IBasicFrictionlessToken Represents the base interface for Frictionless protocol tokens, this interface is used to determine a token type.

Functions

setFrictionlessTokenType

Sets the token type according to the specified enumeration

function setFrictionlessTokenType(FrictionlessTokenTypes newTokenType_) external;

Parameters

Name
Type
Description

newTokenType_

FrictionlessTokenTypes

the token type to set

getFrictionlessTokenType

Returns the token type according to the specified enumeration

function getFrictionlessTokenType() external view returns (FrictionlessTokenTypes);

Returns

Name
Type
Description

<none>

FrictionlessTokenTypes

FrictionlessTokenTypes the token type according to the specified enumeration

Errors

BasicFrictionlessTokenUnableToUpdateFrictionlessTokenType

error thrown if an attempt to set an invalid token type during function setFrictionlessTokenType

error BasicFrictionlessTokenUnableToUpdateFrictionlessTokenType();

Enums

FrictionlessTokenTypes

Enumeration to represent each of the tokens in the Frictionless protocol.

enum FrictionlessTokenTypes {
    NONE,
    FUND_DEPOSIT_TOKEN,
    DIGITAL_SECURITY_TOKEN,
    ON_CHAIN_ASSET_TOKEN
}

Git Source

Compliance

These contracts define the compliance layer for permissioned network participants (KYC/AML, Sanctions, PEP screening), the offering rules and the transfer rules for tokens, which ensures transfers are conducted in line with the legal and regulatory guardrails of MiFID II.

The compliance modules are upgradeable and are tied to specific tokens.

IFrictionlessFundDepositToken

Inherits: IBasicFrictionlessToken

Author: DEFYCA Labs S.à.r.l

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.

A Fund Deposit Token represents a permissioned Investors FIAT contribution to a specific fund IBAN in a denominated FIAT currency. The Fund Deposit Token is used as a means of payment and settlement. The Fund Deposit Token can only be transferred between permissioned Investors in the fund. A daily attestation of the fund IBAN serves to prove the 1:1 backing with FIAT. Exclusively under Frictionless Markets S.à.r.l issuance terms Investors holding a FrictionlessFundDepositToken have the legal right to the FIAT value held in the fund IBAN account.

Functions

setInitData

Sets the immutable data for the FrictionlessFundDepositToken

function setInitData(FFDImmutableData calldata initData) external;

Parameters

Name
Type
Description

initData

FFDImmutableData

the immutable data for the FrictionlessFundDepositToken

getCurrency

Get the currency the FIAT denomination of the deposit token.

function getCurrency() external view returns (string memory);

Returns

Name
Type
Description

<none>

string

the currency the FIAT denomination of the deposit token.

getDescription

Get the description the description of the deposit token.

function getDescription() external view returns (string memory);

Returns

Name
Type
Description

<none>

string

the description the description of the deposit token

getFundIBAN

Get the IBAN which Frictionless Markets S.à.r.l holds a matching FIAT currency ledger with a G-SIB for this currency, attestations are provided on this IBAN. This is restricted to onlyAgent roles.

function getFundIBAN() external returns (string memory);

Returns

Name
Type
Description

<none>

string

the IBAN which Frictionless Markets S.à.r.l holds a matching FIAT currency ledger with a G-SIB for this currency, attestations are provided on this IBAN.

Errors

FrictionlessFundDepositTokenUnableToUpdateInitData

error throw if there is an attempt to modify the immutable data.

error FrictionlessFundDepositTokenUnableToUpdateInitData();

Structs

FFDImmutableData

Struct which represents the immutable data in the Token. Once set it cannot be modified.

struct FFDImmutableData {
    string currency;
    string description;
    string fundIBAN;
}

IFrictionlessModularCompliance

Inherits: IModularCompliance

Author: DEFYCA Labs S.à.r.l

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.

The IFrictionlessModularCompliance is responsible for the compliant transfer of the various Tokens in the Frictionless protocol.

Functions

init

Initializes the modular compliance, sets the maximum allowable modules per token and adds the modules provided

Parameters

updateMaxModulesCount

Set the maximum number of allowable modules which can be bound.

Parameters

addModules

Adds modules based on the array of module addresses provided

Parameters

removeModules

Removes modules based on the array of module addresses provided

Parameters

maxModulesCount

Returns the maximum number of allowable modules which can be bound.

Returns

Events

MaxModulesCountUpdated

Emitted during updateMaxModulesCount to inform of new modules max count updates

ModulesAdded

Emitted during addModules to inform of new modules added

ModulesRemoved

Emitted during removeModules to inform of modules removed

Errors

FrictionlessIsZeroAddress

thrown if specific address is zero.

FrictionlessModularComplianceZeroMaxModulesCount

thrown if an attempt to set the maximum number of allowable modules to zero is made in updateMaxModulesCount

FrictionlessModularComplianceModuleIsAlreadyBound

thrown if an attempt to add an already existing module during addModules

FrictionlessModularComplianceModuleDoesNotExist

thrown if module for the given address is not already bound by the modifier onlyExistingModule

FrictionlessModularComplianceMaxModuleCountReached

thrown if an attempt to add more than the allowable modules during addModules

FrictionlessModularComplianceCallerNotATokenOrOwner

thrown during bindToken or unBindToken if the caller is not the owner or the bound token address

FrictionlessModularComplianceCallerNotAToken

thrown if the the msg.sender is not the bound token address during modifier onlyToken

Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Git Source
function init(address[] calldata modules_, uint256 maxModulesCount_) external;

modules_

address[]

the array of module addresses to be added

maxModulesCount_

uint256

maximum number of allowable modules which can be bound. throws FrictionlessModularComplianceMaxModuleCountReached if the maximum amount of modules has been reached as per the maxModulesCount throws FrictionlessModularComplianceModuleIsAlreadyBound if the module is already bound throws FrictionlessIsZeroAddress if the module address is a zero address throws FrictionlessModularComplianceZeroMaxModulesCount if an attempt to set the maximum number of allowable modules to zero is made in updateMaxModulesCount emits ModulesAdded upon sucessful addition emits MaxModulesCountUpdated upon successful update of the maximum modules count.

function updateMaxModulesCount(uint256 newMaxModulesCount_) external;

newMaxModulesCount_

uint256

maximum number of allowable modules which can be bound. throws FrictionlessModularComplianceZeroMaxModulesCount if an attempt to set the maximum number of allowable modules to zero is made in updateMaxModulesCount emits MaxModulesCountUpdated upon successful update of the maximum modules count.

function addModules(address[] calldata modulesToAdd_) external;

modulesToAdd_

address[]

the array of module addresses to be added throws FrictionlessModularComplianceMaxModuleCountReached if the maximum amount of modules has been reached as per the maxModulesCount throws FrictionlessModularComplianceModuleIsAlreadyBound if the module is already bound throws FrictionlessIsZeroAddress if the module address is a zero address emits ModulesAdded upon sucessful addition

function removeModules(address[] calldata modulesToRemove_) external;

modulesToRemove_

address[]

the array of module addresses to be removed throws FrictionlessModularComplianceModuleDoesNotExist if module for the given address is not already bound emits ModulesRemoved upon sucessful removal

function maxModulesCount() external view returns (uint256);

<none>

uint256

maximum number of allowable modules which can be bound.

event MaxModulesCountUpdated(uint256 newMaxModulesCount, uint256 oldMaxModulesCount);
event ModulesAdded(address[] modules);
event ModulesRemoved(address[] modules);
error FrictionlessIsZeroAddress(string);
error FrictionlessModularComplianceZeroMaxModulesCount();
error FrictionlessModularComplianceModuleIsAlreadyBound(address module);
error FrictionlessModularComplianceModuleDoesNotExist(address module);
error FrictionlessModularComplianceMaxModuleCountReached();
error FrictionlessModularComplianceCallerNotATokenOrOwner(address caller);
error FrictionlessModularComplianceCallerNotAToken(address caller);
Git Source

IFrictionlessOnChainAssetToken

Inherits: IBasicFrictionlessToken

Author: DEFYCA Labs S.à.r.l

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.

Implementation of the storage of the underlying OnChain Asset and it's data.

Functions

setSpecificationData

Sets the specData data for the FrictionlessOnChainAssetToken. throws FrictionlessOnChainAssetTokenUnableToUpdateData This data is immutable, an attempt to modify will generate the error FrictionlessOnChainAssetTokenUnableToUpdateData

function setSpecificationData(FOCASpecData calldata specData) external;

Parameters

Name
Type
Description

specData

FOCASpecData

the specData data for the FrictionlessOnChainAssetToken

setIssuanceData

Sets the issuanceData data for the FrictionlessOnChainAssetToken throws FrictionlessOnChainAssetTokenUnableToUpdateData This data is immutable, an attempt to modify will generate the error FrictionlessOnChainAssetTokenUnableToUpdateData

function setIssuanceData(FOCAIssuanceData calldata issuanceData) external;

Parameters

Name
Type
Description

issuanceData

FOCAIssuanceData

the updatable data for the FrictionlessOnChainAssetToken

setUpdateData

Sets the updatable data for the FrictionlessOnChainAssetToken

function setUpdateData(FOCAUpdateData calldata updateData) external;

Parameters

Name
Type
Description

updateData

FOCAUpdateData

the updatable data for the FrictionlessOnChainAssetToken

getSpecificationData

Get the specData data for the FrictionlessOnChainAssetToken.

function getSpecificationData() external view returns (FOCASpecData memory);

Returns

Name
Type
Description

<none>

FOCASpecData

the specData data for the FrictionlessOnChainAssetToken

getIssuanceData

Get the issuanceData data for the FrictionlessOnChainAssetToken.

function getIssuanceData() external view returns (FOCAIssuanceData memory);

Returns

Name
Type
Description

<none>

FOCAIssuanceData

the issuanceData data for the FrictionlessOnChainAssetToken

getUpdateData

Get the updateData data for the FrictionlessOnChainAssetToken.

function getUpdateData() external view returns (FOCAUpdateData memory);

Returns

Name
Type
Description

<none>

FOCAUpdateData

the updateData data for the FrictionlessOnChainAssetToken

getCurrency

Get the currency the FrictionlessOnChainAssetToken is issued in.

function getCurrency() external view returns (string memory);

Returns

Name
Type
Description

<none>

string

the currency the FrictionlessOnChainAssetToken is issued in.

Errors

FrictionlessOnChainAssetTokenUnableToUpdateData

error throw if there is an attempt to modify the immutable data.

error FrictionlessOnChainAssetTokenUnableToUpdateData();

Structs

FOCASpecData

The specification data for the FrictionlessOnChainAssetToken, this is an immutable data struct.

struct FOCASpecData {
    uint256 issuedOn;
    uint256 maturityDays;
    FrictionlessOnChainAssetSchedule schedule;
    FrictionlessOnChainAssetPaymentFrequency paymentFrequency;
    FrictionlessOnChainAssetYieldType yieldType;
    string baseCurrency;
    uint256 stripTotal;
    string name;
    string symbol;
}

FOCAIssuanceData

The issuance data for the FrictionlessOnChainAssetToken, this is an immutable data struct.

struct FOCAIssuanceData {
    uint256 auctionedOn;
    FrictionlessOnChainAssetPriceStatus priceQuoteStatus;
    string onChainAssetUUID;
    string issuerUUID;
    string isin;
    string issuanceDocs;
    string assetClass;
}

FOCAUpdateData

The uopdatable data for the FrictionlessOnChainAssetToken.

struct FOCAUpdateData {
    uint256 maturesOn;
    uint256 total;
    FrictionlessOnChainAssetStatus status;
    uint256 yield;
    FrictionlessOnChainAssetRiskGrade riskGrade;
    uint256 pullToParValue;
    address custodianAddress;
}

Enums

FrictionlessOnChainAssetSchedule

Enum for the schedule of the payments by the Manager, either pro_rat or coupon/bullet style.

enum FrictionlessOnChainAssetSchedule {
    SCHEDULE_COUPON_ONLY,
    SCHEDULE_PRO_RATA
}

FrictionlessOnChainAssetPaymentFrequency

Enum for the periodicity of payments by the Manager

enum FrictionlessOnChainAssetPaymentFrequency {
    PAYMENT_FREQUENCY_DAILY,
    PAYMENT_FREQUENCY_WEEKLY,
    PAYMENT_FREQUENCY_MONTHLY,
    PAYMENT_FREQUENCY_QUARTERLY,
    PAYMENT_FREQUENCY_SEMI_ANNUALLY,
    PAYMENT_FREQUENCY_ANNUALLY,
    PAYMENT_FREQUENCY_SINGLE
}

FrictionlessOnChainAssetYieldType

Enum for the yield for this FrictionlessOnChainAssetToken is a fixed/floating rate

enum FrictionlessOnChainAssetYieldType {
    YIELD_FIXED,
    YIELD_FLOATING
}

FrictionlessOnChainAssetPriceStatus

Enum for the price quote status obtained at auction

enum FrictionlessOnChainAssetPriceStatus {
    PRICE_QUOTE_STATUS_UNDER_SUBSCRIBED,
    PRICE_QUOTE_STATUS_PRICED_AT_PAR,
    PRICE_QUOTE_STATUS_PRICED_AT_DISCOUNT,
    PRICE_QUOTE_STATUS_PRICED_AT_PREMIUM
}

FrictionlessOnChainAssetStatus

Enum for the current status of the FrictionlessOnChainAssetToken. Updated over time by the Treasury

enum FrictionlessOnChainAssetStatus {
    STATUS_MINTED,
    STATUS_PURCHASED,
    STATUS_MATURED,
    STATUS_IMPAIRED,
    STATUS_REDEEMED
}

FrictionlessOnChainAssetRiskGrade

Enum for the current S&P style riskGrade of the FrictionlessOnChainAssetToken. Updated over time by the Manager/Treasury/Risk Oracle.

enum FrictionlessOnChainAssetRiskGrade {
    BER_AAA,
    BER_AA,
    BER_A,
    BER_BBB,
    BER_BB,
    BER_B,
    BER_CCC,
    BER_CC,
    BER_C,
    BER_D,
    BER_UNRATED
}

IFrictionlessDigitalSecurityToken

Inherits: IBasicFrictionlessToken

Author: DEFYCA Labs S.à.r.l

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.

This is the permissioned & transferable digital security which represents the future cash flow from the FrictionlessOnChainAssetToken and is purchased by the Investor using FrictionlessFundDepositTokens. These digital securities are permissioned and transferable between permissioned Investors in a permissioned secondary market. This token is linked to the FrictionlessOnChainAssetToken and denominated in a FIAT currency at a future date for settlement.

Functions

setInitData

Sets the immutable data for the FrictionlessDigitalSecurityToken

function setInitData(FDSImmutableData calldata initData) external;

Parameters

Name
Type
Description

initData

FDSImmutableData

the immutable data for the FrictionlessDigitalSecurityToken

setUpdateData

Sets the updatable data for the FrictionlessDigitalSecurityToken

function setUpdateData(FDSMutableData calldata mutableData) external;

Parameters

Name
Type
Description

mutableData

FDSMutableData

the updatable data for the FrictionlessDigitalSecurityToken

getCurrency

Get the baseCurrency is the FIAT denomination of the digital security, this is the currency the FrictionlessOnChainAssetToken is issued in.

function getCurrency() external view returns (string memory);

Returns

Name
Type
Description

<none>

string

the baseCurrency is the FIAT denomination of the digital security, this is the currency the FrictionlessOnChainAssetToken is issued in.

getTokenType

Get the type of the token as defined in the enum FrictionlessDigitalSecurityTokenType.

function getTokenType() external view returns (FrictionlessDigitalSecurityTokenType);

Returns

Name
Type
Description

<none>

FrictionlessDigitalSecurityTokenType

the type of the token as defined in the enum.

getOnChainAssetAddress

Get the onChainAssetAddress the address of the FrictionlessOnChainAssetToken for which this token is a future cash distribution.

function getOnChainAssetAddress() external view returns (address);

Returns

Name
Type
Description

<none>

address

onChainAssetAddress the address of the FrictionlessOnChainAssetToken for which this token is a future cash distribution.

getMaturesOn

Get the maturity date of the digital security.

function getMaturesOn() external view returns (uint256);

Returns

Name
Type
Description

<none>

uint256

the maturity date of the digital security.

Errors

FrictionlessDigitalSecurityTokenInitDataHasAlreadyBeenSet

error throw if there is an attempt to modify the immutable data.

error FrictionlessDigitalSecurityTokenInitDataHasAlreadyBeenSet();

Structs

FDSImmutableData

Struct which represents the immutable data in the Token. Once set it cannot be modified.

struct FDSImmutableData {
    string baseCurrency;
    FrictionlessDigitalSecurityTokenType tokenType;
    address onChainAssetAddress;
}

FDSMutableData

Struct which represents the updatable data in the Token. This data can be modified by the Agent only.

struct FDSMutableData {
    uint256 maturesOn;
}

Enums

FrictionlessDigitalSecurityTokenType

enum FrictionlessDigitalSecurityTokenType {
    COUPON,
    STRIP
}

Manager Contracts

The Manager Contracts are the main entry points to the Frictionless protocol, they perform market functions such as permission management, treasury operations, issuance, transfer and settlement of securities, and attestations of deposits (proof-of-reserve) for the underlying of FrictionlessFundDepositTokens.

There are four main manager contracts in the Frictionless protocol, as described below.

The FrictionlessPermissionsManager defines a set of functions and events related to managing participants' permissions in the Frictionless protocol.

The interface includes an enumeration FrictionlessPermissionedUser that enumerates different participants in the Frictionless protocol, such as PROTOCOL_TREASURY, PERMISSIONED_CUSTODIAN, etc.

Only valid agents can register, add or remove users and their associated claims.

The FrictionlessTransferManager manages the transfer of tokens within the Frictionless protocol. It is also responsible for the collection of fees associated with the exchange of tokens. These fees are mapped to specific fee schedules set by managers on their respective issuances.

The Frictionless protocol enables GPs and Managers to collect fees on the primary issuance and secondary trades of digital securities.

The Frictionless protocol enables Investors to bilaterally trade digital securities via the FrictionlessTransferManager smart contract whilst enabling Managers to optionally collect fees on the transaction.

The Frictionless protocol enables Managers and GPs to control cash distributions, waterfalls, and capital calls without the direct action of Investors, enabling sophisticated automation via the Frictionless Markets APIs and Manager automation interface.

onlyTreasury Mode

exchangeTokens , this function will execute the exchange of tokens between two counterparties, but it is executed by the PROTOCOL_TREASURY as the transfer agent optionally collecting fees. For example, payment in FrictionlessFundDepositToken by an Investor for FricitonlessDigitalSecurityToken held by a custodian (Primary trade) or FricitonlessDigitalSecurityToken held by another Investor (secondary trade).

The exchange flow is as follows:

  1. The PROTOCOL_ADMIN optionally sets the transfer fees for the token inbound and outbound.

  2. The PROTOCOL_TREASURY invokes the exchangeTokens function, indicating the polarity of the transaction, such as cash for cash, cash for security, security for cash, or security for security. There are many options, but they all result in the same outcome, the compliant transfer of a Frictionless token for another Frictionless token in a single atomic transaction on-chain.

  3. The transfer is enacted using the ERC-3643-compliant token transfer IToken.forcedTransfer.

onlyCounterpart Mode

createTransferOffer confirmTransferOffer, cancelTransferOffer these functions will execute the exchange tokens in a bilateral P2P mode between two counterparties in a maker-taker mode. This mode also optionally enables the protocol to collect fees.

The exchange flow is as follows:

  1. The PROTOCOL_ADMIN optionally sets the transfer fees for the token inbound and outbound.

  2. Investor X invokes the createTransferOffer function, indicating the offer, such as cash for cash, cash for security, security for cash, or security for security. There are many options, but they all result in the same outcome, the compliant transfer of a Frictionless token for another Frictionless token in a single atomic transaction on-chain.

  3. Investor Y can accept the offer by invoking the confirmTransferOffer function, ensuring the ERC-3643-compliant token transfer using IToken.transferFrom.

  1. Token Minting and Management:

    • The contract provides functions to mint different types of tokens within the Frictionless protocol, including Fund Deposit Tokens (mintFundDepositForTreasury), Digital Security Tokens (mintDigitalSecurity), and On-Chain Asset Tokens (mintOnChainAsset).

    • Tokens are associated with compliance contracts, and their minting is subject to specific conditions, roles, and permissions.

  2. Token Transfer and Burning:

    • The contract allows for the transfer and burning of tokens through functions like transferToken and burnToken. These actions are performed by an agent with the necessary permissions.

  3. Fund Deposit Token Management:

    • The contract keeps track of existing Fund Deposit Tokens using a mapping _existingFundDepositTokens. It prevents the creation of duplicate Fund Deposit Tokens for the same currency and fund IBAN.

The PROTOCOL_ADMIN is the only role permissioned to initially mint any Frictionless tokens, thereafter valid agents such as the PROTOCOL_TREASURY are permitted to increase supply (mint to address), transfer and burn Frictionless tokens.

The FrictionlessAttestationManager responsible for providing attestations of the balances held in the underlying funding account for each FrictionlessFundDepositToken. The attestation is provided and signed by an independent 3rd party, known as PERMISSIONED_FUND_ACCOUNTANT in the Frictionless protocol.

Attestations are proof of balances in each currency on a regular basis for example, daily or hourly, the attestation data is based on the following snapshot of the currency account underpinning the FrictionlessFundDepositToken.

Core Layers of Frictionless protocol, Securitization, Tokenization and Distribution.
Frictionless Protocol: Basic Token Lifecycle

The FrictionlessTransferManager overview is provided in the source .

See mode

See mode

More scenarios for DvP are described in the source .

The FrictionlessTreasuryManager manages the minting, transfer, and burning of various within the Frictionless protocol

ATTESTATION FIELD
ATTESTATION COMMENT

The attestation workflows are described in the source .

Git Source
Git Source

CASH_IBAN

The IBAN of the cash account

CURRENCY

The 3-letter currency code of the cash account

REPORT_START_DATE

The start of this report, for example, yesterday at 6AM

REPORT_END_DATE

The end of this report, for example, today at 6AM

CASH_BALANCE

The actual balance on the account as of REPORT_END_DATEfor example, today 6AM

LAST_TX_COUNTERPARTY_ID

The ID of the counterparty in the last transaction on the account

LAST_TX_TIMESTAMP

The timestamp (same format as REPORT_END_DATE) in the last transaction on the account

LAST_TX_AMOUNT

The amount of the the last transaction on the account, A credit transaction is positive and a debit transaction is negative

exchange
permissioning
FrictionlessPermissionsManager
FrictionlessTransferManager
README
README
FrictionlessTreasuryManager
tokens
FrictionlessAttestationManager
README
FrictionlessPermissionsManager
FrictionlessTransferManager
FrictionlessTreasuryManager
FrictionlessAttestationManager
onlyCounterpart
onlyTreasury

IFrictionlessTransferManager

Inherits: IAbstractFeeModule

Author: DEFYCA Labs S.à.r.l

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.

The IFrictionlessTransferManager is responsible for the management of the various transfer methodologies, fees processing, and defined control paradigm for DvP for all tokens in the Frictionless protocol. The tokens and their lifecycles are defined in the public README for the Frictionless protocol at https://gitlab.com/dfyclabs/protocol/dfyclabs-tokens/-/blob/main/README.md?ref_type=heads#funds-flows

Functions

updateMinRedeemAmount

Set a minimum redemption amount, to ensure there is meaningful settlement amounts, generally this is used to ensure FIAT transfers are above a minimum banking threshold, such as 1 USD.

function updateMinRedeemAmount(uint256 newMinRedeemAmount_) external;

Parameters

Name
Type
Description

newMinRedeemAmount_

uint256

the minimum redemption amount, if not reached , typically throws FrictionlessTransferManagerRedeemAmountIsLessThanMinimum

setTransferFees

Set the transfer fees for the exchange/settlement 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).

function setTransferFees(TokenFeeInfo calldata token0FeeInfo_, TokenFeeInfo calldata token1FeeInfo_) external;

Parameters

Name
Type
Description

token0FeeInfo_

TokenFeeInfo

The fees associated with the transfer of token0 (first token) in the exchange/settlement of the token pair.

token1FeeInfo_

TokenFeeInfo

The fees associated with the transfer of token1 (second token) in the exchange/settlement of the token pair. throws FrictionlessTransferManagerInvalidTokenAddresses if the token addresses are invalid. throws AbstractFeeModuleInvalidFeeRecipient if the feeRecipientAddr is a zero address 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 in either set of fees

setTokenFee

Set the fee associated with the transfer of a Token and manages the mapping of the key to this set of Fees. Can only be set by the Owner (PROTOCOL_ADMIN).

function setTokenFee(bytes32 tokenFeeKey_, TokenFeeInfo calldata tokenFeeInfo_) external;

Parameters

Name
Type
Description

tokenFeeKey_

bytes32

the key, generated by the function getTokenFeeKey, which is used to map a specific transfer polarity for tokens.

tokenFeeInfo_

TokenFeeInfo

The fees associated with the transfer of token, used in the calculation and disbursement of fees during exchange/settlement of a token pair. throws FrictionlessTransferManagerInvalidTokenAddresses if the token addresses are invalid. throws AbstractFeeModuleInvalidFeeRecipient if the feeRecipientAddr is a zero address 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

exchangeTokens

Executes a token pair exchange. This function can only be invoked by the PROTOCOL_TREASURY

function exchangeTokens(TokenTransferData memory token0TransferData_, TokenTransferData memory token1TransferData_)
    external;

Parameters

Name
Type
Description

token0TransferData_

TokenTransferData

the transfer data for the first token in the exchange

token1TransferData_

TokenTransferData

the transfer data for the second token in the exchange throws FrictionlessTransferManagerNotEnoughTokens if the balance of any of the tokens held by any users in the transfer is below the transfer amount throws FrictionlessTransferManagerInvalidTokenAddresses if any of the token addresses are zero. throws FrictionlessTransferManagerZeroAmount if any of the token amounts are zero throws FrictionlessTransferManagerInvalidTokenSenderAddresses if the expectedToken0Sender_ is not the same as the token0TransferData_.tokenSender throws FrictionlessTransferManagerInvalidTokenSenderAddresses if the token1TransferData_.tokenSender is a zero address emits FrictionlessTokensExchanged upon successful exchange.

createTransferOffer

Initiates/Creates a transferOffer between a token pair exchange. Setting the transfer status to PENDING for state management of the overall transfer. This function generates a transferOfferId_ which is returned so invokers of the function can perform further functions such as confirmTransferOffer or cancelOffer.

function createTransferOffer(TokenTransferData memory token0TransferData_, TokenTransferData memory token1TransferData_)
    external
    returns (uint256);

Parameters

Name
Type
Description

token0TransferData_

TokenTransferData

the transfer data for the first token in the exchange

token1TransferData_

TokenTransferData

the transfer data for the second token in the exchange

Returns

Name
Type
Description

<none>

uint256

transferOfferId_ representing the stored transfer in this contract for future operations such as confirmTransferOffer or cancelOffer. throws FrictionlessTransferManagerNotEnoughTokens if the balance of any of the tokens held by any users in the transfer is below the transfer amount throws FrictionlessTransferManagerInvalidTokenAddresses if any of the token addresses are zero. throws FrictionlessTransferManagerZeroAmount if any of the token amounts are zero throws FrictionlessTransferManagerInvalidTokenSenderAddresses if the expectedToken0Sender_ is not the same as the token0TransferData_.tokenSender throws FrictionlessTransferManagerInvalidTokenSenderAddresses if the token1TransferData_.tokenSender is a zero address emits FrictionlessTransferOfferCreated upon successful offer created.

redeemTokens

Redeem/Burn an amount for tokens for the specified tokenAddr_ and msg.sender

function redeemTokens(address tokenAddr_, uint256 redeemAmount_) external;

Parameters

Name
Type
Description

tokenAddr_

address

the address of the token

redeemAmount_

uint256

the amount of the token to burn (redeem) throws FrictionlessTransferManagerZeroAddress if the token address or the msg.sender is a zero address throws FrictionlessTransferManagerZeroAmount if the redeemAmount_ is zero throws FrictionlessTransferManagerNotEnoughTokens if the balance of a user for a given token is below the redeemAmount_ emits FrictionlessTokensRedeemed when the burn has occurred

redeemERC20Tokens

Redeem/Burn an amount for tokens for the specified ERC20 tokenAddr_ and msg.sender, this will convert the ERC20 token to a FrictionlessFundDepositToken first, then redeem See {IFrictionlessERC20ConverterManager-isTokenSupported} {IFrictionlessERC20ConverterManager-convertFromERC20}

function redeemERC20Tokens(address erc20Token_, address fundDepositToken_, uint256 tokenRedeemAmount_) external;

Parameters

Name
Type
Description

erc20Token_

address

the address of the ERC20 token

fundDepositToken_

address

the address of the FundDeposit token

tokenRedeemAmount_

uint256

the amount of the token to convert & burn (redeem) throws FrictionlessTransferManagerZeroAddress if the token address or the msg.sender is a zero address throws FrictionlessTransferManagerZeroAmount if the tokenRedeemAmount_ is zero throws FrictionlessTransferManagerNotEnoughTokens if the balance of a user for a given token is below the tokenRedeemAmount_ throws FrictionlessTransferManagerInvalidERC20TokenForRedeem if the tokenAddr_ is noy a valid convertible ERC20 token emits FrictionlessTokensRedeemed when the burn has occurred

redeemTokensFrom

Redeem/Burn an amount for tokens for the specified tokenAddr_ and userAddr_. This function can only be invoked by the PROTOCOL_TREASURY

function redeemTokensFrom(address tokenAddr_, address userAddr_, uint256 redeemAmount_) external;

Parameters

Name
Type
Description

tokenAddr_

address

the address of the token

userAddr_

address

the address of the holder of the token

redeemAmount_

uint256

the amount of the token to burn (redeem) throws FrictionlessTransferManagerZeroAddress if the token address or the userAddr_ is a zero address throws FrictionlessTransferManagerZeroAmount if the redeemAmount_ is zero throws FrictionlessTransferManagerNotEnoughTokens if the balance of a user for a given token is below the redeemAmount_ emits FrictionlessTokensRedeemed when the burn has occurred

redeemERC20TokensFrom

Redeem/Burn an amount for tokens for the specified ERC20 tokenAddr_ and userAddr_. This will convert the ERC20 token to a FrictionlessFundDepositToken first, then reedem. This function can only be invoked by the PROTOCOL_TREASURY See {IFrictionlessERC20ConverterManager-isTokenSupported} {IFrictionlessERC20ConverterManager-convertFromERC20}

function redeemERC20TokensFrom(
    address erc20Token_,
    address fundDepositToken_,
    address userAddr_,
    uint256 tokenRedeemAmount_
) external;

Parameters

Name
Type
Description

erc20Token_

address

the address of the ERC20 token

fundDepositToken_

address

the address of the FundDeposit token

userAddr_

address

the address of the holder of the token

tokenRedeemAmount_

uint256

the amount of the token to convert and burn (redeem) throws FrictionlessTransferManagerZeroAddress if the token address or the userAddr_ is a zero address throws FrictionlessTransferManagerZeroAmount if the tokenRedeemAmount_ is zero throws FrictionlessTransferManagerNotEnoughTokens if the balance of a user for a given token is below the tokenRedeemAmount_ throws FrictionlessTransferManagerInvalidERC20TokenForRedeem if the tokenAddr_ is noy a valid convertible ERC20 token emits FrictionlessTokensRedeemed when the burn has occurred

confirmTransferOffer

Confirms and processes the transfer for the respective transferOfferId_, which results int he compliant token transfers under ERC-3643 specification to occur.

function confirmTransferOffer(uint256 transferOfferId_) external;

Parameters

Name
Type
Description

transferOfferId_

uint256

the id of the transfer returned/emitted in the function createTransferOffer Requires the transfer status is TransferStatuses.PENDING throws FrictionlessTransferManagerInvalidTransferStatus if the transfer status is NOT TransferStatuses.PENDING throws FrictionlessTransferManagerNotEnoughPermissions If the msg.sender is not the tokenSender of the second token in the exchange or if the msg.sender is not a valid TREX Agent of either toekns in the exchange. emits FrictionlessTransferOfferConfirmed upon successful completion of the transfers.

cancelTransferOffer

Cancels a transfer for the given transferOfferId_, which results in the transfer status being set to TransferStatuses.CANCELED and the relevant FrictionlessTransferOfferCanceled being emitted.

function cancelTransferOffer(uint256 transferOfferId_) external;

Parameters

Name
Type
Description

transferOfferId_

uint256

the generated transferOfferId_ used to store the state of transfers in the contract. requires the Transfer to be in a PENDING state. throws FrictionlessTransferManagerInvalidTransferStatus if the transfer status is NOT TransferStatuses.PENDING throws FrictionlessTransferManagerNotEnoughPermissions If the msg.sender is not the tokenSender of the second token in the exchange or if the msg.sender is not a valid TREX Agent of either tokens in the exchange.

nextTransferOfferId

Generates the next transferOfferId in the smart contract, used to store state of a transfer.

function nextTransferOfferId() external view returns (uint256);

Returns

Name
Type
Description

<none>

uint256

the next transferOfferId in the smart contract, used to store state of a transfer.

minRedeemAmount

Get the minimum redemption amount configured

function minRedeemAmount() external view returns (uint256);

Returns

Name
Type
Description

<none>

uint256

minimum redemption amount, to ensure there is meaningful settlement amounts, generally this is used to ensure FIAT transfers are above a minimum banking threshold, such as 1 USD.

getTransferData

Returns the transfer data stored for the given transferOfferId_

function getTransferData(uint256 transferOfferId_) external view returns (TransferData memory);

Parameters

Name
Type
Description

transferOfferId_

uint256

the generated transferOfferId_ used to store the state of transfers in the contract

Returns

Name
Type
Description

<none>

TransferData

TransferData, the transfer data for the given transferOfferId_

getTransferFeesInfo

get the tokenFeeInfo set for the fees associated per token in an exchange.

function getTransferFeesInfo(address token0_, address token1_) external view returns (FeeInfo memory, FeeInfo memory);

Parameters

Name
Type
Description

token0_

address

the address of the first token in an exchange

token1_

address

the address of the second token in an exchange

Returns

Name
Type
Description

<none>

FeeInfo

FeeInfo set for the fees associated per token in an exchange.

<none>

FeeInfo

getTransferFeeKeys

Generates keys based on the packed encoding of the addresses of sets of tokens using the keccak256 hashing function. Used to store tokenFees in mappings.

function getTransferFeeKeys(address token0_, address token1_) external view returns (bytes32, bytes32);

Parameters

Name
Type
Description

token0_

address

the address of the token 0 in a transfer fee calculation

token1_

address

the address of the token 1 in a transfer fee calculation

Returns

Name
Type
Description

<none>

bytes32

keys based on the packed encoding of the addresses of sets of tokens using the keccak256 hashing function.

<none>

bytes32

getTokenFeeKey

Generates a key based on the packed encoding of the addresses of both tokens using the keccak256 hashing function. Used to store tokenFees in mappings.

function getTokenFeeKey(address token0_, address token1_) external view returns (bytes32);

Parameters

Name
Type
Description

token0_

address

the address of the token 0 in a transfer fee calculation

token1_

address

the address of the token 1 in a transfer fee calculation

Returns

Name
Type
Description

<none>

bytes32

generates a key based on the packed encoding of the addresses of both tokens using the keccak256 hashing function.

Events

FrictionlessTransferOfferCreated

Event emitted during createTransferOffer

event FrictionlessTransferOfferCreated(uint256 transferId);

FrictionlessTransferOfferConfirmed

Event emitted during confirmTransferOffer

event FrictionlessTransferOfferConfirmed(uint256 transferId);

FrictionlessTransferOfferCanceled

Event emitted during cancelOffer

event FrictionlessTransferOfferCanceled(uint256 transferId);

FrictionlessTokensExchanged

Event emitted during exchangeTokens

event FrictionlessTokensExchanged(TokenTransferData token0TransferData, TokenTransferData token1TransferData);

FrictionlessTokensRedeemed

Event emitted during redeemTokens and redeemTokensFrom

event FrictionlessTokensRedeemed(address tokenAddr, address userAddr, uint256 redeemAmount);

Errors

FrictionlessTransferManagerInvalidTokenAddresses

error thrown during setTransferFees, setTransferFees, exchangeTokens or createTransferOffer if any of the token addresses are zero.

error FrictionlessTransferManagerInvalidTokenAddresses(address token0, address token1);

FrictionlessTransferManagerInvalidTokenSenderAddresses

error thrown during exchangeTokens or createTransferOffer if any of the tokenSender address in an exchange is a zero address

error FrictionlessTransferManagerInvalidTokenSenderAddresses(address token0Sender, address token1Sender);

FrictionlessTransferManagerInvalidTokensPairForRedeem

error FrictionlessTransferManagerInvalidTokensPairForRedeem(address erc20Token, address funDepositToken);

FrictionlessTransferManagerCannotTransferToken

error thrown during createTransferOffer if the token transfer is prohibited under Compliance contract rules

error FrictionlessTransferManagerCannotTransferToken(address tokenAddr, address from, address to, uint256 amount);

FrictionlessTransferManagerZeroAddress

error thrown during redeemTokens or redeemTokensFrom if the token address or the msg.sender is a zero address

error FrictionlessTransferManagerZeroAddress();

FrictionlessTransferManagerZeroAmount

error thrown during exchangeTokens, createTransferOffer, redeemTokens or redeemTokensFrom if any of the token amounts are zero

error FrictionlessTransferManagerZeroAmount();

FrictionlessTransferManagerRedeemAmountIsLessThanMinimum

error thrown when the redemption amount is below the configured minimum, during redeemTokens or redeemERC20Tokens

error FrictionlessTransferManagerRedeemAmountIsLessThanMinimum(uint256 redeemAmount);

FrictionlessTransferManagerNotEnoughTokens

error thrown during exchangeTokens, createTransferOffer, redeemTokens or redeemTokensFrom if the balance of any of the tokens held by any users in the transfer is below the transfer amount

error FrictionlessTransferManagerNotEnoughTokens(address tokenAddr, address userAddr, uint256 tokensToTransfer);

FrictionlessTransferManagerInvalidTransferStatus

error thrown during confirmTransferOffer or cancelOffer if the transfer status expectedStatus does not match the actualStatus

error FrictionlessTransferManagerInvalidTransferStatus(TransferStatuses expectedStatus, TransferStatuses actualStatus);

FrictionlessTransferManagerNotEnoughPermissions

error thrown during createTransferOffer or confirmTransferOffer if any of the msg.sender is not an Agent of the tokens in the transfer.

error FrictionlessTransferManagerNotEnoughPermissions();

Structs

TokenFeeInfo

TokenFeeInfo represents the fee (zero or otherwise) that is associated with the transfer of a token in the Transfer Manager exchange.

struct TokenFeeInfo {
    address tokenAddr;
    FeeInfo feeInfo;
}

TokenTransferData

TokenTransferData represents the data set in a transfer of a token

struct TokenTransferData {
    address tokenAddr;
    address tokenSender;
    uint256 tokenAmount;
}

TransferData

TransferData represents a maker/taker model of transfer, where 1 token is exchanged for another

struct TransferData {
    TokenTransferData token0Data;
    TokenTransferData token1Data;
    uint256 feeInBps0;
    uint256 feeInBps1;
    TransferStatuses status;
}

Enums

TransferStatuses

Enumeration to track transfer statuses

enum TransferStatuses {
    NONE,
    PENDING,
    CONFIRMED,
    CANCELED
}

IFrictionlessPermissionsManager

Author: DEFYCA Labs S.à.r.l

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.

The IFrictionlessPermissionsManager is responsible for the management of permission of the various participants in the Frictionless protocol. The roles and responsibilities are defined in the public README for the Frictionless protocol at https://gitlab.com/dfyclabs/protocol/dfyclabs-tokens/-/blob/main/README.md?ref_type=heads#roles-responsibilities

Functions

isPermissioned

Validates if a wallet address is permissioned in the Frictionless protocol

function isPermissioned(address userAddress) external view returns (bool);

Parameters

Name
Type
Description

userAddress

address

the wallet address to verify

Returns

Name
Type
Description

<none>

bool

true if the address is permissioned in the Frictionless Protocol.

registerIdentity

Registers a users wallet address as an OnChainId (Identity) to the Frictionless protocol. This Identity is used when permissioning a user to the protocol by invoking the addUser function later.

function registerIdentity(address userAddress, uint16 userISOCountry) external returns (address);

Parameters

Name
Type
Description

userAddress

address

the address of the user's wallet to register

userISOCountry

uint16

the ISO 3166-1 numeric code of the user, can be the place of residence or the location KYC/AML onboarding was undertaken. requires The msg.sender to have the TREX Agent permissions (PROTOCOL_TREASURY or PROTOCOL_ADMIN)

Returns

Name
Type
Description

<none>

address

address the address of the user's OnChainId (Identity) with the associated claims.

getIdentity

Gets a users OnChainId (Identity) in the Frictionless protocol.

function getIdentity(address userAddress) external returns (address);

Parameters

Name
Type
Description

userAddress

address

the address of the user's wallet to register requires The msg.sender to have the TREX Agent permissions (PROTOCOL_TREASURY or PROTOCOL_ADMIN)

Returns

Name
Type
Description

<none>

address

address the address of the user's OnChainId (Identity) with the associated claims.

getClaimMsgHash

Get the signed claimData message to be used in the addUser function. The message must be signed using the PK of the ClaimIssuer (PROTOCOL_ADMIN)

function getClaimMsgHash(address userIdentity, IFrictionlessPermissionsManager.FrictionlessPermissionedUser userType)
    external
    view
    returns (bytes32);

Parameters

Name
Type
Description

userIdentity

address

the address of the user's OnChainId (Identity)

userType

IFrictionlessPermissionsManager.FrictionlessPermissionedUser

the type of the user as per the enum

Returns

Name
Type
Description

<none>

bytes32

signed claimData message to be used in the addUser unction once signed by the ClaimIssuer PK.

hasClaim

verify if the userAddress is permissioned in the Frictionless protocol and has a valid claim

function hasClaim(address userAddress, FrictionlessPermissionedUser userType) external view returns (bool);

Parameters

Name
Type
Description

userAddress

address

the address of the user's wallet to verify

userType

FrictionlessPermissionedUser

the type of the user as per the enum

Returns

Name
Type
Description

<none>

bool

true if a valid permissioned user and has a valid claim, otherwise false.

addUser

Adds a user's OnChainId (Identity) to the Frictionless protocol along with its associated claim data. The Identity is created by invoking the registerIdentity function first.

function addUser(
    address userIdentity,
    FrictionlessPermissionedUser userType,
    bytes memory claimSignature,
    string memory claimURI
) external returns (address);

Parameters

Name
Type
Description

userIdentity

address

the address of the user's OnChainId (Identity)

userType

FrictionlessPermissionedUser

the type of the user as per the enum

claimSignature

bytes

the signed claimData by the ClaimIssuer

claimURI

string

the URI of the off-chain claim for the user. i.e. The Frictionless Markets graphQL endpoint requires The msg.sender to be the Owner if the userType is the PROTOCOL_TREASURY requires The msg.sender to have the TREX Agent permissions (PROTOCOL_TREASURY or PROTOCOL_ADMIN) to add any user

Returns

Name
Type
Description

<none>

address

address the address of the user's OnChainId (Identity) with the associated claims.

removeUser

Removes a user from the Frictionless protocol along with its associated claim data.

function removeUser(address userAddress) external returns (bool);

Parameters

Name
Type
Description

userAddress

address

the address of the user's wallet requires The msg.sender to have the TREX Agent permissions (PROTOCOL_TREASURY or PROTOCOL_ADMIN) to remove any user

Returns

Name
Type
Description

<none>

bool

true if the user is removed from the Frictionless protocol along with its associated claim data, otherwise false.

Events

FrictionlessPermissionedUserAdded

Emitted when a user is added to the Frictionless protocol. This event is emitted by the addUser function.

event FrictionlessPermissionedUserAdded(address userIdentity, uint256 userType, string claimURI);

FrictionlessPermissionedUserRegistered

Emitted when a user is registered in the Frictionless protocol. This event is emitted by the registerIdentity function.

event FrictionlessPermissionedUserRegistered(address userAddress, uint16 userISOCountry);

FrictionlessPermissionedUserRemoved

Emitted when a user is removed in the Frictionless protocol. This event is emitted by the removeUser function.

event FrictionlessPermissionedUserRemoved(address userAddress);

Errors

FrictionlessIsZeroAddress

throws if specific address is zero.

error FrictionlessIsZeroAddress(string);

FrictionlessInvalidPermissionForTreasury

throws if treasury tries to add or remove treasury.

error FrictionlessInvalidPermissionForTreasury();

FrictionlessUserIsNotPermssionedInvestor

throws if user is not a permissioned investor

error FrictionlessUserIsNotPermssionedInvestor();

Structs

Claim

the internal struct defining a Claim for a PERMISSIONED_USER in the protocol. Used to submit claims for the OnChainId by the ClaimIssuer.

struct Claim {
    address issuer;
    uint256 topic;
    uint8 scheme;
    address identity;
    bytes signature;
    bytes data;
}

Enums

FrictionlessPermissionedUser

Enum of the Frictionless protocol participants.

enum FrictionlessPermissionedUser {
    PROTOCOL_TREASURY,
    PERMISSIONED_CUSTODIAN,
    PERMISSIONED_INVESTOR,
    PERMISSIONED_MANAGER,
    PERMISSIONED_CALCULATING_AGENT,
    PERMISSIONED_TRANSFER_AGENT,
    PERMISSIONED_FUND_ACCOUNTANT
}

Automated Fee Collection

The Frictionless protocol is designed to automate cash operations across the lifecycle of a fund, part of this automation is the collection of contracted fee structures within a fund, such as management and/or performance fees.

The smart contracts for securities exchange, transfer, ERC20 swap and FX swaps may be programmed to automatically collect fees for Managers, opening new revenue streams for Managers whilst ensuring the visibility of fees for Investors and Managers alike.

The following diagram illustrates the design of the fee module, which enables the definition of fees to be automatically collected by a defined fee recipient during any of the value exchange functions in the protocol.

Fees may be configured to be collected in the following transactions:

  1. P2P (bi-lateral) transfer of tokens between permissioned counterparties, for example, a direct transfer of securities between two Investors, such as a secondary trade.

  2. Exchange of securities, executed by the protocol during a primary issuance, in the form of management fees upon committed capital or deployed capital.

  3. Settlement of securities, executed by the protocol or by the Investor.

  4. Conversion of an ERC20 token to/from a FrictionlessFundDepositToken, for example, converting USDC to the USD equivalent FrictionlessFundDepositToken or conversion of another ERC20 collateral.

  5. FX swap of FrictionlessFundDepositToken of different currencies.

The fee architecture permissions the protocol admin to establish fees, this ensures that the market integrity for fees is maintained, for example, the FX rates are taken from our FX partner's spot and forward rates quoted, and the conversion of ERC20 stablecoins such as USDC and USDT to it's USD equivalent FrictionlessFundDepositToken.

IAbstractFeeModule

Author: DEFYCA Labs S.à.r.l

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.

Functions

getFeeInfo

get the FeeInfo for a given key.

function getFeeInfo(bytes32 feeKey_) external view returns (FeeInfo memory);

Parameters

Name
Type
Description

feeKey_

bytes32

the key as generated by the function getTokenFeeKey

Returns

Name
Type
Description

<none>

FeeInfo

FeeInfo the fees associated with a token transfer.

getFeeInBps

get the feeInBps value for a given key

function getFeeInBps(bytes32 tokenFeeKey_) external view returns (uint256);

Parameters

Name
Type
Description

tokenFeeKey_

bytes32

the key as generated by the function getTokenFeeKey

Returns

Name
Type
Description

<none>

uint256

the feeInBps value

getFeeRecipient

get the feeRecipientAddr value for a given key

function getFeeRecipient(bytes32 tokenFeeKey_) external view returns (address);

Parameters

Name
Type
Description

tokenFeeKey_

bytes32

the key as generated by the function getTokenFeeKey

Returns

Name
Type
Description

<none>

address

the feeRecipientAddr value

calculateFeeAmount

Calculates the actual fee in absolute terms for a given fee in basis points.

function calculateFeeAmount(uint256 tokensAmount_, uint256 feeInBps_) external pure returns (uint256 feeAmount_);

Parameters

Name
Type
Description

tokensAmount_

uint256

the amount of tokens used to determine the base calculation.

feeInBps_

uint256

the fee in basis points for calculation.

Returns

Name
Type
Description

feeAmount_

uint256

the actual fee in absolute terms for a given fee in basis points.

Events

FrictionlessFeeSet

Event emitted during _setTokenFee

event FrictionlessFeeSet(bytes32 indexed feeKey, FeeInfo feeInfo);

Errors

AbstractFeeModuleInvalidFeeRecipient

error thrown if the recipient is a zero address

error AbstractFeeModuleInvalidFeeRecipient();

AbstractFeeModuleInvalidFee

error thrown if the feesInBps is outside the valid range

error AbstractFeeModuleInvalidFee(uint256 feeInBps);

Structs

FeeInfo

Struct which defines the FeeInfo, representing the fee in basis points and the recipient of the fees on-chain.

struct FeeInfo {
    uint256 feeInBps;
    address feeRecipientAddr;
}

IFrictionlessComplianceFactory

Author: DEFYCA Labs S.à.r.l

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.

Interface defining the upgradeable compliance factory for all tokens in the Frictionless protocol.

Functions

setTreasuryManager

Sets the Treasury Manager to be the specified address.

function setTreasuryManager(address newTreasuryManager_) external;

Parameters

Name
Type
Description

newTreasuryManager_

address

the address of the treasury manager to set throws FrictionlessComplianceFactoryZeroAddress if the newTreasuryManager_ is a zero address

updateModularComplianceImpl

Updates and upgrades the modular compliance implementation

function updateModularComplianceImpl(address newModularComplianceImpl_) external;

Parameters

Name
Type
Description

newModularComplianceImpl_

address

the address of the modular compliance implementation

updateSupportedComplianceData

Updates the set of supported modular compliance modules.

function updateSupportedComplianceData(UpdateSupportedComplianceData[] calldata updateSupportedComplianceDataArr_)
    external;

Parameters

Name
Type
Description

updateSupportedComplianceDataArr_

UpdateSupportedComplianceData[]

the set of supported modular compliance modules.

updateModularComplianceData

Updates the modular compliance data.

function updateModularComplianceData(UpdateModularComplianceData[] calldata updateModularComplianceDataArr_) external;

Parameters

Name
Type
Description

updateModularComplianceDataArr_

UpdateModularComplianceData[]

the modular compliance data.

deployCompliance

Deploys the compliance contract using the ProxyBeacon with the associated FrictionlessPermissionsManager contract

function deployCompliance(IBasicFrictionlessToken.FrictionlessTokenTypes tokenType_) external returns (address);

Parameters

Name
Type
Description

tokenType_

IBasicFrictionlessToken.FrictionlessTokenTypes

The Frictionless token type as defined by IBasicFrictionlessToken.FrictionlessTokenTypes

Returns

Name
Type
Description

<none>

address

the address of the deployed compliance contract for the specified Frictionless token type throws FrictionlessComplianceFactoryNotATreasuryManager if the msg.sender is not the treasury manager emits FrictionlessComplianceDeployed event upon successful deployment of the compliance contract.

treasuryManager

returns the address of the treasuryManager

function treasuryManager() external view returns (address);

Returns

Name
Type
Description

<none>

address

the address of the treasuryManager

modularComplianceBeacon

returns the ProxyBeacon of the ModularCompliance

function modularComplianceBeacon() external view returns (ProxyBeacon);

Returns

Name
Type
Description

<none>

ProxyBeacon

the ProxyBeacon of the ModularCompliance

getModularComplianceImpl

returns the address of the ModularCompliance

function getModularComplianceImpl() external view returns (address);

Returns

Name
Type
Description

<none>

address

the address of the ModularCompliance

getModularComplianceTokenType

returns the FrictionlessTokenTypes which is bound by the ModularCompliance

function getModularComplianceTokenType(address modularComplianceAddr_)
    external
    view
    returns (IBasicFrictionlessToken.FrictionlessTokenTypes);

Parameters

Name
Type
Description

modularComplianceAddr_

address

the address of the ModularComplianceImpl

Returns

Name
Type
Description

<none>

IBasicFrictionlessToken.FrictionlessTokenTypes

the address of the ModularCompliance

getSupportedComplianceModulesCount

returns the amount of supported compliances ModularCompliance for the specified tokenType_

function getSupportedComplianceModulesCount(IBasicFrictionlessToken.FrictionlessTokenTypes tokenType_)
    external
    view
    returns (uint256);

Parameters

Name
Type
Description

tokenType_

IBasicFrictionlessToken.FrictionlessTokenTypes

the type of token as defined by the IBasicFrictionlessToken.FrictionlessTokenTypes enumerated type

Returns

Name
Type
Description

<none>

uint256

the amount of supported compliances

getSupportedComplianceModules

returns the array of supported compliances ModularCompliance for the specified tokenType_

function getSupportedComplianceModules(IBasicFrictionlessToken.FrictionlessTokenTypes tokenType_)
    external
    view
    returns (address[] memory);

Parameters

Name
Type
Description

tokenType_

IBasicFrictionlessToken.FrictionlessTokenTypes

the type of token as defined by the IBasicFrictionlessToken.FrictionlessTokenTypes enumerated type

Returns

Name
Type
Description

<none>

address[]

the array of supported compliances

getSupportedComplianceInfo

function getSupportedComplianceInfo(IBasicFrictionlessToken.FrictionlessTokenTypes tokenType_)
    external
    view
    returns (ModularComplianceInfo memory);

isSupportedComplianceModule

returns true if the compliance module supports the Frictionless token type, otherwise false

function isSupportedComplianceModule(IBasicFrictionlessToken.FrictionlessTokenTypes tokenType_, address moduleToCheck_)
    external
    view
    returns (bool);

Parameters

Name
Type
Description

tokenType_

IBasicFrictionlessToken.FrictionlessTokenTypes

the type of token as defined by the IBasicFrictionlessToken.FrictionlessTokenTypes enumerated type

moduleToCheck_

address

the address of the modular compliance contract to verify

Returns

Name
Type
Description

<none>

bool

true if the compliance module supports the Frictionless token type, otherwise false

isModularCompliance

Returns true if the address provided is a ModularCompliance contract

function isModularCompliance(address modularComplianceAddr_) external view returns (bool);

Parameters

Name
Type
Description

modularComplianceAddr_

address

the address of the ModularCompliance contract

Returns

Name
Type
Description

<none>

bool

true if the address provided is a ModularCompliance contract, otherwise false

Events

FrictionlessComplianceDeployed

Event emitted upon successful deployment of a compliance contract.

event FrictionlessComplianceDeployed(
    IBasicFrictionlessToken.FrictionlessTokenTypes indexed tokenType, address newComplianceContract
);

Errors

FrictionlessComplianceFactoryZeroAddr

error thrown if the specified contract address is a zero address, during init, setTreasuryManager, and updateModularComplianceImpl

error FrictionlessComplianceFactoryZeroAddr(string);

FrictionlessComplianceFactoryNotATreasuryManager

error thrown if the msg.sender is not the treasury manager during the function deployCompliance

error FrictionlessComplianceFactoryNotATreasuryManager(address);

FrictionlessComplianceFactoryNotAModularCompliance

error thrown if the modular compliance is invlaid for hte token type during the function updateModularCompliancesModules

error FrictionlessComplianceFactoryNotAModularCompliance(address);

FrictionlessComplianceFactoryInvalidTokenType

error thrown if an invalid tokenType is specified during deployCompliance

error FrictionlessComplianceFactoryInvalidTokenType();

FrictionlessComplianceFactoryInvalidModularComplianceData

error thrown if an invalid module is specified during updateModularCompliancesModules

error FrictionlessComplianceFactoryInvalidModularComplianceData(UpdateModularComplianceData modularComplianceData);

Structs

SupportedComplianceData

struct SupportedComplianceData {
    uint256 maxModulesCount;
    EnumerableSet.AddressSet modules;
    bytes32[48] _gap;
}

ModularComplianceInfo

struct ModularComplianceInfo {
    uint256 maxModulesCount;
    address[] modules;
}

UpdateModularComplianceData

Structure to represent the update of modular compliance data.

struct UpdateModularComplianceData {
    address modularCompliance;
    ModularComplianceInfo complianceInfo;
    bool isAdding;
}

UpdateSupportedComplianceData

Structure to represent the update of modular compliance data for a given token type

struct UpdateSupportedComplianceData {
    IBasicFrictionlessToken.FrictionlessTokenTypes tokenType;
    ModularComplianceInfo complianceInfo;
    bool isAdding;
}

IFrictionlessComplianceModule

Inherits: IModule

Author: DEFYCA Labs S.à.r.l

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.

The IFrictionlessCompliance is responsible for the compliant transfer of the various Tokens in the Frictionless protocol.

Functions

setPermissionsManager

Sets the instance of the IFrictionlessPermissionsManager to determine permissions for users.

function setPermissionsManager(address frictionlessPermissionsManager_) external;

Parameters

Name
Type
Description

frictionlessPermissionsManager_

address

the address of the IFrictionlessPermissionsManager contract

setComplianceFactory

Sets the instance of the IFrictionlessComplianceFactory to determine the compliance module for the protocol.

function setComplianceFactory(address newComplianceFactory_) external;

Parameters

Name
Type
Description

newComplianceFactory_

address

the address of the IFrictionlessComplianceFactory contract

permissionsManager

Gets the instance of the IFrictionlessPermissionsManager to determine permissions for users.

function permissionsManager() external view returns (IFrictionlessPermissionsManager);

Returns

Name
Type
Description

<none>

IFrictionlessPermissionsManager

the address of the IFrictionlessPermissionsManager contract

complianceFactory

Gets the instance of the IFrictionlessComplianceFactory to determine the compliance module for the protocol.

function complianceFactory() external view returns (IFrictionlessComplianceFactory);

Returns

Name
Type
Description

<none>

IFrictionlessComplianceFactory

the address of the IFrictionlessComplianceFactory contract

isTreasury

Verifies if the specified wallet address is a PROTOCOL_TREASURY user.

function isTreasury(address walletAddress_) external view returns (bool);

Parameters

Name
Type
Description

walletAddress_

address

the address of the users wallet.

Returns

Name
Type
Description

<none>

bool

true if the specified wallet address is a PROTOCOL_TREASURY user, otherwise false

isCustodian

Verifies if the specified wallet address is a PERMISSIONED_CUSTODIAN user.

function isCustodian(address walletAddress_) external view returns (bool);

Parameters

Name
Type
Description

walletAddress_

address

the address of the users wallet.

Returns

Name
Type
Description

<none>

bool

true if the specified wallet address is a PERMISSIONED_CUSTODIAN user, otherwise false

isInvestor

Verifies if the specified wallet address is a PERMISSIONED_INVESTOR user.

function isInvestor(address walletAddress_) external view returns (bool);

Parameters

Name
Type
Description

walletAddress_

address

the address of the users wallet.

Returns

Name
Type
Description

<none>

bool

true if the specified wallet address is a PERMISSIONED_INVESTOR user, otherwise false

isManager

Verifies if the specified wallet address is a PERMISSIONED_MANAGER user.

function isManager(address walletAddress_) external view returns (bool);

Parameters

Name
Type
Description

walletAddress_

address

the address of the users wallet.

Returns

Name
Type
Description

<none>

bool

true if the specified wallet address is a PERMISSIONED_MANAGER user, otherwise false

isCalculatingAgent

Verifies if the specified wallet address is a PERMISSIONED_CALCULATING_AGENT user.

function isCalculatingAgent(address walletAddress_) external view returns (bool);

Parameters

Name
Type
Description

walletAddress_

address

the address of the users wallet.

Returns

Name
Type
Description

<none>

bool

true if the specified wallet address is a PERMISSIONED_CALCULATING_AGENT user, otherwise false

isTransferAgent

Verifies if the specified wallet address is a PERMISSIONED_TRANSFER_AGENT user.

function isTransferAgent(address walletAddress_) external view returns (bool);

Parameters

Name
Type
Description

walletAddress_

address

the address of the users wallet.

Returns

Name
Type
Description

<none>

bool

true if the specified wallet address is a PERMISSIONED_TRANSFER_AGENT user, otherwise false

isFundAccountant

Verifies if the specified wallet address is a PERMISSIONED_FUND_ACCOUNTANT user.

function isFundAccountant(address walletAddress_) external view returns (bool);

Parameters

Name
Type
Description

walletAddress_

address

the address of the users wallet.

Returns

Name
Type
Description

<none>

bool

true if the specified wallet address is a PERMISSIONED_FUND_ACCOUNTANT user, otherwise false

isUser

Verifies if the specified wallet address is a permissioned user in the Frictionless protocol.

function isUser(address walletAddress_) external view returns (bool);

Parameters

Name
Type
Description

walletAddress_

address

the address of the users wallet.

Returns

Name
Type
Description

<none>

bool

true if the specified wallet address is a permissioned user in the Frictionless protocol, otherwise false

hasClaim

verify if the userAddress is permissioned in the Frictionless protocol and has a valid claim

function hasClaim(address userAddress_, IFrictionlessPermissionsManager.FrictionlessPermissionedUser userType_)
    external
    view
    returns (bool);

Parameters

Name
Type
Description

userAddress_

address

the address of the user's wallet to verify

userType_

IFrictionlessPermissionsManager.FrictionlessPermissionedUser

the type of the user as per the enum

Returns

Name
Type
Description

<none>

bool

true if a valid permissioned user and has a valid claim, otherwise false.

Events

FrictionlessTokenTransferred

Event emitted during compliance module transfers

event FrictionlessTokenTransferred(
    IBasicFrictionlessToken.FrictionlessTokenTypes tokenType,
    address tokenAddr,
    address from,
    address to,
    uint256 amount
);

Errors

FrictionlessIsZeroAddress

throws if specific address is zero.

error FrictionlessIsZeroAddress(string);

FrictionlessComplianceModuleInvalidCompliance

thrown if the compliance module address is invalid during bindCompliance and unBindCompliance

error FrictionlessComplianceModuleInvalidCompliance(address compliance);

FrictionlessComplianceModuleNotAnApprovedCompliance

thrown if the compliance module address is not approved during bindCompliance

error FrictionlessComplianceModuleNotAnApprovedCompliance(address compliance);

FrictionlessComplianceModuleComplianceIsAlreadyBound

thrown if the compliance module address is already bound, thrown by bindCompliance

error FrictionlessComplianceModuleComplianceIsAlreadyBound(address compliance);

FrictionlessComplianceModuleNotABoundCompliance

thrown if the compliance module address is not already bound during unBindCompliance

error FrictionlessComplianceModuleNotABoundCompliance(address compliance);

AbstractFrictionlessComplianceModule

Inherits: IFrictionlessComplianceModule, OwnableUpgradeable

Author: DEFYCA Labs S.à.r.l

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.

See {IFrictionlessComplianceModule}

State Variables

permissionsManager

The IFrictionlessPermissionsManager for the protocol.

IFrictionlessPermissionsManager public override permissionsManager;

complianceFactory

The IFrictionlessComplianceFactory for the protocol.

IFrictionlessComplianceFactory public override complianceFactory;

_complianceBound

the mapping of compliance modules bound.

mapping(address => bool) private _complianceBound;

Functions

onlyApprovedCompliance

modifier used to very that only approved compliance modules can be used.

modifier onlyApprovedCompliance();

onlyBoundCompliance

modifier used to very that only modules that are bound, can be used.

modifier onlyBoundCompliance();

__AbstractFrictionlessComplianceModule_init

Initiatizes the compliance module

function __AbstractFrictionlessComplianceModule_init(
    address frictionlessPermissionsManager_,
    address complianceFactory_
) internal onlyInitializing;

Parameters

Name
Type
Description

frictionlessPermissionsManager_

address

the address of the frictionless permissions manager

complianceFactory_

address

the address of the compliance dfactory

setPermissionsManager

Sets the instance of the IFrictionlessPermissionsManager to determine permissions for users.

function setPermissionsManager(address frictionlessPermissionsManager_) external override onlyOwner;

Parameters

Name
Type
Description

frictionlessPermissionsManager_

address

the address of the IFrictionlessPermissionsManager contract

setComplianceFactory

Sets the instance of the IFrictionlessComplianceFactory to determine the compliance module for the protocol.

function setComplianceFactory(address newComplianceFactory_) external override onlyOwner;

Parameters

Name
Type
Description

newComplianceFactory_

address

the address of the IFrictionlessComplianceFactory contract

bindCompliance

function bindCompliance(address compliance_) external override onlyApprovedCompliance;

unbindCompliance

function unbindCompliance(address compliance_) external override;

moduleTransferAction

function moduleTransferAction(address from_, address to_, uint256 value_)
    external
    virtual
    override
    onlyBoundCompliance;

moduleMintAction

function moduleMintAction(address to_, uint256 value_) external virtual override onlyBoundCompliance;

moduleBurnAction

function moduleBurnAction(address from_, uint256 value_) external virtual override onlyBoundCompliance;

moduleCheck

function moduleCheck(address, address, uint256, address) public view virtual override returns (bool);

isComplianceBound

function isComplianceBound(address compliance_) public view override returns (bool);

isTreasury

Verifies if the specified wallet address is a PROTOCOL_TREASURY user.

function isTreasury(address userAddress_) public view override returns (bool);

Parameters

Name
Type
Description

userAddress_

address

Returns

Name
Type
Description

<none>

bool

true if the specified wallet address is a PROTOCOL_TREASURY user, otherwise false

isCustodian

Verifies if the specified wallet address is a PERMISSIONED_CUSTODIAN user.

function isCustodian(address userAddress_) public view override returns (bool);

Parameters

Name
Type
Description

userAddress_

address

Returns

Name
Type
Description

<none>

bool

true if the specified wallet address is a PERMISSIONED_CUSTODIAN user, otherwise false

isInvestor

Verifies if the specified wallet address is a PERMISSIONED_INVESTOR user.

function isInvestor(address userAddress_) public view override returns (bool);

Parameters

Name
Type
Description

userAddress_

address

Returns

Name
Type
Description

<none>

bool

true if the specified wallet address is a PERMISSIONED_INVESTOR user, otherwise false

isManager

Verifies if the specified wallet address is a PERMISSIONED_MANAGER user.

function isManager(address userAddress_) public view override returns (bool);

Parameters

Name
Type
Description

userAddress_

address

Returns

Name
Type
Description

<none>

bool

true if the specified wallet address is a PERMISSIONED_MANAGER user, otherwise false

isCalculatingAgent

Verifies if the specified wallet address is a PERMISSIONED_CALCULATING_AGENT user.

function isCalculatingAgent(address userAddress_) public view override returns (bool);

Parameters

Name
Type
Description

userAddress_

address

Returns

Name
Type
Description

<none>

bool

true if the specified wallet address is a PERMISSIONED_CALCULATING_AGENT user, otherwise false

isTransferAgent

Verifies if the specified wallet address is a PERMISSIONED_TRANSFER_AGENT user.

function isTransferAgent(address userAddress_) public view override returns (bool);

Parameters

Name
Type
Description

userAddress_

address

Returns

Name
Type
Description

<none>

bool

true if the specified wallet address is a PERMISSIONED_TRANSFER_AGENT user, otherwise false

isFundAccountant

Verifies if the specified wallet address is a PERMISSIONED_FUND_ACCOUNTANT user.

function isFundAccountant(address userAddress_) public view override returns (bool);

Parameters

Name
Type
Description

userAddress_

address

Returns

Name
Type
Description

<none>

bool

true if the specified wallet address is a PERMISSIONED_FUND_ACCOUNTANT user, otherwise false

isUser

Verifies if the specified wallet address is a permissioned user in the Frictionless protocol.

function isUser(address userAddress_) public view override returns (bool);

Parameters

Name
Type
Description

userAddress_

address

Returns

Name
Type
Description

<none>

bool

true if the specified wallet address is a permissioned user in the Frictionless protocol, otherwise false

hasClaim

verify if the userAddress is permissioned in the Frictionless protocol and has a valid claim

function hasClaim(address userAddress_, IFrictionlessPermissionsManager.FrictionlessPermissionedUser userType_)
    public
    view
    override
    returns (bool);

Parameters

Name
Type
Description

userAddress_

address

the address of the user's wallet to verify

userType_

IFrictionlessPermissionsManager.FrictionlessPermissionedUser

the type of the user as per the enum

Returns

Name
Type
Description

<none>

bool

true if a valid permissioned user and has a valid claim, otherwise false.

_setPermissionsManager

Impl of the setting of the permissions manager

function _setPermissionsManager(address newFrictionlessPermissionsManager_) internal;

_setComplianceFactory

Impl of the setting of the compliance factory

function _setComplianceFactory(address newComplianceFactory_) internal;

_checkZeroAddr

Verifies if an address is a zero address

function _checkZeroAddr(address addrToCheck_, string memory addrName_) internal pure;

_onlyBoundCompliance

Verifies if the compliance_ address supplied is bound as per the mapping

function _onlyBoundCompliance(address compliance_) internal view virtual;

_onlyValidCompliance

Verifies if the compliance_ address supplied is valid

function _onlyValidCompliance(address compliance_) internal view;

_onlyApprovedCompliance

Verifies if the msg.sender is a valid modular compliance

function _onlyApprovedCompliance() internal view;

_getTokenBound

Returns the address of the IToken bound by this compliance

function _getTokenBound(address compliance_) internal view returns (address);

_hasClaim

Determine if a claim is present for a given userAddress and userType

function _hasClaim(address userAddress_, IFrictionlessPermissionsManager.FrictionlessPermissionedUser userType_)
    internal
    view
    virtual
    returns (bool);

Parameters

Name
Type
Description

userAddress_

address

the address if the users wallet

userType_

IFrictionlessPermissionsManager.FrictionlessPermissionedUser

the type of the user as defined by the enumeration IFrictionlessPermissionsManager.FrictionlessPermissionedUser

AbstractFeeModule

Inherits: IAbstractFeeModule

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.

State Variables

ZERO_FEES_IN_BPS

Use SafeERC20 for any ERC20 token in the conversion

represents 0 bps in fees (the minima of fees or 0%)

MAX_FEES_IN_BPS

represents 10000 bps in fees (the maxima of fees or 100%)

_feesInfo

Functions

getFeeInfo

getFeeInBps

getFeeRecipient

calculateFeeAmount

_setTokenFee

Shouldnt arrise due to validation, but being doubly sure, we can't compute incorrect fees.

_transferFees

_validateFeeInfo

Validates the FeeInfo, specifically validates the non zero address of the feeRecipientAddr and the range for the feeInBps (0 to MAX_FEES_IN_BPS).

Parameters

ERC20 Swaps

ERC20 Swaps were designed by the developers in the Frictionless protocol to risk off permissionless stablecoins such as USDC or USDT.

Permissionless are a great innovation from the crypto markets which were designed for permissionless crypto referencing to US Dollars, however handling stablecoins for traditional institutional partners is still a risky proposition.

Using the ERC20 Converter contracts, FrictionlessFundDepositTokens can be converted to/from stablecoins using the Frictionless protocol to help Managers accept stablecoins whilst off-loading their associated risks, such as de-peg events, underlying community bank reliance and liquidity risks.

The PROTOCOL_TREASURY manages the on/off ramp of the ERC20 stablecoin, such as USDC/USDT within its fund structures of FRICTIONLESS MARKETS SECURITIES FT.

The availability of a valid configured ERC20 token for conversion to/from FrictionlessFundDepositToken along with the associated fees is transparent, any market participant may query the smart contract.

The principle of an ERC20 Swap is simple.

  1. The PROTOCOL_ADMIN defines the valid token pairs which are convertible on a 1:1 basis.

  2. Fees can be optionally defined for the conversion to/from the ERC20 token.

  3. The holder (Investor) of ERC20 tokens invokes the convertFromERC20function of the smart contract, the ERC20 tokens are sent to the PROTOCOL_TREASURY and a matching amount of FrictionlessFundDepositToken is minted and sent to the holder (Investor).

  4. If the Investor wishes to convert their FrictionlessFundDepositToken to a valid configured ERC20 token, such as USDC/USDT, then they can invoke the convertToERC20function of the smart contract. In this case, the PROTOCOL_TREASURY will receive the FrictionlessFundDepositToken and burn it, transferring the matching amount of ERC20 (less any fees) to the Investor.

An example of two live ERC20 swaps on the Avalanche C-Chain are;

In these swaps, you can observe the collection of optional fees and the atomic settlement of the swap of the fsUSD tokens with USDC into the PROTOCOL_TREASURY.

Deployments

Always check that the smart contracts you interact with are valid contracts issued by the Frictionless Markets Protocol Administrator.

The PROTOCOL_ADMIN address is 0x55749224f94d79687Ba3955db2180d7C5D7D2409

Any other address purporting to offer the Frictionless protocol is not valid.

If you have any queries or wish to report any suspected issues, please contact the protocol admin team via protocol_admin@frictionless.markets

Deployed Contracts

Frictionless FX Swaps

Frictionless FX Swaps enable Investors to invest instantly, securely and risk-free at super low cost in multiple currencies.

The FX Swap contracts in the Frictionless protocol provide an instant/atomic swap of a currency pair at a quoted spot or forward rate.

Frictionless FX Swaps remove the complexity of investing in multi-currency, whilst providing ultimate flexibility and transparency of FX rates and settlement.

FX Swaps work by automating the treasury operations in an FX transaction, namely:

  1. Establishment of optional FX fees to be paid by the seller of currency A,

  2. Utilization of the buying rate for currency Z in the swap. The rate utilized in the Frictionless protocol is obtained from our FX partners, the Frictionless Markets team support both spot and forward rates for FX Swaps offering clients the ultimate flexibility and transparency in FX swaps.

  3. Execution of the swap as a single atomic transaction whereby currency A and currency Z are burned and minted from/to two counterparties with the automatic collection of optional fees. This operation can only be directed by the PROTOCOL_TREASURY to avoid market manipulation of FX rates.

In this FX Swap USD was sold for 5,000 EUR. The rate used was a spot rate provided to the Frictionless Markets team. In the block explorer, you can see the collection of fees, burn of fsUSD and mint of fsEUR. The swap and fee collection ran as a single atomic transaction and cost 0.80 USD to execute on the Avalanche C-Chain.

Overview

Release v2.0.0 of the Frictionless Markets APIs built on OpenAPI specification on confidential compute cluster to ISO-27001 and SOC-2 specifications are due for release on Jan 24th 2024 (24/1/24).

IFrictionlessAttestationManager

Author: DEFYCA Labs S.à.r.l

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.

The IFrictionlessAttestationManager See the flow and description of the attestation workflow in the diagram at https://gitlab.com/dfyclabs/protocol/dfyclabs-tokens/-/raw/main/docs/img/frictionless-fund-deposit-flow-attestation.png

Functions

updateAttestationToken

Update the token address of the FrictionlessFundDepositToken for the currency_ and iban_ pair.

Parameters

confirmAttestation

Confirm the attestation by signing the signature, this is the proof of the attestation by the PERMISSIONED_FUND_ACCOUNTANT

Parameters

minBalance

Get the minimum balance amount configured, for which an attestation can be run. If the balance of the attestation is below the value configured, the error will be thrown. The minimum allowed is 10_000 or 0.01

Returns

minWindow

Get minimum time (reportEnd - reportStart) in blocktime for which an attestation can be run. Typically this is 1 hour, and dependent on the availability of transaction data in the underlying fund account as specified by the IBAN. The minimum allowed is 300 seconds.

Returns

maxWindow

Get maximum time (reportEnd - reportStart) in blocktime for which an attestation can be run. Typically this is 30 days, aligned with the reporting as per regulation for the underlying fund and issuer of the deposit token. The maximum allowed is 365 days.

Returns

getAccountAttestationDataKeys

Retrieves the keys of attestation data associated with a specific account identified by IBAN and currency.

Parameters

Returns

getAccountLastAttestationData

Retrieves the last attestation data associated with a specific account identified by IBAN and currency.

Parameters

Returns

getAccountLastAttestationDataKey

Retrieves the key of the last attestation data associated with a specific account identified by IBAN and currency.

Parameters

Returns

getAttestationData

Retrieves attestation data by the attestation data key.

Parameters

Returns

getTokenAddress

Get the valid FrictionlessFundDepositToken for the currency_ and iban_ pair.

Parameters

Returns

getAttestationDataHash

Mint a new attestation, it returns hash of attestation data to sign by the PERMISSIONED_FUND_ACCOUNTANT

Parameters

Returns

getAccountAttestationKey

Retrieves the attestation data key associated with a specific account identified by currency and IBAN.

Parameters

Returns

Events

FrictionlessFundDepositAttestationTokenUpdated

Emitted when the FrictionlessFundDepositToken is updated in the IFrictionlessAttestationManager.

FrictionlessFundDepositAttestationConfirmed

Event emitted upon the confirmation of a FrictionlessFundDepositToken in the IFrictionlessAttestationManager

Errors

FrictionlessAttestationManagerCallerNotAProtocolTreasury

thrown if msg.sender address is not a PROTOCOL_TREASURY, during updateAttestationToken

FrictionlessAttestationManagerTokenZeroAddress

thrown if tokenAddress_ address is a zero address, during updateAttestationToken

FrictionlessAttestationManagerPermissionsZeroAddress

thrown if permissionManagerAddr_ address is a zero address, during init

FrictionlessAttestationManagerInvalidToken

thrown if the FrictionlessFundDepositToken has not been registered for the IBAN, currency pair.

FrictionlessAttestationManagerInvalidReport

thrown if the passed AttestationData report is invalid.

FrictionlessAttestationManagerBalanceTooLow

thrown if the attestation balance is too small, below the configurable amount.

FrictionlessAttestationManagerDuplicateLastTxHash

thrown if the last transaction hash for the attestation has already been used, this avoids duplicate attestations.

FrictionlessAttestationManagerInvalidAttestationSigner

thrown if the attestation cannot be confirmed, meaning the signed attestation cannot be verified.

Structs

AttestationData

struct to hold attestation data, which is designed to provide the most recent attestation of balance and verified last transaction in an attestation window.

AccountAttestationData

struct to hold account attestation data

IFrictionlessERC20ConverterManager

Inherits: IAbstractFeeModule

Author: DEFYCA Labs S.à.r.l

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.

Interface defining the frictionless conversion and atomic swapping of ERC-20 tokens for FrictionlessFundDepositToken on the Frictionless protocol. The conversion of tokens is considered frictionless as the protocol does not impose any fee structures on the conversion itself.

Functions

pause

See {PausableUpgradeable-_pause}

unpause

See {PausableUpgradeable-_unpause}

setConvertTokensFees

Set the conversion fees for the 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).

Parameters

setConvertTokensFee

Set the conversion fees for the token pair using the tokenFeeKey_. 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).

Parameters

removeFrictionlessTokensConvertInfo

Removes the conversion fees for the token pair using the tokenFeeKey_. Fees can only be set by the Owner (PROTOCOL_ADMIN).

Parameters

addFrictionlessTokensConvertInfo

Sets the mapping for the convertible tokens in the contract, calling this will add a new conversion pair to the contract.

Parameters

convertFromERC20

Converts from an ERC20 token to a FrictionlessFundDepositToken, using the safe precision conversion. The ERC20 token is transferred to configured treasuryAddress in the conversion and the minted FrictionlessFundDepositToken is sent to the msg.sender

Parameters

convertFromERC20

Converts from an ERC20 token to a FrictionlessFundDepositToken, using the safe precision conversion. The ERC20 token is transferred to configured treasuryAddress in the conversion and the minted FrictionlessFundDepositToken is sent to the convertedTokensRecipient_

Parameters

Returns

convertToERC20

Converts to an ERC20 token from a FrictionlessFundDepositToken, using the safe precision conversion. The FrictionlessFundDepositToken is burned in the conversion and the ERC20 is sent to the msg.sender from the treasuryAddress.

Parameters

Returns

convertToERC20

Converts to an ERC20 token from a FrictionlessFundDepositToken, using the safe precision conversion. The FrictionlessFundDepositToken is burned in the conversion and the ERC20 is sent to the convertedTokensRecipient_ from the treasuryAddress.

Parameters

Returns

getConvertTokenInfo

Returns the FrictionlessTokensConvertInfo for the given conversion key

Parameters

Returns

getConvertTokenKeysByToken

Returns the conversion keys for the given tokenAddr_

Parameters

Returns

getConvertTokenKeysCountByToken

Returns the count of conversion keys for the given tokenAddr_

Parameters

Returns

getConvertTokenInfosByToken

Returns the FrictionlessTokensConvertInfo for the given tokenAddr_

Parameters

Returns

isTokenSupported

Returns true if the token specified by the tokenAddr_ has been registered as a valid convertible pair.

Parameters

Returns

isTokenPairSupported

Returns true if the token pair specified have been registered as a valid convertible pair.

Parameters

Returns

isConvertTokenKeySupported

Returns true if the conversion key is supported.

Parameters

Returns

getConvertTokensKey

Returns the conversion key for the given token pair.

Parameters

Returns

Events

FrictionlessTokensConverted

Event emitted when a successful conversion occurs between an ERC20 and a FrictionlessFuncDepositToken.

Errors

FrictionlessERC20ConverterManagerInvalidTokenConvertInfo

thrown during addFrictionlessTokensConvertInfo if the tokensConvertInfoArr_ contains zero addresses

FrictionlessERC20ConverterManagerUnableToUpdateConvertInfo

thrown during addFrictionlessTokensConvertInfo if the tokensConvertInfoArr_ cannot be updated

FrictionlessERC20ConverterManagerUnsupportedPair

FrictionlessERC20ConverterManagerInvalidTokensAmountAfterConversion

thrown during a convert to/from an ERC20 if the conversion resolves to zero

FrictionlessERC20ConverterManagerIdenticalAddresses

thrown during a convert to/from an ERC20 if the conversion is attempted for the same token

FrictionlessERC20ConverterManagerZeroAddress

thrown if the IFrictionlessERC20ConverterManager is configured as a zero address

Structs

FrictionlessTokensConvertInfo

Struct to represent the conversion between an ERC20 token and a FrictionlessFundDepositToken on the Frictionless protocol

Name
Type
Description

The Frictionless protocol is designed and built on the , for public-permissioned issuance, trade and settlement of private markets digital securities in compliance with the blockchain & securitization laws of Luxembourg.

The network is the Frictionless Markets Treasury Chain, which means that issuances and settlement of Frictionless tokens are carried out on Avalanche.

The Frictionless has deployed at the following contract addresses.

The Frictionless protocol contracts are deployed at the following addresses on Avalanche.

Contract Name
Address

Built on cash custody with G-SIB banking providers and FX partners in the EU, the list of supported currencies and currency pairs is maintained in our listing.

An example of a live FX Swap on the Avalanche C-Chain is at .

Please check back with us or watch for announcements on our socials and .

The Frictionless platform is built on a microservice pattern, deployed on Confidential Google clusters for dedicated ISO-27001 secured environments, the stack is built to standard and interacts with the Frictionless via our internal proprietary Frictionless Chain Service built over the massively scalable and .

Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description

Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Git Source
Git Source
Git Source
Git Source
Git Source
Git Source
uint256 public constant ZERO_FEES_IN_BPS = 0;
uint256 public constant MAX_FEES_IN_BPS = 10000;
mapping(bytes32 => FeeInfo) private _feesInfo;
function getFeeInfo(bytes32 tokenFeeKey_) public view override returns (FeeInfo memory);
function getFeeInBps(bytes32 tokenFeeKey_) public view override returns (uint256);
function getFeeRecipient(bytes32 tokenFeeKey_) public view override returns (address);
function calculateFeeAmount(uint256 tokensAmount_, uint256 feeInBps_)
    public
    pure
    override
    returns (uint256 feeAmount_);
function _setTokenFee(bytes32 feeKey_, FeeInfo memory feeInfo_) internal;
function _transferFees(bytes32 feeKey_, IERC20 token_, address tokenSender_, uint256 tokensAmount_)
    internal
    returns (uint256);
function _validateFeeInfo(FeeInfo memory feeInfo_) internal pure;

feeInfo_

FeeInfo

the FeeInfo to validate. throws AbstractFeeModuleInvalidFeeRecipient if the feeRecipientAddr is a zero address throws AbstractFeeModuleInvalidFee if the feeInBps is not in the valid range (ZERO_FEES_IN_BPS to MAX_FEES_IN_BPS)

function updateAttestationToken(address tokenAddress_, string calldata iban_, string calldata currency_) external;

tokenAddress_

address

the address of deposit FrictionlessFundDepositToken

iban_

string

the IBAN associated with the FrictionlessFundDepositToken

currency_

string

the currency associated with the FrictionlessFundDepositToken throws FrictionlessAttestationManagerTokenZeroAddress if tokenAddress_ address is a zero address emits FrictionlessFundDepositAttestationTokenUpdated upon successful updating

function confirmAttestation(AttestationData calldata attestationData_, bytes calldata sig_) external;

attestationData_

AttestationData

attestation data to sign

sig_

bytes

the signature to sign by the PERMISSIONED_FUND_ACCOUNTANT throws FrictionlessAttestationManagerNotEnoughPermissions if the msg.sender does not have the role PERMISSIONED_FUND_ACCOUNTANT throws FrictionlessAttestationManagerInvalidAttestation if the attestation cannot be confirmed, meaning the signed attestation cannot be verified. emits FrictionlessFundDepositAttestationConfirmed upon successful signing

function minBalance() external view returns (uint256);

<none>

uint256

minimum attestation balance.

function minWindow() external view returns (uint256);

<none>

uint256

minimum attestation window.

function maxWindow() external view returns (uint256);

<none>

uint256

maximum attestation window.

function getAccountAttestationDataKeys(string calldata iban_, string calldata currency_)
    external
    view
    returns (bytes32[] memory);

iban_

string

the IBAN associated with the FrictionlessFundDepositToken

currency_

string

the currency associated with the FrictionlessFundDepositToken

<none>

bytes32[]

the array of bytes32 attestation data keys associated with the account.

function getAccountLastAttestationData(string calldata iban_, string calldata currency_)
    external
    view
    returns (AttestationData memory);

iban_

string

the IBAN associated with the FrictionlessFundDepositToken

currency_

string

the currency associated with the FrictionlessFundDepositToken

<none>

AttestationData

the AttestationData struct representing the last attestation data associated with the account.

function getAccountLastAttestationDataKey(string calldata iban_, string calldata currency_)
    external
    view
    returns (bytes32);

iban_

string

the IBAN associated with the FrictionlessFundDepositToken

currency_

string

the currency associated with the FrictionlessFundDepositToken

<none>

bytes32

the last attestation data key associated with the account.

function getAttestationData(bytes32 attestationDataKey_) external view returns (AttestationData memory);

attestationDataKey_

bytes32

the key identifying the attestation data

<none>

AttestationData

the AttestationData struct representing the attestation data associated with the given key.

function getTokenAddress(string memory iban_, string memory currency_) external view returns (address);

iban_

string

the IBAN associated with the FrictionlessFundDepositToken

currency_

string

the currency associated with the FrictionlessFundDepositToken

<none>

address

the address of the valid FrictionlessFundDepositToken for the currency_ and iban_ pair

function getAttestationDataHash(AttestationData calldata attestationData_) external view returns (bytes32);

attestationData_

AttestationData

the complete set of attestation data to for the PERMISSIONED_FUND_ACCOUNTANT to certify/sign.

<none>

bytes32

a hash of the attestationData which will be signed to confirm the attestation

function getAccountAttestationKey(string calldata currency_, string calldata iban_) external pure returns (bytes32);

currency_

string

the currency associated with the FrictionlessFundDepositToken

iban_

string

the IBAN associated with the FrictionlessFundDepositToken

<none>

bytes32

the accound attestation key.

event FrictionlessFundDepositAttestationTokenUpdated(
    bytes32 accountAttestationKey, address newTokenAddress, address oldTokenAddress
);
event FrictionlessFundDepositAttestationConfirmed(AttestationData attestationData);
error FrictionlessAttestationManagerCallerNotAProtocolTreasury(address caller);
error FrictionlessAttestationManagerTokenZeroAddress();
error FrictionlessAttestationManagerPermissionsZeroAddress();
error FrictionlessAttestationManagerInvalidToken(string iban, string currency);
error FrictionlessAttestationManagerInvalidReport(AttestationData attestationData);
error FrictionlessAttestationManagerBalanceTooLow(uint256 balance);
error FrictionlessAttestationManagerDuplicateLastTxHash(string lastTxHash);
error FrictionlessAttestationManagerInvalidAttestationSigner(address signer, bytes32 attestationHash, bytes sig);
struct AttestationData {
    address tokenAddr;
    string iban;
    string currency;
    uint256 reportStart;
    uint256 reportEnd;
    uint256 balance;
    string lastTxHash;
}
struct AccountAttestationData {
    address attestationTokenAddr;
    bytes32 lastAttestationDataKey;
    EnumerableSet.Bytes32Set allAttestationDataKeys;
}
function pause() external;
function unpause() external;
function setConvertTokensFees(address erc20Token_, address fundDepositToken_, FeeInfo calldata feeInfo_) external;

erc20Token_

address

the address of the ERC20 token.

fundDepositToken_

address

the address of the FundDeposit token.

feeInfo_

FeeInfo

The fees associated with the conversion of the token pair. throws FrictionlessERC20ConverterManagerUnsupportedPair if the token pair is not valid throws AbstractFeeModuleInvalidFeeRecipient if the feeRecipientAddr is a zero address 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 in either set of fees

function setConvertTokensFee(bytes32 tokenFeeKey_, FeeInfo calldata feeInfo_) external;

tokenFeeKey_

bytes32

the tokenFeeKey as determined getConvertTokensKey

feeInfo_

FeeInfo

The fees associated with the conversion of the token pair. throws FrictionlessERC20ConverterManagerUnsupportedPair if the token pair is not valid throws AbstractFeeModuleInvalidFeeRecipient if the feeRecipientAddr is a zero address 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 in either set of fees

function removeFrictionlessTokensConvertInfo(address erc20Token_, address fundDepositToken_) external;

erc20Token_

address

the address of the ERC20 token.

fundDepositToken_

address

the address of the FundDeposit token.

function addFrictionlessTokensConvertInfo(FrictionlessTokensConvertInfo[] calldata tokensConvertInfoArr_) external;

tokensConvertInfoArr_

FrictionlessTokensConvertInfo[]

the array of token conversions to set. throws FrictionlessERC20ConverterManagerInvalidTokenConvertInfo if the tokensConvertInfoArr_ contains zero addresses throws FrictionlessERC20ConverterManagerUnableToUpdateConvertInfo if the tokensConvertInfoArr_ cannot be updated

function convertFromERC20(address erc20Token_, address fundDepositToken_, uint256 erc20TokensAmount_)
    external
    returns (uint256);

erc20Token_

address

the address of the ERC20 token to convert from, which must exist in a FrictionlessTokensConvertInfo in order to succeed.

fundDepositToken_

address

the address of the FundDeposit token to convert to, which must exist in a FrictionlessTokensConvertInfo in order to succeed.

erc20TokensAmount_

uint256

the amount of tokens to convert throws FrictionlessERC20ConverterManagerInvalidTokenType if the tokenAddr_ is not a configured convertible erc20Token throw FrictionlessERC20ConverterManagerInvalidTokensAmountAfterConversion if the conversion resolves to zero Emits the event FrictionlessTokensConverted detailing the full convertibility

function convertFromERC20(
    address erc20Token_,
    address fundDepositToken_,
    address convertedTokensRecipient_,
    uint256 erc20TokensAmount_
) external returns (uint256);

erc20Token_

address

the address of the ERC20 token to convert from, which must exist in a FrictionlessTokensConvertInfo in order to succeed.

fundDepositToken_

address

the address of the FundDeposit token to convert to, which must exist in a FrictionlessTokensConvertInfo in order to succeed.

convertedTokensRecipient_

address

the destination of the converted FrictionlessFundDepositToken

erc20TokensAmount_

uint256

the amount of tokens to convert

<none>

uint256

the amount of FrictionlessFundDepositToken converted throws FrictionlessERC20ConverterManagerInvalidTokenType if the tokenAddr_ is not a configured convertible erc20Token throw FrictionlessERC20ConverterManagerInvalidTokensAmountAfterConversion if the conversion resolves to zero Emits the event FrictionlessTokensConverted detailing the full convertibility

function convertToERC20(address erc20Token_, address fundDepositToken_, uint256 fundDepositTokensAmount_)
    external
    returns (uint256);

erc20Token_

address

fundDepositToken_

address

the address of the FrictionlessFundDepositToken token to convert from, which must exist in a FrictionlessTokensConvertInfo in order to succeed.

fundDepositTokensAmount_

uint256

the amount of tokens to convert

<none>

uint256

the amount of ERC20 converted throws FrictionlessERC20ConverterManagerInvalidTokenType if the tokenAddr_ is not a configured convertible fundDepositToken throw FrictionlessERC20ConverterManagerInvalidTokensAmountAfterConversion if the conversion resolves to zero Emits the event FrictionlessTokensConverted detailing the full convertibility

function convertToERC20(
    address erc20Token_,
    address fundDepositToken_,
    address convertedTokensRecipient_,
    uint256 fundDepositTokensAmount_
) external returns (uint256);

erc20Token_

address

fundDepositToken_

address

the address of the FrictionlessFundDepositToken token to convert from, which must exist in a FrictionlessTokensConvertInfo in order to succeed.

convertedTokensRecipient_

address

the destination of the converted ERC20 token

fundDepositTokensAmount_

uint256

the amount of tokens to convert

<none>

uint256

the amount of ERC20 converted throws FrictionlessERC20ConverterManagerInvalidTokenType if the tokenAddr_ is not a configured convertible fundDepositToken throw FrictionlessERC20ConverterManagerInvalidTokensAmountAfterConversion if the conversion resolves to zero Emits the event FrictionlessTokensConverted detailing the full convertibility

function getConvertTokenInfo(bytes32 convertInfoKey_) external view returns (FrictionlessTokensConvertInfo memory);

convertInfoKey_

bytes32

the address of the token to validate.

<none>

FrictionlessTokensConvertInfo

the FrictionlessTokensConvertInfo for the given conversion key

function getConvertTokenKeysByToken(address tokenAddr_) external view returns (bytes32[] memory);

tokenAddr_

address

the address of the token to validate.

<none>

bytes32[]

the conversion keys arr for the given tokenAddr_

function getConvertTokenKeysCountByToken(address tokenAddr_) external view returns (uint256);

tokenAddr_

address

the address of the token to validate.

<none>

uint256

the count of conversion keys arr for the given tokenAddr_

function getConvertTokenInfosByToken(address tokenAddr_)
    external
    view
    returns (FrictionlessTokensConvertInfo[] memory);

tokenAddr_

address

the address of the token to validate.

<none>

FrictionlessTokensConvertInfo[]

the FrictionlessTokensConvertInfo for the given tokenAddr_

function isTokenSupported(address tokenAddr_) external view returns (bool);

tokenAddr_

address

the address of the token to validate.

<none>

bool

true if the token specified by the tokenAddr_ has been registered as a valid convertible pair, otherwise false

function isTokenPairSupported(address erc20Token_, address fundDepositToken_) external view returns (bool);

erc20Token_

address

the address of the ERC20 token.

fundDepositToken_

address

the address of the FundDeposit token.

<none>

bool

true if the token pair specified have been registered as a valid convertible pair, otherwise false

function isConvertTokenKeySupported(bytes32 convertTokenKey_) external view returns (bool);

convertTokenKey_

bytes32

the conversion key as defined by getConvertTokensKey

<none>

bool

true if Returns true if the conversion key is supported, otherwise false

function getConvertTokensKey(address token0_, address token1_) external pure returns (bytes32);

token0_

address

the first token in the convertible pair

token1_

address

the second token in the convertible pair

<none>

bytes32

the conversion key for the given token pair throws FrictionlessERC20ConverterManagerIdenticalAddresses if both tokens are identical throws FrictionlessERC20ConverterManagerZeroAddress if the tokens are a zero address

event FrictionlessTokensConverted(
    address fromToken, address toToken, address toTokensRecipient, uint256 fromAmount, uint256 toAmount
);
error FrictionlessERC20ConverterManagerInvalidTokenConvertInfo(FrictionlessTokensConvertInfo);
error FrictionlessERC20ConverterManagerUnableToUpdateConvertInfo(FrictionlessTokensConvertInfo);
error FrictionlessERC20ConverterManagerUnsupportedPair(address, address);
error FrictionlessERC20ConverterManagerInvalidTokensAmountAfterConversion();
error FrictionlessERC20ConverterManagerIdenticalAddresses();
error FrictionlessERC20ConverterManagerZeroAddress();
struct FrictionlessTokensConvertInfo {
    address erc20Token;
    address fundDepositToken;
    address treasuryAddress;
}
Git Source
USDC swapped for fsUSD
fsUSD swapped for USDC
Avalanche C-Chain
Avalanche C-Chain
PROTOCOL_ADMIN
Frictionless Institutional Deposit Tokens
https://snowtrace.io/tx/0x115570645b70ac573e9ce2f2d4e03f0bd71f502e4dd7019bab6a155417138851?chainId=43114
LinkedIn
Kubernetes
OpenAPI
smart contracts
Neo4J
graphQL
Git Source
Git Source

FrictionlessFundDepositToken

FrictionlessOnChainAssetToken

FrictionlessDigitalSecurityToken

FrictionlessPermissionsManager

FrictionlessTreasuryManager

FrictionlessTransferManager

FrictionlessERC20ConverterManager

FrictionlessAttestationManager

FrictionlessFXSwap

Frictionless Markets APIs

Release v2.0.0 of the Frictionless Markets APIs built on OpenAPI specification on confidential compute cluster to ISO-27001 and SOC-2 specifications are due for release on Jan 24th 2024 (24/1/24).

Institutional Deposit Tokens

Always check that the smart contracts you interact with are valid contracts issued by the Frictionless Markets Protocol Administrator.

The PROTOCOL_ADMIN address is 0x55749224f94d79687Ba3955db2180d7C5D7D2409

Any other address purporting to offer the Frictionless protocol is not valid.

If you have any queries or wish to report any suspected issues, please contact the protocol admin team via protocol_admin@frictionless.markets

Deployed Institutional Deposit Tokens

Structure of Frictionless Institutional Deposit Tokens

The Frictionless Institutional Deposit Token (FricitonlessFundDepositToken) is designed as a method of recording a FIAT contribution for a PERMISSIONED_INVESTOR into a listed fund on the Frictionless protocol.

Neither Frictionless Markets nor its parent company DEFYA HOLDINGS nor any subsidiaries actively manage currency contributions for Investors or permissioned participants in the protocol. All investment decisions must made exclusively by Investors or their appointed wealth advisors or agents.

The Frictionless Markets team passively manages a collection of open-ended fund structures which are designed to securitise the currency contributions, so thereafter these tokens can be used to record payment, settlement and trade in tokenized securities from funds listed on the Frictionless protocol.

The following high-level diagram describes the main participants and their high-level interaction with the protocol.

License

Security & Access

Release v2.0.0 of the Frictionless Markets APIs built on OpenAPI specification on confidential compute cluster to ISO-27001 and SOC-2 specifications are due for release on Jan 24th 2024 (24/1/24).

Please check back with us or watch for announcements on our socials and .

The attestations for Frictionless Institutional Deposit Tokens are proved by the PERMISSIONED_FUND_ACCOUNTANT (Creatrust Luxembourg) and are publicly available at

The Frictionless has deployed the following FrictionlessFundDepositTokens.

The Frictionless Institutional Deposit Tokens are deployed at the following token addresses on Avalanche.

Currency
Frictionless Token Address

USD

EUR

GBP

CHF

HKD

SGD

JPY

AED

For more information on the legal structure of the FRICTIONLESS MARKETS SECURITIES FT, consult our

The Frictionless Markets APIs are offered under commercial license terms if you wish to license the technology including the secure APIs, GraphQL data store, UI and automation services, please contact the team at or via profile.

Please check back with us or watch for announcements on our socials and .

0xbF99d9472eC0cb97cb2bCaD5e9564f3844347604
0x08b93133C214ad306d4e16b88b6703911b29E77f
0xA2Db6E187b34BDfb8C1592B53Bfbe242Ae5c5728
0x684759399AC55804603CB84A9210686B52f4A627
0xD6bf0870C69a23d0f25238Dba7DBF112Afbef344
0xB07DDDcB7501Da7064adC68aDc5533d9C41033dC
0xb33a34Cef89398195739ad5566B314F6A50FE233
0x143F369d362E6F9Bb2b9282c48e55d19f5EB5305
0xA6dE189d26428A285c0d56dfCaFF8E11F664B9fC
LinkedIn
https://snowtrace.io/address/0x143F369d362E6F9Bb2b9282c48e55d19f5EB5305
PROTOCOL_ADMIN
legal & fund documentation
https://www.frictionless.markets/
LinkedIn
LinkedIn
Frictionless U.S. Dollar - fsUSD
Frictionless Euro - fsEUR
Frictionless Bristish Pound Sterling - fsGBP
Frictionless Swisss Franc - fsCHF
Frictionless Hong Kong Dollar - fsHKD
Frictionless Signapore Dollar - fsSGD
Frictionless Japanese Yen - fsJPY
Frictionless Emirati Dirham - fsAED

IFrictionlessFXSwap

Inherits: IAbstractFeeModule

Author: DEFYCA Labs S.à.r.l

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.

Interface defining the frictionless conversion and atomic swapping of any FrictionlessFundDepositToken currency pair on the Frictionless protocol. The FX rates are set from the live spot & forward FX partners on the protocol.

Functions

setFXDeskFeeAddr

Sets the address of the FXDesk fee recipient Only Owner (PROTOCOL_ADMIN) can call this function

function setFXDeskFeeAddr(address newFXDeskFeeAddr_) external;

Parameters

Name
Type
Description

newFXDeskFeeAddr_

address

The new address of the FXDesk fee recipient

setSwapFees

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).

function setSwapFees(
    FrictionlessTokenFXFeeInfo calldata token0FeeInfo_,
    FrictionlessTokenFXFeeInfo calldata token1FeeInfo_
) external;

Parameters

Name
Type
Description

token0FeeInfo_

FrictionlessTokenFXFeeInfo

The fees associated with the token0 (first token) in the token pair during the swap.

token1FeeInfo_

FrictionlessTokenFXFeeInfo

The fees associated with the token1 (second token) in the token pair during the swap. throws FrictionlessFXSwapInvalidTokenAddresses if the token addresses are invalid. throws FrictionlessFXSwapInvalidFeeRecipientAddr if the feeRecipientAddr doesn't equal to the fxDeskFeeAddr. throws AbstractFeeModuleInvalidFeeRecipient if the feeRecipientAddr is a zero address 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

setTokenFee

Set the fee associated with the swap of a Token and manages the mapping of the key to this set of Fees. Can only be set by the Owner (PROTOCOL_ADMIN).

function setTokenFee(bytes32 tokenFeeKey_, FrictionlessTokenFXFeeInfo calldata tokenFeeInfo_) external;

Parameters

Name
Type
Description

tokenFeeKey_

bytes32

The key, generated by the function getTokenFeeKey, which is used to map a specific swap polarity for tokens.

tokenFeeInfo_

FrictionlessTokenFXFeeInfo

The fees associated with the swap of token, used in the calculation and disbursement of fees during swap of a token pair. throws FrictionlessFXSwapInvalidTokenAddresses if the token addresses are invalid. throws FrictionlessFXSwapInvalidFeeRecipientAddr if the feeRecipientAddr doesn't equal to the fxDeskFeeAddr. throws AbstractFeeModuleInvalidFeeRecipient if the feeRecipientAddr is a zero address 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

swapTokens

Swaps tokens between addresses at a specified exchange rate Only PROTOCOL_TREASURY can call this function

function swapTokens(
    address sellingTokenAddr_,
    address buyingTokenAddr_,
    address tokenSender_,
    address tokenRecipient_,
    uint256 buyingTokensAmount_,
    uint256 buyingTokenExchangeRate_
) external;

Parameters

Name
Type
Description

sellingTokenAddr_

address

The address of the token to be sold

buyingTokenAddr_

address

The address of the token to be bought

tokenSender_

address

The address of the sender initiating the swap

tokenRecipient_

address

The address where the bought tokens will be sent

buyingTokensAmount_

uint256

The amount of tokens being bought

buyingTokenExchangeRate_

uint256

The exchange rate of the token being bought to the token being sold

fxDeskFeeAddr

Retrieves the address of the FXDesk fee recipient

function fxDeskFeeAddr() external view returns (address);

Returns

Name
Type
Description

<none>

address

The address of the FXDesk fee recipient

treasuryManager

Retrieves the Frictionless Treasury Manager contract

function treasuryManager() external view returns (IFrictionlessTreasuryManager);

Returns

Name
Type
Description

<none>

IFrictionlessTreasuryManager

The address of the Frictionless Treasury Manager contract

permissionManager

Retrieves the Frictionless Permissions Manager contract

function permissionManager() external view returns (IFrictionlessPermissionsManager);

Returns

Name
Type
Description

<none>

IFrictionlessPermissionsManager

The address of the Frictionless Permissions Manager contract

getSwapFeesInfo

get the tokenFeeInfo set for the fees associated per token in an exchange.

function getSwapFeesInfo(address token0_, address token1_) external view returns (FeeInfo memory, FeeInfo memory);

Parameters

Name
Type
Description

token0_

address

the address of the first token in an exchange

token1_

address

the address of the second token in an exchange

Returns

Name
Type
Description

<none>

FeeInfo

FeeInfo set for the fees associated per token in an exchange.

<none>

FeeInfo

getSwapFeeKeys

Generates keys based on the packed encoding of the addresses of sets of tokens using the keccak256 hashing function. Used to store tokenFees in mappings.

function getSwapFeeKeys(address token0_, address token1_) external view returns (bytes32, bytes32);

Parameters

Name
Type
Description

token0_

address

the address of the token 0 in a transfer fee calculation

token1_

address

the address of the token 1 in a transfer fee calculation

Returns

Name
Type
Description

<none>

bytes32

keys based on the packed encoding of the addresses of sets of tokens using the keccak256 hashing function.

<none>

bytes32

getTokenFeeKey

Generates a key based on the packed encoding of the addresses of both tokens using the keccak256 hashing function. Used to store tokenFees in mappings.

function getTokenFeeKey(address token0_, address token1_) external view returns (bytes32);

Parameters

Name
Type
Description

token0_

address

the address of the token 0 in a transfer fee calculation

token1_

address

the address of the token 1 in a transfer fee calculation

Returns

Name
Type
Description

<none>

bytes32

generates a key based on the packed encoding of the addresses of both tokens using the keccak256 hashing function.

getSellingTokensAmount

Calculates the amount of selling tokens based on the buying amount and exchange rate

function getSellingTokensAmount(uint256 buyingTokensAmount_, uint256 buyingTokenExchangeRate_)
    external
    view
    returns (uint256);

Parameters

Name
Type
Description

buyingTokensAmount_

uint256

The amount of tokens being bought

buyingTokenExchangeRate_

uint256

The exchange rate of the token being bought to the token being sold

Returns

Name
Type
Description

<none>

uint256

The amount of selling tokens

Events

FrictionlessFXTokensSwapped

Event emitted upon successful token swaps

event FrictionlessFXTokensSwapped(
    address sellingTokenAddr,
    address buyingTokenAddr,
    address tokenSender,
    address tokenRecipient,
    uint256 sellingTokensAmount,
    uint256 buyingTokensAmount,
    uint256 buyingTokenExchangeRate
);

Errors

FrictionlessFXSwapInvalidTokenAddresses

error thrown during setSwapFees if token adresses are invalid (zero addresses, equals addresses and etc.).

error FrictionlessFXSwapInvalidTokenAddresses(address token0, address token1);

FrictionlessFXSwapInvalidFeeRecipientAddr

error thrown during setSwapFees, setTokenFee and swapTokens if the fxDeskFeeRecipient doesn't equal to the stored fxDeskFeeAddr

error FrictionlessFXSwapInvalidFeeRecipientAddr(address newFeeRecipient);

FrictionlessFXSwapNotEnoughPermissions

error thrown during swapTokens if the msg.sender is not a PROTOCOL_TREASURY.

error FrictionlessFXSwapNotEnoughPermissions();

Structs

FrictionlessTokenFXFeeInfo

Structure representing token fee information including the token address and fee information

struct FrictionlessTokenFXFeeInfo {
    address tokenAddr;
    uint256 feeAbsoluteLimit;
    FeeInfo feeInfo;
}

Git Source
Schematic of Frictionless transfer of tokens by the PROTOCOL_TREASURY
Schematic of Frictionless transfer of tokens bilaterally by Investors
Arctitecture of the Frictionless Fee Module
Schematic of a Frictionless ERC20 (USDC stablecoin) Swap
Frictionless ERC20 Swap - USDC for fsUSD with automatic fee collection
Frictionless ERC20 Swap - fsUSDC for USDC with no fee collection
Built on Avalanche!
Schematic a Frictionless FX Swap
Live FX Swap - fsUSD for fsEUR (spot rate from Alpha FX)
High Level Architecture of Frictionless Protocol & APIs
Passive Securitization Structure of Frictionless Institutional Deposit Tokens

IFrictionlessTreasuryManager

Author: DEFYCA Labs S.à.r.l

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.

The IFrictionlessTreasuryManager is responsible for all token operations, minting, transferring and burning in the Frictionless protocol. The tokens and their lifecycles are defined in the public README for the Frictionless protocol at https://gitlab.com/dfyclabs/protocol/dfyclabs-tokens/-/tree/main?ref_type=heads#tokens-overview

Functions

setTokensInitData

Sets and associates the implementation authority with the associated token type

function setTokensInitData(FrictionlessTokenInitData[] calldata initDataArr_) external;

Parameters

Name
Type
Description

initDataArr_

FrictionlessTokenInitData[]

the FrictionlessTokenInitData configuration associating the implementation authority with the associated token type.

mintFundDepositForTreasury

Mints a Fund Deposit Token in the specified currency/IBAN pair. This function is invoked to create the genesis mint of the deposit token in the PROTOCOL_TREASURY.

function mintFundDepositForTreasury(
    IFrictionlessFundDepositToken.FFDImmutableData calldata depositData,
    address treasuryAddress,
    uint256 amount
) external returns (address);

Parameters

Name
Type
Description

depositData

IFrictionlessFundDepositToken.FFDImmutableData

the immutable deposit data for the token

treasuryAddress

address

the address of the treasury, which receives the deposit tokens

amount

uint256

the amount of tokens

Returns

Name
Type
Description

<none>

address

address of the token minted emits FrictionlessTokenMinted event throws error FrictionlessTreasuryManagerInvalidDepositData if the deposit data is invalid. requires the depositData.currency to be a 3 letter currency code requires the depositData.description to be not empty requires the depositData.IBAN to be not empty

mintDigitalSecurity

Mints a FrictionlessDigitalSecurityToken as the future dated cash distribution from the underlying FrictionlessOnChainAssetToken. This function is invoked to create the genesis mint of the deposit token in the PROTOCOL_TREASURY.

function mintDigitalSecurity(
    IFrictionlessDigitalSecurityToken.FDSImmutableData memory initData,
    IFrictionlessDigitalSecurityToken.FDSMutableData memory updateData,
    uint256 amount,
    address userAddress
) external returns (address);

Parameters

Name
Type
Description

initData

IFrictionlessDigitalSecurityToken.FDSImmutableData

the immutable data for the token

updateData

IFrictionlessDigitalSecurityToken.FDSMutableData

the mutable data for the token

amount

uint256

the amount of tokens

userAddress

address

the address of the protocol user, which receives the digital security tokens

Returns

Name
Type
Description

<none>

address

address of the token minted emits FrictionlessTokenMinted event throws error FrictionlessTreasuryManagerInvalidFDSImmutableData if the initData is invalid. requires the initData.currency to be a 3 letter currency code requires the initData.onChainAssetAddress to be non 0 address

mintOnChainAsset

Mints a FrictionlessOnChainAssetToken as the representation of the asset to be securitized, fractionalized & sold. This function is invoked to create the genesis mint of the deposit token to the PERMISSIONED_CUSTODIAN.

function mintOnChainAsset(
    IFrictionlessOnChainAssetToken.FOCASpecData memory specData,
    IFrictionlessOnChainAssetToken.FOCAIssuanceData memory issuanceData,
    IFrictionlessOnChainAssetToken.FOCAUpdateData memory updateData,
    address custodianAddress
) external returns (address);

Parameters

Name
Type
Description

specData

IFrictionlessOnChainAssetToken.FOCASpecData

the immutable data for the token

issuanceData

IFrictionlessOnChainAssetToken.FOCAIssuanceData

the issuance data for the token

updateData

IFrictionlessOnChainAssetToken.FOCAUpdateData

the update data for the token

custodianAddress

address

the address of the protocol custodian, which receives the FrictionlessOnChainAssetToken

Returns

Name
Type
Description

<none>

address

address of the token minted emits FrictionlessTokenMinted event throws error FrictionlessTreasuryManagerInvalidFOCASpecData or FrictionlessTreasuryManagerInvalidFOCAIssuanceData if the specData or issuanceData is invalid.

mintTokenForUser

Used to increase the mint of a Frictionless token which already exists.

function mintTokenForUser(address token, address userAddress, uint256 amount) external;

Parameters

Name
Type
Description

token

address

the address of the token

userAddress

address

the address to min the token to

amount

uint256

the amount of tokens to mint emits FrictionlessTokenMinted event

transferToken

Used to increase the mint of a Frictionless token which already exists.

function transferToken(address token, address userAddressFrom, address userAddressTo, uint256 amount) external;

Parameters

Name
Type
Description

token

address

the address of the token

userAddressFrom

address

the address to transfer the tokens from

userAddressTo

address

the address to transfer the tokens to

amount

uint256

the amount of tokens to mint emits FrictionlessTokenTransferred event

burnToken

Used to burn an amount of Frictionless token which already exists.

function burnToken(address token, address userAddress, uint256 amount) external;

Parameters

Name
Type
Description

token

address

the address of the token

userAddress

address

the address to burn the tokens from

amount

uint256

the amount of tokens to burn emits FrictionlessTokenBurned event

getFundDepositToken

returns the address of the fund deposit token by currency and fundIBAN

function getFundDepositToken(string calldata currency_, string calldata fundIBAN_) external view returns (address);

Parameters

Name
Type
Description

currency_

string

the currency of the fund deposit token

fundIBAN_

string

the fundIBAN of the fund deposit token

Returns

Name
Type
Description

<none>

address

the address of the fund deposit token for specified currency and fundIBAN

getFundDepositTokenKey

returns fund deposit token key by currency and fundIBAN

function getFundDepositTokenKey(string memory currency_, string memory fundIBAN_) external pure returns (bytes32);

Parameters

Name
Type
Description

currency_

string

the currency of the fund deposit token you need

fundIBAN_

string

the fundIBAN of the fund deposit token you need

Returns

Name
Type
Description

<none>

bytes32

the fund deposit token key

Events

FrictionlessTokenMinted

Event emitted when a FrictionlessFundDeposit, FrictionlessDigitalSecurity or FrictionlessOnChainAsset is minted.

event FrictionlessTokenMinted(
    IBasicFrictionlessToken.FrictionlessTokenTypes tokenType,
    address token,
    string tokenName,
    string tokenSymbol,
    uint256 amount,
    address toAddress
);

FrictionlessTokenTransferred

Event emitted when a FrictionlessFundDeposit, FrictionlessDigitalSecurity or FrictionlessOnChainAsset is transferred.

event FrictionlessTokenTransferred(
    IBasicFrictionlessToken.FrictionlessTokenTypes tokenType,
    address token,
    uint256 amount,
    address fromAddress,
    address toAddress
);

FrictionlessTokenBurned

Event emitted when a FrictionlessFundDeposit, FrictionlessDigitalSecurity or FrictionlessOnChainAsset is burned.

event FrictionlessTokenBurned(
    IBasicFrictionlessToken.FrictionlessTokenTypes tokenType, address token, uint256 amount, address fromAddress
);

Errors

FrictionlessIsZeroAddress

throws if specific address is zero.

error FrictionlessIsZeroAddress(string);

FrictionlessTreasuryManagerNotAProtocolTreasury

error throw if the function caller is not a PROTOCOL_TREASURY address. Thrown during the mintFundDepositForTreasury

error FrictionlessTreasuryManagerNotAProtocolTreasury(address);

FrictionlessTreasuryManagerFundDepositTokenAlreadyExists

error throw if the FundDepositToken for specified currency and fundIBAN already exists

error FrictionlessTreasuryManagerFundDepositTokenAlreadyExists(string currency, string fundIBAN);

FrictionlessTreasuryManagerInvalidTokenInitData

error throw if the data for the token init data FrictionlessTokenInitData is invalid. Thrown during the _setTokensInitData

error FrictionlessTreasuryManagerInvalidTokenInitData(FrictionlessTokenInitData);

FrictionlessTreasuryManagerUnableToUpdateTokenInitData

error throw if the data for the token init data FrictionlessTokenInitData is already set. Thrown during the _setTokensInitData

error FrictionlessTreasuryManagerUnableToUpdateTokenInitData(IBasicFrictionlessToken.FrictionlessTokenTypes);

FrictionlessTreasuryManagerInvalidDepositData

error throw if the data for the IFrictionlessFundDepositToken is invalid. Thrown during the mintFundDepositForTreasury

error FrictionlessTreasuryManagerInvalidDepositData(IFrictionlessFundDepositToken.FFDImmutableData);

FrictionlessTreasuryManagerInvalidFDSImmutableData

error throw if the data for the IFrictionlessDigitalSecurityToken is invalid. Thrown during the mintDigitalSecurity

error FrictionlessTreasuryManagerInvalidFDSImmutableData(IFrictionlessDigitalSecurityToken.FDSImmutableData);

FrictionlessTreasuryManagerInvalidFOCASpecData

error throw if the data for the IFrictionlessDigitalSecurityToken is invalid. Thrown during the mintOnChainAsset

error FrictionlessTreasuryManagerInvalidFOCASpecData(IFrictionlessOnChainAssetToken.FOCASpecData);

FrictionlessTreasuryManagerInvalidFOCAIssuanceData

error throw if the data for the IFrictionlessDigitalSecurityToken is invalid. Thrown during the mintOnChainAsset

error FrictionlessTreasuryManagerInvalidFOCAIssuanceData(IFrictionlessOnChainAssetToken.FOCAIssuanceData);

Structs

FrictionlessTokenInitData

Structure that encapsulates both the implAuthority and the compliance for the specific token.

struct FrictionlessTokenInitData {
    address implAuthority;
    IBasicFrictionlessToken.FrictionlessTokenTypes tokenType;
}

Git Source