Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ERC: Interest Rate Swaps #178

Merged
merged 79 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
1892ea5
Add ERC: Interest Rate Swaps
Edoumou Dec 31, 2023
65dc440
Create erc-xxxx.md
Edoumou Dec 31, 2023
ecfa5dd
Update erc-template.md
Edoumou Dec 31, 2023
ff13f59
interface functions
Edoumou Dec 31, 2023
1257279
Update ERCS/erc-xxxx.md
Edoumou Dec 31, 2023
45cfe5b
Update erc-xxxx.md
Edoumou Dec 31, 2023
029cbc0
update comments
Edoumou Dec 31, 2023
a123099
small fix
Edoumou Dec 31, 2023
1036a36
expressing the benchmark in uint8
Edoumou Dec 31, 2023
4ff4f8d
Update erc-xxxx.md
Edoumou Jan 1, 2024
c869b40
add motivation section
Edoumou Jan 1, 2024
ef580da
Update the specification
Edoumou Jan 1, 2024
ec831ac
Update ERCS/erc-xxxx.md
Edoumou Jan 1, 2024
1349022
Rename erc-xxxx.md to erc-7586.md
Edoumou Jan 1, 2024
fbf4307
Shorten the description
Edoumou Jan 1, 2024
104ce6a
minor fix
Edoumou Jan 2, 2024
4836806
rename fixedRate to swapRate
Edoumou Jan 2, 2024
4ae6ef8
requires ERC721
Edoumou Jan 2, 2024
754fc79
update terminologies
Edoumou Jan 2, 2024
4db8f41
update the rationale section
Edoumou Jan 3, 2024
b49c691
fix link
Edoumou Jan 3, 2024
dca3618
Update spec
Edoumou Jan 3, 2024
4dc7fa9
update spec
Edoumou Jan 3, 2024
6a1ed07
swap param tokenization
Edoumou Jan 3, 2024
58bd40d
minor fix
Edoumou Jan 3, 2024
5dd4c78
backwards compatibility section
Edoumou Jan 3, 2024
ef1524f
add the security consideration section
Edoumou Jan 4, 2024
60734bc
minor fix
Edoumou Jan 4, 2024
fac7e39
fix
Edoumou Jan 4, 2024
5ea17b7
small fix
Edoumou Jan 4, 2024
ebbc886
exclude ERC721 inheritance
Edoumou Jan 5, 2024
7ec0811
add `isActive` and `terminateSwap` functions
Edoumou Jan 5, 2024
65e511c
add `agree` function
Edoumou Jan 5, 2024
76187bb
minor fix
Edoumou Jan 5, 2024
6fc35b6
fix
Edoumou Jan 5, 2024
104de9a
add TerminateSwap event
Edoumou Jan 5, 2024
6161a1c
small fix
Edoumou Jan 5, 2024
d0b6952
change return type for benchmark
Edoumou Jan 7, 2024
9d436c8
minor fix -remove isActive function
Edoumou Jan 10, 2024
67a3af8
Create ERC7586.sol
Edoumou Jan 10, 2024
bcd54b1
Update ERC7586.sol
Edoumou Jan 10, 2024
9273382
Create ERC20.sol
Edoumou Jan 10, 2024
c943fc7
Update ERC20.sol
Edoumou Jan 10, 2024
a94aaea
Create IERC20.sol
Edoumou Jan 10, 2024
f351354
Update IERC20.sol
Edoumou Jan 10, 2024
1465458
Update ERC20.sol
Edoumou Jan 10, 2024
586568b
add reference implementation
Edoumou Jan 10, 2024
33cf391
Update erc-7586.md
Edoumou Jan 10, 2024
7776598
Update erc-7586.md
Edoumou Jan 10, 2024
4191bc8
change status
Edoumou Jan 19, 2024
22d45cb
Update ERC20.sol
Edoumou Jan 23, 2024
c9d8a53
Update ERC7586.sol
Edoumou Jan 23, 2024
3f65f10
Merge branch 'master' into patch-1
Edoumou Jan 24, 2024
5300d57
Merge branch 'master' into patch-1
Edoumou Feb 20, 2024
5f87cbf
Update ERCS/erc-7586.md
Edoumou Mar 6, 2024
66fd6c5
Update ERCS/erc-7586.md
Edoumou Mar 6, 2024
f547b01
Update ERCS/erc-7586.md
Edoumou Mar 6, 2024
20b30e2
Update ERCS/erc-7586.md
Edoumou Mar 6, 2024
4e299a2
Update ERCS/erc-7586.md
Edoumou Mar 6, 2024
8fb3cf8
Update ERCS/erc-7586.md
Edoumou Mar 6, 2024
291d88c
Update ERCS/erc-7586.md
Edoumou Mar 6, 2024
8604643
Update ERCS/erc-7586.md
Edoumou Mar 6, 2024
ad89478
Update ERCS/erc-7586.md
Edoumou Mar 6, 2024
0fe73b4
Update erc-7586.md
Edoumou Mar 6, 2024
6d258c3
Update erc-7586.md
Edoumou Mar 7, 2024
d1573cf
Update erc-7586.md
Edoumou Mar 7, 2024
1a65f02
Update erc-7586.md
Edoumou Mar 7, 2024
ab64251
Merge branch 'master' into patch-1
Edoumou Mar 7, 2024
957923e
updates rates name and adds rateDecimals function
Edoumou Mar 10, 2024
940015b
Merge branch 'master' into patch-1
Edoumou Mar 10, 2024
067c06e
Create IERC7586.sol
Edoumou Mar 10, 2024
cee3c58
Update ERC7586.sol
Edoumou Mar 11, 2024
f27fb49
Update ERC20.sol
Edoumou Mar 11, 2024
5356afd
Update ERC20.sol
Edoumou Mar 11, 2024
98fb795
Merge branch 'master' into patch-1
Edoumou Mar 17, 2024
7dba98b
add irs img
Edoumou Mar 18, 2024
123641a
add img
Edoumou Mar 18, 2024
a13fe80
Update erc-7586.md
Edoumou Mar 18, 2024
1b1ac56
fix link
Edoumou Mar 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 183 additions & 0 deletions ERCS/erc-7586.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
---
eip: 7586
title: Interest Rate Swaps
description: Interest rate swaps derivative contracts
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
description: Interest rate swaps derivative contracts
description: On-chain implementation of derivative contracts swapping fixed and floating interest rates.

Feel free to continue improving this, but your description needs to be more descriptive than just your title.

author: Samuel Gwlanold Edoumou (@Edoumou)
discussions-to: https://ethereum-magicians.org/t/interest-rate-swaps/17777
status: Draft
type: Standards Track
category: ERC
created: 2023-12-31
requires: 20, 165
---

## Abstract

This proposal introduces a standardized framework for on-chain interest rate swaps. The proposed standard aims to facilitate the seamless exchange of fixed and floating interest rate cash flows between parties, providing a foundation for decentralized finance (DeFi) applications.
Edoumou marked this conversation as resolved.
Show resolved Hide resolved

## Motivation

Interest Rate Swapping (IRS) denotes a derivative contract wherein two parties mutually consent to exchange a series of forthcoming interest payments based on a specified notional amount. This financial instrument serves as a strategic tool for hedging against interest rate fluctuations. The mechanism entails the utilization of a benchmark index to facilitate the exchange between a variable interest rate and a fixed rate. Despite its widespread use, there is currently an absence of a standardized framework that enables the representation of IRS contracts on blockchain platforms.

This proposal addresses this gap by establishing a consistent and transparent methodology for representing IRS contracts within the blockchain environment. By doing so, it would enhance the interoperability, security, and efficiency of interest rate swap transactions on distributed ledger technology.

## Specification

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.

### Example Flow

![alt text](../assets/eip-7586/irs.jpeg "IRS diagram")

Every contract compliant with this ERC MUST implement the following interface. The contract MUST inherit from [`ERC20`](./eip-20) to tokenize the swap cash flows.

```solidity
pragma solidity ^0.8.0;

/**
* @title ERC-7586 Interest Rate Swaps
*/
interface IERC7586 /** is ERC20, ERC165 */ {
// events
/**
* @notice MUST be emitted when interest rates are swapped
* @param _amount the interest difference to be transferred
* @param _account the recipient account to send the interest difference to. MUST be either the `payer` or the `receiver`
*/
event Swap(uint256 _amount, address _account);

/**
* @notice MUST be emitted when the swap contract is terminated
* @param _payer the swap payer
* @param _receiver the swap receiver
*/
event TerminateSwap(address indexed _payer, address indexed _receiver);

// functions
/**
* @notice Returns the IRS `payer` account address. The party who agreed to pay fixed interest
*/
function fixedInterestPayer() external view returns(address);

/**
* @notice Returns the IRS `receiver` account address. The party who agreed to pay floating interest
*/
function floatingInterestPayer() external view returns(address);

/**
* @notice Returns the number of decimals the swap rate and spread use - e.g. `4` means to divide the rates by `10000`
* To express the interest rates in basis points unit, the decimal MUST be equal to `2`. This means rates MUST be divided by `100`
* 1 basis point = 0.01% = 0.0001
* ex: if interest rate = 2.5%, then swapRate() => 250 `basis points`
*/
function ratesDecimals() external view returns(uint8);

/**
* @notice Returns the fixed interest rate
*/
function swapRate() external view returns(uint256);

/**
* @notice Returns the floating rate spread, i.e. the fixed part of the floating interest rate
*
* floatingRate = benchmark + spread
*/
function spread() external view returns(uint256);

/**
* @notice Returns the contract address of the asset to be transferred when swapping IRS. Depending on what the two parties agreed upon, this could be a currency, etc.
* Example: If the two parties agreed to swap interest rates in USDC, then this function should return the USDC contract address.
* This address SHOULD be used in the `swap` function to transfer the interest difference to either the `payer` or the `receiver`. Example: IERC(assetContract).transfer
*/
function assetContract() external view returns(address);

/**
* @notice Returns the notional amount in unit of asset to be transferred when swapping IRS. This amount serves as the basis for calculating the interest payments, and may not be exchanged
* Example: If the two parties aggreed to swap interest rates in USDC, then the notional amount may be equal to 1,000,000 USDC
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think removing "USDC" here would make it more clear.

*/
function notionalAmount() external view returns(uint256);

/**
* @notice Returns the interest payment frequency
*/
function paymentFrequency() external view returns(uint256);
Comment on lines +100 to +103
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is in seconds? Might be good to note that in the comment.


/**
* @notice Returns an array of specific dates on which the interest payments are exchanged. Each date MUST be a Unix timestamp like the one returned by block.timestamp
* The length of the array returned by this function MUST equal the total number of swaps that should be realized
*
* OPTIONAL
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does "OPTIONAL" mean here: that the contract doesn't need to implement this function, or that this function may revert? Should make that clear in the comment.

*/
function paymentDates() external view returns(uint256[] memory);

/**
* @notice Returns the starting date of the swap contract. This is a Unix Timestamp like the one returned by block.timestamp
*/
function startingDate() external view returns(uint256);

/**
* @notice Returns the maturity date of the swap contract. This is a Unix Timestamp like the one returned by block.timestamp
*/
function maturityDate() external view returns(uint256);

/**
* @notice Returns the benchmark in basis point unit
* Example: value of one the following rates: CF BIRC, EURIBOR, HIBOR, SHIBOR, SOFR, SONIA, TONAR, etc.
*/
function benchmark() external view returns(uint256);

/**
* @notice Returns the oracle contract address for the benchmark rate, or the zero address when the two parties agreed to set the benchmark manually.
* This contract SHOULD be used to fetch real time benchmark rate
* Example: Contract address for `CF BIRC`
*
* OPTIONAL. The two parties MAY agree to set the benchmark manually
Edoumou marked this conversation as resolved.
Show resolved Hide resolved
*/
function oracleContractForBenchmark() external view returns(address);

/**
* @notice Makes swap calculation and transfers the interest difference to either the `payer` or the `receiver`
*/
function swap() external returns(bool);

/**
* @notice Terminates the swap contract before its maturity date. MUST be called by either the `payer`or the `receiver`.
*/
function terminateSwap() external;
}
```
### Tokenization of Swap Cash Flows

The interest payments associated with the IRS MUST be tokenized by issuing digital [ERC-20](./eip-20) tokens to the respective parties according to the terms of the swap. Each token SHOULD represent a specific interest payment. Every time a swap happens (the `swap` function is called), one token MUST be burned from each party.

## Rationale
Edoumou marked this conversation as resolved.
Show resolved Hide resolved

This standard allows parties involved in the IRS contract to define essential parameters such as notional amount, interest rates, payment frequency, and payment dates. This flexibility accommodates a diverse range of financial agreements, catering to the unique needs of different participants.

To accommodate a wide array of use cases, the standard introduces optional features such as payment dates and manual benchmark setting. This allows parties to tailor the contract to specific requirements, while maintaining a core set of functions for essential functionality.

To ensure real-time and accurate benchmark rates, the standard integrates with oracles. Parties have the option to use oracles for fetching benchmark rates, enhancing the reliability and accuracy of interest rate calculations.

## Backwards Compatibility

This standard is backward compatible with ERC-20.

## Reference Implementation

The complete reference implementation can be found [here](../assets/eip-7586/ERC7586.sol).

This reference implementation serves as a foundation for the implementation of more advanced types of swaps.

## Security Considerations

Security considerations of various types must be thoroughly evaluated

* Interest Rate Risk: This pertains to the potential impact of fluctuations in interest rates.
* Credit Risk: There exists the possibility that one or both parties may default on their respective responsibilities.
* ERC-20 Risks: All security aspects outlined in the ERC-20 standard must be taken into account.

Both parties must acknowledge their awareness of these security risks before proceeding with the implementation of the standard.

## Copyright

Copyright and related rights waived via [CC0](../LICENSE.md).
124 changes: 124 additions & 0 deletions assets/erc-7586/ERC7586.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.0;

import "./IERC7586.sol";
import "./Tokens/ERC20.sol";

contract ERC7586 is IERC7586, ERC20 {
constructor(string memory _name, string memory _symbol, IRS memory _irs) ERC20(_name, _symbol) {
irsSymbol = _symbol;
irs = _irs;

_isActive = true;

_balanceOf[_irs.payer] = _irs.paymentDates.length * 1 ether;
_balanceOf[_irs.receiver] = _irs.paymentDates.length * 1 ether;
_totalSupply = _irs.paymentDates.length * 2 * 1 ether;
}

function fixedInterestPayer() external view returns(address) {
return irs.payer;
}

function floatingInterestPayer() external view returns(address) {
return irs.receiver;
}

function ratesDecimals() external view returns(uint8) {
return irs.ratesDecimals;
}

function swapRate() external view returns(uint256) {
return irs.swapRate;
}

function spread() external view returns(uint256) {
return irs.spread;
}

function assetContract() external view returns(address) {
return irs.assetContract;
}

function notionalAmount() external view returns(uint256) {
return irs.notionalAmount;
}

function paymentFrequency() external view returns(uint256) {
return irs.paymentFrequency;
}

function paymentDates() external view returns(uint256[] memory) {
return irs.paymentDates;
}

function startingDate() external view returns(uint256) {
return irs.startingDate;
}

function maturityDate() external view returns(uint256) {
return irs.maturityDate;
}

function benchmark() external view returns(uint256) {
// This should be fetched from an oracle contract
return irs.benchmark;
}

function oracleContractForBenchmark() external view returns(address) {
return irs.oracleContractForBenchmark;
}

function isActive() public view returns(bool) {
return _isActive;
}

function swap() external returns(bool) {
require(_isActive, "Contract not Active");
require(_hasAgreed[irs.payer], "Missing Agreement");
require(_hasAgreed[irs.receiver], "Missing Agreement");

uint256 fixedRate = irs.swapRate;
uint256 floatingRate = irs.benchmark + irs.spread;
uint256 notional = irs.notionalAmount;

uint256 fixedInterest = notional * fixedRate;
uint256 floatingInterest = notional * floatingRate;

uint256 interestToTransfer;
address _recipient;
address _payer;

if(fixedInterest == floatingInterest) {
revert("Nothing to swap");
} else if(fixedInterest > floatingInterest) {
interestToTransfer = fixedInterest - floatingInterest;
_recipient = irs.receiver;
_payer = irs.payer;
} else {
interestToTransfer = floatingInterest - fixedInterest;
_recipient = irs.payer;
_payer = irs.receiver;
}

burn(irs.payer, 1 ether);
burn(irs.receiver, 1 ether);

uint256 _paymentCount = paymentCount;
paymentCount = _paymentCount + 1;

IERC20(irs.assetContract).transferFrom(_payer, _recipient, interestToTransfer * 1 ether / 10_000);

if(paymentCount == irs.paymentDates.length) {
_isActive = false;
}

return true;
}

function terminateSwap() external {
require(_isActive, "Contract not Active");

_isActive = false;
}
}
Loading
Loading