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 EIP: Financial Bonds #7092

Merged
merged 100 commits into from
Jul 25, 2023
Merged
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
100 commits
Select commit Hold shift + click to select a range
8822539
Add financial bonds draft
Edoumou May 28, 2023
1e35c33
Update eip-financial_bonds.md
Edoumou May 28, 2023
af2e228
Merge pull request #1 from Edoumou/Edoumou-financial-bonds
Edoumou May 29, 2023
d1771e5
Update and rename eip-financial_bonds.md to eip-7092.md
Edoumou May 29, 2023
c03771c
Add embedded options logic
Edoumou May 29, 2023
bceaf4e
Update eip-7092.md
Edoumou May 29, 2023
0911029
Update eip-7092.md
Edoumou May 29, 2023
dfccd4f
Merge branch 'master' into master
Edoumou May 29, 2023
ded0567
change disapprove functions to decreaseAllowance functions
Edoumou May 30, 2023
f1aae56
Update eip-7092.md
Edoumou May 30, 2023
e344b7a
update to RECOMMENDED
Edoumou May 30, 2023
3d14ede
change IERC to IERC7092
Edoumou May 30, 2023
080c40e
Merge branch 'master' into master
Edoumou May 30, 2023
b850ad3
change event Disapprove to AllowanceDecreased
Edoumou May 30, 2023
289d3f6
Create ERC7092.sol in the assets folder
Edoumou May 30, 2023
19b3059
Move eip-7092 in EIPS folder
Edoumou May 30, 2023
7803f60
Rename eip-7092 to eip-7092.md
Edoumou May 30, 2023
f9f9d82
Create IERC7092.sol
Edoumou May 30, 2023
452ba91
Create BondStorage.sol
Edoumou May 30, 2023
b5b003a
Update eip-7092.md
Edoumou May 30, 2023
b2ccf25
Update eip-7092.md
Edoumou May 30, 2023
52584f8
Update eip-7092.md
Edoumou May 30, 2023
49087ac
Update eip-7092.md
Edoumou May 30, 2023
595a551
updates ref
Edoumou May 30, 2023
3155389
Update ref
Edoumou May 30, 2023
5deeeb3
remove md file in the EIP root
Edoumou May 30, 2023
1813eea
change disapprove to decreaseAllowance
Edoumou May 30, 2023
abc560c
Update eip-7092.md
Edoumou May 31, 2023
569e826
Merge branch 'master' into master
Edoumou May 31, 2023
f19c2d0
Create CouponMath.sol
Edoumou May 31, 2023
562ef59
change EIP to EIP7092 in CouponMath.sol
Edoumou May 31, 2023
79ed8a6
Update BondStorage.sol
Edoumou May 31, 2023
ec29ff9
Update embedded options functions
Edoumou May 31, 2023
e40a0e2
Update ERC7092.sol
Edoumou May 31, 2023
09c84e5
Update BondStorage.sol
Edoumou May 31, 2023
c6f4665
Merge branch 'master' into master
Edoumou May 31, 2023
1751724
Update contracts with embeded options
Edoumou Jun 1, 2023
2008a08
wip
Edoumou Jun 1, 2023
14f77fe
Merge branch 'master' into master
Edoumou Jun 3, 2023
f7ac53a
Merge branch 'master' into master
Edoumou Jun 8, 2023
bc6a9a3
fix a couple of typos
Edoumou Jun 13, 2023
f5bd2ff
Merge branch 'master' into master
Edoumou Jun 24, 2023
385d354
Merge branch 'master' into master
Edoumou Jul 1, 2023
6b1e4b3
change transfers functions to return a boolean
Edoumou Jul 4, 2023
59ebe03
change _transfer function to return a bioolean
Edoumou Jul 4, 2023
36b96bb
Merge branch 'master' into master
Edoumou Jul 11, 2023
547cb97
implement a third level heading for bonds embedded options title
Edoumou Jul 11, 2023
11b9ab9
update specs
Edoumou Jul 11, 2023
b923f8e
update motivation
Edoumou Jul 11, 2023
b9d0ed3
update rational
Edoumou Jul 11, 2023
768913a
update
Edoumou Jul 11, 2023
a788b53
Update eip-7092
Edoumou Jul 11, 2023
b7e609d
Update eip-7092.md
Edoumou Jul 11, 2023
dca3c95
Update eip-7092.md
Edoumou Jul 11, 2023
d91b241
Update eip-7092.md
Edoumou Jul 11, 2023
11bbc0b
Update eip-7092.md
Edoumou Jul 11, 2023
4e06ad5
Merge branch 'master' into master
Edoumou Jul 11, 2023
ac6d577
Update eip-7092.md
Edoumou Jul 11, 2023
eb8b5f2
Update eip-7092.md
Edoumou Jul 11, 2023
3feb68d
Update eip-7092.md
Edoumou Jul 11, 2023
a46ae1a
Update eip-7092.md
Edoumou Jul 11, 2023
8b40631
Update eip-7092.md
Edoumou Jul 11, 2023
0acad77
Update eip-7092.md
Edoumou Jul 11, 2023
b1808c8
update rationale
Edoumou Jul 11, 2023
cc09ae7
return boolean for approve function
Edoumou Jul 12, 2023
16aa28b
Update eip-7092.md
Edoumou Jul 12, 2023
2d55234
return boolean to approve and decrease allowance
Edoumou Jul 12, 2023
bad0f6c
Update ERC7092.sol
Edoumou Jul 12, 2023
8c9d913
Update Rationale
Edoumou Jul 12, 2023
945b652
Update
Edoumou Jul 12, 2023
ba325e7
Update eip-7092
Edoumou Jul 12, 2023
97ffee7
Add optional key
Edoumou Jul 12, 2023
dcb36f9
Update eip-7092.md
Edoumou Jul 12, 2023
a893fdc
Update eip-7092.md
Edoumou Jul 12, 2023
2563f2c
Update eip-7092.md
Edoumou Jul 12, 2023
ef19d49
Update eip-7092.md
Edoumou Jul 12, 2023
49628de
Update eip-7092.md
Edoumou Jul 12, 2023
083dcf7
Update eip-7092.md
Edoumou Jul 12, 2023
802d341
Update ERC7092.sol
Edoumou Jul 17, 2023
71e3f11
Update eip-7092.md
Edoumou Jul 19, 2023
6d0bb75
Update eip-7092.md
Edoumou Jul 19, 2023
7cba929
Update eip-7092.md
Edoumou Jul 19, 2023
6fffe58
add totalSupply and balanceOf in BondStorage
Edoumou Jul 19, 2023
4c22f16
add totalSupply and balanceOf functions
Edoumou Jul 19, 2023
63eeb8e
add totalSupply and balanceOf functions
Edoumou Jul 19, 2023
a68c650
remove totalSupply and balanceOf in bondStorage - already defined in …
Edoumou Jul 19, 2023
7d9f137
Update eip-7092.md
Edoumou Jul 21, 2023
af75721
Update CouponMath.sol
Edoumou Jul 23, 2023
2e6418c
update text: replace tracker by explorer
Edoumou Jul 24, 2023
6250c34
add link to etherscan
Edoumou Jul 24, 2023
54c6200
remove link: not supported
Edoumou Jul 24, 2023
aeb7991
update the eip-7092 according to comments from @lightclient
Edoumou Jul 24, 2023
5967954
keep backward compatibility as sub-sub-section for tests to pass
Edoumou Jul 25, 2023
62358ad
Update EIPS/eip-7092.md
Edoumou Jul 25, 2023
ca61a31
Update eip-7092.md
Edoumou Jul 25, 2023
c18b8d6
UIpdarte the Backward Compatibility to appear as a section
Edoumou Jul 25, 2023
053c391
Update assets/eip-7092/IERC7092.sol
Edoumou Jul 25, 2023
b7e8fd0
Update assets/eip-7092/ERC7092.sol
Edoumou Jul 25, 2023
420b0c8
Update assets/eip-7092/BondStorage.sol
Edoumou Jul 25, 2023
0984d88
Update CouponMath.sol
Edoumou Jul 25, 2023
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
342 changes: 342 additions & 0 deletions EIPS/eip-7092.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,342 @@
---
eip: 7092
title: Financial Bonds
description: This interface defines a specification for financial bonds tokenization
Copy link
Contributor

Choose a reason for hiding this comment

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

This description restates the title too much. Try to add new information in the description that isn't in the title.

author: Samuel Gwlanold Edoumou (@Edoumou)
discussions-to: https://ethereum-magicians.org/t/financial-bonds/14461
status: Draft
type: Standards Track
category: ERC
created: 2023-05-28
---

## Abstract

The proposed standard allows for the implementation of basic functionality for fixed income financial bonds with smart contracts.
Principal bonds characteristics such as the bond isin, the issue volume, the issue date, the maturity date, the coupon rate,
the coupon frequency, the principal, or the day count basis are defined to allow issuing bonds in the primary market (origination),
and different transfer functions allow to buy or sell bonds in the secondary market. The standard also providses a functionality to
allow bonds to be approved by owners in order to be spent by third party.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
The proposed standard allows for the implementation of basic functionality for fixed income financial bonds with smart contracts.
Principal bonds characteristics such as the bond isin, the issue volume, the issue date, the maturity date, the coupon rate,
the coupon frequency, the principal, or the day count basis are defined to allow issuing bonds in the primary market (origination),
and different transfer functions allow to buy or sell bonds in the secondary market. The standard also providses a functionality to
allow bonds to be approved by owners in order to be spent by third party.
This proposal introduces fixed income financial bonds. Important bonds characteristics such as the International Securities Identification Number (ISIN), the issue volume, the issue date, the maturity date, the coupon rate,
the coupon frequency, the principal, or the day count basis are defined to allow issuing bonds in the primary market (origination), and different transfer functions allow to buy or sell bonds in the secondary market. The standard also provides a functionality to allow bonds to be approved by owners in order to be spent by third party.


## Motivation

Fixed income instruments are one of the asset classes that is widely used by corporations and other entities to raise funds. Bonds
Edoumou marked this conversation as resolved.
Show resolved Hide resolved
are considered more secured than equity since the issuer is supposed to repay the principal at maturity in addition to coupons
that are paid to investsors.

This standard interface allows fixed income instruments to be represented as on-chain tokens, so as they can be managed through wallets,
and be used by applications like decentrailized exchanges.

Edoumou marked this conversation as resolved.
Show resolved Hide resolved
## 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.

**Every contract compliant with the [ERC-7092](./eip-7092.md) MUST implement the following interface**

```solidity
pragma solidity ^0.8.0;

/**
* @title ERC-7092 Financial Bonds tandard
*/
interface IERC7092 {
/**
* @notice Returns the bond isin
*/
function isin() external view returns(string memory);

/**
* @notice Returs the bond name
Edoumou marked this conversation as resolved.
Show resolved Hide resolved
Edoumou marked this conversation as resolved.
Show resolved Hide resolved
*/
function name() external view returns(string memory);

/**
* @notice Returns the bond symbol
*/
function symbol() external view returns(string memory);

/**
* @notice Returns the numbr of decimals the bond uses - e?g `10`, means to divide the token amount by `10000000000`
Edoumou marked this conversation as resolved.
Show resolved Hide resolved
Edoumou marked this conversation as resolved.
Show resolved Hide resolved
*
* OPTIONAL
*/
function decimals() external view returns(uint8);

/**
* @notice Returns the bond currency. This is the contract address of the token used to pay and return the bond principal
*/
function currency() external view returns(address);

/**
* @notice Returns the copoun currency. This is the contract address of the token used to pay coupons. It can be same as the the one used for the principal
*/
function currencyOfCoupon() external view returns(address);

/**
* @notice Returns the bond denominiation. This is the minimum amount in which the Bonds may be issued. It must be expressend in unnit of the principal currency
Edoumou marked this conversation as resolved.
Show resolved Hide resolved
* ex: If the denomination is equal to 1,000 and the currency is USDC, then bond denomination is equal to 1,000 USDC
*/
function denomination() external view returns(uint256);

/**
* @notice Returns the issue volume (total debt amount). It is RECOMMENDED to express the issue volume in denomination unit.
* ex: if denomination = $1,000, and the total debt is $5,000,000
* then, issueVolume() = $5,000, 000 / $1,000 = 5,000 bonds
*/
function issueVolume() external view returns(uint256);

/**
* @notice Returns the bond interest rate. It is RECOMMENDED to express the interest rate in basis point unit.
* 1 basis point = 0.01% = 0.0001
* ex: if interest rate = 5%, then coupon() => 500 basis points
*/
function couponRate() external view returns(uint256);

/**
* @notice Returns the coupon type
* ex: 0: Zero coupon, 1: Fixed Rate, 2: Floating Rate, etc...
*/
function couponType() external view returns(uint256);

/**
* @notice Returns the coupon frequency, i.e. the number of times coupons are paid in a year.
*/
function couponFrequency() external view returns(uint256);

/**
* @notice Returns the date when bonds were issued to investors. This is a Unix Timestamp like the one returned by block.timestamp
*/
function issueDate() external view returns(uint256);

/**
* @notice Returns the bond maturity date, i.e, the date when the pricipal is repaid. This is a Unix Timestamp like the one returned by block.timestamp
* The maturity date MUST be greater than the issue date
*/
function maturityDate() external view returns(uint256);

/**
* @notice Returns the day count basis
* Ex: 0: actual/actual, 1: actual/360, etc...
*/
function dayCountBasis() external view returns(uint256);

/**
* @notice Returns the principal of an account. It is RECOMMENDED to express the principal in denomination unit.
* Ex: if denomination = $1,000, and the user has invested $5,000
* then principalOf(_account) = 5,000/1,000 = 5
* @param _account account address
*/
function principalOf(address _account) external view returns(uint256);

/**
* @notice Returns the amount of tokens the `_spender` account has been authorized by the `_owner``
* acount to manage their bonds
* @param _owner the bondholder address
* @param _spender the address that has been authorized by the bondholder
*/
function approval(address _owner, address _spender) external view returns(uint256);

/**
* @notice Authorizes `_spender` account to manage `_amount`of their bonds
* @param _spender the address to be authorized by the bondholder
* @param _amount amount of bond to approve. _amount MUST be a multiple of denomination
*/
function approve(address _spender, uint256 _amount) external;

/**
* @notice Authorizes the `_spender` account to manage all their bonds
* @param _spender the address to be authorized by the bondholder
*/
function approveAll(address _spender) external;

/**
* @notice Lower the allowance of `_spender` by `_amount`
* @param _spender the address to be authorized by the bondholder
* @param _amount amount of bond to remove approval; _amount MUST be a multiple of denomination
*/
function decreaseAllowance(address _spender, uint256 _amount) external;

/**
* @notice Remove the allowance for `_spender`
* @param _spender the address to remove the authorization by from
*/
function decreaseAllowanceForAll(address _spender) external;

/**
* @notice Moves `_amount` bonds to address `_to`
* @param _to the address to send the bonds to
* @param _amount amount of bond to transfer. _amount MUST be a multiple of denomination
* @param _data additional information provided by the token holder
*/
function transfer(address _to, uint256 _amount, bytes calldata _data) external;

/**
* @notice Moves all bonds to address `_to`
* @param _to the address to send the bonds to
* @param _data additional information provided by the token holder
*/
function transferAll(address _to, bytes calldata _data) external;

/**
* @notice Moves `_amount` bonds from an account that has authorized through the approve function
* @param _from the bondholder address
* @param _to the address to transfer bonds to
* @param _amount amount of bond to transfer. _amount MUST be a multiple of denomination
* @param _data additional information provided by the token holder
*/
function transferFrom(address _from, address _to, uint256 _amount, bytes calldata _data) external;

/**
* @notice Moves all bonds from an `_from` to `_to`. The caller must have been authorized through the approve function
* @param _from the bondholder address
* @param _to the address to transfer bonds to
* @param _data additional information provided by the token holder
*/
function transferAllFrom(address _from, address _to, bytes calldata _data) external;

/**
* @notice MUST be emitted when bonds are transferred
* @param _from the account that owns bonds
* @param _to the account that receives the bond
* @param _amount the amount of bonds to be transferred
* @param _data additional information provided by the token holder
*/
event Transferred(address _from, address _to, uint256 _amount, bytes _data);

/**
* @notice MUST be emitted when an account is approved
* @param _owner the bonds owner
* @param _spender the account to be allowed to spend bonds
* @param _amount the amount allowed by _owner to be spent by _spender.
*/
event Approved(address _owner, address _spender, uint256 _amount);

/**
* @notice MUST be emmitted when the `_owner` decreases allowance from `_sepnder` by quantity `_amount`
* @param _owner the bonds owner
* @param _spender the account that has been allowed to spend bonds
* @param _amount the amount of tokens to disapprove
*/
event AllowanceDecreased(address _owner, address _spender, uint256 _amount);
}
```

## Rationale

The financial bond standard is designed to represent fixed income assets, which reprensent a loan made by an investor to a borrower.
The proposed design has been motivated by the necessity to tokenize fixed income assets, and to represent the bond token with same
characteristics as in traditional finance. Keeping the same properties as in tradional finance is necessary for issuers and investors
to move to tokenized bonds without major difficulties. The same structure used in tradional finace, i.e issuer-investment bank-investors
can be used for the bond standard, in that case the investment bank intermediary may be replaced by smart contracts. In the case of
institutional issuance, the smart contracts can be managed by the investment bank. Decentralized exchanges may also use the bond standard
to list bonds, in that case, decentralized exchanges will be in charge of managing the smart contracts. Other entities may also create
tokenized bonds by integrating this financial bond interface.

Tokenizing bonds will offer several advantages compared to traditional bond issuance and trading, among with:

1. Fractional ownership: The bond standard does not limit the bond denomination to some minimum value compared to traditioanal bonds where the denomination is typically equal to $100 or $1,000.
2. Accessibility: By allowing lower investment thresholds, tokenized bonds are supposed to attract retail investors who could not participate in traditional markets due to high minimum investment requirements.
3. Increased liquidity: Fractioanal ownership will bring new investors in the bond market, this will increase liquidity in the bond market.
4. Cost savings: By replacing intermediaries with smart contracts, bond's tokenization will reduce costs associated with the bond issuance and management.
5. Easy accessibility and 24/7 trading: Tokenized bonds are supposed to be traded on digital platforms such as decentralized exchanges. Therefore, they will be more accessible compared to tradional bond market.
Copy link
Contributor

Choose a reason for hiding this comment

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

This list belongs in motivation. The rationale section should describe technical choices made within the EIP itself, while the motivation should justify the existence of the EIP as a whole.

A good example of what you should include in your rationale section is why you don't extend an existing token standard, like ERC-20 or ERC-1155.


## Reference Implementation

The reference implementation of the [ERC-7092](./eip-7092.md) can be found [here](../assets/eip-7092/ERC7092.sol).

Some bonds have embedded options attached to them. As an example we can cite:

1. Callable bonds that have an option that gives the issuer the right to retire bonds before they mature.
2. Puttable bonds that have an option that gives investors the right to retire bonds before they mature.
3. Convertible bonds that gives investors the right to convert their bonds to equity.

Bonds with embedded options can be created by inheriting from the basic ERC-7092 that integrates the proposed interface.

CALLABLE BONDS:
Copy link
Contributor

Choose a reason for hiding this comment

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

You can use a third level heading here (### Callable Bonds)


```solidity
pragma solidity ^0.8.0;

import 'ERC7092.sol';

contract ERC7092Callable is ERC7092 {
// WRITE THE LOGIC TO ALLOW THE ISSUER TO CALL BONDS
// STATE VARIABLES AND FUNCTIONS NEEDED

/**
* @notice call bonds owned by `_investor`
* MUST be called by the issuer only
*/
function call(address _investor) public {
require(_principals[_investor] > 0, "ERC7092Callable: ONLY_ISSUER");
require(block.timestamp < _bond[bondISIN].maturityDate, "ERC7092Callable: BOND_MATURED");

uint256 principal = _principals[_investor];
_principals[_investor] = 0;

// ADD LOGIC HERE
}
}
```

PUTTABLE BONDS:

```solidity
pragma solidity ^0.8.0;

import 'ERC7092.sol';

contract ERC7092Puttable is ERC7092 {
// WRITE THE LOGIC TO ALLOW INVESTORS TO PUT BONDS
// STATE VARIABLES AND FUNCTIONS NEEDED

/**
* @notice put bonds
* MUST be called by investors who own bonds
*/
function put() public {
require(_principals[msg.sender] > 0, "ERC7092Puttable: ONLY_INVESTORS");
require(block.timestamp < _bond[bondISIN].maturityDate, "ERC7092Puttable: BOND_MATURED");

uint256 principal = _principals[msg.sender];
_principals[msg.sender] = 0;

// ADD LOGIC
}
}
```

CONVERTIBLE BONDS:

```solidity
pragma solidity ^0.8.0;

import 'ERC7092.sol';

contract ERC7092Convertible is ERC7092 {
// WRITE THE LOGIC TO ALLOW INVESTOR OR ISSUER TO CONVERT BONDS TO EQUITY
// STATE VARIABLES AND FUNCTIONS NEEDED

/**
* @notice convert bonds to equity. Here we assumed that the investors must convert their bonds to equity
* Issuer can also convert invetsors bonds to equity.
*/
function convert() public {
require(_principals[msg.sender] > 0, "ERC7092Convertible: ONLY_INVESTORS");
require(block.timestamp < _bond[bondISIN].maturityDate, "ERC7092Convertible: BOND_MATURED");

uint256 principal = _principals[msg.sender];
_principals[msg.sender] = 0;

// ADD LOGIC HERE
}
}
```

## Security Considerations

When implementing the ERC-7092, it is important to consider security risk related to functions that give approval to operators to manage owner's bonds, and to functions that allow to transfer bonds. Functions `transferAll` and `transferAllFrom` allow to transfer all the balance of an account. Therefore, it is crucial to ensure that only the bonds owner and accounts that have been approved by the bonds owner can call these functions.

## Copyright

Copyright and related rights waived via [CC0](../LICENSE.md).
Loading