Detalles
|
@ -1,87 +0,0 @@
|
|||
cta de Asamblea General Ordinaria N°1
|
||||
## Decentralized Climate Foundation A.C.
|
||||
|
||||
|
||||
En la Ciudad de México, Delegación Benito Juárez, a los 31 días del mes de Diciembre del año 2022, en el domicilio de la calle San Antonio Nº 123, Departamento 03, en las oficinas de la Decentralized Climate Foundation A.C., siendo las 17:00 horas, y habiéndose reunido el Quórum necesario conforme las directrices del Acta Constitutiva, se da comienzo a la Asamblea General Ordinaria, convocada por la Comisión Directiva, a fin de tratar el siguiente Orden del Día:
|
||||
|
||||
1) Lectura del Acta Constitutiva e Informe de Actividades Realizadas
|
||||
2) Tratamiento y aprobación del Balance Anual correspondiente al primer año de actividades
|
||||
3) Elección de los cargos Presidente y Secretario
|
||||
4) Elección de los cargos de Tesorero
|
||||
___
|
||||
|
||||
Esta Asamblea es presidida por el C. Luis Alberto Saavedra Nieto, Director y asistido por el Ing. David Pérez-Negron Rocha, fundador.
|
||||
|
||||
|
||||
Se informa que se encuentra reunido el Quórum necesario para dar comienzo a la Asamblea con la presencia de la totalidad de sus asociados, según Planilla de Asistencia.
|
||||
|
||||
Acto seguido se pasa a tratar el **PRIMER PUNTO** del orden del día.
|
||||
Luego de la lectura del Informe de Actividades Realizadas y después de un breve intercambio de opiniones se aprueba que los asociados designados para suscribir la presente Acta sean Luis Alberto Saavedra Nieto y David Perez-Negron Rocha.
|
||||
|
||||
|
||||
A continuación se trata el **SEGUNDO PUNTO** del Orden del Día.
|
||||
Luego de la escucha del Reporte un breve diálogo al respecto, la votación dio como resultado la **APROBACIÓN POR UNANIMIDAD** el Balance Anual tratado; quedando de esta manera aprobado por mayoría el Balance Anual.
|
||||
|
||||
Se pasa a tratar el **TERCER PUNTO** del Orden del Día.
|
||||
Habiendo presentación de las Listas, se procede a su lectura. Luego de un breve debate e intercambio de opiniones entre los asociados, la votación dio como resultado la APROBACIÓN POR UNANIMIDAD de la Lista, se proponen como candidatos a las siguientes personas:
|
||||
|
||||
**Para el cargo de Secretario: el C. Alfonso Núñez Navarro
|
||||
Para el cargo de Tesorero: el C. Omar Octavio Huerta Valdez**
|
||||
|
||||
Los asociados propuestos como candidatos aceptan su candidatura.
|
||||
|
||||
Luego de un breve debate e intercambio de opiniones la votación dio como resultado:
|
||||
|
||||
Para el cargo de Secretario, **4 votos para Alfonso Núñez Navarro, 1 abstención, 0 votos en contra.**
|
||||
|
||||
Se pasa a tratar el **PUNTO CUATRO** del Orden del Día.
|
||||
Habiendo presentación de Listas, se procede a su lectura. Luego de un breve debate e intercambio de opiniones la votación dio como resultado la APROBACIÓN POR UNANIMIDAD de la Lista. Luego de un breve debate e intercambio de opiniones la votación dio como resultado:
|
||||
|
||||
Para el cargo de Tesorero, **4 votos para Omar Octavio Huerta Valdez, 1 abstención, 0 votos en contra.**
|
||||
|
||||
Finalmente se trata el **PUNTO QUINTO** del Orden del Día.
|
||||
|
||||
|
||||
Los asociados propuestos como candidatos aceptan el cargo para el que fueron electos.
|
||||
|
||||
De esta forma se proclaman a las autoridades electas por el término de 5 años y contar desde el día de la fecha, con la siguiente conformación:
|
||||
|
||||
|
||||
**Del Consejo General**
|
||||
Secretario: Alfonso Núñez Navarro
|
||||
Tesorero: Octavio Huerta Valdez
|
||||
|
||||
|
||||
Todos los candidatos electos aceptan expresamente el cargo.
|
||||
|
||||
Siendo las 19:00 horas del día 31 de Diciembre del 2022 y habiéndose cumplimentado en su totalidad el Orden del Día previsto, se da por finalizada la Asamblea General. Se da lectura a esta Acta, y firman de conformidad los asambleístas designados, conjuntamente con el Presidente y el Consejo General, en el lugar y fecha indicados al inicio.
|
||||
|
||||
|
||||
|
||||
## **Firmas de los Presentes**
|
||||
|
||||
![](https://imgur.com/9ghNAPk.png)
|
||||
______________________
|
||||
Luis Alberto Saavedra Nieto.
|
||||
|
||||
![](https://i.imgur.com/xertJxD.png)
|
||||
______________________
|
||||
David E. Pérez Negron R.
|
||||
|
||||
![](https://i.imgur.com/8TbRdeR.png)
|
||||
______________________
|
||||
Omar Octavio Huerta Valdez.
|
||||
|
||||
![](https://i.imgur.com/UQD4ehY.png)
|
||||
______________________
|
||||
Christian Sandoval.
|
||||
|
||||
![](https://i.imgur.com/0LGljhs.png)
|
||||
______________________
|
||||
Alfonso Nuñez.
|
||||
|
||||
![](https://i.imgur.com/mXssbm0.png)
|
||||
______________________
|
||||
Marco Blanke.
|
||||
|
||||
|
Before Width: | Height: | Size: 79 KiB |
Before Width: | Height: | Size: 92 KiB |
Before Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 172 KiB |
Before Width: | Height: | Size: 102 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 74 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 77 KiB |
Before Width: | Height: | Size: 117 KiB |
Before Width: | Height: | Size: 215 KiB |
Before Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 53 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 282 KiB |
Before Width: | Height: | Size: 1.5 MiB |
Before Width: | Height: | Size: 67 KiB |
Before Width: | Height: | Size: 88 KiB |
Before Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 53 KiB |
Before Width: | Height: | Size: 239 KiB |
Before Width: | Height: | Size: 882 KiB |
|
@ -1,455 +0,0 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
// Copyright (c) 2019 Chris Haoyu LIN, Runchao HAN, Jiangshan YU
|
||||
// ERC2266 is compatible with ERC20 standard: https://theethereum.wiki/w/index.php/ERC20_Token_Standard
|
||||
// naming style follows the guide: https://solidity.readthedocs.io/en/v0.5.11/style-guide.html#naming-styles
|
||||
|
||||
pragma solidity ^0.5.11;
|
||||
|
||||
contract ERC20 {
|
||||
function totalSupply() public view returns (uint);
|
||||
function balanceOf(address tokenOwner) public view returns (uint balance);
|
||||
function allowance(address tokenOwner, address spender) public view returns (uint remaining);
|
||||
function transfer(address to, uint tokens) public returns (bool success);
|
||||
function approve(address spender, uint tokens) public returns (bool success);
|
||||
function transferFrom(address from, address to, uint tokens) public returns (bool success);
|
||||
event Transfer(address indexed from, address indexed to, uint tokens);
|
||||
event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
|
||||
}
|
||||
|
||||
contract Example
|
||||
{
|
||||
enum AssetState { Empty, Filled, Redeemed, Refunded }
|
||||
|
||||
struct Swap {
|
||||
bytes32 secretHash;
|
||||
bytes32 secret;
|
||||
address payable initiator;
|
||||
address payable participant;
|
||||
address tokenA;
|
||||
address tokenB;
|
||||
}
|
||||
|
||||
struct InitiatorAsset {
|
||||
uint256 amount;
|
||||
uint256 refundTimestamp;
|
||||
AssetState state;
|
||||
}
|
||||
|
||||
struct ParticipantAsset {
|
||||
uint256 amount;
|
||||
uint256 refundTimestamp;
|
||||
AssetState state;
|
||||
}
|
||||
|
||||
struct Premium {
|
||||
uint256 amount;
|
||||
uint256 refundTimestamp;
|
||||
AssetState state;
|
||||
}
|
||||
|
||||
mapping(bytes32 => Swap) public swap;
|
||||
mapping(bytes32 => InitiatorAsset) public initiatorAsset;
|
||||
mapping(bytes32 => ParticipantAsset) public participantAsset;
|
||||
mapping(bytes32 => Premium) public premium;
|
||||
|
||||
event SetUp(
|
||||
bytes32 secretHash,
|
||||
address initiator,
|
||||
address participant,
|
||||
address tokenA,
|
||||
address tokenB,
|
||||
uint256 initiatorAssetAmount,
|
||||
uint256 participantAssetAmount,
|
||||
uint256 premiumAmount
|
||||
);
|
||||
|
||||
event Initiated(
|
||||
uint256 initiateTimestamp,
|
||||
bytes32 secretHash,
|
||||
address initiator,
|
||||
address participant,
|
||||
address initiatorAssetToken,
|
||||
uint256 initiatorAssetAmount,
|
||||
uint256 initiatorAssetRefundTimestamp
|
||||
);
|
||||
|
||||
event PremiumFilled(
|
||||
uint256 fillPremiumTimestamp,
|
||||
bytes32 secretHash,
|
||||
address initiator,
|
||||
address participant,
|
||||
address premiumToken,
|
||||
uint256 premiumAmount,
|
||||
uint256 premiumRefundTimestamp
|
||||
);
|
||||
|
||||
event Participated(
|
||||
uint256 participateTimestamp,
|
||||
bytes32 secretHash,
|
||||
address initiator,
|
||||
address participant,
|
||||
address participantAssetToken,
|
||||
uint256 participantAssetAmount,
|
||||
uint256 participantAssetRefundTimestamp
|
||||
);
|
||||
|
||||
event InitiatorAssetRedeemed(
|
||||
uint256 redeemTimestamp,
|
||||
bytes32 secretHash,
|
||||
bytes32 secret,
|
||||
address redeemer,
|
||||
address assetToken,
|
||||
uint256 amount
|
||||
);
|
||||
|
||||
event ParticipantAssetRedeemed(
|
||||
uint256 redeemTimestamp,
|
||||
bytes32 secretHash,
|
||||
bytes32 secret,
|
||||
address redeemer,
|
||||
address assetToken,
|
||||
uint256 amount
|
||||
);
|
||||
|
||||
event InitiatorAssetRefunded(
|
||||
uint256 refundTimestamp,
|
||||
bytes32 secretHash,
|
||||
address refunder,
|
||||
address assetToken,
|
||||
uint256 amount
|
||||
);
|
||||
|
||||
event ParticipantAssetRefunded(
|
||||
uint256 refundTimestamp,
|
||||
bytes32 secretHash,
|
||||
address refunder,
|
||||
address assetToken,
|
||||
uint256 amount
|
||||
);
|
||||
|
||||
event PremiumRedeemed(
|
||||
uint256 redeemTimestamp,
|
||||
bytes32 secretHash,
|
||||
address redeemer,
|
||||
address token,
|
||||
uint256 amount
|
||||
);
|
||||
|
||||
event PremiumRefunded(
|
||||
uint256 refundTimestamp,
|
||||
bytes32 secretHash,
|
||||
address refunder,
|
||||
address token,
|
||||
uint256 amount
|
||||
);
|
||||
|
||||
constructor() public {}
|
||||
|
||||
modifier isInitiatorAssetEmptyState(bytes32 secretHash) {
|
||||
require(initiatorAsset[secretHash].state == AssetState.Empty);
|
||||
_;
|
||||
}
|
||||
|
||||
modifier isParticipantAssetEmptyState(bytes32 secretHash) {
|
||||
require(participantAsset[secretHash].state == AssetState.Empty);
|
||||
_;
|
||||
}
|
||||
|
||||
modifier isPremiumEmptyState(bytes32 secretHash) {
|
||||
require(premium[secretHash].state == AssetState.Empty);
|
||||
_;
|
||||
}
|
||||
|
||||
modifier canSetup(bytes32 secretHash) {
|
||||
require(initiatorAsset[secretHash].state == AssetState.Empty);
|
||||
require(participantAsset[secretHash].state == AssetState.Empty);
|
||||
require(premium[secretHash].state == AssetState.Empty);
|
||||
_;
|
||||
}
|
||||
|
||||
modifier canInitiate(bytes32 secretHash) {
|
||||
require(swap[secretHash].initiator == msg.sender);
|
||||
require(initiatorAsset[secretHash].state == AssetState.Empty);
|
||||
require(ERC20(swap[secretHash].tokenA).balanceOf(msg.sender) >= initiatorAsset[secretHash].amount);
|
||||
_;
|
||||
}
|
||||
|
||||
modifier canFillPremium(bytes32 secretHash) {
|
||||
require(swap[secretHash].initiator == msg.sender);
|
||||
require(premium[secretHash].state == AssetState.Empty);
|
||||
require(ERC20(swap[secretHash].tokenB).balanceOf(msg.sender) >= premium[secretHash].amount);
|
||||
_;
|
||||
}
|
||||
|
||||
modifier canParticipate(bytes32 secretHash) {
|
||||
require(swap[secretHash].participant == msg.sender);
|
||||
require(participantAsset[secretHash].state == AssetState.Empty);
|
||||
require(premium[secretHash].state == AssetState.Filled);
|
||||
require(ERC20(swap[secretHash].tokenB).balanceOf(msg.sender) >= participantAsset[secretHash].amount);
|
||||
_;
|
||||
}
|
||||
|
||||
modifier checkRefundTimestampOverflow(uint256 refundTime) {
|
||||
uint256 refundTimestamp = block.timestamp + refundTime;
|
||||
require(refundTimestamp > block.timestamp, "calc refundTimestamp overflow");
|
||||
require(refundTimestamp > refundTime, "calc refundTimestamp overflow");
|
||||
_;
|
||||
}
|
||||
|
||||
modifier isAssetRedeemable(bytes32 secretHash, bytes32 secret) {
|
||||
if (swap[secretHash].initiator == msg.sender) {
|
||||
require(initiatorAsset[secretHash].state == AssetState.Filled);
|
||||
require(block.timestamp <= initiatorAsset[secretHash].refundTimestamp);
|
||||
} else {
|
||||
require(swap[secretHash].participant == msg.sender);
|
||||
require(participantAsset[secretHash].state == AssetState.Filled);
|
||||
require(block.timestamp <= participantAsset[secretHash].refundTimestamp);
|
||||
}
|
||||
require(sha256(abi.encodePacked(secret)) == secretHash);
|
||||
_;
|
||||
}
|
||||
|
||||
modifier isAssetRefundable(bytes32 secretHash) {
|
||||
if (swap[secretHash].initiator == msg.sender) {
|
||||
require(initiatorAsset[secretHash].state == AssetState.Filled);
|
||||
require(block.timestamp > initiatorAsset[secretHash].refundTimestamp);
|
||||
} else {
|
||||
require(swap[secretHash].participant == msg.sender);
|
||||
require(participantAsset[secretHash].state == AssetState.Filled);
|
||||
require(block.timestamp > participantAsset[secretHash].refundTimestamp);
|
||||
}
|
||||
_;
|
||||
}
|
||||
|
||||
modifier isPremiumFilledState(bytes32 secretHash) {
|
||||
require(premium[secretHash].state == AssetState.Filled);
|
||||
_;
|
||||
}
|
||||
|
||||
// Premium is redeemable for Bob if Bob participates and redeem
|
||||
// before premium's timelock expires
|
||||
modifier isPremiumRedeemable(bytes32 secretHash) {
|
||||
// the participant invokes this method to redeem the premium
|
||||
require(swap[secretHash].participant == msg.sender);
|
||||
// the premium should be deposited
|
||||
require(premium[secretHash].state == AssetState.Filled);
|
||||
// if Bob participates, which means participantAsset will be: Filled -> (Redeemed/Refunded)
|
||||
require(participantAsset[secretHash].state == AssetState.Refunded || participantAsset[secretHash].state == AssetState.Redeemed);
|
||||
// the premium timelock should not be expired
|
||||
require(block.timestamp <= premium[secretHash].refundTimestamp);
|
||||
_;
|
||||
}
|
||||
|
||||
// Premium is refundable for Alice only when Alice initiates
|
||||
// but Bob does not participate after premium's timelock expires
|
||||
modifier isPremiumRefundable(bytes32 secretHash) {
|
||||
// the initiator invokes this method to refund the premium
|
||||
require(swap[secretHash].initiator == msg.sender);
|
||||
// the premium should be deposited
|
||||
require(premium[secretHash].state == AssetState.Filled);
|
||||
// asset2 should be empty
|
||||
// which means Bob does not participate
|
||||
require(participantAsset[secretHash].state == AssetState.Empty);
|
||||
require(block.timestamp > premium[secretHash].refundTimestamp);
|
||||
_;
|
||||
}
|
||||
|
||||
function setup(bytes32 secretHash,
|
||||
address payable initiator,
|
||||
address tokenA,
|
||||
address tokenB,
|
||||
uint256 initiatorAssetAmount,
|
||||
address payable participant,
|
||||
uint256 participantAssetAmount,
|
||||
uint256 premiumAmount)
|
||||
public
|
||||
payable
|
||||
canSetup(secretHash)
|
||||
{
|
||||
swap[secretHash].secretHash = secretHash;
|
||||
swap[secretHash].initiator = initiator;
|
||||
swap[secretHash].participant = participant;
|
||||
swap[secretHash].tokenA = tokenA;
|
||||
swap[secretHash].tokenB = tokenB;
|
||||
initiatorAsset[secretHash].amount = initiatorAssetAmount;
|
||||
initiatorAsset[secretHash].state = AssetState.Empty;
|
||||
participantAsset[secretHash].amount = participantAssetAmount;
|
||||
participantAsset[secretHash].state = AssetState.Empty;
|
||||
premium[secretHash].amount = premiumAmount;
|
||||
premium[secretHash].state = AssetState.Empty;
|
||||
|
||||
emit SetUp(
|
||||
secretHash,
|
||||
initiator,
|
||||
participant,
|
||||
tokenA,
|
||||
tokenB,
|
||||
initiatorAssetAmount,
|
||||
participantAssetAmount,
|
||||
premiumAmount
|
||||
);
|
||||
}
|
||||
|
||||
// Initiator needs to pay for the initiatorAsset(tokenA) with initiatorAssetAmount
|
||||
// Initiator will also need to call tokenA.approve(this_contract_address, initiatorAssetAmount) in advance
|
||||
function initiate(bytes32 secretHash, uint256 assetRefundTime)
|
||||
public
|
||||
payable
|
||||
canInitiate(secretHash)
|
||||
checkRefundTimestampOverflow(assetRefundTime)
|
||||
{
|
||||
ERC20(swap[secretHash].tokenA).transferFrom(swap[secretHash].initiator, address(this), initiatorAsset[secretHash].amount);
|
||||
initiatorAsset[secretHash].state = AssetState.Filled;
|
||||
initiatorAsset[secretHash].refundTimestamp = block.timestamp + assetRefundTime;
|
||||
|
||||
emit Initiated(
|
||||
block.timestamp,
|
||||
secretHash,
|
||||
msg.sender,
|
||||
swap[secretHash].participant,
|
||||
swap[secretHash].tokenA,
|
||||
initiatorAsset[secretHash].amount,
|
||||
initiatorAsset[secretHash].refundTimestamp
|
||||
);
|
||||
}
|
||||
|
||||
// Initiator needs to pay for the premium(tokenB) with premiumAmount
|
||||
// Initiator will also need to call tokenB.approve(this_contract_address, premiumAmount) in advance
|
||||
function fillPremium(bytes32 secretHash, uint256 premiumRefundTime)
|
||||
public
|
||||
payable
|
||||
canFillPremium(secretHash)
|
||||
checkRefundTimestampOverflow(premiumRefundTime)
|
||||
{
|
||||
ERC20(swap[secretHash].tokenB).transferFrom(swap[secretHash].initiator, address(this), premium[secretHash].amount);
|
||||
premium[secretHash].state = AssetState.Filled;
|
||||
premium[secretHash].refundTimestamp = block.timestamp + premiumRefundTime;
|
||||
|
||||
emit PremiumFilled(
|
||||
block.timestamp,
|
||||
secretHash,
|
||||
msg.sender,
|
||||
swap[secretHash].participant,
|
||||
swap[secretHash].tokenB,
|
||||
premium[secretHash].amount,
|
||||
premium[secretHash].refundTimestamp
|
||||
);
|
||||
}
|
||||
|
||||
// Participant needs to pay for the participantAsset(tokenB) with participantAssetAmount
|
||||
// Participant will also need to call tokenB.approve(this_contract_address, participantAssetAmount) in advance
|
||||
function participate(bytes32 secretHash, uint256 assetRefundTime)
|
||||
public
|
||||
payable
|
||||
canParticipate(secretHash)
|
||||
checkRefundTimestampOverflow(assetRefundTime)
|
||||
{
|
||||
ERC20(swap[secretHash].tokenB).transferFrom(swap[secretHash].participant, address(this), participantAsset[secretHash].amount);
|
||||
participantAsset[secretHash].state = AssetState.Filled;
|
||||
participantAsset[secretHash].refundTimestamp = block.timestamp + assetRefundTime;
|
||||
|
||||
emit Participated(
|
||||
block.timestamp,
|
||||
secretHash,
|
||||
swap[secretHash].initiator,
|
||||
msg.sender,
|
||||
swap[secretHash].tokenB,
|
||||
participantAsset[secretHash].amount,
|
||||
participantAsset[secretHash].refundTimestamp
|
||||
);
|
||||
}
|
||||
|
||||
function redeemAsset(bytes32 secret, bytes32 secretHash)
|
||||
public
|
||||
isAssetRedeemable(secretHash, secret)
|
||||
{
|
||||
swap[secretHash].secret = secret;
|
||||
if (swap[secretHash].initiator == msg.sender) {
|
||||
ERC20(swap[secretHash].tokenB).transfer(msg.sender, participantAsset[secretHash].amount);
|
||||
participantAsset[secretHash].state = AssetState.Redeemed;
|
||||
|
||||
emit ParticipantAssetRedeemed(
|
||||
block.timestamp,
|
||||
secretHash,
|
||||
secret,
|
||||
msg.sender,
|
||||
swap[secretHash].tokenB,
|
||||
participantAsset[secretHash].amount
|
||||
);
|
||||
} else {
|
||||
ERC20(swap[secretHash].tokenA).transfer(msg.sender, initiatorAsset[secretHash].amount);
|
||||
initiatorAsset[secretHash].state = AssetState.Redeemed;
|
||||
|
||||
emit InitiatorAssetRedeemed(
|
||||
block.timestamp,
|
||||
secretHash,
|
||||
secret,
|
||||
msg.sender,
|
||||
swap[secretHash].tokenA,
|
||||
initiatorAsset[secretHash].amount
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function refundAsset(bytes32 secretHash)
|
||||
public
|
||||
isPremiumFilledState(secretHash)
|
||||
isAssetRefundable(secretHash)
|
||||
{
|
||||
if (swap[secretHash].initiator == msg.sender) {
|
||||
ERC20(swap[secretHash].tokenA).transfer(msg.sender, initiatorAsset[secretHash].amount);
|
||||
initiatorAsset[secretHash].state = AssetState.Refunded;
|
||||
|
||||
emit InitiatorAssetRefunded(
|
||||
block.timestamp,
|
||||
secretHash,
|
||||
msg.sender,
|
||||
swap[secretHash].tokenA,
|
||||
initiatorAsset[secretHash].amount
|
||||
);
|
||||
} else {
|
||||
ERC20(swap[secretHash].tokenB).transfer(msg.sender, participantAsset[secretHash].amount);
|
||||
participantAsset[secretHash].state = AssetState.Refunded;
|
||||
|
||||
emit ParticipantAssetRefunded(
|
||||
block.timestamp,
|
||||
secretHash,
|
||||
msg.sender,
|
||||
swap[secretHash].tokenB,
|
||||
participantAsset[secretHash].amount
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function redeemPremium(bytes32 secretHash)
|
||||
public
|
||||
isPremiumRedeemable(secretHash)
|
||||
{
|
||||
ERC20(swap[secretHash].tokenB).transfer(msg.sender, premium[secretHash].amount);
|
||||
premium[secretHash].state = AssetState.Redeemed;
|
||||
|
||||
emit PremiumRefunded(
|
||||
block.timestamp,
|
||||
swap[secretHash].secretHash,
|
||||
msg.sender,
|
||||
swap[secretHash].tokenB,
|
||||
premium[secretHash].amount
|
||||
);
|
||||
}
|
||||
|
||||
function refundPremium(bytes32 secretHash)
|
||||
public
|
||||
isPremiumRefundable(secretHash)
|
||||
{
|
||||
ERC20(swap[secretHash].tokenB).transfer(msg.sender, premium[secretHash].amount);
|
||||
premium[secretHash].state = AssetState.Refunded;
|
||||
|
||||
emit PremiumRefunded(
|
||||
block.timestamp,
|
||||
swap[secretHash].secretHash,
|
||||
msg.sender,
|
||||
swap[secretHash].tokenB,
|
||||
premium[secretHash].amount
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
abstract contract Extsload {
|
||||
function extsload(bytes32[] memory slots)
|
||||
external
|
||||
view
|
||||
returns (bytes32[] memory)
|
||||
{
|
||||
for (uint256 i; i < slots.length; i++) {
|
||||
bytes32 slot = slots[i];
|
||||
bytes32 val;
|
||||
assembly {
|
||||
val := sload(slot)
|
||||
}
|
||||
slots[i] = val;
|
||||
}
|
||||
return slots;
|
||||
}
|
||||
}
|
||||
|
||||
// A contract who can make their state publicly accessible without EIP-2330
|
||||
contract DeFiProtocol is Extsload {
|
||||
// code
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
## Contributors
|
||||
|
||||
* Andrew Redden (@androolloyd)
|
||||
* Patrick Gallagher (@pi0neerpat)
|
||||
* Leo Alt (@leonardoalt)
|
||||
* Santiago Palladino (@spalladino)
|
||||
* William Entriken (@fulldecent)
|
||||
* Gonçalo Sá (@GNSPS)
|
||||
* Brian Burns (@Droopy78)
|
||||
* Ramesh Nair(@hiddentao)
|
||||
* Jules Goddard (@JulesGoddard)
|
||||
* Micah Zoltu (@MicahZoltu)
|
||||
* Sam Wilson (@SamWilsn)
|
||||
* William Morriss (@wjmelements)
|
||||
* Zachary (@Remscar)
|
||||
* Patrick Collins (@PatrickAlphaC)
|
||||
* Hadrien Croubois (@Amxx)
|
||||
* (@farreldarian)
|
||||
* Kelvin Schoofs (@SchoofsKelvin)
|
||||
* (@0xpApaSmURf)
|
||||
* Nathan Sala (@nataouze)
|
||||
* Anders Torbjornsen (@anders-torbjornsen)
|
||||
* (@Pandapip1)
|
||||
* Xavier Iturralde (@xibot)
|
||||
* Coder Dan (@cinnabarhorse)
|
||||
* GldnXross (@gldnxross)
|
||||
* Christian Reitwiessner (@chriseth)
|
||||
* Timidan (@Timidan)
|
||||
* cyotee doge (@cyotee)
|
||||
* Glory Praise Emmanuel (@emmaglorypraise)
|
||||
* Ed Zynda (@ezynda3)
|
||||
* Arthur Nesbitt (@nesbitta)
|
||||
* Cliff Hall (@cliffhall)
|
||||
* Tyler Scott Ward (@tylerscottward)
|
||||
* Troy Murray (@DannyDesert)
|
||||
* Dan Finlay (@danfinlay)
|
||||
* Theodore Georgas (@tgeorgas)
|
||||
* Aditya Palepu (@apalepu23)
|
||||
* Ronan Sandford (@wighawag)
|
||||
* Markus Waas (@gorgos)
|
||||
* Blessing Emah (@BlessingEmah)
|
||||
* Andrew Edwards
|
||||
* Ashwin Yardi (@ashwinYardi)
|
||||
* Marco Castignoli (@marcocastignoli)
|
||||
* Blaine Bublitz (@phated)
|
||||
* Bearded
|
||||
* Nick Barry (@ItsNickBarry)
|
||||
* (@Vectorized)
|
||||
* Rachit Srivastava (@rachit2501)
|
||||
* Neeraj Kashyap (@zomglings)
|
||||
* Zac Denham (@zdenham)
|
||||
* JA (@ubinatus)
|
||||
* Carter Carlson (@cartercarlson)
|
||||
* James Sayer (@jamessayer98)
|
||||
* Arpit Temani (@temaniarpit27)
|
||||
* Parv Garg (@parv3213)
|
||||
* Publius (@publiuss)
|
||||
* Guy Hance (@guyhance)
|
||||
* Payn (@Ayuilos)
|
||||
* Luis Schliesske (@gitpusha)
|
||||
* Hilmar Orth (@hilmarx)
|
||||
* Matthieu Marie Joseph (@Gauddel)
|
||||
* David Uzochukwu (@davidpius95)
|
||||
* TJ VanSlooten (@tjvsx)
|
||||
* 0xFluffyBeard (@0xFluffyBeard)
|
||||
* Florian Pfeiffer (@FlorianPfeifferKanaloaNetwork)
|
||||
* Mick de Graaf(@MickdeGraaf)
|
||||
* Alessio Delmonti (@Alexintosh)
|
||||
* Neirenoir (@Neirenoir)
|
||||
* Evert Kors (@Evert0x)
|
||||
* Patrick Kim (@pakim249CAL)
|
||||
* Ersan YAKIT (@ersanyakit)
|
||||
* Matias Arazi (@MatiArazi)
|
||||
* Lucas Grasso Ramos (@LucasGrasso)
|
||||
* Nikolay Angelov (@NikolayAngelov)
|
||||
* John Reynolds (@gweiworld)
|
||||
* Viraz Malhotra (@viraj124)
|
||||
* Kemal Emre Ballı (@emrbli)
|
||||
* Zack Peng (@zackpeng)
|
Before Width: | Height: | Size: 52 KiB |
|
@ -1,70 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg viewBox="0 0 726.54108 726.54108" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<linearGradient id="a">
|
||||
<stop stop-color="#1d1533" offset="0"/>
|
||||
<stop stop-color="#fff" offset="1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="ac" x1="74.5" x2="465.5" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
|
||||
<linearGradient id="ab" x1="132.96" x2="266.18" y1="384.24" y2="553.76" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
|
||||
<linearGradient id="aa" x1="269.77" x2="270.23" y1="556.35" y2="383.37" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
|
||||
<linearGradient id="z" x1="228.61" x2="237.63" y1="376.58" y2="492.48" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
|
||||
<linearGradient id="y" x1="352.53" x2="300.15" y1="381.77" y2="494.21" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
|
||||
<linearGradient id="x" x1="132.96" x2="237.91" y1="383.5" y2="494.21" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
|
||||
<linearGradient id="w" x1="202.8" x2="109.49" y1="491.61" y2="376.58" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
|
||||
<linearGradient id="v" x1="34.792" x2="202.91" y1="343.72" y2="494.21" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
|
||||
<linearGradient id="u" x1="300.36" x2="385.42" y1="494.21" y2="376.58" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
|
||||
<linearGradient id="t" x1="408.75" x2="270.38" y1="381.64" y2="557.22" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
|
||||
<linearGradient id="s" x1="465.97" x2="337.49" y1="380.9" y2="494.21" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
|
||||
<linearGradient id="r" x1="134.03" x2="81.019" y1="323.51" y2="375.47" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
|
||||
<linearGradient id="q" x1="133.39" x2="110.78" y1="323.01" y2="375.47" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
|
||||
<linearGradient id="p" x1="171.83" x2="135.14" y1="311.81" y2="321.9" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
|
||||
<linearGradient id="o" x1="208.7" x2="134.33" y1="333.28" y2="322.18" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
|
||||
<linearGradient id="n" x1="207.69" x2="134.33" y1="333.05" y2="371.39" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
|
||||
<linearGradient id="m" x1="175.36" x2="270.5" y1="310.25" y2="311.12" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
|
||||
<linearGradient id="l" x1="270.26" x2="184.24" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
|
||||
<linearGradient id="k" x1="330.57" x2="210.94" y1="332.27" y2="332.78" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
|
||||
<linearGradient id="j" x1="302.79" x2="353.48" y1="350.2" y2="372.4" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
|
||||
<linearGradient id="i" x1="361.18" x2="270.36" y1="311.98" y2="311.98" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
|
||||
<linearGradient id="h" x1="405.17" x2="331.8" y1="323.7" y2="332.27" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
|
||||
<linearGradient id="g" x1="331.01" x2="406.97" y1="332.04" y2="371.89" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
|
||||
<linearGradient id="f" x1="405" x2="430.32" y1="322" y2="374.46" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
|
||||
<linearGradient id="e" x1="406.01" x2="453.39" y1="323.01" y2="373.96" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
|
||||
<linearGradient id="d" x1="405.15" x2="376.96" y1="322.55" y2="312.17" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
|
||||
<linearGradient id="c" x1="429.64" x2="336.33" y1="378.31" y2="493.34" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
|
||||
<radialGradient id="b" cx="509.21" cy="317.17" r="38.288" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#fff" offset="0"/>
|
||||
<stop stop-color="#fff" stop-opacity=".5" offset="1"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<g transform="matrix(1.4531 0 0 1.4531 -28.804 -245.37)">
|
||||
<path d="m75 372.36h390v10h-390z" fill="url(#ac)"/>
|
||||
<path d="m270 557.36-30-60-110-115 75 115z" fill="url(#ab)"/>
|
||||
<path d="m270 557.36-30-60 30-115 30 115z" fill="url(#aa)"/>
|
||||
<path d="m270 382.36-30 115-55-115c30-5 55-5 85 0z" fill="url(#z)"/>
|
||||
<path d="m300 497.36 55-115c-30-5-55-5-85 0z" fill="url(#y)"/>
|
||||
<path d="m240 497.36-55-115c-20-5-35-5-55 0z" fill="url(#x)"/>
|
||||
<path d="m205 497.36-75-115c-15-5-25-5-40 0z" fill="url(#w)"/>
|
||||
<path d="m205 497.36-115-115c-5-5-10-5-15 0z" fill="url(#v)"/>
|
||||
<path d="m300 497.36 110-115c-20-5-35-5-55 0z" fill="url(#u)"/>
|
||||
<path d="m270 557.36 30-60 110-115-75 115z" fill="url(#t)"/>
|
||||
<path d="m335 497.36 130-115c-5-5-10-5-15 0z" fill="url(#s)"/>
|
||||
<path d="m75 372.36 60-50-45 50c-5 5-10 5-15 0z" fill="url(#r)"/>
|
||||
<path d="m90 372.36c15 5 25 5 40 0l5-50z" fill="url(#q)"/>
|
||||
<path d="m135 322.36 40-10h-30z" fill="url(#p)"/>
|
||||
<path d="m135 322.36-5 50 80-40-35-20z" fill="url(#o)"/>
|
||||
<path d="m130 372.36c20 5 35 5 55 0l25-40z" fill="url(#n)"/>
|
||||
<path d="m210 332.36-35-20h95z" fill="url(#m)"/>
|
||||
<path d="m210 332.36-25 40c30 5 55 5 85 0z" fill="url(#l)"/>
|
||||
<path d="m210 332.36 60-20 60 20-60 40z" fill="url(#k)"/>
|
||||
<path d="m270 372.36c30 5 55 5 85 0l-25-40z" fill="url(#j)"/>
|
||||
<path d="m270 312.36 60 20 35-20z" fill="url(#i)"/>
|
||||
<path d="m330 332.36 35-20 40 10 5 50z" fill="url(#h)"/>
|
||||
<path d="m330 332.36 25 40c20 5 35 5 55 0z" fill="url(#g)"/>
|
||||
<path d="m410 372.36-5-50 45 50c-15 5-25 5-40 0z" fill="url(#f)"/>
|
||||
<path d="m450 372.36-45-50 60 50c-5 5-10 5-15 0z" fill="url(#e)"/>
|
||||
<path d="m365 312.36 40 10-10-10z" fill="url(#d)"/>
|
||||
<path d="m450 382.36c-15-5-25-5-40 0l-75 115z" fill="url(#c)"/>
|
||||
<path transform="matrix(1.4469 0 0 1.4469 -606.41 -87.478)" d="m528.46 350.51-17.465-27.849 2.2397 32.796-4.6278-32.545-11.293 30.871 9.0094-31.613-22.873 23.609 21.089-25.216-30.498 12.264 29.522-14.458-32.85-1.2007 32.85-1.2006-29.522-14.458 30.498 12.264-21.089-25.216 22.873 23.609-9.0094-31.613 11.293 30.871 4.6278-32.545-2.2397 32.796 17.465-27.849-15.385 29.049 27.282-18.337-25.871 20.28 32.382-5.6555-31.883 8.0043 31.883 8.0043-32.382-5.6555 25.871 20.28-27.282-18.337z" fill="url(#b)" fill-opacity=".94"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 72 KiB |
Before Width: | Height: | Size: 68 KiB |
|
@ -1,589 +0,0 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
/******************************************************************************\
|
||||
* Author: Nick Mudge <nick@perfectabstractions.com>, Twitter/Github: @mudgen
|
||||
* EIP-2535 Diamonds
|
||||
/******************************************************************************/
|
||||
|
||||
// NOTE:
|
||||
// To see the various things in this file in their proper directory structure
|
||||
// please download the zip archive version of this reference implementation.
|
||||
// The zip archive also includes a deployment script and tests.
|
||||
|
||||
interface IDiamond {
|
||||
enum FacetCutAction {Add, Replace, Remove}
|
||||
// Add=0, Replace=1, Remove=2
|
||||
|
||||
struct FacetCut {
|
||||
address facetAddress;
|
||||
FacetCutAction action;
|
||||
bytes4[] functionSelectors;
|
||||
}
|
||||
|
||||
event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);
|
||||
}
|
||||
|
||||
interface IDiamondCut is IDiamond {
|
||||
/// @notice Add/replace/remove any number of functions and optionally execute
|
||||
/// a function with delegatecall
|
||||
/// @param _diamondCut Contains the facet addresses and function selectors
|
||||
/// @param _init The address of the contract or facet to execute _calldata
|
||||
/// @param _calldata A function call, including function selector and arguments
|
||||
/// _calldata is executed with delegatecall on _init
|
||||
function diamondCut(
|
||||
FacetCut[] calldata _diamondCut,
|
||||
address _init,
|
||||
bytes calldata _calldata
|
||||
) external;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// LibDiamond
|
||||
// LibDiamond defines the diamond storage that is used by this reference
|
||||
// implementation.
|
||||
// LibDiamond contains internal functions and no external functions.
|
||||
// LibDiamond internal functions are used by DiamondCutFacet,
|
||||
// DiamondLoupeFacet and the diamond proxy contract (the Diamond contract).
|
||||
|
||||
error NoSelectorsGivenToAdd();
|
||||
error NotContractOwner(address _user, address _contractOwner);
|
||||
error NoSelectorsProvidedForFacetForCut(address _facetAddress);
|
||||
error CannotAddSelectorsToZeroAddress(bytes4[] _selectors);
|
||||
error NoBytecodeAtAddress(address _contractAddress, string _message);
|
||||
error IncorrectFacetCutAction(uint8 _action);
|
||||
error CannotAddFunctionToDiamondThatAlreadyExists(bytes4 _selector);
|
||||
error CannotReplaceFunctionsFromFacetWithZeroAddress(bytes4[] _selectors);
|
||||
error CannotReplaceImmutableFunction(bytes4 _selector);
|
||||
error CannotReplaceFunctionWithTheSameFunctionFromTheSameFacet(bytes4 _selector);
|
||||
error CannotReplaceFunctionThatDoesNotExists(bytes4 _selector);
|
||||
error RemoveFacetAddressMustBeZeroAddress(address _facetAddress);
|
||||
error CannotRemoveFunctionThatDoesNotExist(bytes4 _selector);
|
||||
error CannotRemoveImmutableFunction(bytes4 _selector);
|
||||
error InitializationFunctionReverted(address _initializationContractAddress, bytes _calldata);
|
||||
|
||||
library LibDiamond {
|
||||
bytes32 constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage");
|
||||
|
||||
struct FacetAddressAndSelectorPosition {
|
||||
address facetAddress;
|
||||
uint16 selectorPosition;
|
||||
}
|
||||
|
||||
struct DiamondStorage {
|
||||
// function selector => facet address and selector position in selectors array
|
||||
mapping(bytes4 => FacetAddressAndSelectorPosition) facetAddressAndSelectorPosition;
|
||||
bytes4[] selectors;
|
||||
mapping(bytes4 => bool) supportedInterfaces;
|
||||
// owner of the contract
|
||||
address contractOwner;
|
||||
}
|
||||
|
||||
function diamondStorage() internal pure returns (DiamondStorage storage ds) {
|
||||
bytes32 position = DIAMOND_STORAGE_POSITION;
|
||||
assembly {
|
||||
ds.slot := position
|
||||
}
|
||||
}
|
||||
|
||||
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
|
||||
|
||||
function setContractOwner(address _newOwner) internal {
|
||||
DiamondStorage storage ds = diamondStorage();
|
||||
address previousOwner = ds.contractOwner;
|
||||
ds.contractOwner = _newOwner;
|
||||
emit OwnershipTransferred(previousOwner, _newOwner);
|
||||
}
|
||||
|
||||
function contractOwner() internal view returns (address contractOwner_) {
|
||||
contractOwner_ = diamondStorage().contractOwner;
|
||||
}
|
||||
|
||||
function enforceIsContractOwner() internal view {
|
||||
if(msg.sender != diamondStorage().contractOwner) {
|
||||
revert NotContractOwner(msg.sender, diamondStorage().contractOwner);
|
||||
}
|
||||
}
|
||||
|
||||
event DiamondCut(IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata);
|
||||
|
||||
// Internal function version of diamondCut
|
||||
function diamondCut(
|
||||
IDiamondCut.FacetCut[] memory _diamondCut,
|
||||
address _init,
|
||||
bytes memory _calldata
|
||||
) internal {
|
||||
for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) {
|
||||
bytes4[] memory functionSelectors = _diamondCut[facetIndex].functionSelectors;
|
||||
address facetAddress = _diamondCut[facetIndex].facetAddress;
|
||||
if(functionSelectors.length == 0) {
|
||||
revert NoSelectorsProvidedForFacetForCut(facetAddress);
|
||||
}
|
||||
IDiamondCut.FacetCutAction action = _diamondCut[facetIndex].action;
|
||||
if (action == IDiamond.FacetCutAction.Add) {
|
||||
addFunctions(facetAddress, functionSelectors);
|
||||
} else if (action == IDiamond.FacetCutAction.Replace) {
|
||||
replaceFunctions(facetAddress, functionSelectors);
|
||||
} else if (action == IDiamond.FacetCutAction.Remove) {
|
||||
removeFunctions(facetAddress, functionSelectors);
|
||||
} else {
|
||||
revert IncorrectFacetCutAction(uint8(action));
|
||||
}
|
||||
}
|
||||
emit DiamondCut(_diamondCut, _init, _calldata);
|
||||
initializeDiamondCut(_init, _calldata);
|
||||
}
|
||||
|
||||
function addFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
|
||||
if(_facetAddress == address(0)) {
|
||||
revert CannotAddSelectorsToZeroAddress(_functionSelectors);
|
||||
}
|
||||
DiamondStorage storage ds = diamondStorage();
|
||||
uint16 selectorCount = uint16(ds.selectors.length);
|
||||
enforceHasContractCode(_facetAddress, "LibDiamondCut: Add facet has no code");
|
||||
for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
|
||||
bytes4 selector = _functionSelectors[selectorIndex];
|
||||
address oldFacetAddress = ds.facetAddressAndSelectorPosition[selector].facetAddress;
|
||||
if(oldFacetAddress != address(0)) {
|
||||
revert CannotAddFunctionToDiamondThatAlreadyExists(selector);
|
||||
}
|
||||
ds.facetAddressAndSelectorPosition[selector] = FacetAddressAndSelectorPosition(_facetAddress, selectorCount);
|
||||
ds.selectors.push(selector);
|
||||
selectorCount++;
|
||||
}
|
||||
}
|
||||
|
||||
function replaceFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
|
||||
DiamondStorage storage ds = diamondStorage();
|
||||
if(_facetAddress == address(0)) {
|
||||
revert CannotReplaceFunctionsFromFacetWithZeroAddress(_functionSelectors);
|
||||
}
|
||||
enforceHasContractCode(_facetAddress, "LibDiamondCut: Replace facet has no code");
|
||||
for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
|
||||
bytes4 selector = _functionSelectors[selectorIndex];
|
||||
address oldFacetAddress = ds.facetAddressAndSelectorPosition[selector].facetAddress;
|
||||
// can't replace immutable functions -- functions defined directly in the diamond in this case
|
||||
if(oldFacetAddress == address(this)) {
|
||||
revert CannotReplaceImmutableFunction(selector);
|
||||
}
|
||||
if(oldFacetAddress == _facetAddress) {
|
||||
revert CannotReplaceFunctionWithTheSameFunctionFromTheSameFacet(selector);
|
||||
}
|
||||
if(oldFacetAddress == address(0)) {
|
||||
revert CannotReplaceFunctionThatDoesNotExists(selector);
|
||||
}
|
||||
// replace old facet address
|
||||
ds.facetAddressAndSelectorPosition[selector].facetAddress = _facetAddress;
|
||||
}
|
||||
}
|
||||
|
||||
function removeFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
|
||||
DiamondStorage storage ds = diamondStorage();
|
||||
uint256 selectorCount = ds.selectors.length;
|
||||
if(_facetAddress != address(0)) {
|
||||
revert RemoveFacetAddressMustBeZeroAddress(_facetAddress);
|
||||
}
|
||||
for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
|
||||
bytes4 selector = _functionSelectors[selectorIndex];
|
||||
FacetAddressAndSelectorPosition memory oldFacetAddressAndSelectorPosition = ds.facetAddressAndSelectorPosition[selector];
|
||||
if(oldFacetAddressAndSelectorPosition.facetAddress == address(0)) {
|
||||
revert CannotRemoveFunctionThatDoesNotExist(selector);
|
||||
}
|
||||
|
||||
|
||||
// can't remove immutable functions -- functions defined directly in the diamond
|
||||
if(oldFacetAddressAndSelectorPosition.facetAddress == address(this)) {
|
||||
revert CannotRemoveImmutableFunction(selector);
|
||||
}
|
||||
// replace selector with last selector
|
||||
selectorCount--;
|
||||
if (oldFacetAddressAndSelectorPosition.selectorPosition != selectorCount) {
|
||||
bytes4 lastSelector = ds.selectors[selectorCount];
|
||||
ds.selectors[oldFacetAddressAndSelectorPosition.selectorPosition] = lastSelector;
|
||||
ds.facetAddressAndSelectorPosition[lastSelector].selectorPosition = oldFacetAddressAndSelectorPosition.selectorPosition;
|
||||
}
|
||||
// delete last selector
|
||||
ds.selectors.pop();
|
||||
delete ds.facetAddressAndSelectorPosition[selector];
|
||||
}
|
||||
}
|
||||
|
||||
function initializeDiamondCut(address _init, bytes memory _calldata) internal {
|
||||
if (_init == address(0)) {
|
||||
return;
|
||||
}
|
||||
enforceHasContractCode(_init, "LibDiamondCut: _init address has no code");
|
||||
(bool success, bytes memory error) = _init.delegatecall(_calldata);
|
||||
if (!success) {
|
||||
if (error.length > 0) {
|
||||
// bubble up error
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
let returndata_size := mload(error)
|
||||
revert(add(32, error), returndata_size)
|
||||
}
|
||||
} else {
|
||||
revert InitializationFunctionReverted(_init, _calldata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function enforceHasContractCode(address _contract, string memory _errorMessage) internal view {
|
||||
uint256 contractSize;
|
||||
assembly {
|
||||
contractSize := extcodesize(_contract)
|
||||
}
|
||||
if(contractSize == 0) {
|
||||
revert NoBytecodeAtAddress(_contract, _errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// These facets are added to the diamond.
|
||||
///////////////////////////////////////////////
|
||||
|
||||
contract DiamondCutFacet is IDiamondCut {
|
||||
/// @notice Add/replace/remove any number of functions and optionally execute
|
||||
/// a function with delegatecall
|
||||
/// @param _diamondCut Contains the facet addresses and function selectors
|
||||
/// @param _init The address of the contract or facet to execute _calldata
|
||||
/// @param _calldata A function call, including function selector and arguments
|
||||
/// _calldata is executed with delegatecall on _init
|
||||
function diamondCut(
|
||||
FacetCut[] calldata _diamondCut,
|
||||
address _init,
|
||||
bytes calldata _calldata
|
||||
) external override {
|
||||
LibDiamond.enforceIsContractOwner();
|
||||
LibDiamond.diamondCut(_diamondCut, _init, _calldata);
|
||||
}
|
||||
}
|
||||
|
||||
// The functions in DiamondLoupeFacet MUST be added to a diamond.
|
||||
// The EIP-2535 Diamond standard requires these functions.
|
||||
|
||||
interface IERC165 {
|
||||
/// @notice Query if a contract implements an interface
|
||||
/// @param interfaceId The interface identifier, as specified in ERC-165
|
||||
/// @dev Interface identification is specified in ERC-165. This function
|
||||
/// uses less than 30,000 gas.
|
||||
/// @return `true` if the contract implements `interfaceID` and
|
||||
/// `interfaceID` is not 0xffffffff, `false` otherwise
|
||||
function supportsInterface(bytes4 interfaceId) external view returns (bool);
|
||||
}
|
||||
|
||||
// A loupe is a small magnifying glass used to look at diamonds.
|
||||
// These functions look at diamonds
|
||||
interface IDiamondLoupe {
|
||||
/// These functions are expected to be called frequently
|
||||
/// by tools.
|
||||
|
||||
struct Facet {
|
||||
address facetAddress;
|
||||
bytes4[] functionSelectors;
|
||||
}
|
||||
|
||||
/// @notice Gets all facet addresses and their four byte function selectors.
|
||||
/// @return facets_ Facet
|
||||
function facets() external view returns (Facet[] memory facets_);
|
||||
|
||||
/// @notice Gets all the function selectors supported by a specific facet.
|
||||
/// @param _facet The facet address.
|
||||
/// @return facetFunctionSelectors_
|
||||
function facetFunctionSelectors(address _facet) external view returns (bytes4[] memory facetFunctionSelectors_);
|
||||
|
||||
/// @notice Get all the facet addresses used by a diamond.
|
||||
/// @return facetAddresses_
|
||||
function facetAddresses() external view returns (address[] memory facetAddresses_);
|
||||
|
||||
/// @notice Gets the facet that supports the given selector.
|
||||
/// @dev If facet is not found return address(0).
|
||||
/// @param _functionSelector The function selector.
|
||||
/// @return facetAddress_ The facet address.
|
||||
function facetAddress(bytes4 _functionSelector) external view returns (address facetAddress_);
|
||||
}
|
||||
|
||||
contract DiamondLoupeFacet is IDiamondLoupe, IERC165 {
|
||||
// Diamond Loupe Functions
|
||||
////////////////////////////////////////////////////////////////////
|
||||
/// These functions are expected to be called frequently by tools.
|
||||
//
|
||||
// struct Facet {
|
||||
// address facetAddress;
|
||||
// bytes4[] functionSelectors;
|
||||
// }
|
||||
/// @notice Gets all facets and their selectors.
|
||||
/// @return facets_ Facet
|
||||
function facets() external override view returns (Facet[] memory facets_) {
|
||||
LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
|
||||
uint256 selectorCount = ds.selectors.length;
|
||||
// create an array set to the maximum size possible
|
||||
facets_ = new Facet[](selectorCount);
|
||||
// create an array for counting the number of selectors for each facet
|
||||
uint16[] memory numFacetSelectors = new uint16[](selectorCount);
|
||||
// total number of facets
|
||||
uint256 numFacets;
|
||||
// loop through function selectors
|
||||
for (uint256 selectorIndex; selectorIndex < selectorCount; selectorIndex++) {
|
||||
bytes4 selector = ds.selectors[selectorIndex];
|
||||
address facetAddress_ = ds.facetAddressAndSelectorPosition[selector].facetAddress;
|
||||
bool continueLoop = false;
|
||||
// find the functionSelectors array for selector and add selector to it
|
||||
for (uint256 facetIndex; facetIndex < numFacets; facetIndex++) {
|
||||
if (facets_[facetIndex].facetAddress == facetAddress_) {
|
||||
facets_[facetIndex].functionSelectors[numFacetSelectors[facetIndex]] = selector;
|
||||
numFacetSelectors[facetIndex]++;
|
||||
continueLoop = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if functionSelectors array exists for selector then continue loop
|
||||
if (continueLoop) {
|
||||
continueLoop = false;
|
||||
continue;
|
||||
}
|
||||
// create a new functionSelectors array for selector
|
||||
facets_[numFacets].facetAddress = facetAddress_;
|
||||
facets_[numFacets].functionSelectors = new bytes4[](selectorCount);
|
||||
facets_[numFacets].functionSelectors[0] = selector;
|
||||
numFacetSelectors[numFacets] = 1;
|
||||
numFacets++;
|
||||
}
|
||||
for (uint256 facetIndex; facetIndex < numFacets; facetIndex++) {
|
||||
uint256 numSelectors = numFacetSelectors[facetIndex];
|
||||
bytes4[] memory selectors = facets_[facetIndex].functionSelectors;
|
||||
// setting the number of selectors
|
||||
assembly {
|
||||
mstore(selectors, numSelectors)
|
||||
}
|
||||
}
|
||||
// setting the number of facets
|
||||
assembly {
|
||||
mstore(facets_, numFacets)
|
||||
}
|
||||
}
|
||||
|
||||
/// @notice Gets all the function selectors supported by a specific facet.
|
||||
/// @param _facet The facet address.
|
||||
/// @return _facetFunctionSelectors The selectors associated with a facet address.
|
||||
function facetFunctionSelectors(address _facet) external override view returns (bytes4[] memory _facetFunctionSelectors) {
|
||||
LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
|
||||
uint256 selectorCount = ds.selectors.length;
|
||||
uint256 numSelectors;
|
||||
_facetFunctionSelectors = new bytes4[](selectorCount);
|
||||
// loop through function selectors
|
||||
for (uint256 selectorIndex; selectorIndex < selectorCount; selectorIndex++) {
|
||||
bytes4 selector = ds.selectors[selectorIndex];
|
||||
address facetAddress_ = ds.facetAddressAndSelectorPosition[selector].facetAddress;
|
||||
if (_facet == facetAddress_) {
|
||||
_facetFunctionSelectors[numSelectors] = selector;
|
||||
numSelectors++;
|
||||
}
|
||||
}
|
||||
// Set the number of selectors in the array
|
||||
assembly {
|
||||
mstore(_facetFunctionSelectors, numSelectors)
|
||||
}
|
||||
}
|
||||
|
||||
/// @notice Get all the facet addresses used by a diamond.
|
||||
/// @return facetAddresses_
|
||||
function facetAddresses() external override view returns (address[] memory facetAddresses_) {
|
||||
LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
|
||||
uint256 selectorCount = ds.selectors.length;
|
||||
// create an array set to the maximum size possible
|
||||
facetAddresses_ = new address[](selectorCount);
|
||||
uint256 numFacets;
|
||||
// loop through function selectors
|
||||
for (uint256 selectorIndex; selectorIndex < selectorCount; selectorIndex++) {
|
||||
bytes4 selector = ds.selectors[selectorIndex];
|
||||
address facetAddress_ = ds.facetAddressAndSelectorPosition[selector].facetAddress;
|
||||
bool continueLoop = false;
|
||||
// see if we have collected the address already and break out of loop if we have
|
||||
for (uint256 facetIndex; facetIndex < numFacets; facetIndex++) {
|
||||
if (facetAddress_ == facetAddresses_[facetIndex]) {
|
||||
continueLoop = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// continue loop if we already have the address
|
||||
if (continueLoop) {
|
||||
continueLoop = false;
|
||||
continue;
|
||||
}
|
||||
// include address
|
||||
facetAddresses_[numFacets] = facetAddress_;
|
||||
numFacets++;
|
||||
}
|
||||
// Set the number of facet addresses in the array
|
||||
assembly {
|
||||
mstore(facetAddresses_, numFacets)
|
||||
}
|
||||
}
|
||||
|
||||
/// @notice Gets the facet address that supports the given selector.
|
||||
/// @dev If facet is not found return address(0).
|
||||
/// @param _functionSelector The function selector.
|
||||
/// @return facetAddress_ The facet address.
|
||||
function facetAddress(bytes4 _functionSelector) external override view returns (address facetAddress_) {
|
||||
LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
|
||||
facetAddress_ = ds.facetAddressAndSelectorPosition[_functionSelector].facetAddress;
|
||||
}
|
||||
|
||||
// This implements ERC-165.
|
||||
function supportsInterface(bytes4 _interfaceId) external override view returns (bool) {
|
||||
LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
|
||||
return ds.supportedInterfaces[_interfaceId];
|
||||
}
|
||||
}
|
||||
|
||||
/// @title ERC-173 Contract Ownership Standard
|
||||
/// Note: the ERC-165 identifier for this interface is 0x7f5828d0
|
||||
/* is ERC165 */
|
||||
interface IERC173 {
|
||||
/// @dev This emits when ownership of a contract changes.
|
||||
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
|
||||
|
||||
/// @notice Get the address of the owner
|
||||
/// @return owner_ The address of the owner.
|
||||
function owner() external view returns (address owner_);
|
||||
|
||||
/// @notice Set the address of the new owner of the contract
|
||||
/// @dev Set _newOwner to address(0) to renounce any ownership.
|
||||
/// @param _newOwner The address of the new owner of the contract
|
||||
function transferOwnership(address _newOwner) external;
|
||||
}
|
||||
|
||||
contract OwnershipFacet is IERC173 {
|
||||
function transferOwnership(address _newOwner) external override {
|
||||
LibDiamond.enforceIsContractOwner();
|
||||
LibDiamond.setContractOwner(_newOwner);
|
||||
}
|
||||
|
||||
function owner() external override view returns (address owner_) {
|
||||
owner_ = LibDiamond.contractOwner();
|
||||
}
|
||||
}
|
||||
///////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// DiamondInit
|
||||
// This contract and function are used to initialize state variables and/or do other actions
|
||||
// when the `diamondCut` function is called.
|
||||
// It is expected that this contract is customized if you want to deploy your diamond
|
||||
// with data from a deployment script. Use the init function to initialize state variables
|
||||
// of your diamond. Add parameters to the init funciton if you need to.
|
||||
// DiamondInit can be used during deployment or for upgrades.
|
||||
|
||||
// Adding parameters to the `init` or other functions you add here can make a single deployed
|
||||
// DiamondInit contract reusable accross upgrades, and can be used for multiple diamonds.
|
||||
|
||||
contract DiamondInit {
|
||||
|
||||
// You can add parameters to this function in order to pass in
|
||||
// data to set your own state variables
|
||||
function init() external {
|
||||
// adding ERC165 data
|
||||
LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
|
||||
ds.supportedInterfaces[type(IERC165).interfaceId] = true;
|
||||
ds.supportedInterfaces[type(IDiamondCut).interfaceId] = true;
|
||||
ds.supportedInterfaces[type(IDiamondLoupe).interfaceId] = true;
|
||||
ds.supportedInterfaces[type(IERC173).interfaceId] = true;
|
||||
|
||||
// add your own state variables
|
||||
// EIP-2535 specifies that the `diamondCut` function takes two optional
|
||||
// arguments: address _init and bytes calldata _calldata
|
||||
// These arguments are used to execute an arbitrary function using delegatecall
|
||||
// in order to set state variables in the diamond during deployment or an upgrade
|
||||
// More info in the EIP2535 Diamonds standard.
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// DiamondMultiInit
|
||||
// This version of DiamondInit can be used to execute multiple initialization functions.
|
||||
// It is expected that this contract is customized if you want to deploy or upgrade your diamond with it.
|
||||
|
||||
error AddressAndCalldataLengthDoNotMatch(uint256 _addressesLength, uint256 _calldataLength);
|
||||
|
||||
contract DiamondMultiInit {
|
||||
|
||||
// This function is provided in the third parameter of the `diamondCut` function.
|
||||
// The `diamondCut` function executes this function to execute multiple initializer functions for a single upgrade.
|
||||
|
||||
function multiInit(address[] calldata _addresses, bytes[] calldata _calldata) external {
|
||||
if(_addresses.length != _calldata.length) {
|
||||
revert AddressAndCalldataLengthDoNotMatch(_addresses.length, _calldata.length);
|
||||
}
|
||||
for(uint i; i < _addresses.length; i++) {
|
||||
LibDiamond.initializeDiamondCut(_addresses[i], _calldata[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// Diamond
|
||||
// The diamond proxy contract.
|
||||
|
||||
|
||||
// When no function exists for function called
|
||||
error FunctionNotFound(bytes4 _functionSelector);
|
||||
|
||||
// This is used in diamond constructor
|
||||
// more arguments are added to this struct
|
||||
// this avoids stack too deep errors
|
||||
struct DiamondArgs {
|
||||
address owner;
|
||||
address init;
|
||||
bytes initCalldata;
|
||||
}
|
||||
|
||||
contract Diamond {
|
||||
|
||||
// Remember to add the loupe functions from DiamondLoupeFacet to the diamond.
|
||||
// The loupe functions are required by the EIP2535 Diamonds standard
|
||||
|
||||
constructor(IDiamondCut.FacetCut[] memory _diamondCut, DiamondArgs memory _args) payable {
|
||||
LibDiamond.setContractOwner(_args.owner);
|
||||
LibDiamond.diamondCut(_diamondCut, _args.init, _args.initCalldata);
|
||||
|
||||
// Code can be added here to perform actions and set state variables.
|
||||
}
|
||||
|
||||
// Find facet for function that is called and execute the
|
||||
// function if a facet is found and return any value.
|
||||
fallback() external payable {
|
||||
LibDiamond.DiamondStorage storage ds;
|
||||
bytes32 position = LibDiamond.DIAMOND_STORAGE_POSITION;
|
||||
// get diamond storage
|
||||
assembly {
|
||||
ds.slot := position
|
||||
}
|
||||
// get facet from function selector
|
||||
address facet = ds.facetAddressAndSelectorPosition[msg.sig].facetAddress;
|
||||
if(facet == address(0)) {
|
||||
revert FunctionNotFound(msg.sig);
|
||||
}
|
||||
// Execute external function from facet using delegatecall and return any value.
|
||||
assembly {
|
||||
// copy function selector and any arguments
|
||||
calldatacopy(0, 0, calldatasize())
|
||||
// execute function call using the facet
|
||||
let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0)
|
||||
// get any return value
|
||||
returndatacopy(0, 0, returndatasize())
|
||||
// return any return value or error back to the caller
|
||||
switch result
|
||||
case 0 {
|
||||
revert(0, returndatasize())
|
||||
}
|
||||
default {
|
||||
return(0, returndatasize())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
receive() external payable {}
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
// Diamond Storage is particularly good for isolating or compartmenting state variables to specific
|
||||
// facets or functionality. This is great for creating modular facets that can be understood as their
|
||||
// own units and be added to diamonds. A diamond with a lot of functionality is well organized and
|
||||
// understandable if each of its facets can be understood in isolation. Diamond Storage helps make that
|
||||
// possible.
|
||||
|
||||
// However, you may want to share state variables specific to your application with facets that are specific
|
||||
// to your application. It can get somewhat tedious to call a `diamondStorage()` function in every function
|
||||
// that you want to access state variables.
|
||||
|
||||
// `AppStorage` is a specialized version of Diamond Storage. It is a more convenient way to access
|
||||
// application specific state variables that are shared among facets.
|
||||
|
||||
// The pattern works in the following way:
|
||||
|
||||
// 1. Define a struct called AppStorage that contains all the state variables specific to your application
|
||||
// and that you plan to share with different facets. Store AppStorage in a file. Any of your facets can
|
||||
// now import this file to access the state variables.
|
||||
|
||||
struct AppStorage {
|
||||
uint256 secondVar;
|
||||
uint256 firstVar;
|
||||
uint256 lastVar;
|
||||
// add other state variables ...
|
||||
}
|
||||
|
||||
|
||||
// 2. In a facet that imports the AppStorage struct declare an AppStorage state variable called `s`.
|
||||
// This should be the only state variable declared in the facet.
|
||||
|
||||
// 3. In your facet you can now access all the state variables in AppStorage by prepending state variables
|
||||
// with `s.`. Here is example code:
|
||||
|
||||
|
||||
// import { AppStorage } from "./LibAppStorage.sol";
|
||||
|
||||
contract AFacet {
|
||||
AppStorage internal s;
|
||||
|
||||
function sumVariables() external {
|
||||
s.lastVar = s.firstVar + s.secondVar;
|
||||
}
|
||||
|
||||
function getFirsVar() external view returns (uint256) {
|
||||
return s.firstVar;
|
||||
}
|
||||
|
||||
function setLastVar(uint256 _newValue) external {
|
||||
s.lastVar = _newValue;
|
||||
}
|
||||
}
|
||||
|
||||
// Sharing AppStorage in another facet:
|
||||
|
||||
// import { AppStorage } from "./LibAppStorage.sol";
|
||||
|
||||
contract SomeOtherFacet {
|
||||
AppStorage internal s;
|
||||
|
||||
function getLargerVar() external view returns (uint256) {
|
||||
uint256 firstVar = s.firstVar;
|
||||
uint256 secondVar = s.secondVar;
|
||||
if(firstVar > secondVar) {
|
||||
return firstVar;
|
||||
}
|
||||
else {
|
||||
return secondVar;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Using the 's.' prefix to access AppStorage is a nice convention because it makes state variables
|
||||
// concise, easy to access, and it distinguishes state variables from local variables and prevents
|
||||
// name clashes/shadowing with local variables and function names. It helps identify and make
|
||||
// explicit state variables in a convenient and concise way. AppStorage can be used in regualar
|
||||
// contracts as well as proxy contracts, diamonds, implementation contracts, Solidity libraries and
|
||||
// facets.
|
||||
|
||||
// Since `AppStorage s` is the first and only state variable declared in facets its position in
|
||||
// contract storage is `0`. This fact can be used to access AppStorage in Solidity libraries using
|
||||
// diamond storage access. Here's an example of that:
|
||||
|
||||
library LibAppStorage {
|
||||
function appStorage() internal pure returns (AppStorage storage ds) {
|
||||
assembly { ds.slot := 0 }
|
||||
}
|
||||
|
||||
function someFunction() internal {
|
||||
AppStorage storage s = appStorage();
|
||||
s.firstVar = 8;
|
||||
//... do more stuff
|
||||
}
|
||||
}
|
||||
|
||||
// `AppStorage s` can be declared as the one and only state variable in facets or it can be declared in a
|
||||
// contract that facets inherit.
|
||||
|
||||
// AppStorage won't work if state variables are declared outside of AppStorage and outside of Diamond Storage.
|
||||
// It is a common error for a facet to inherit a contract that declares state variables outside AppStorage and
|
||||
// Diamond Storage. This causes a misalignment of state variables.
|
||||
|
||||
// One downside is that state variables can't be declared public in structs so getter functions can't
|
||||
// automatically be created this way. But it can be nice to make your own getter functions for
|
||||
// state variables because it is explicit.
|
||||
|
||||
// The rules for upgrading AppStorage are the same for Diamond Storage. These rules can be found at
|
||||
// the end of the file ./DiamondStorage.sol
|
|
@ -1,156 +0,0 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
// Diamond storage is a contract storage strategy that is used in proxy contracts and diamonds.
|
||||
|
||||
// It greatly simplifies organizing and using state variables in proxy contracts and diamonds.
|
||||
|
||||
// Diamond storage relies on Solidity structs that contain sets of state variables.
|
||||
|
||||
// A struct can be defined with state variables and then used in a particular position in contract
|
||||
// storage. The position can be determined by a hash of a unique string or other data. The string
|
||||
// acts like a namespace for the struct. For example a diamond storage string for a struct could
|
||||
// be 'com.mycompany.projectx.mystruct'. That will look familiar to you if you have used programming
|
||||
// languages that use namespaces.
|
||||
|
||||
// Namespaces are used in some programming languages to package data and code together as separate
|
||||
// reusable units. Diamond storage packages sets of state variables as separate, reusable data units
|
||||
// in contract storage.
|
||||
|
||||
// Let's look at a simple example of diamond storage:
|
||||
|
||||
library LibERC721 {
|
||||
bytes32 constant ERC721_POSITION = keccak256("erc721.storage");
|
||||
|
||||
// Instead of using a hash of a string other schemes can be used to create positions in contract storage.
|
||||
// Here is a scheme that could be used:
|
||||
//
|
||||
// bytes32 constant ERC721_POSITION =
|
||||
// keccak256(abi.encodePacked(
|
||||
// ERC721.interfaceId,
|
||||
// ERC721.name
|
||||
// ));
|
||||
|
||||
struct ERC721Storage {
|
||||
// tokenId => owner
|
||||
mapping (uint256 => address) tokenIdToOwner;
|
||||
// owner => count of tokens owned
|
||||
mapping (address => uint256) ownerToNFTokenCount;
|
||||
|
||||
string name;
|
||||
string symbol;
|
||||
}
|
||||
|
||||
// Return ERC721 storage struct for reading and writing
|
||||
function getStorage() internal pure returns (ERC721Storage storage storageStruct) {
|
||||
bytes32 position = ERC721_POSITION;
|
||||
assembly {
|
||||
storageStruct.slot := position
|
||||
}
|
||||
}
|
||||
|
||||
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
|
||||
|
||||
// This is a very simplified implementation.
|
||||
// It does not include all necessary validation of input.
|
||||
// It is used to show diamond storage.
|
||||
function transferFrom(address _from, address _to, uint256 _tokenId) internal {
|
||||
ERC721Storage storage erc721Storage = LibERC721.getStorage();
|
||||
address tokenOwner = erc721Storage.tokenIdToOwner[_tokenId];
|
||||
require(tokenOwner == _from);
|
||||
erc721Storage.tokenIdToOwner[_tokenId] = _to;
|
||||
erc721Storage.ownerToNFTokenCount[_from]--;
|
||||
erc721Storage.ownerToNFTokenCount[_to]++;
|
||||
emit Transfer(_from, _to, _tokenId);
|
||||
}
|
||||
}
|
||||
|
||||
// Note that this is not a full or correct ERC721 implementation.
|
||||
// This is an example of using diamond storage.
|
||||
|
||||
// Note that the ERC721.name and ERC721.symbol storage variables would probably be set
|
||||
// in an `init` function at deployment time or during an upgrade.
|
||||
|
||||
|
||||
// Shows use of LibERC721 and diamond storage
|
||||
contract ERC721Facet {
|
||||
|
||||
function name() external view returns (string memory name_) {
|
||||
name_ = LibERC721.getStorage().name;
|
||||
}
|
||||
|
||||
function symbol() external view returns (string memory symbol_) {
|
||||
symbol_ = LibERC721.getStorage().symbol;
|
||||
}
|
||||
|
||||
function transferFrom(address _from, address _to, uint256 _tokenId) external {
|
||||
LibERC721.transferFrom(_from, _to, _tokenId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Here we show how we can share state variables and internal functions between facets by
|
||||
// using Solidity libraries. Sharing internal functions between facets can also be done by
|
||||
// inheriting contracts that contain internal functions.
|
||||
contract ERC721BatchTransferFacet {
|
||||
|
||||
function batchTransferFrom(address _from, address _to, uint256[] calldata _tokenIds) external {
|
||||
for(uint256 i; i < _tokenIds.length; i++) {
|
||||
LibERC721.transferFrom(_from, _to, _tokenIds[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// HOW TO UPGRADE DIAMOND STORAGE
|
||||
//--------------------------------------------
|
||||
|
||||
// It is important not to corrupt state variables during an upgrade. It is easy to handle state
|
||||
// variables correctly in upgrades.
|
||||
|
||||
// Here's some things that can be done:
|
||||
|
||||
// 1. To add new state variables to an AppStorage struct or a Diamond Storage struct, add them
|
||||
// to the end of the struct.
|
||||
|
||||
// 2. New state variables can be added to the ends of structs that are stored in mappings.
|
||||
|
||||
// 3. The names of state variables can be changed, but that might be confusing if different
|
||||
// facets are using different names for the same storage locations.
|
||||
|
||||
// Do not do the following:
|
||||
|
||||
// 1. If you are using AppStorage then do not declare and use state variables outside the
|
||||
// AppStorage struct. Except Diamond Storage can be used. Diamond Storage and AppStorage
|
||||
// can be used together.
|
||||
|
||||
// 2. Do not add new state variables to the beginning or middle of structs. Doing this
|
||||
// makes the new state variable overwrite existing state variable data and all state
|
||||
// variables after the new state variable reference the wrong storage location.
|
||||
|
||||
// 3. Do not put structs directly in structs unless you don’t plan on ever adding more state
|
||||
// variables to the inner structs. You won't be able to add new state variables to inner
|
||||
// structs in upgrades.
|
||||
|
||||
// 4. Do not add new state variables to structs that are used in arrays.
|
||||
|
||||
// 5. When using Diamond Storage do not use the same namespace string for different structs.
|
||||
// This is obvious. Two different structs at the same location will overwrite each other.
|
||||
|
||||
// 6. Do not allow any facet to be able to call `selfdestruct`. This is easy. Simply don’t
|
||||
// allow the `selfdestruct` command to exist in any facet source code and don’t allow
|
||||
// that command to be called via a delegatecall. Because `selfdestruct` could delete a
|
||||
// facet that is used by a diamond, or `selfdestruct` could be used to delete a diamond
|
||||
// proxy contract.
|
||||
|
||||
// A trick to use inner structs and still enable them to be extended is to put them in mappings.
|
||||
// A struct stored in a mapping can be extended in upgrades. You could use a value like 0 defined
|
||||
// with a constant like INNER_STRUCT. Put your structs in mappings and then access them with the
|
||||
// INNER_STRUCT constant. Example: MyStruct storage mystruct = storage.mystruct[INNER_STRUCT];
|
||||
|
||||
// Note that any Solidity data type can be used in Diamond Storage or AppStorage structs. It is
|
||||
// just that structs directly in structs and structs that are used in arrays can’t be extended
|
||||
// with more state variables in the future. That could be fine in some cases.
|
||||
|
||||
// These rules will make sense if you understand how Solidity assigns storage locations to state
|
||||
// variables. I recommend reading and understanding this section of the Solidity documentation:
|
||||
// 'Layout of State Variables in Storage'
|
|
@ -1,22 +0,0 @@
|
|||
# Set of test vectors to perform benchmarking of EIP-2537
|
||||
|
||||
## Inlined vectors
|
||||
|
||||
Here one can find inputs (encoded with ABI from the main spec spec) that can be considered "worst cases" for "double-and-add" multiplication algorithm, and also some cases for pairing call. Those are purely for convenience of initial benchmarking of the full ABI without manual test generation.
|
||||
|
||||
```
|
||||
G1 addition example input =
|
||||
0000000000000000000000000000000012196c5a43d69224d8713389285f26b98f86ee910ab3dd668e413738282003cc5b7357af9a7af54bb713d62255e80f560000000000000000000000000000000006ba8102bfbeea4416b710c73e8cce3032c31c6269c44906f8ac4f7874ce99fb17559992486528963884ce429a992fee000000000000000000000000000000000001101098f5c39893765766af4512a0c74e1bb89bc7e6fdf14e3e7337d257cc0f94658179d83320b99f31ff94cd2bac0000000000000000000000000000000003e1a9f9f44ca2cdab4f43a1a3ee3470fdf90b2fc228eb3b709fcd72f014838ac82a6d797aeefed9a0804b22ed1ce8f7
|
||||
G2 addition example input =
|
||||
0000000000000000000000000000000018c0ada6351b70661f053365deae56910798bd2ace6e2bf6ba4192d1a229967f6af6ca1c9a8a11ebc0a232344ee0f6d6000000000000000000000000000000000cc70a587f4652039d8117b6103858adcd9728f6aebe230578389a62da0042b7623b1c0436734f463cfdd187d20903240000000000000000000000000000000009f50bd7beedb23328818f9ffdafdb6da6a4dd80c5a9048ab8b154df3cad938ccede829f1156f769d9e149791e8e0cd900000000000000000000000000000000079ba50d2511631b20b6d6f3841e616e9d11b68ec3368cd60129d9d4787ab56c4e9145a38927e51c9cd6271d493d938800000000000000000000000000000000192fa5d8732ff9f38e0b1cf12eadfd2608f0c7a39aced7746837833ae253bb57ef9c0d98a4b69eeb2950901917e99d1e0000000000000000000000000000000009aeb10c372b5ef1010675c6a4762fda33636489c23b581c75220589afbc0cc46249f921eea02dd1b761e036ffdbae220000000000000000000000000000000002d225447600d49f932b9dd3ca1e6959697aa603e74d8666681a2dca8160c3857668ae074440366619eb8920256c4e4a00000000000000000000000000000000174882cdd3551e0ce6178861ff83e195fecbcffd53a67b6f10b4431e423e28a480327febe70276036f60bb9c99cf7633
|
||||
G1 mul double and add worst case =
|
||||
0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
G2 mul double and add worst case =
|
||||
00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79beffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
Pairing case for 2 pairs =
|
||||
0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be
|
||||
Pairing case for 4 pairs =
|
||||
0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be
|
||||
Pairing case for 6 pairs =
|
||||
0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be
|
||||
```
|
|
@ -1,245 +0,0 @@
|
|||
# Field element to curve point mapping used by EIP 2537
|
||||
|
||||
For a BLS12-381 implemented by EIP-2537 a short Weierstrass curve equation y^2 = x^3 + A * x + B has a property that a product AB = 0, so to implement a mapping function two step algorithms is performed:
|
||||
- Field element is mapped to a some other curve with AB != 0
|
||||
- Isogeny is applied to one to one map a point of this other curve to a point on BLS12-381
|
||||
- Cofactor is cleared for a point now on BLS12-381
|
||||
|
||||
Below we describe generic algorithms for mapping and isogeny application, and later on give concrete parameters for the algorithms
|
||||
|
||||
## Helper function to clear a cofactor
|
||||
|
||||
Later on we use a helper function to clear a cofactor of the curve point. It's implemented as
|
||||
|
||||
~~~
|
||||
clear_cofactor(P) := h_eff * P
|
||||
~~~
|
||||
|
||||
where values of h_eff are given below in parameters sections
|
||||
|
||||
## Simplified SWU for AB != 0
|
||||
|
||||
The function map\_to\_curve\_simple\_swu(u) implements a simplification
|
||||
of the Shallue-van de Woestijne-Ulas mapping described by Brier et
|
||||
al., which they call the "simplified SWU" map. Wahby and Boneh generalize and optimize this mapping.
|
||||
|
||||
Preconditions: A Weierstrass curve y^2 = g(x) x^3 + A * x + B where A != 0 and B != 0.
|
||||
|
||||
Constants:
|
||||
|
||||
- A and B, the parameters of the Weierstrass curve.
|
||||
|
||||
- Z, an element of F meeting the below criteria.
|
||||
The criteria are:
|
||||
1. Z is non-square in F,
|
||||
2. Z != -1 in F,
|
||||
3. the polynomial g(x) - Z is irreducible over F, and
|
||||
4. g(B / (Z * A)) is square in F.
|
||||
|
||||
Sign of y: Inputs u and -u give the same x-coordinate.
|
||||
Thus, we set sgn0(y) == sgn0(u).
|
||||
|
||||
Exceptions: The exceptional cases are values of u such that
|
||||
Z^2 * u^4 + Z * u^2 == 0. This includes u == 0, and may include
|
||||
other values depending on Z. Implementations must detect
|
||||
this case and set x1 = B / (Z * A), which guarantees that g(x1)
|
||||
is square by the condition on Z given above.
|
||||
|
||||
Operations:
|
||||
|
||||
~~~
|
||||
1. tv1 = inv0(Z^2 * u^4 + Z * u^2)
|
||||
2. x1 = (-B / A) * (1 + tv1)
|
||||
3. If tv1 == 0, set x1 = B / (Z * A)
|
||||
4. gx1 = x1^3 + A * x1 + B
|
||||
5. x2 = Z * u^2 * x1
|
||||
6. gx2 = x2^3 + A * x2 + B
|
||||
7. If is_square(gx1), set x = x1 and y = sqrt(gx1)
|
||||
8. Else set x = x2 and y = sqrt(gx2)
|
||||
9. If sgn0(u) != sgn0(y), set y = -y
|
||||
10. return (x, y)
|
||||
~~~
|
||||
|
||||
## Simplified SWU for AB == 0
|
||||
|
||||
Wahby and Boneh show how to adapt the simplified SWU mapping to
|
||||
Weierstrass curves having A == 0 or B == 0, which the mapping of
|
||||
simple SWU does not support.
|
||||
|
||||
This method requires finding another elliptic curve E' given by the equation
|
||||
|
||||
~~~
|
||||
y'^2 = g'(x') = x'^3 + A' * x' + B'
|
||||
~~~
|
||||
|
||||
that is isogenous to E and has A' != 0 and B' != 0.
|
||||
This isogeny defines a map iso\_map(x', y') given by a pair of rational functions.
|
||||
iso\_map takes as input a point on E' and produces as output a point on E.
|
||||
|
||||
Once E' and iso\_map are identified, this mapping works as follows: on input
|
||||
u, first apply the simplified SWU mapping to get a point on E', then apply
|
||||
the isogeny map to that point to get a point on E.
|
||||
|
||||
Note that iso\_map is a group homomorphism, meaning that point addition
|
||||
commutes with iso\_map.
|
||||
Thus, when using this mapping in the hash\_to\_curve construction of {{roadmap}},
|
||||
one can effect a small optimization by first mapping u0 and u1 to E', adding
|
||||
the resulting points on E', and then applying iso\_map to the sum.
|
||||
This gives the same result while requiring only one evaluation of iso\_map.
|
||||
|
||||
Preconditions: An elliptic curve E' with A' != 0 and B' != 0 that is
|
||||
isogenous to the target curve E with isogeny map iso\_map from
|
||||
E' to E.
|
||||
|
||||
So the full mapping algorithm looks as:
|
||||
|
||||
- map\_to\_curve\_simple\_swu is the simple SWU mapping to E'
|
||||
- iso\_map is the isogeny map from E' to E
|
||||
|
||||
Sign of y: for this map, the sign is determined by map\_to\_curve\_simple\_swu.
|
||||
No further sign adjustments are necessary.
|
||||
|
||||
Exceptions: map\_to\_curve\_simple\_swu handles its exceptional cases.
|
||||
Exceptional cases of iso\_map are inputs that cause the denominator of
|
||||
either rational function to evaluate to zero; such cases MUST return the
|
||||
identity point on E.
|
||||
|
||||
## Full algorithm restated
|
||||
|
||||
~~~
|
||||
1. (x', y') = map_to_curve_simple_swu(u) # (x', y') is on E'
|
||||
2. (x, y) = iso_map(x', y') # (x, y) is on E
|
||||
3. (x, y) = clear_cofactor((x, y)) # clears cofactor for point (x, y) on E
|
||||
4. return (x, y)
|
||||
~~~
|
||||
|
||||
## Parameters for EIP-2537
|
||||
|
||||
### Fp-to-G1 mapping
|
||||
|
||||
|
||||
- Z: 11
|
||||
- E': y'^2 = x'^3 + A' * x' + B', where
|
||||
- A' = 0x144698a3b8e9433d693a02c96d4982b0ea985383ee66a8d8e8981aefd881ac98936f8da0e0f97f5cf428082d584c1d
|
||||
- B' = 0x12e2908d11688030018b12e8753eee3b2016c1f0f24f4070a0b9c14fcef35ef55a23215a316ceaa5d1cc48e98e172be0
|
||||
- h\_eff: 0xd201000000010001
|
||||
|
||||
The 11-isogeny map from (x', y') on E' to (x, y) on E is given by the following rational functions:
|
||||
|
||||
- x = x\_num / x\_den, where
|
||||
- x\_num = k\_(1,11) * x'^11 + k\_(1,10) * x'^10 + k\_(1,9) * x'^9 + ... + k\_(1,0)
|
||||
- x\_den = x'^10 + k\_(2,9) * x'^9 + k\_(2,8) * x'^8 + ... + k\_(2,0)
|
||||
|
||||
- y = y' * y\_num / y\_den, where
|
||||
- y\_num = k\_(3,15) * x'^15 + k\_(3,14) * x'^14 + k\_(3,13) * x'^13 + ... + k\_(3,0)
|
||||
- y\_den = x'^15 + k\_(4,14) * x'^14 + k\_(4,13) * x'^13 + ... + k\_(4,0)
|
||||
|
||||
The constants used to compute x\_num are as follows:
|
||||
|
||||
- k\_(1,0) = 0x11a05f2b1e833340b809101dd99815856b303e88a2d7005ff2627b56cdb4e2c85610c2d5f2e62d6eaeac1662734649b7
|
||||
- k\_(1,1) = 0x17294ed3e943ab2f0588bab22147a81c7c17e75b2f6a8417f565e33c70d1e86b4838f2a6f318c356e834eef1b3cb83bb
|
||||
- k\_(1,2) = 0xd54005db97678ec1d1048c5d10a9a1bce032473295983e56878e501ec68e25c958c3e3d2a09729fe0179f9dac9edcb0
|
||||
- k\_(1,3) = 0x1778e7166fcc6db74e0609d307e55412d7f5e4656a8dbf25f1b33289f1b330835336e25ce3107193c5b388641d9b6861
|
||||
- k\_(1,4) = 0xe99726a3199f4436642b4b3e4118e5499db995a1257fb3f086eeb65982fac18985a286f301e77c451154ce9ac8895d9
|
||||
- k\_(1,5) = 0x1630c3250d7313ff01d1201bf7a74ab5db3cb17dd952799b9ed3ab9097e68f90a0870d2dcae73d19cd13c1c66f652983
|
||||
- k\_(1,6) = 0xd6ed6553fe44d296a3726c38ae652bfb11586264f0f8ce19008e218f9c86b2a8da25128c1052ecaddd7f225a139ed84
|
||||
- k\_(1,7) = 0x17b81e7701abdbe2e8743884d1117e53356de5ab275b4db1a682c62ef0f2753339b7c8f8c8f475af9ccb5618e3f0c88e
|
||||
- k\_(1,8) = 0x80d3cf1f9a78fc47b90b33563be990dc43b756ce79f5574a2c596c928c5d1de4fa295f296b74e956d71986a8497e317
|
||||
- k\_(1,9) = 0x169b1f8e1bcfa7c42e0c37515d138f22dd2ecb803a0c5c99676314baf4bb1b7fa3190b2edc0327797f241067be390c9e
|
||||
- k\_(1,10) = 0x10321da079ce07e272d8ec09d2565b0dfa7dccdde6787f96d50af36003b14866f69b771f8c285decca67df3f1605fb7b
|
||||
- k\_(1,11) = 0x6e08c248e260e70bd1e962381edee3d31d79d7e22c837bc23c0bf1bc24c6b68c24b1b80b64d391fa9c8ba2e8ba2d229
|
||||
|
||||
The constants used to compute x\_den are as follows:
|
||||
|
||||
- k\_(2,0) = 0x8ca8d548cff19ae18b2e62f4bd3fa6f01d5ef4ba35b48ba9c9588617fc8ac62b558d681be343df8993cf9fa40d21b1c
|
||||
- k\_(2,1) = 0x12561a5deb559c4348b4711298e536367041e8ca0cf0800c0126c2588c48bf5713daa8846cb026e9e5c8276ec82b3bff
|
||||
- k\_(2,2) = 0xb2962fe57a3225e8137e629bff2991f6f89416f5a718cd1fca64e00b11aceacd6a3d0967c94fedcfcc239ba5cb83e19
|
||||
- k\_(2,3) = 0x3425581a58ae2fec83aafef7c40eb545b08243f16b1655154cca8abc28d6fd04976d5243eecf5c4130de8938dc62cd8
|
||||
- k\_(2,4) = 0x13a8e162022914a80a6f1d5f43e7a07dffdfc759a12062bb8d6b44e833b306da9bd29ba81f35781d539d395b3532a21e
|
||||
- k\_(2,5) = 0xe7355f8e4e667b955390f7f0506c6e9395735e9ce9cad4d0a43bcef24b8982f7400d24bc4228f11c02df9a29f6304a5
|
||||
- k\_(2,6) = 0x772caacf16936190f3e0c63e0596721570f5799af53a1894e2e073062aede9cea73b3538f0de06cec2574496ee84a3a
|
||||
- k\_(2,7) = 0x14a7ac2a9d64a8b230b3f5b074cf01996e7f63c21bca68a81996e1cdf9822c580fa5b9489d11e2d311f7d99bbdcc5a5e
|
||||
- k\_(2,8) = 0xa10ecf6ada54f825e920b3dafc7a3cce07f8d1d7161366b74100da67f39883503826692abba43704776ec3a79a1d641
|
||||
- k\_(2,9) = 0x95fc13ab9e92ad4476d6e3eb3a56680f682b4ee96f7d03776df533978f31c1593174e4b4b7865002d6384d168ecdd0a
|
||||
|
||||
The constants used to compute y\_num are as follows:
|
||||
|
||||
- k\_(3,0) = 0x90d97c81ba24ee0259d1f094980dcfa11ad138e48a869522b52af6c956543d3cd0c7aee9b3ba3c2be9845719707bb33
|
||||
- k\_(3,1) = 0x134996a104ee5811d51036d776fb46831223e96c254f383d0f906343eb67ad34d6c56711962fa8bfe097e75a2e41c696
|
||||
- k\_(3,2) = 0xcc786baa966e66f4a384c86a3b49942552e2d658a31ce2c344be4b91400da7d26d521628b00523b8dfe240c72de1f6
|
||||
- k\_(3,3) = 0x1f86376e8981c217898751ad8746757d42aa7b90eeb791c09e4a3ec03251cf9de405aba9ec61deca6355c77b0e5f4cb
|
||||
- k\_(3,4) = 0x8cc03fdefe0ff135caf4fe2a21529c4195536fbe3ce50b879833fd221351adc2ee7f8dc099040a841b6daecf2e8fedb
|
||||
- k\_(3,5) = 0x16603fca40634b6a2211e11db8f0a6a074a7d0d4afadb7bd76505c3d3ad5544e203f6326c95a807299b23ab13633a5f0
|
||||
- k\_(3,6) = 0x4ab0b9bcfac1bbcb2c977d027796b3ce75bb8ca2be184cb5231413c4d634f3747a87ac2460f415ec961f8855fe9d6f2
|
||||
- k\_(3,7) = 0x987c8d5333ab86fde9926bd2ca6c674170a05bfe3bdd81ffd038da6c26c842642f64550fedfe935a15e4ca31870fb29
|
||||
- k\_(3,8) = 0x9fc4018bd96684be88c9e221e4da1bb8f3abd16679dc26c1e8b6e6a1f20cabe69d65201c78607a360370e577bdba587
|
||||
- k\_(3,9) = 0xe1bba7a1186bdb5223abde7ada14a23c42a0ca7915af6fe06985e7ed1e4d43b9b3f7055dd4eba6f2bafaaebca731c30
|
||||
- k\_(3,10) = 0x19713e47937cd1be0dfd0b8f1d43fb93cd2fcbcb6caf493fd1183e416389e61031bf3a5cce3fbafce813711ad011c132
|
||||
- k\_(3,11) = 0x18b46a908f36f6deb918c143fed2edcc523559b8aaf0c2462e6bfe7f911f643249d9cdf41b44d606ce07c8a4d0074d8e
|
||||
- k\_(3,12) = 0xb182cac101b9399d155096004f53f447aa7b12a3426b08ec02710e807b4633f06c851c1919211f20d4c04f00b971ef8
|
||||
- k\_(3,13) = 0x245a394ad1eca9b72fc00ae7be315dc757b3b080d4c158013e6632d3c40659cc6cf90ad1c232a6442d9d3f5db980133
|
||||
- k\_(3,14) = 0x5c129645e44cf1102a159f748c4a3fc5e673d81d7e86568d9ab0f5d396a7ce46ba1049b6579afb7866b1e715475224b
|
||||
- k\_(3,15) = 0x15e6be4e990f03ce4ea50b3b42df2eb5cb181d8f84965a3957add4fa95af01b2b665027efec01c7704b456be69c8b604
|
||||
|
||||
The constants used to compute y\_den are as follows:
|
||||
|
||||
- k\_(4,0) = 0x16112c4c3a9c98b252181140fad0eae9601a6de578980be6eec3232b5be72e7a07f3688ef60c206d01479253b03663c1
|
||||
- k\_(4,1) = 0x1962d75c2381201e1a0cbd6c43c348b885c84ff731c4d59ca4a10356f453e01f78a4260763529e3532f6102c2e49a03d
|
||||
- k\_(4,2) = 0x58df3306640da276faaae7d6e8eb15778c4855551ae7f310c35a5dd279cd2eca6757cd636f96f891e2538b53dbf67f2
|
||||
- k\_(4,3) = 0x16b7d288798e5395f20d23bf89edb4d1d115c5dbddbcd30e123da489e726af41727364f2c28297ada8d26d98445f5416
|
||||
- k\_(4,4) = 0xbe0e079545f43e4b00cc912f8228ddcc6d19c9f0f69bbb0542eda0fc9dec916a20b15dc0fd2ededda39142311a5001d
|
||||
- k\_(4,5) = 0x8d9e5297186db2d9fb266eaac783182b70152c65550d881c5ecd87b6f0f5a6449f38db9dfa9cce202c6477faaf9b7ac
|
||||
- k\_(4,6) = 0x166007c08a99db2fc3ba8734ace9824b5eecfdfa8d0cf8ef5dd365bc400a0051d5fa9c01a58b1fb93d1a1399126a775c
|
||||
- k\_(4,7) = 0x16a3ef08be3ea7ea03bcddfabba6ff6ee5a4375efa1f4fd7feb34fd206357132b920f5b00801dee460ee415a15812ed9
|
||||
- k\_(4,8) = 0x1866c8ed336c61231a1be54fd1d74cc4f9fb0ce4c6af5920abc5750c4bf39b4852cfe2f7bb9248836b233d9d55535d4a
|
||||
- k\_(4,9) = 0x167a55cda70a6e1cea820597d94a84903216f763e13d87bb5308592e7ea7d4fbc7385ea3d529b35e346ef48bb8913f55
|
||||
- k\_(4,10) = 0x4d2f259eea405bd48f010a01ad2911d9c6dd039bb61a6290e591b36e636a5c871a5c29f4f83060400f8b49cba8f6aa8
|
||||
- k\_(4,11) = 0xaccbb67481d033ff5852c1e48c50c477f94ff8aefce42d28c0f9a88cea7913516f968986f7ebbea9684b529e2561092
|
||||
- k\_(4,12) = 0xad6b9514c767fe3c3613144b45f1496543346d98adf02267d5ceef9a00d9b8693000763e3b90ac11e99b138573345cc
|
||||
- k\_(4,13) = 0x2660400eb2e4f3b628bdd0d53cd76f2bf565b94e72927c1cb748df27942480e420517bd8714cc80d1fadc1326ed06f7
|
||||
- k\_(4,14) = 0xe0fa1d816ddc03e6b24255e0d7819c171c40f65e273b853324efcd6356caa205ca2f570f13497804415473a1d634b8f
|
||||
|
||||
### Fp2-to-G2 mapping
|
||||
|
||||
Symbol `I` means a non-residue used to make an extension field Fp2
|
||||
|
||||
- Z: -(2 + I)
|
||||
- E': y'^2 = x'^3 + A' * x' + B', where
|
||||
- A' = 240 * I
|
||||
- B' = 1012 * (1 + I)
|
||||
- h\_eff: 0xbc69f08f2ee75b3584c6a0ea91b352888e2a8e9145ad7689986ff031508ffe1329c2f178731db956d82bf015d1212b02ec0ec69d7477c1ae954cbc06689f6a359894c0adebbf6b4e8020005aaa95551
|
||||
|
||||
The 3-isogeny map from (x', y') on E' to (x, y) on E is given by the following rational functions:
|
||||
|
||||
- x = x\_num / x\_den, where
|
||||
- x\_num = k\_(1,3) * x'^3 + k\_(1,2) * x'^2 + k\_(1,1) * x' + k\_(1,0)
|
||||
- x\_den = x'^2 + k\_(2,1) * x' + k\_(2,0)
|
||||
|
||||
- y = y' * y\_num / y\_den, where
|
||||
- y\_num = k\_(3,3) * x'^3 + k\_(3,2) * x'^2 + k\_(3,1) * x' + k\_(3,0)
|
||||
- y\_den = x'^3 + k\_(4,2) * x'^2 + k\_(4,1) * x' + k\_(4,0)
|
||||
|
||||
The constants used to compute x\_num are as follows:
|
||||
|
||||
- k\_(1,0) = 0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97d6 + 0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97d6 * I
|
||||
- k\_(1,1) = 0x11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71a * I
|
||||
- k\_(1,2) = 0x11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71e + 0x8ab05f8bdd54cde190937e76bc3e447cc27c3d6fbd7063fcd104635a790520c0a395554e5c6aaaa9354ffffffffe38d * I
|
||||
- k\_(1,3) = 0x171d6541fa38ccfaed6dea691f5fb614cb14b4e7f4e810aa22d6108f142b85757098e38d0f671c7188e2aaaaaaaa5ed1
|
||||
|
||||
The constants used to compute x\_den are as follows:
|
||||
|
||||
- k\_(2,0) = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa63 * I
|
||||
- k\_(2,1) = 0xc + 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa9f * I
|
||||
|
||||
The constants used to compute y\_num are as follows:
|
||||
|
||||
- k\_(3,0) = 0x1530477c7ab4113b59a4c18b076d11930f7da5d4a07f649bf54439d87d27e500fc8c25ebf8c92f6812cfc71c71c6d706 + 0x1530477c7ab4113b59a4c18b076d11930f7da5d4a07f649bf54439d87d27e500fc8c25ebf8c92f6812cfc71c71c6d706 * I
|
||||
- k\_(3,1) = 0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97be * I
|
||||
- k\_(3,2) = 0x11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71c + 0x8ab05f8bdd54cde190937e76bc3e447cc27c3d6fbd7063fcd104635a790520c0a395554e5c6aaaa9354ffffffffe38f * I
|
||||
- k\_(3,3) = 0x124c9ad43b6cf79bfbf7043de3811ad0761b0f37a1e26286b0e977c69aa274524e79097a56dc4bd9e1b371c71c718b10
|
||||
|
||||
The constants used to compute y\_den are as follows:
|
||||
|
||||
- k\_(4,0) = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa8fb + 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa8fb * I
|
||||
- k\_(4,1) = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa9d3 * I
|
||||
- k\_(4,2) = 0x12 + 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa99 * I
|
Before Width: | Height: | Size: 171 KiB |
Before Width: | Height: | Size: 156 KiB |
Before Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 64 KiB |
|
@ -1,483 +0,0 @@
|
|||
{
|
||||
"title": "Package Manifest",
|
||||
"description": "EthPM Manifest Specification",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"manifest"
|
||||
],
|
||||
"version": "3",
|
||||
"not": {
|
||||
"required": ["manifest_version"]
|
||||
},
|
||||
"properties": {
|
||||
"manifest": {
|
||||
"type": "string",
|
||||
"title": "Manifest",
|
||||
"description": "EthPM Manifest Version",
|
||||
"default": "ethpm/3",
|
||||
"enum": ["ethpm/3"]
|
||||
},
|
||||
"name": {
|
||||
"$ref": "#/definitions/PackageName"
|
||||
},
|
||||
"version": {
|
||||
"title": "Package Version",
|
||||
"description": "The version of the package that this release is for",
|
||||
"type": "string"
|
||||
},
|
||||
"meta": {
|
||||
"$ref": "#/definitions/PackageMeta"
|
||||
},
|
||||
"sources": {
|
||||
"title": "Sources",
|
||||
"description": "The source files included in this release",
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
".*": {
|
||||
"$ref": "#/definitions/Source"
|
||||
}
|
||||
}
|
||||
},
|
||||
"compilers": {
|
||||
"title": "Compilers",
|
||||
"description": "The compiler versions used in this release",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/CompilerInformation"
|
||||
}
|
||||
},
|
||||
"contractTypes": {
|
||||
"title": "Contract Types",
|
||||
"description": "The contract types included in this release",
|
||||
"type": "object",
|
||||
"propertyNames": {
|
||||
"$ref": "#/definitions/ContractTypeName"
|
||||
},
|
||||
"patternProperties": {
|
||||
"": {
|
||||
"$ref": "#/definitions/ContractType"
|
||||
}
|
||||
}
|
||||
},
|
||||
"deployments": {
|
||||
"title": "Deployments",
|
||||
"description": "The deployed contract instances in this release",
|
||||
"type": "object",
|
||||
"propertyNames": {
|
||||
"$ref": "#/definitions/BlockchainURI"
|
||||
},
|
||||
"patternProperties": {
|
||||
"": {
|
||||
"$ref": "#/definitions/Deployment"
|
||||
}
|
||||
}
|
||||
},
|
||||
"buildDependencies": {
|
||||
"title": "Build Dependencies",
|
||||
"type": "object",
|
||||
"propertyNames": {
|
||||
"$ref": "#/definitions/PackageName"
|
||||
},
|
||||
"patternProperties": {
|
||||
"": {
|
||||
"$ref": "#/definitions/ContentURI"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"Source": {
|
||||
"title": "Source",
|
||||
"description": "Information about a source file included in this package",
|
||||
"type": "object",
|
||||
"anyOf": [
|
||||
{"required": ["content"]},
|
||||
{"required": ["urls"]}
|
||||
],
|
||||
"properties": {
|
||||
"checksum": {
|
||||
"$ref": "#/definitions/ChecksumObject"
|
||||
},
|
||||
"urls": {
|
||||
"title": "URLs",
|
||||
"description": "Array of urls that resolve to the source file",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/ContentURI"
|
||||
}
|
||||
},
|
||||
"content": {
|
||||
"title": "Inlined source code",
|
||||
"type": "string"
|
||||
},
|
||||
"installPath": {
|
||||
"title": "Target file path to install source file",
|
||||
"type": "string",
|
||||
"pattern": "^\\.\\/.*$"
|
||||
},
|
||||
"type": {
|
||||
"title": "Type",
|
||||
"description": "File type of this source",
|
||||
"type": "string"
|
||||
},
|
||||
"license": {
|
||||
"title": "License",
|
||||
"description": "The license associated with the source file",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PackageMeta": {
|
||||
"title": "Package Meta",
|
||||
"description": "Metadata about the package",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"authors": {
|
||||
"title": "Authors",
|
||||
"description": "Authors of this package",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"license": {
|
||||
"title": "License",
|
||||
"description": "The license that this package and its source are released under",
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"title": "Description",
|
||||
"description": "Description of this package",
|
||||
"type": "string"
|
||||
},
|
||||
"keywords": {
|
||||
"title": "Keywords",
|
||||
"description": "Keywords that apply to this package",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"title": "Links",
|
||||
"descriptions": "URIs for resources related to this package",
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string",
|
||||
"format": "uri"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"PackageName": {
|
||||
"title": "Package Name",
|
||||
"description": "The name of the package that this release is for",
|
||||
"type": "string",
|
||||
"pattern": "^[a-z][-a-z0-9]{0,255}$"
|
||||
},
|
||||
"ContractType": {
|
||||
"title": "Contract Type",
|
||||
"description": "Data for a contract type included in this package",
|
||||
"type": "object",
|
||||
"properties":{
|
||||
"contractName": {
|
||||
"$ref": "#/definitions/ContractTypeName"
|
||||
},
|
||||
"sourceId": {
|
||||
"title": "Source ID",
|
||||
"description": "The source ID that corresponds to this contract type",
|
||||
"type": "string"
|
||||
},
|
||||
"deploymentBytecode": {
|
||||
"$ref": "#/definitions/BytecodeObject"
|
||||
},
|
||||
"runtimeBytecode": {
|
||||
"$ref": "#/definitions/BytecodeObject"
|
||||
},
|
||||
"abi": {
|
||||
"title": "ABI",
|
||||
"description": "The ABI for this contract type",
|
||||
"type": "array"
|
||||
},
|
||||
"devdoc": {
|
||||
"title": "Devdoc",
|
||||
"description": "The dev-doc for this contract",
|
||||
"type": "object"
|
||||
},
|
||||
"userdoc": {
|
||||
"title": "Userdoc",
|
||||
"description": "The user-doc for this contract",
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ContractInstance": {
|
||||
"title": "Contract Instance",
|
||||
"description": "Data for a deployed instance of a contract",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"contractType",
|
||||
"address"
|
||||
],
|
||||
"properties": {
|
||||
"contractType": {
|
||||
"anyOf": [
|
||||
{"$ref": "#/definitions/ContractTypeName"},
|
||||
{"$ref": "#/definitions/NestedContractTypeName"}
|
||||
]
|
||||
},
|
||||
"address": {
|
||||
"$ref": "#/definitions/Address"
|
||||
},
|
||||
"transaction": {
|
||||
"$ref": "#/definitions/TransactionHash"
|
||||
},
|
||||
"block": {
|
||||
"$ref": "#/definitions/BlockHash"
|
||||
},
|
||||
"runtimeBytecode": {
|
||||
"$ref": "#/definitions/BytecodeObject"
|
||||
},
|
||||
"linkDependencies": {
|
||||
"title": "Link Dependencies",
|
||||
"description": "The values for the link references found within this contract instances runtime bytecode",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/LinkValue"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ContractTypeName": {
|
||||
"title": "Contract Type Name",
|
||||
"description": "The name of the contract type",
|
||||
"type": "string",
|
||||
"pattern": "^(?:[a-z][-a-z0-9]{0,255}\\:)?[a-zA-Z_$][-a-zA-Z0-9_$]{0,255}(?:[-a-zA-Z0-9]{1,256}])?$"
|
||||
},
|
||||
"ByteString": {
|
||||
"title": "Byte String",
|
||||
"description": "0x-prefixed hexadecimal string representing bytes",
|
||||
"type": "string",
|
||||
"pattern": "^0x([0-9a-fA-F]{2})*$"
|
||||
},
|
||||
"BytecodeObject": {
|
||||
"title": "Bytecode Object",
|
||||
"type": "object",
|
||||
"anyOf": [
|
||||
{"required": ["bytecode"]},
|
||||
{"required": ["linkDependencies"]}
|
||||
],
|
||||
"properties": {
|
||||
"bytecode": {
|
||||
"$ref": "#/definitions/ByteString"
|
||||
},
|
||||
"linkReferences": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/LinkReference"
|
||||
}
|
||||
},
|
||||
"linkDependencies": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/LinkValue"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ChecksumObject": {
|
||||
"title": "Checksum Object",
|
||||
"description": "Checksum information about the contents of a source file",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"hash",
|
||||
"algorithm"
|
||||
],
|
||||
"properties": {
|
||||
"hash": {
|
||||
"type": "string"
|
||||
},
|
||||
"algorithm": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"LinkReference": {
|
||||
"title": "Link Reference",
|
||||
"description": "A defined location in some bytecode which requires linking",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"offsets",
|
||||
"length",
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"offsets": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
}
|
||||
},
|
||||
"length": {
|
||||
"type": "integer",
|
||||
"minimum": 1
|
||||
},
|
||||
"name": {
|
||||
"anyOf": [
|
||||
{"$ref": "#/definitions/ContractTypeName"},
|
||||
{"$ref": "#/definitions/NestedContractTypeName"}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"LinkValue": {
|
||||
"title": "Link Value",
|
||||
"description": "A value for an individual link reference in a contract's bytecode",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"offsets",
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"offsets": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"description": "The type of link value",
|
||||
"type": "string"
|
||||
},
|
||||
"value": {
|
||||
"description": "The value for the link reference"
|
||||
}
|
||||
},
|
||||
"oneOf": [{
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["literal"]
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/definitions/ByteString"
|
||||
}
|
||||
}
|
||||
}, {
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["reference"]
|
||||
},
|
||||
"value": {
|
||||
"anyOf": [
|
||||
{"$ref": "#/definitions/ContractInstanceName"},
|
||||
{"$ref": "#/definitions/NestedContractInstanceName"}
|
||||
]
|
||||
}
|
||||
}
|
||||
}]
|
||||
},
|
||||
"ContractInstanceName": {
|
||||
"title": "Contract Instance Name",
|
||||
"description": "The name of the deployed contract instance",
|
||||
"type": "string",
|
||||
"pattern": "^[a-zA-Z_$][-a-zA-Z0-9_$]{0,255}(?:[-a-zA-Z0-9]{1,256})?$"
|
||||
},
|
||||
"Deployment": {
|
||||
"title": "Deployment",
|
||||
"type": "object",
|
||||
"propertyNames": {
|
||||
"$ref": "#/definitions/ContractInstanceName"
|
||||
},
|
||||
"patternProperties": {
|
||||
"": {
|
||||
"$ref": "#/definitions/ContractInstance"
|
||||
}
|
||||
}
|
||||
},
|
||||
"NestedContractTypeName": {
|
||||
"title": "Nested Contract Type Name",
|
||||
"description": "Name of a nested contract type from somewhere down the dependency tree",
|
||||
"type": "string",
|
||||
"pattern": "^(?:[a-z][-a-z0-9]{0,255}\\:)+[a-zA-Z_$][-a-zA-Z0-9_$]{0,255}(?:[-a-zA-Z0-9]{1,256})?$"
|
||||
},
|
||||
"NestedContractInstanceName": {
|
||||
"title": "Nested Contract Instance Name",
|
||||
"description": "Name of a nested contract instance from somewhere down the dependency tree",
|
||||
"type": "string",
|
||||
"pattern": "^(?:[a-z][-a-z0-9]{0,255}\\:)+[a-zA-Z_$][-a-zA-Z0-9_$]{0,255}(?:[-a-zA-Z0-9]{1,256})?$"
|
||||
},
|
||||
"CompilerInformation": {
|
||||
"title": "Compiler Information",
|
||||
"description": "Information about the software that was used to compile a contract type or deployment",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"version"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"description": "The name of the compiler",
|
||||
"type": "string"
|
||||
},
|
||||
"version": {
|
||||
"description": "The version string for the compiler",
|
||||
"type": "string"
|
||||
},
|
||||
"settings": {
|
||||
"description": "The settings used for compilation",
|
||||
"type": "object"
|
||||
},
|
||||
"contractTypes": {
|
||||
"description": "The contract types that targeted this compiler.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/ContractTypeName"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Address": {
|
||||
"title": "Address",
|
||||
"description": "A 0x-prefixed Ethereum address",
|
||||
"allOf": [
|
||||
{ "$ref": "#/definitions/ByteString" },
|
||||
{ "minLength": 42, "maxLength": 42 }
|
||||
]
|
||||
},
|
||||
"TransactionHash": {
|
||||
"title": "Transaction Hash",
|
||||
"description": "A 0x-prefixed Ethereum transaction hash",
|
||||
"allOf": [
|
||||
{ "$ref": "#/definitions/ByteString" },
|
||||
{ "minLength": 66, "maxLength": 66 }
|
||||
]
|
||||
},
|
||||
"BlockHash": {
|
||||
"title": "Block Hash",
|
||||
"description": "An Ethereum block hash",
|
||||
"allOf": [
|
||||
{ "$ref": "#/definitions/ByteString" },
|
||||
{ "minLength": 66, "maxLength": 66 }
|
||||
]
|
||||
},
|
||||
"ContentURI": {
|
||||
"title": "Content URI",
|
||||
"description": "An content addressable URI",
|
||||
"type": "string",
|
||||
"format": "uri"
|
||||
},
|
||||
"BlockchainURI": {
|
||||
"title": "Blockchain URI",
|
||||
"description": "An BIP122 URI",
|
||||
"type": "string",
|
||||
"pattern": "^blockchain\\://[0-9a-fA-F]{64}\\/block\\/[0-9a-fA-F]{64}$"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"name": ["version"],
|
||||
"version": ["name"]
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 51 KiB |
Before Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 21 KiB |
|
@ -1,131 +0,0 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
pragma solidity ^0.7.1;
|
||||
import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";
|
||||
import { ABDKMath64x64 } from "abdk-libraries-solidity/ABDKMath64x64.sol";
|
||||
import { BaseLock } from "./BaseLock.sol";
|
||||
|
||||
/// @title Bidding on Ethereum addresses
|
||||
/// @author Victor Porton
|
||||
/// @notice Not audited, not enough tested.
|
||||
/// This allows anyone claim conditional tokens in order for him to transfer money from the future.
|
||||
/// See `docs/future-money.rst`.
|
||||
abstract contract BaseBidOnAddresses is BaseLock {
|
||||
using ABDKMath64x64 for int128;
|
||||
using SafeMath for uint256;
|
||||
|
||||
/// A condition score was stored in the chain by an oracle.
|
||||
/// @param oracleId The oracle ID.
|
||||
/// @param condition The conditional (customer addresses).
|
||||
/// @param numerator The relative score provided by the oracle.
|
||||
event ReportedNumerator(
|
||||
uint64 indexed oracleId,
|
||||
uint256 indexed condition,
|
||||
uint256 numerator
|
||||
);
|
||||
|
||||
/// Some condition scores were stored in the chain by an oracle.
|
||||
/// @param oracleId The oracle ID.
|
||||
/// @param conditions The conditionals (customer addresses).
|
||||
/// @param numerators The relative scores provided by the oracle.
|
||||
event ReportedNumeratorsBatch(
|
||||
uint64 indexed oracleId,
|
||||
uint64[] indexed conditions,
|
||||
uint256[] numerators
|
||||
);
|
||||
|
||||
// Whether an oracle finished its work.
|
||||
mapping(uint64 => bool) private oracleFinishedMap;
|
||||
// Mapping (oracleId => (condition => numerator)) for payout numerators.
|
||||
mapping(uint64 => mapping(uint256 => uint256)) private payoutNumeratorsMap;
|
||||
// Mapping (oracleId => denominator) for payout denominators.
|
||||
mapping(uint256 => uint) private payoutDenominatorMap;
|
||||
|
||||
/// Constructor.
|
||||
/// @param _uri Our ERC-1155 tokens description URI.
|
||||
constructor(string memory _uri) BaseLock(_uri) { }
|
||||
|
||||
/// Retrieve the last stored payout numerator (relative score of a condition).
|
||||
/// @param _oracleId The oracle ID.
|
||||
/// @param _condition The condition (the original receiver of a conditional token).
|
||||
/// The result can't change if the oracle has finished.
|
||||
function payoutNumerator(uint64 _oracleId, uint256 _condition) public view returns (uint256) {
|
||||
return payoutNumeratorsMap[_oracleId][_condition];
|
||||
}
|
||||
|
||||
/// Retrieve the last stored payout denominator (the sum of all numerators of the oracle).
|
||||
/// @param _oracleId The oracle ID.
|
||||
/// The result can't change if the oracle has finished.
|
||||
function payoutDenominator(uint64 _oracleId) public view returns (uint256) {
|
||||
return payoutDenominatorMap[_oracleId];
|
||||
}
|
||||
|
||||
/// Called by the oracle owner for reporting results of conditions.
|
||||
/// @param _oracleId The oracle ID.
|
||||
/// @param _condition The condition.
|
||||
/// @param _numerator The relative score of the condition.
|
||||
/// Note: We could make oracles easily verificable by a hash of all the data, but
|
||||
/// - It may need allowing to set a numerator only once.
|
||||
/// - It may be not necessary because future technology will allow to aggregate blockchains.
|
||||
function reportNumerator(uint64 _oracleId, uint256 _condition, uint256 _numerator) external
|
||||
_isOracle(_oracleId)
|
||||
_oracleNotFinished(_oracleId) // otherwise an oracle can break data consistency
|
||||
{
|
||||
_updateNumerator(_oracleId, _numerator, _condition);
|
||||
emit ReportedNumerator(_oracleId, _condition, _numerator);
|
||||
}
|
||||
|
||||
/// Called by the oracle owner for reporting results of several conditions.
|
||||
/// @param _oracleId The oracle ID.
|
||||
/// @param _conditions The conditions.
|
||||
/// @param _numerators The relative scores of the condition.
|
||||
function reportNumeratorsBatch(uint64 _oracleId, uint64[] calldata _conditions, uint256[] calldata _numerators) external
|
||||
_isOracle(_oracleId)
|
||||
_oracleNotFinished(_oracleId) // otherwise an oracle can break data consistency
|
||||
{
|
||||
require(_conditions.length == _numerators.length, "Length mismatch.");
|
||||
for (uint _i = 0; _i < _conditions.length; ++_i) {
|
||||
_updateNumerator(_oracleId, _numerators[_i], _conditions[_i]);
|
||||
}
|
||||
emit ReportedNumeratorsBatch(_oracleId, _conditions, _numerators);
|
||||
}
|
||||
|
||||
/// Need to be called after all numerators were reported.
|
||||
/// @param _oracleId The oracle ID.
|
||||
///
|
||||
/// You should set grace period end time before calling this method.
|
||||
///
|
||||
/// TODO: Maybe it makes sense to allow to set finish time in a point of the future?
|
||||
function finishOracle(uint64 _oracleId) external
|
||||
_isOracle(_oracleId)
|
||||
{
|
||||
oracleFinishedMap[_oracleId] = true;
|
||||
emit OracleFinished(_oracleId);
|
||||
}
|
||||
|
||||
/// Check if an oracle has finished.
|
||||
/// @param _oracleId The oracle ID.
|
||||
/// @return `true` if it has finished.
|
||||
function isOracleFinished(uint64 _oracleId) public view override returns (bool) {
|
||||
return oracleFinishedMap[_oracleId];
|
||||
}
|
||||
|
||||
function _updateNumerator(uint64 _oracleId, uint256 _numerator, uint256 _condition) private {
|
||||
payoutDenominatorMap[_oracleId] = payoutDenominatorMap[_oracleId].add(_numerator).sub(payoutNumeratorsMap[_oracleId][_condition]);
|
||||
payoutNumeratorsMap[_oracleId][_condition] = _numerator;
|
||||
}
|
||||
|
||||
// Virtuals //
|
||||
|
||||
function _calcRewardShare(uint64 _oracleId, uint256 _condition) internal virtual override view returns (int128) {
|
||||
uint256 _numerator = payoutNumeratorsMap[_oracleId][_condition];
|
||||
uint256 _denominator = payoutDenominatorMap[_oracleId];
|
||||
return ABDKMath64x64.divu(_numerator, _denominator);
|
||||
}
|
||||
|
||||
// Modifiers //
|
||||
|
||||
modifier _oracleNotFinished(uint64 _oracleId) {
|
||||
require(!isOracleFinished(_oracleId), "Oracle is finished.");
|
||||
_;
|
||||
}
|
||||
}
|
|
@ -1,510 +0,0 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
pragma solidity ^0.7.1;
|
||||
import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";
|
||||
import { ABDKMath64x64 } from "abdk-libraries-solidity/ABDKMath64x64.sol";
|
||||
import { ERC1155WithTotals } from "./ERC1155/ERC1155WithTotals.sol";
|
||||
import { ERC1155Holder } from "@openzeppelin/contracts/token/ERC1155/ERC1155Holder.sol";
|
||||
import { IERC1155 } from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
|
||||
import { ERC721Holder } from "@openzeppelin/contracts/token/ERC721/ERC721Holder.sol";
|
||||
|
||||
/// @title A base class to lock collaterals and distribute them proportional to an oracle result.
|
||||
/// @author Victor Porton
|
||||
/// @notice Not audited, not enough tested.
|
||||
///
|
||||
/// One can also donate/bequest a smart wallet (explain how).
|
||||
///
|
||||
/// We have two kinds of ERC-1155 token IDs:
|
||||
/// - conditional tokens: numbers < 2**64
|
||||
/// - a combination of a collateral contract address and collateral token ID
|
||||
/// (a counter of donated amount of collateral tokens, don't confuse with collateral tokens themselves)
|
||||
///
|
||||
/// Inheriting from here don't forget to create `createOracle()` external method.
|
||||
abstract contract BaseLock is
|
||||
ERC1155WithTotals,
|
||||
ERC1155Holder, // You are recommended to use `donate()` function instead.
|
||||
ERC721Holder // It can be used through an ERC-1155 wrapper.
|
||||
{
|
||||
using ABDKMath64x64 for int128;
|
||||
using SafeMath for uint256;
|
||||
|
||||
/// Emitted when an oracle is created.
|
||||
/// @param oracleId The ID of the created oracle.
|
||||
event OracleCreated(uint64 oracleId);
|
||||
|
||||
/// Emitted when an oracle owner is set.
|
||||
/// @param oracleOwner Who created an oracle
|
||||
/// @param oracleId The ID of the oracle.
|
||||
event OracleOwnerChanged(address indexed oracleOwner, uint64 indexed oracleId);
|
||||
|
||||
/// Emitted when an oracle owner is set.
|
||||
/// @param sender Who created the condition
|
||||
/// @param customer The owner of the condition.
|
||||
/// @param condition The created condition ID.
|
||||
event ConditionCreated(address indexed sender, address indexed customer, uint256 indexed condition);
|
||||
|
||||
/// Emitted when a collateral is donated.
|
||||
/// @param collateralContractAddress The ERC-1155 contract of the donated token.
|
||||
/// @param collateralTokenId The ERC-1155 ID of the donated token.
|
||||
/// @param sender Who donated.
|
||||
/// @param amount The amount donated.
|
||||
/// @param to Whose account the donation is assigned to.
|
||||
/// @param data Additional transaction data.
|
||||
event DonateCollateral(
|
||||
IERC1155 indexed collateralContractAddress,
|
||||
uint256 indexed collateralTokenId,
|
||||
address indexed sender,
|
||||
uint256 amount,
|
||||
address to,
|
||||
bytes data
|
||||
);
|
||||
|
||||
/// Emitted when an oracle is marked as having finished its work.
|
||||
/// @param oracleId The oracle ID.
|
||||
event OracleFinished(uint64 indexed oracleId);
|
||||
|
||||
/// Emitted when collateral is withdrawn.
|
||||
/// @param contractAddress The ERC-1155 contract of the collateral token.
|
||||
/// @param collateralTokenId The ERC-1155 token ID of the collateral.
|
||||
/// @param oracleId The oracle ID for which withdrawal is done.
|
||||
/// @param user Who has withdrawn.
|
||||
/// @param amount The amount withdrawn.
|
||||
event CollateralWithdrawn(
|
||||
IERC1155 indexed contractAddress,
|
||||
uint256 indexed collateralTokenId,
|
||||
uint64 indexed oracleId,
|
||||
address user,
|
||||
uint256 amount
|
||||
);
|
||||
|
||||
// Next ID.
|
||||
uint64 public maxOracleId; // It doesn't really need to be public.
|
||||
uint64 public maxConditionId; // It doesn't really need to be public.
|
||||
|
||||
// Mapping (oracleId => oracle owner).
|
||||
mapping(uint64 => address) private oracleOwnersMap;
|
||||
// Mapping (oracleId => time) the max time for first withdrawal.
|
||||
mapping(uint64 => uint) private gracePeriodEnds;
|
||||
// The user lost the right to transfer conditional tokens: (user => (conditionalToken => bool)).
|
||||
mapping(address => mapping(uint256 => bool)) private userUsedRedeemMap;
|
||||
// Mapping (token => (original user => amount)) used to calculate withdrawal of collateral amounts.
|
||||
mapping(uint256 => mapping(address => uint256)) public lastCollateralBalanceFirstRoundMap;
|
||||
// Mapping (token => (original user => amount)) used to calculate withdrawal of collateral amounts.
|
||||
mapping(uint256 => mapping(address => uint256)) public lastCollateralBalanceSecondRoundMap;
|
||||
/// Mapping (oracleId => amount user withdrew in first round) (see `docs/Calculations.md`).
|
||||
mapping(uint64 => uint256) public usersWithdrewInFirstRound;
|
||||
|
||||
// Mapping (condition ID => original account)
|
||||
mapping(uint256 => address) public conditionOwners;
|
||||
|
||||
/// Constructor.
|
||||
/// @param _uri Our ERC-1155 tokens description URI.
|
||||
constructor(string memory _uri) ERC1155WithTotals(_uri) {
|
||||
_registerInterface(
|
||||
BaseLock(0).onERC1155Received.selector ^
|
||||
BaseLock(0).onERC1155BatchReceived.selector ^
|
||||
BaseLock(0).onERC721Received.selector
|
||||
);
|
||||
}
|
||||
|
||||
/// This function makes no sense, because it would produce a condition with zero tokens.
|
||||
// function createCondition() public returns (uint64) {
|
||||
// return _createCondition();
|
||||
// }
|
||||
|
||||
/// Modify the owner of an oracle.
|
||||
/// @param _newOracleOwner New owner.
|
||||
/// @param _oracleId The oracle whose owner to change.
|
||||
function changeOracleOwner(address _newOracleOwner, uint64 _oracleId) public _isOracle(_oracleId) {
|
||||
oracleOwnersMap[_oracleId] = _newOracleOwner;
|
||||
emit OracleOwnerChanged(_newOracleOwner, _oracleId);
|
||||
}
|
||||
|
||||
/// Set the end time of the grace period.
|
||||
///
|
||||
/// The first withdrawal can be done *only* during the grace period.
|
||||
/// The second withdrawal can be done after the end of the grace period and only if the first withdrawal was done.
|
||||
///
|
||||
/// The intention of the grace period is to check which of users are active ("alive").
|
||||
function updateGracePeriodEnds(uint64 _oracleId, uint _time) public _isOracle(_oracleId) {
|
||||
gracePeriodEnds[_oracleId] = _time;
|
||||
}
|
||||
|
||||
/// Donate funds in an ERC-1155 token.
|
||||
///
|
||||
/// First, the collateral token need to be approved to be spent by this contract from the address `_from`.
|
||||
///
|
||||
/// It also mints a token (with a different ID), that counts donations in that token.
|
||||
///
|
||||
/// @param _collateralContractAddress The collateral ERC-1155 contract address.
|
||||
/// @param _collateralTokenId The collateral ERC-1155 token ID.
|
||||
/// @param _oracleId The oracle ID to whose ecosystem to donate to.
|
||||
/// @param _amount The amount to donate.
|
||||
/// @param _from From whom to take the donation.
|
||||
/// @param _to On whose account the donation amount is assigned.
|
||||
/// @param _data Additional transaction data.
|
||||
function donate(
|
||||
IERC1155 _collateralContractAddress,
|
||||
uint256 _collateralTokenId,
|
||||
uint64 _oracleId,
|
||||
uint256 _amount,
|
||||
address _from,
|
||||
address _to,
|
||||
bytes calldata _data) public
|
||||
{
|
||||
uint _donatedPerOracleCollateralTokenId = _collateralDonatedPerOracleTokenId(_collateralContractAddress, _collateralTokenId, _oracleId);
|
||||
_mint(_to, _donatedPerOracleCollateralTokenId, _amount, _data);
|
||||
uint _donatedCollateralTokenId = _collateralDonatedTokenId(_collateralContractAddress, _collateralTokenId);
|
||||
_mint(_to, _donatedCollateralTokenId, _amount, _data);
|
||||
emit DonateCollateral(_collateralContractAddress, _collateralTokenId, _from, _amount, _to, _data);
|
||||
_collateralContractAddress.safeTransferFrom(_from, address(this), _collateralTokenId, _amount, _data); // last against reentrancy attack
|
||||
}
|
||||
|
||||
/// Gather a DeFi profit of a token previous donated to this contact.
|
||||
/// @param _collateralContractAddress The collateral ERC-1155 contract address.
|
||||
/// @param _collateralTokenId The collateral ERC-1155 token ID.
|
||||
/// @param _oracleId The oracle ID to whose ecosystem to donate to.
|
||||
/// @param _data Additional transaction data.
|
||||
/// TODO: Batch calls in several tokens and/or to several oracles for less gas usage?
|
||||
function gatherDeFiProfit(
|
||||
IERC1155 _collateralContractAddress,
|
||||
uint256 _collateralTokenId,
|
||||
uint64 _oracleId,
|
||||
bytes calldata _data) external
|
||||
{
|
||||
uint _donatedPerOracleCollateralTokenId = _collateralDonatedPerOracleTokenId(_collateralContractAddress, _collateralTokenId, _oracleId);
|
||||
uint _donatedCollateralTokenId = _collateralDonatedTokenId(_collateralContractAddress, _collateralTokenId);
|
||||
|
||||
// We consider an overflow an error and just revert:
|
||||
// FIXME: Impossible due to reentrancy vulnerability? (Really? It's a view!)
|
||||
uint256 _difference =
|
||||
_collateralContractAddress.balanceOf(address(this), _collateralTokenId).sub(
|
||||
balanceOf(address(this), _donatedCollateralTokenId));
|
||||
uint256 _amount = // rounding down to prevent overflows
|
||||
_difference *
|
||||
balanceOf(address(this), _donatedPerOracleCollateralTokenId) /
|
||||
balanceOf(address(this), _donatedCollateralTokenId);
|
||||
|
||||
// Last to avoid reentrancy vulnerability.
|
||||
donate(
|
||||
_collateralContractAddress,
|
||||
_collateralTokenId,
|
||||
_oracleId,
|
||||
_amount,
|
||||
address(this),
|
||||
address(this),
|
||||
_data);
|
||||
}
|
||||
|
||||
/// Calculate how much collateral is owed to a user.
|
||||
/// @param _collateralContractAddress The ERC-1155 collateral token contract.
|
||||
/// @param _collateralTokenId The ERC-1155 collateral token ID.
|
||||
/// @param _oracleId From which oracle's "account" to withdraw.
|
||||
/// @param _condition The condition (the original receiver of a conditional token).
|
||||
/// @param _user The user to which we may owe.
|
||||
function collateralOwing(
|
||||
IERC1155 _collateralContractAddress,
|
||||
uint256 _collateralTokenId,
|
||||
uint64 _oracleId,
|
||||
uint256 _condition,
|
||||
address _user
|
||||
) external view returns(uint256) {
|
||||
bool _inFirstRound = _isInFirstRound(_oracleId);
|
||||
(, uint256 _donated) =
|
||||
_collateralOwingBase(_collateralContractAddress, _collateralTokenId, _oracleId, _condition, _user, _inFirstRound);
|
||||
return _donated;
|
||||
}
|
||||
|
||||
/// Transfer to `msg.sender` the collateral ERC-1155 token.
|
||||
///
|
||||
/// The amount transferred is proportional to the score of `_condition` by the oracle.
|
||||
/// @param _collateralContractAddress The ERC-1155 collateral token contract.
|
||||
/// @param _collateralTokenId The ERC-1155 collateral token ID.
|
||||
/// @param _oracleId From which oracle's "account" to withdraw.
|
||||
/// @param _condition The condition.
|
||||
/// @param _data Additional data.
|
||||
///
|
||||
/// Notes:
|
||||
/// - It is made impossible to withdraw somebody's other collateral, as otherwise we can't mark non-active
|
||||
/// accounts in grace period.
|
||||
/// - We can't transfer to somebody other than `msg.sender` because anybody can transfer
|
||||
/// (needed for multi-level transfers).
|
||||
/// - After this function is called, it becomes impossible to transfer the corresponding conditional token
|
||||
/// of `msg.sender` (to prevent its repeated withdrawal).
|
||||
function withdrawCollateral(
|
||||
IERC1155 _collateralContractAddress,
|
||||
uint256 _collateralTokenId,
|
||||
uint64 _oracleId,
|
||||
uint256 _condition,
|
||||
bytes calldata _data) external
|
||||
{
|
||||
require(isOracleFinished(_oracleId), "too early"); // to prevent the denominator or the numerators change meantime
|
||||
bool _inFirstRound = _isInFirstRound(_oracleId);
|
||||
userUsedRedeemMap[msg.sender][_condition] = true;
|
||||
// _burn(msg.sender, _condition, conditionalBalance); // Burning it would break using the same token for multiple markets.
|
||||
(uint _donatedPerOracleCollateralTokenId, uint256 _owingDonated) =
|
||||
_collateralOwingBase(_collateralContractAddress, _collateralTokenId, _oracleId, _condition, msg.sender, _inFirstRound);
|
||||
|
||||
// Against rounding errors. Not necessary because of rounding down.
|
||||
// if(_owing > balanceOf(address(this), _collateralTokenId)) _owing = balanceOf(address(this), _collateralTokenId);
|
||||
|
||||
if (_owingDonated != 0) {
|
||||
uint256 _newTotal = totalSupply(_donatedPerOracleCollateralTokenId);
|
||||
if (_inFirstRound) {
|
||||
lastCollateralBalanceFirstRoundMap[_donatedPerOracleCollateralTokenId][msg.sender] = _newTotal;
|
||||
} else {
|
||||
lastCollateralBalanceSecondRoundMap[_donatedPerOracleCollateralTokenId][msg.sender] = _newTotal;
|
||||
}
|
||||
}
|
||||
if (!_inFirstRound) {
|
||||
usersWithdrewInFirstRound[_oracleId] = usersWithdrewInFirstRound[_oracleId].add(_owingDonated);
|
||||
}
|
||||
// Last to prevent reentrancy attack:
|
||||
_collateralContractAddress.safeTransferFrom(address(this), msg.sender, _collateralTokenId, _owingDonated, _data);
|
||||
emit CollateralWithdrawn(
|
||||
_collateralContractAddress,
|
||||
_collateralTokenId,
|
||||
_oracleId,
|
||||
msg.sender,
|
||||
_owingDonated
|
||||
);
|
||||
}
|
||||
|
||||
/// An ERC-1155 function.
|
||||
///
|
||||
/// We disallow transfers of conditional tokens after redeem `_to` prevent "gathering" them before redeeming
|
||||
/// each oracle.
|
||||
function safeTransferFrom(
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _id,
|
||||
uint256 _value,
|
||||
bytes calldata _data
|
||||
)
|
||||
public override
|
||||
{
|
||||
_checkTransferAllowed(_id, _from);
|
||||
_baseSafeTransferFrom(_from, _to, _id, _value, _data);
|
||||
}
|
||||
|
||||
/// An ERC-1155 function.
|
||||
///
|
||||
/// We disallow transfers of conditional tokens after redeem `_to` prevent "gathering" them before redeeming
|
||||
/// each oracle.
|
||||
function safeBatchTransferFrom(
|
||||
address _from,
|
||||
address _to,
|
||||
uint256[] calldata _ids,
|
||||
uint256[] calldata _values,
|
||||
bytes calldata _data
|
||||
)
|
||||
public override
|
||||
{
|
||||
for(uint _i = 0; _i < _ids.length; ++_i) {
|
||||
_checkTransferAllowed(_ids[_i], _from);
|
||||
}
|
||||
_baseSafeBatchTransferFrom(_from, _to, _ids, _values, _data);
|
||||
}
|
||||
|
||||
// Getters //
|
||||
|
||||
/// Get the oracle owner.
|
||||
/// @param _oracleId The oracle ID.
|
||||
function oracleOwner(uint64 _oracleId) public view returns (address) {
|
||||
return oracleOwnersMap[_oracleId];
|
||||
}
|
||||
|
||||
/// Is the oracle marked as having finished its work?
|
||||
///
|
||||
/// `oracleId` is the oracle ID.
|
||||
function isOracleFinished(uint64 /*oracleId*/) public virtual view returns (bool) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Are transfers of a conditinal token locked?
|
||||
///
|
||||
/// This is used to prevent its repeated withdrawal.
|
||||
/// @param _user Querying if locked for this user.
|
||||
/// @param _condition The condition (the original receiver of a conditional token).
|
||||
function isConditionalLocked(address _user, uint256 _condition) public view returns (bool) {
|
||||
return userUsedRedeemMap[_user][_condition];
|
||||
}
|
||||
|
||||
/// Retrieve the end of the grace period.
|
||||
/// @param _oracleId For which oracle.
|
||||
function gracePeriodEnd(uint64 _oracleId) public view returns (uint) {
|
||||
return gracePeriodEnds[_oracleId];
|
||||
}
|
||||
|
||||
// Virtual functions //
|
||||
|
||||
/// Current address of a user.
|
||||
/// @param _originalAddress The original address of the user.
|
||||
function originalToCurrentAddress(address _originalAddress) internal virtual returns (address) {
|
||||
return _originalAddress;
|
||||
}
|
||||
|
||||
/// Mint a conditional to a customer.
|
||||
function _mintToCustomer(address _customer, uint256 _condition, uint256 _amount, bytes calldata _data)
|
||||
internal virtual
|
||||
{
|
||||
require(conditionOwners[_condition] == _customer, "Other's salary get attempt.");
|
||||
_mint(originalToCurrentAddress(_customer), _condition, _amount, _data);
|
||||
}
|
||||
|
||||
/// Calculate the share of a condition in an oracle's market.
|
||||
/// @param _oracleId The oracle ID.
|
||||
/// @return Uses `ABDKMath64x64` number ID.
|
||||
function _calcRewardShare(uint64 _oracleId, uint256 _condition) internal virtual view returns (int128);
|
||||
|
||||
function _calcMultiplier(uint64 _oracleId, uint256 _condition, int128 _oracleShare) internal virtual view returns (int128) {
|
||||
int128 _rewardShare = _calcRewardShare(_oracleId, _condition);
|
||||
return _oracleShare.mul(_rewardShare);
|
||||
}
|
||||
|
||||
function _doTransfer(uint256 _id, address _from, address _to, uint256 _value) internal virtual {
|
||||
_balances[_id][_from] = _balances[_id][_from].sub(_value);
|
||||
_balances[_id][_to] = _value.add(_balances[_id][_to]);
|
||||
}
|
||||
|
||||
// Internal //
|
||||
|
||||
/// Generate the ERC-1155 token ID that counts amount of donations per oracle for a ERC-1155 collateral token.
|
||||
/// @param _collateralContractAddress The ERC-1155 contract of the collateral token.
|
||||
/// @param _collateralTokenId The ERC-1155 ID of the collateral token.
|
||||
/// @param _oracleId The oracle ID.
|
||||
/// Note: It does not conflict with other tokens kinds, because the only other one is the uint64 conditional.
|
||||
function _collateralDonatedPerOracleTokenId(IERC1155 _collateralContractAddress, uint256 _collateralTokenId, uint64 _oracleId)
|
||||
internal pure returns (uint256)
|
||||
{
|
||||
return uint256(keccak256(abi.encodePacked(_collateralContractAddress, _collateralTokenId, _oracleId)));
|
||||
}
|
||||
|
||||
/// Generate the ERC-1155 token ID that counts amount of donations for a ERC-1155 collateral token.
|
||||
/// @param _collateralContractAddress The ERC-1155 contract of the collateral token.
|
||||
/// @param _collateralTokenId The ERC-1155 ID of the collateral token.
|
||||
/// Note: It does not conflict with other tokens kinds, because the only other one is the uint64 conditional.
|
||||
function _collateralDonatedTokenId(IERC1155 _collateralContractAddress, uint256 _collateralTokenId)
|
||||
internal pure returns (uint256)
|
||||
{
|
||||
return uint256(keccak256(abi.encodePacked(_collateralContractAddress, _collateralTokenId)));
|
||||
}
|
||||
|
||||
function _checkTransferAllowed(uint256 _id, address _from) internal view {
|
||||
require(!userUsedRedeemMap[_from][_id], "You can't trade conditional tokens after redeem.");
|
||||
}
|
||||
|
||||
function _baseSafeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes memory _data) private {
|
||||
require(_to != address(0), "ERC1155: target address must be non-zero");
|
||||
require(
|
||||
_from == msg.sender || _operatorApprovals[_from][msg.sender] == true,
|
||||
"ERC1155: need operator approval for 3rd party transfers."
|
||||
);
|
||||
|
||||
_doTransfer(_id, _from, _to, _value);
|
||||
|
||||
emit TransferSingle(msg.sender, _from, _to, _id, _value);
|
||||
|
||||
_doSafeTransferAcceptanceCheck(msg.sender, _from, _to, _id, _value, _data);
|
||||
}
|
||||
|
||||
function _baseSafeBatchTransferFrom(
|
||||
address _from,
|
||||
address _to,
|
||||
uint256[] memory _ids,
|
||||
uint256[] memory _values,
|
||||
bytes memory _data
|
||||
)
|
||||
private
|
||||
{
|
||||
require(_ids.length == _values.length, "ERC1155: IDs and _values must have same lengths");
|
||||
require(_to != address(0), "ERC1155: target address must be non-zero");
|
||||
require(
|
||||
_from == msg.sender || _operatorApprovals[_from][msg.sender] == true,
|
||||
"ERC1155: need operator approval for 3rd party transfers."
|
||||
);
|
||||
|
||||
for (uint256 _i = 0; _i < _ids.length; ++_i) {
|
||||
uint256 _id = _ids[_i];
|
||||
uint256 _value = _values[_i];
|
||||
|
||||
_doTransfer(_id, _from, _to, _value);
|
||||
}
|
||||
|
||||
emit TransferBatch(msg.sender, _from, _to, _ids, _values);
|
||||
|
||||
_doSafeBatchTransferAcceptanceCheck(msg.sender, _from, _to, _ids, _values, _data);
|
||||
}
|
||||
|
||||
function _createOracle() internal returns (uint64) {
|
||||
uint64 _oracleId = ++maxOracleId;
|
||||
oracleOwnersMap[_oracleId] = msg.sender;
|
||||
emit OracleCreated(_oracleId);
|
||||
emit OracleOwnerChanged(msg.sender, _oracleId);
|
||||
return _oracleId;
|
||||
}
|
||||
|
||||
/// Start with 1, not 0, to avoid glitch with `conditionalTokens` variable.
|
||||
///
|
||||
/// TODO: Use uint64 variables instead?
|
||||
function _createCondition(address _customer) internal returns (uint256) {
|
||||
return _doCreateCondition(_customer);
|
||||
}
|
||||
|
||||
/// Start with 1, not 0, to avoid glitch with `conditionalTokens` variable.
|
||||
///
|
||||
/// TODO: Use uint64 variables instead?
|
||||
function _doCreateCondition(address _customer) internal virtual returns (uint256) {
|
||||
uint64 _condition = ++maxConditionId;
|
||||
|
||||
conditionOwners[_condition] = _customer;
|
||||
|
||||
emit ConditionCreated(msg.sender, _customer, _condition);
|
||||
|
||||
return _condition;
|
||||
}
|
||||
|
||||
function _collateralOwingBase(
|
||||
IERC1155 _collateralContractAddress,
|
||||
uint256 _collateralTokenId,
|
||||
uint64 _oracleId,
|
||||
uint256 _condition,
|
||||
address _user,
|
||||
bool _inFirstRound
|
||||
)
|
||||
private view returns (uint _donatedPerOracleCollateralTokenId, uint256 _donated)
|
||||
{
|
||||
uint256 _conditionalBalance = balanceOf(_user, _condition);
|
||||
uint256 _totalConditionalBalance =
|
||||
_inFirstRound ? totalSupply(_condition) : usersWithdrewInFirstRound[_oracleId];
|
||||
_donatedPerOracleCollateralTokenId = _collateralDonatedPerOracleTokenId(_collateralContractAddress, _collateralTokenId, _oracleId);
|
||||
// Rounded to below for no out-of-funds:
|
||||
int128 _oracleShare = ABDKMath64x64.divu(_conditionalBalance, _totalConditionalBalance);
|
||||
uint256 _newDividendsDonated =
|
||||
totalSupply(_donatedPerOracleCollateralTokenId) -
|
||||
(_inFirstRound
|
||||
? lastCollateralBalanceFirstRoundMap[_donatedPerOracleCollateralTokenId][_user]
|
||||
: lastCollateralBalanceSecondRoundMap[_donatedPerOracleCollateralTokenId][_user]);
|
||||
int128 _multiplier = _calcMultiplier(_oracleId, _condition, _oracleShare);
|
||||
_donated = _multiplier.mulu(_newDividendsDonated);
|
||||
}
|
||||
|
||||
function _isInFirstRound(uint64 _oracleId) internal view returns (bool) {
|
||||
return block.timestamp <= gracePeriodEnds[_oracleId];
|
||||
}
|
||||
|
||||
function _isConditional(uint256 _tokenId) internal pure returns (bool) {
|
||||
// Zero 2**-192 probability that tokenId < (1<<64) if it's not a conditional.
|
||||
// Note to auditor: It's a hack, check for no errors carefully.
|
||||
return _tokenId < (1<<64);
|
||||
}
|
||||
|
||||
modifier _isOracle(uint64 _oracleId) {
|
||||
require(oracleOwnersMap[_oracleId] == msg.sender, "Not the oracle owner.");
|
||||
_;
|
||||
}
|
||||
|
||||
modifier checkIsConditional(uint256 _tokenId) {
|
||||
require(_isConditional(_tokenId), "It's not your conditional.");
|
||||
_;
|
||||
}
|
||||
}
|
|
@ -1,174 +0,0 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
pragma solidity ^0.7.1;
|
||||
import "./Salary.sol";
|
||||
|
||||
/// @author Victor Porton
|
||||
/// @notice Not audited, not enough tested.
|
||||
/// A base class for salary with receiver accounts that can be restored by an "attorney".
|
||||
abstract contract BaseRestorableSalary is BaseSalary {
|
||||
// INVARIANT: `_originalAddress(newToOldAccount[newAccount]) == _originalAddress(newAccount)`
|
||||
// if `newToOldAccount[newAccount] != address(0)` for every `newAccount`
|
||||
// INVARIANT: originalAddresses and originalToCurrentAddresses are mutually inverse.
|
||||
// That is:
|
||||
// - `originalAddresses[originalToCurrentAddresses[x]] == x` if `originalToCurrentAddresses[x] != address(0)`
|
||||
// - `originalToCurrentAddresses[originalAddresses[x]] == x` if `originalAddresses[x] != address(0)`
|
||||
|
||||
/// Mapping (current address => very first address an account had).
|
||||
mapping(address => address) public originalAddresses;
|
||||
|
||||
/// Mapping (very first address an account had => current address).
|
||||
mapping(address => address) public originalToCurrentAddresses;
|
||||
|
||||
// Mapping from old to new account addresses (created after every change of an address).
|
||||
mapping(address => address) public newToOldAccount;
|
||||
|
||||
/// Constructor.
|
||||
/// @param _uri Our ERC-1155 tokens description URI.
|
||||
constructor (string memory _uri) BaseSalary(_uri) { }
|
||||
|
||||
/// Below copied from https://github.com/vporton/restorable-funds/blob/f6192fd23cad529b84155d52ae202430cd97db23/contracts/RestorableERC1155.sol
|
||||
|
||||
/// Give the user the "permission" to move funds from `_oldAccount` to `_newAccount`.
|
||||
///
|
||||
/// This function is intended to be called by an attorney or the user to move to a new account.
|
||||
/// @param _oldAccount is a current address.
|
||||
/// @param _newAccount is a new address.
|
||||
function permitRestoreAccount(address _oldAccount, address _newAccount) public {
|
||||
if (msg.sender != _oldAccount) {
|
||||
checkAllowedRestoreAccount(_oldAccount, _newAccount); // only authorized "attorneys" or attorney DAOs
|
||||
}
|
||||
_avoidZeroAddressManipulatins(_oldAccount, _newAccount);
|
||||
address _orig = _originalAddress(_oldAccount);
|
||||
|
||||
// We don't disallow joining several accounts together to consolidate salaries for different projects.
|
||||
// require(originalAddresses[_newAccount] == 0, "Account is taken.")
|
||||
|
||||
newToOldAccount[_newAccount] = _oldAccount;
|
||||
originalAddresses[_newAccount] = _orig;
|
||||
originalToCurrentAddresses[_orig] = _newAccount;
|
||||
// Auditor: Check that the above invariant hold.
|
||||
emit AccountRestored(_oldAccount, _newAccount);
|
||||
}
|
||||
|
||||
/// Retire the user's "permission" to move funds from `_oldAccount` to `_newAccount`.
|
||||
///
|
||||
/// This function is intended to be called by an attorney.
|
||||
/// @param _oldAccount is an old current address.
|
||||
/// @param _newAccount is a new address.
|
||||
/// (In general) it isn't allowed to be called by `msg.sender == _oldAccount`,
|
||||
/// because it would allow to keep stealing the salary by hijacked old account.
|
||||
function dispermitRestoreAccount(address _oldAccount, address _newAccount) public {
|
||||
checkAllowedUnrestoreAccount(_oldAccount, _newAccount); // only authorized "attorneys" or attorney DAOs
|
||||
_avoidZeroAddressManipulatins(_oldAccount, _newAccount);
|
||||
newToOldAccount[_newAccount] = address(0);
|
||||
originalToCurrentAddresses[_oldAccount] = address(0);
|
||||
originalAddresses[_newAccount] = address(0);
|
||||
// Auditor: Check that the above invariants hold.
|
||||
emit AccountUnrestored(_oldAccount, _newAccount);
|
||||
}
|
||||
|
||||
/// Move the entire balance of a token from an old account to a new account of the same user.
|
||||
/// @param _oldAccount Old account.
|
||||
/// @param _newAccount New account.
|
||||
/// @param _token The ERC-1155 token ID.
|
||||
/// This function can be called by the affected user.
|
||||
///
|
||||
/// Remark: We don't need to create new tokens like as on a regular transfer,
|
||||
/// because it isn't a transfer to a trader.
|
||||
function restoreFunds(address _oldAccount, address _newAccount, uint256 _token) public
|
||||
checkMovedOwner(_oldAccount, _newAccount)
|
||||
{
|
||||
uint256 _amount = _balances[_token][_oldAccount];
|
||||
|
||||
_balances[_token][_newAccount] = _balances[_token][_oldAccount];
|
||||
_balances[_token][_oldAccount] = 0;
|
||||
|
||||
emit TransferSingle(_msgSender(), _oldAccount, _newAccount, _token, _amount);
|
||||
}
|
||||
|
||||
/// Move the entire balance of tokens from an old account to a new account of the same user.
|
||||
/// @param _oldAccount Old account.
|
||||
/// @param _newAccount New account.
|
||||
/// @param _tokens The ERC-1155 token IDs.
|
||||
/// This function can be called by the affected user.
|
||||
///
|
||||
/// Remark: We don't need to create new tokens like as on a regular transfer,
|
||||
/// because it isn't a transfer to a trader.
|
||||
function restoreFundsBatch(address _oldAccount, address _newAccount, uint256[] calldata _tokens) public
|
||||
checkMovedOwner(_oldAccount, _newAccount)
|
||||
{
|
||||
uint256[] memory _amounts = new uint256[](_tokens.length);
|
||||
for (uint _i = 0; _i < _tokens.length; ++_i) {
|
||||
uint256 _token = _tokens[_i];
|
||||
uint256 _amount = _balances[_token][_oldAccount];
|
||||
_amounts[_i] = _amount;
|
||||
|
||||
_balances[_token][_newAccount] = _balances[_token][_oldAccount];
|
||||
_balances[_token][_oldAccount] = 0;
|
||||
}
|
||||
|
||||
emit TransferBatch(_msgSender(), _oldAccount, _newAccount, _tokens, _amounts);
|
||||
}
|
||||
|
||||
// Internal functions //
|
||||
|
||||
function _avoidZeroAddressManipulatins(address _oldAccount, address _newAccount) internal view {
|
||||
// To avoid make-rich-quick manipulations with lost funds:
|
||||
require(_oldAccount != address(0) && _newAccount != address(0) &&
|
||||
originalAddresses[_newAccount] != address(0) && newToOldAccount[_newAccount] != address(0),
|
||||
"Trying to get nobody's funds.");
|
||||
}
|
||||
|
||||
// Virtual functions //
|
||||
|
||||
/// Check if `msg.sender` is an attorney allowed to restore a user's account.
|
||||
function checkAllowedRestoreAccount(address /*_oldAccount*/, address /*_newAccount*/) public virtual;
|
||||
|
||||
/// Check if `msg.sender` is an attorney allowed to unrestore a user's account.
|
||||
function checkAllowedUnrestoreAccount(address /*_oldAccount*/, address /*_newAccount*/) public virtual;
|
||||
|
||||
/// Find the original address of a given account.
|
||||
/// This function is internal, because it can be calculated off-chain.
|
||||
/// @param _account The current address.
|
||||
function _originalAddress(address _account) internal view virtual returns (address) {
|
||||
address _newAddress = originalAddresses[_account];
|
||||
return _newAddress != address(0) ? _newAddress : _account;
|
||||
}
|
||||
|
||||
// Find the current address for an original address.
|
||||
// @param _conditional The original address.
|
||||
function originalToCurrentAddress(address _customer) internal virtual override returns (address) {
|
||||
address current = originalToCurrentAddresses[_customer];
|
||||
return current != address(0) ? current : _customer;
|
||||
}
|
||||
|
||||
// TODO: Is the following function useful to save gas in other contracts?
|
||||
// function getCurrent(address _account) public returns (uint256) {
|
||||
// address _original = originalAddresses[_account];
|
||||
// return _original == 0 ? 0 : originalToCurrentAddress(_original);
|
||||
// }
|
||||
|
||||
// Modifiers //
|
||||
|
||||
/// Check that `_newAccount` is the user that has the right to restore funds from `_oldAccount`.
|
||||
///
|
||||
/// We also allow funds restoration by attorneys for convenience of users.
|
||||
/// This is not an increased security risk, because a dishonest attorney can anyway transfer money to himself.
|
||||
modifier checkMovedOwner(address _oldAccount, address _newAccount) virtual {
|
||||
if (_msgSender() != _newAccount) {
|
||||
checkAllowedRestoreAccount(_oldAccount, _newAccount); // only authorized "attorneys" or attorney DAOs
|
||||
}
|
||||
|
||||
for (address _account = _oldAccount; _account != _newAccount; _account = newToOldAccount[_account]) {
|
||||
require(_account != address(0), "Not a moved owner");
|
||||
}
|
||||
|
||||
_;
|
||||
}
|
||||
|
||||
// Events //
|
||||
|
||||
event AccountRestored(address indexed oldAccount, address indexed newAccount);
|
||||
|
||||
event AccountUnrestored(address indexed oldAccount, address indexed newAccount);
|
||||
}
|
|
@ -1,239 +0,0 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
pragma solidity ^0.7.1;
|
||||
import "./BaseBidOnAddresses.sol";
|
||||
|
||||
/// @title Base class for a "salary" that is paid one token per second using minted conditionals.
|
||||
/// @author Victor Porton
|
||||
/// @notice Not audited, not enough tested.
|
||||
/// It was considered to allow the DAO to adjust registration date to pay salary retrospectively,
|
||||
/// but this seems giving too much rights to the DAO similarly as if it had the right to declare anyone dead.
|
||||
///
|
||||
/// It would cause this effect: A scientist who is already great may register then his date is moved back
|
||||
/// in time and instantly he or she receives a very big sum of money to his account.
|
||||
/// If it is done erroneously, there may be no way to move the registration date again forward in time,
|
||||
/// because the tokens may be already withdrawn. And it cannot be done in a fully decentralized way because
|
||||
/// it needs oracles. So errors are seem inevitable.
|
||||
/// On the other hand, somebody malicious may create and register in my system a pool of Ethereum addresses that
|
||||
/// individuals can receive from them as if they themselves registered in the past.
|
||||
/// So it in some cases (if the registration date is past the contract deployment) this issue is impossible to
|
||||
/// mitigate.
|
||||
///
|
||||
/// The salary is paid in minted tokens groups into "chains":
|
||||
/// the original salary token and anyone can replace it by another token, next in the chain.
|
||||
contract BaseSalary is BaseBidOnAddresses {
|
||||
/// Salary receiver registered.
|
||||
/// @param customer The customer address.
|
||||
/// @param oracleId The oracle ID for which he registers.
|
||||
/// @param data Additional data.
|
||||
event CustomerRegistered(
|
||||
address indexed customer,
|
||||
uint64 indexed oracleId,
|
||||
uint256 indexed condition,
|
||||
bytes data
|
||||
);
|
||||
|
||||
/// Salary tokens minted.
|
||||
/// @param customer The customer address.
|
||||
/// @param oracleId The oracle ID.
|
||||
/// @param amount The minted amount.
|
||||
/// @param data Additional data.
|
||||
event SalaryMinted(
|
||||
address indexed customer,
|
||||
uint64 indexed oracleId,
|
||||
uint256 indexed condition,
|
||||
uint256 amount,
|
||||
bytes data
|
||||
);
|
||||
|
||||
/// Salary token recreated (salary recalculation request).
|
||||
/// @param customer The customer address.
|
||||
/// @param originalCondition The original token ID.
|
||||
/// @param newCondition The new token ID.
|
||||
event ConditionReCreate(
|
||||
address indexed customer,
|
||||
uint256 indexed originalCondition,
|
||||
uint256 indexed newCondition
|
||||
);
|
||||
|
||||
// Mapping (condition ID => registration time).
|
||||
mapping(uint256 => uint) public conditionCreationDates;
|
||||
// Mapping (condition ID => salary block time).
|
||||
mapping(uint256 => uint) public lastSalaryDates;
|
||||
/// Mapping (condition ID => account) - salary recipients.
|
||||
mapping(uint256 => address) public salaryReceivers;
|
||||
|
||||
/// Mapping (condition ID => first condition ID in the chain)
|
||||
///
|
||||
/// I call _chain_ of conditions the list of conditions resulting from creating and recreating conditions.
|
||||
mapping(uint256 => uint256) public firstConditionInChain;
|
||||
/// Mapping (first condition ID in the chain => last condition ID in the chain)
|
||||
///
|
||||
/// I call _chain_ of conditions the list of conditions resulting from creating and recreating conditions.
|
||||
mapping(uint256 => uint256) public firstToLastConditionInChain;
|
||||
|
||||
/// Constructor.
|
||||
/// @param _uri The ERC-1155 token URI.
|
||||
constructor(string memory _uri) BaseBidOnAddresses(_uri) { }
|
||||
|
||||
/// Mint a salary token.
|
||||
/// @param _oracleId The oracle ID.
|
||||
/// @param _condition The condition ID.
|
||||
/// @param _data Additional data.
|
||||
/// This method can be called only by the salary receiver.
|
||||
function mintSalary(uint64 _oracleId, uint256 _condition, bytes calldata _data)
|
||||
ensureLastConditionInChain(_condition) external
|
||||
{
|
||||
uint _lastSalaryDate = lastSalaryDates[_condition];
|
||||
require(_lastSalaryDate != 0, "You are not registered.");
|
||||
// Note: Even if you withdraw once per 20 years, you will get only 630,720,000 tokens.
|
||||
// This number is probably not to big to be displayed well in UIs.
|
||||
uint256 _amount = (block.timestamp - _lastSalaryDate) * 10**18; // one token per second
|
||||
_mintToCustomer(msg.sender, firstToLastConditionInChain[_condition], _amount, _data);
|
||||
lastSalaryDates[_condition] = block.timestamp;
|
||||
emit SalaryMinted(msg.sender, _oracleId, _condition, _amount, _data);
|
||||
}
|
||||
|
||||
/// Make a new condition that replaces the old one.
|
||||
///
|
||||
/// In other words, it is a request to recalculate somebody's salary.
|
||||
///
|
||||
/// Anyone can request to recalculate anyone's salary.
|
||||
///
|
||||
/// It's also useful to punish someone for decreasing his work performance or an evil act.
|
||||
/// This is to be called among other when a person dies.
|
||||
///
|
||||
/// Recalculation is also forced when a salary receiver transfers away his current salary token.
|
||||
/// It is useful to remove a trader's incentive to kill the issuer to reduce the circulating supply.
|
||||
///
|
||||
/// Issue to solve later: Should we recommend:
|
||||
/// - calling this function on each new project milestone?
|
||||
/// - calling this function regularly (e.g. every week)?
|
||||
///
|
||||
/// This function also withdraws the old token.
|
||||
function recreateCondition(uint256 _condition) public returns (uint256) {
|
||||
return _recreateCondition(_condition);
|
||||
}
|
||||
|
||||
function _doCreateCondition(address _customer) internal virtual override returns (uint256) {
|
||||
uint256 _condition = super._doCreateCondition(_customer);
|
||||
salaryReceivers[_condition] = _customer;
|
||||
conditionCreationDates[_condition] = block.timestamp;
|
||||
firstConditionInChain[_condition] = _condition;
|
||||
firstToLastConditionInChain[_condition] = _condition;
|
||||
return _condition;
|
||||
}
|
||||
|
||||
/// Make a new condition that replaces the old one.
|
||||
/// The same can be done by transferring to yourself 0 tokens, but this method uses less gas.
|
||||
///
|
||||
/// We need to create a new condition every time when an outgoimg transfer of a conditional token happens.
|
||||
/// Otherwise an investor would gain if he kills a scientist to reduce the circulating supply of his token to increase the price.
|
||||
/// Allowing old tokens to be exchangeable for new ones? (Allowing the reverse swap would create killer's gain.)
|
||||
/// Additional benefit of this solution: We can have different rewards at different stages of project,
|
||||
/// what may be beneficial for early startups funding.
|
||||
///
|
||||
/// Problem to be solved later: There should be an advice to switch to a new token at each milestone of a project?
|
||||
///
|
||||
/// Anyone can create a ERC-1155 contract that allows to use any of the tokens in the list
|
||||
/// by locking any of the tokens in the list as a new "general" token. We should recommend customers not to
|
||||
/// use such contracts, because it creates for them the killer exploit.
|
||||
///
|
||||
/// If we would exchange the old and new tokens for the same amounts of collaterals, then it would be
|
||||
/// effectively the same token and therefore minting more new token would possibly devalue the old one,
|
||||
/// thus triggering the killer's exploit again. So we make old and new completely independent.
|
||||
///
|
||||
/// Old token is 1:1 converted to the new token.
|
||||
///
|
||||
/// Remark: To make easy to exchange the token even if it is recreated, we can make a wrapper or locker
|
||||
/// token that uses `firstConditionInChain[]` to aggregate several tokens together.
|
||||
/// A similar wrapper (the customer need to `setApprovalForAll()` on it) that uses
|
||||
/// `firstToLastConditionInChain[]` can be used to transfer away recreated tokens
|
||||
/// even if an evil DAO tries to frontrun the customer by recreating his tokens very often.
|
||||
/// TODO: Test that it's possible to create such a locker.
|
||||
///
|
||||
/// Note: That wrapper could be carelessly used to create the investor's killing customer incentive
|
||||
/// by the customer using it to transfer to an investor. Even if the customer uses it only for
|
||||
/// exchanges, an investor can buy at an exchange and be a killer.
|
||||
/// To make it safe, it must stop accepting any new tokens after a transfer.
|
||||
/// It can determine if a token is new just comparing by `<` operator.
|
||||
/// It's strongly recommended that an app that uses this contract provides its own swap/exchange UI
|
||||
/// and warns the user not to use arbitrary exchanges as being an incentive to kill the user.
|
||||
///
|
||||
/// We allow anybody (not just the account owner or DAO) to recreate a condition, because:
|
||||
/// - Exchanges can create a "composite" token that allows to withdraw any of the tokens in the chain
|
||||
/// up to a certain period of time (using on-chain `conditionCreationDates`).
|
||||
/// - Therefore somebody's token can be withdrawn even if its ID changes arbitrarily often.
|
||||
///
|
||||
/// @param _condition The condition ID.
|
||||
function _recreateCondition(uint256 _condition)
|
||||
internal ensureFirstConditionInChain(_condition) returns (uint256)
|
||||
{
|
||||
address _customer = salaryReceivers[_condition];
|
||||
uint256 _oldCondition = firstToLastConditionInChain[_condition];
|
||||
uint256 _newCondition = _doCreateCondition(_customer);
|
||||
firstConditionInChain[_newCondition] = _condition;
|
||||
|
||||
uint256 _amount = _balances[_oldCondition][_customer];
|
||||
_balances[_newCondition][_customer] = _amount;
|
||||
_balances[_oldCondition][_customer] = 0;
|
||||
|
||||
// TODO: Should we swap two following lines?
|
||||
emit TransferSingle(msg.sender, _customer, address(0), _condition, _amount);
|
||||
emit TransferSingle(msg.sender, address(0), _customer, _newCondition, _amount);
|
||||
|
||||
lastSalaryDates[_newCondition] = lastSalaryDates[_condition];
|
||||
// TODO: Should we here set `lastSalaryDates[_condition] = 0` to save storage space? // TODO: It would also eliminate the need to check in mint function.
|
||||
|
||||
emit ConditionReCreate(_customer, _condition, _newCondition);
|
||||
return _newCondition;
|
||||
}
|
||||
|
||||
/// Check if it is the first condition in a chain of conditions.
|
||||
/// @param _id The condition ID.
|
||||
///
|
||||
/// Must be called with `_id != 0`.
|
||||
function isFirstConditionInChain(uint256 _id) internal view returns (bool) {
|
||||
return firstConditionInChain[_id] == _id;
|
||||
}
|
||||
|
||||
/// Check if it is the last condition in a chain of conditions.
|
||||
/// @param _id The condition ID.
|
||||
///
|
||||
/// Must be called with `_id != 0`.
|
||||
///
|
||||
/// TODO: Should make this function public?
|
||||
function isLastConditionInChain(uint256 _id) internal view returns (bool) {
|
||||
return firstToLastConditionInChain[firstConditionInChain[_id]] == _id;
|
||||
}
|
||||
|
||||
function _doTransfer(uint256 _id, address _from, address _to, uint256 _value) internal virtual override {
|
||||
super._doTransfer(_id, _from, _to, _value);
|
||||
|
||||
if (_id != 0 && salaryReceivers[_id] == msg.sender) {
|
||||
if (isLastConditionInChain(_id)) { // correct because `_id != 0`
|
||||
_recreateCondition(_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _registerCustomer(address _customer, uint64 _oracleId, bytes calldata _data)
|
||||
virtual internal returns (uint256)
|
||||
{
|
||||
uint256 _condition = _doCreateCondition(_customer);
|
||||
lastSalaryDates[_condition] = block.timestamp;
|
||||
emit CustomerRegistered(msg.sender, _oracleId, _condition, _data);
|
||||
return _condition;
|
||||
}
|
||||
|
||||
modifier ensureFirstConditionInChain(uint256 _id) {
|
||||
// TODO: Is `_id != 0` check needed?
|
||||
require(_isConditional(_id) && _id != 0 && isFirstConditionInChain(_id), "Only for the last salary token.");
|
||||
_;
|
||||
}
|
||||
|
||||
modifier ensureLastConditionInChain(uint256 _id) {
|
||||
// TODO: Is `_id != 0` check needed?
|
||||
require(_isConditional(_id) && _id != 0 && isLastConditionInChain(_id), "Only for the last salary token.");
|
||||
_;
|
||||
}
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
pragma solidity ^0.7.1;
|
||||
import "./BaseBidOnAddresses.sol";
|
||||
|
||||
/// @title Bidding on Ethereum addresses
|
||||
/// @author Victor Porton
|
||||
/// @notice Not audited, not enough tested.
|
||||
/// This allows anyone to claim 1000 conditional tokens in order for him to transfer money from the future.
|
||||
/// See `docs/future-money.rst` and anyone to donate.
|
||||
///
|
||||
/// We have two kinds of ERC-1155 token IDs:
|
||||
/// - conditional tokens: numbers < 2**64
|
||||
/// - a combination of a collateral contract address and collateral token ID
|
||||
/// (a counter of donated amount of collateral tokens, don't confuse with collateral tokens themselves)
|
||||
///
|
||||
/// In functions of this contact `condition` is always a customer's original address.
|
||||
///
|
||||
/// We receive funds in ERC-1155, see also https://github.com/vporton/wrap-tokens
|
||||
contract BidOnAddresses is BaseBidOnAddresses {
|
||||
uint constant INITIAL_CUSTOMER_BALANCE = 1000 * 10**18; // an arbitrarily chosen value
|
||||
|
||||
/// Customer registered.
|
||||
/// @param sender `msg.sender`.
|
||||
/// @param customer The customer address.
|
||||
/// @param data Additional data.
|
||||
event CustomerRegistered(
|
||||
address indexed sender,
|
||||
address indexed customer,
|
||||
uint256 indexed condition,
|
||||
bytes data
|
||||
);
|
||||
|
||||
/// @param _uri The ERC-1155 token URI.
|
||||
constructor(string memory _uri) BaseBidOnAddresses(_uri) {
|
||||
_registerInterface(
|
||||
BidOnAddresses(0).onERC1155Received.selector ^
|
||||
BidOnAddresses(0).onERC1155BatchReceived.selector
|
||||
);
|
||||
}
|
||||
|
||||
/// Anyone can register anyone.
|
||||
///
|
||||
/// This can be called both before or after the oracle finish. However registering after the finish is useless.
|
||||
///
|
||||
/// We check that `oracleId` exists (we don't want "spammers" to register themselves for a million oracles).
|
||||
///
|
||||
/// We allow anyone to register anyone. This is useful for being registered by robots.
|
||||
/// At first it seems to be harmful to make somebody a millionaire unwillingly (he then needs a fortress and bodyguards),
|
||||
/// but: Salary tokens will be worth real money, only if the registered person publishes his works together
|
||||
/// with his Ethereum address. So, he can be made rich against his will only by impersonating him. But if somebody
|
||||
/// impersonates him, then they are able to present him richer than he is anyway, so making him vulnerable to
|
||||
/// kidnappers anyway. So having somebody registered against his will seems not to be a problem at all
|
||||
/// (except that he will see superfluous worthless tokens in Etherscan data of his account.)
|
||||
///
|
||||
/// An alternative way would be to make registration gasless but requiring a registrant signature.
|
||||
/// This is not very good, probably:
|
||||
/// - It requires to install MetaMask.
|
||||
/// - It bothers the person to sign something, when he could just be hesitant to get what he needs.
|
||||
/// - It somehow complicates this contract.
|
||||
/// @param _customer The address of the customer. // TODO: current or original
|
||||
/// @param _oracleId The oracle ID.
|
||||
/// @param _data Additional data.
|
||||
function registerCustomer(address _customer, uint64 _oracleId, bytes calldata _data) external {
|
||||
require(_oracleId <= maxOracleId, "Oracle doesn't exist.");
|
||||
uint256 _condition = _createCondition(_customer);
|
||||
_mintToCustomer(_customer, _condition, INITIAL_CUSTOMER_BALANCE, _data);
|
||||
emit CustomerRegistered(msg.sender, _customer, _condition, _data);
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
pragma solidity ^0.7.1;
|
||||
|
||||
/// @notice The "DAO plugin" interface.
|
||||
/// @author Victor Porton
|
||||
/// @notice Not audited, not enough tested.
|
||||
interface DAOInterface {
|
||||
/// Check if `msg.sender` is an attorney allowed to restore a given account.
|
||||
function checkAllowedRestoreAccount(address _oldAccount, address _newAccount) external;
|
||||
|
||||
/// Check if `msg.sender` is an attorney allowed to unrestore a given account.
|
||||
function checkAllowedUnrestoreAccount(address _oldAccount, address _newAccount) external;
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
pragma solidity ^0.7.1;
|
||||
import "./DAOInterface.sol";
|
||||
|
||||
/// @notice "Default" contract for `DAOInterface`.
|
||||
/// @author Victor Porton
|
||||
/// @notice Not audited, not enough tested.
|
||||
contract DefaultDAOInterface is DAOInterface {
|
||||
function checkAllowedRestoreAccount(address /*_oldAccount*/, address /*_newAccount*/) external pure override {
|
||||
revert("unimplemented");
|
||||
}
|
||||
|
||||
function checkAllowedUnrestoreAccount(address /*_oldAccount*/, address /*_newAccount*/) external pure override {
|
||||
revert("unimplemented");
|
||||
}
|
||||
}
|
|
@ -1,414 +0,0 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
pragma solidity >=0.6.0 <0.8.0;
|
||||
|
||||
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
|
||||
import "@openzeppelin/contracts/token/ERC1155/IERC1155MetadataURI.sol";
|
||||
import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
|
||||
import "@openzeppelin/contracts/GSN/Context.sol";
|
||||
import "@openzeppelin/contracts/introspection/ERC165.sol";
|
||||
import "@openzeppelin/contracts/math/SafeMath.sol";
|
||||
import "@openzeppelin/contracts/utils/Address.sol";
|
||||
|
||||
/**
|
||||
*
|
||||
* @dev Implementation of the basic standard multi-token.
|
||||
* See https://eips.ethereum.org/EIPS/eip-1155
|
||||
* Originally based on code by Enjin: https://github.com/enjin/erc-1155
|
||||
*
|
||||
* _Available since v3.1._
|
||||
*/
|
||||
contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
|
||||
using SafeMath for uint256;
|
||||
using Address for address;
|
||||
|
||||
// Mapping from token ID to account balances
|
||||
mapping (uint256 => mapping(address => uint256)) internal _balances;
|
||||
|
||||
// Mapping from account to operator approvals
|
||||
mapping (address => mapping(address => bool)) internal _operatorApprovals;
|
||||
|
||||
// Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
|
||||
string private _uri;
|
||||
|
||||
/*
|
||||
* bytes4(keccak256('balanceOf(address,uint256)')) == 0x00fdd58e
|
||||
* bytes4(keccak256('balanceOfBatch(address[],uint256[])')) == 0x4e1273f4
|
||||
* bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465
|
||||
* bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5
|
||||
* bytes4(keccak256('safeTransferFrom(address,address,uint256,uint256,bytes)')) == 0xf242432a
|
||||
* bytes4(keccak256('safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)')) == 0x2eb2c2d6
|
||||
*
|
||||
* => 0x00fdd58e ^ 0x4e1273f4 ^ 0xa22cb465 ^
|
||||
* 0xe985e9c5 ^ 0xf242432a ^ 0x2eb2c2d6 == 0xd9b67a26
|
||||
*/
|
||||
bytes4 private constant _INTERFACE_ID_ERC1155 = 0xd9b67a26;
|
||||
|
||||
/*
|
||||
* bytes4(keccak256('uri(uint256)')) == 0x0e89341c
|
||||
*/
|
||||
bytes4 private constant _INTERFACE_ID_ERC1155_METADATA_URI = 0x0e89341c;
|
||||
|
||||
/**
|
||||
* @dev See {_setURI}.
|
||||
*/
|
||||
constructor (string memory uri_) {
|
||||
_setURI(uri_);
|
||||
|
||||
// register the supported interfaces to conform to ERC1155 via ERC165
|
||||
_registerInterface(_INTERFACE_ID_ERC1155);
|
||||
|
||||
// register the supported interfaces to conform to ERC1155MetadataURI via ERC165
|
||||
_registerInterface(_INTERFACE_ID_ERC1155_METADATA_URI);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev See {IERC1155MetadataURI-uri}.
|
||||
*
|
||||
* This implementation returns the same URI for *all* token types. It relies
|
||||
* on the token type ID substitution mechanism
|
||||
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
|
||||
*
|
||||
* Clients calling this function must replace the `\{id\}` substring with the
|
||||
* actual token type ID.
|
||||
*/
|
||||
function uri(uint256) external view override returns (string memory) {
|
||||
return _uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev See {IERC1155-balanceOf}.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `account` cannot be the zero address.
|
||||
*/
|
||||
function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {
|
||||
require(account != address(0), "ERC1155: balance query for the zero address");
|
||||
return _balances[id][account];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev See {IERC1155-balanceOfBatch}.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `accounts` and `ids` must have the same length.
|
||||
*/
|
||||
function balanceOfBatch(
|
||||
address[] memory accounts,
|
||||
uint256[] memory ids
|
||||
)
|
||||
public
|
||||
view
|
||||
virtual
|
||||
override
|
||||
returns (uint256[] memory)
|
||||
{
|
||||
require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch");
|
||||
|
||||
uint256[] memory batchBalances = new uint256[](accounts.length);
|
||||
|
||||
for (uint256 i = 0; i < accounts.length; ++i) {
|
||||
require(accounts[i] != address(0), "ERC1155: batch balance query for the zero address");
|
||||
batchBalances[i] = _balances[ids[i]][accounts[i]];
|
||||
}
|
||||
|
||||
return batchBalances;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev See {IERC1155-setApprovalForAll}.
|
||||
*/
|
||||
function setApprovalForAll(address operator, bool approved) public virtual override {
|
||||
require(_msgSender() != operator, "ERC1155: setting approval status for self");
|
||||
|
||||
_operatorApprovals[_msgSender()][operator] = approved;
|
||||
emit ApprovalForAll(_msgSender(), operator, approved);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev See {IERC1155-isApprovedForAll}.
|
||||
*/
|
||||
function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {
|
||||
return _operatorApprovals[account][operator];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev See {IERC1155-safeTransferFrom}.
|
||||
*/
|
||||
function safeTransferFrom(
|
||||
address from,
|
||||
address to,
|
||||
uint256 id,
|
||||
uint256 amount,
|
||||
bytes memory data
|
||||
)
|
||||
public
|
||||
virtual
|
||||
override
|
||||
{
|
||||
require(to != address(0), "ERC1155: transfer to the zero address");
|
||||
require(
|
||||
from == _msgSender() || isApprovedForAll(from, _msgSender()),
|
||||
"ERC1155: caller is not owner nor approved"
|
||||
);
|
||||
|
||||
address operator = _msgSender();
|
||||
|
||||
_beforeTokenTransfer(operator, from, to, _asSingletonArray(id), _asSingletonArray(amount), data);
|
||||
|
||||
_balances[id][from] = _balances[id][from].sub(amount, "ERC1155: insufficient balance for transfer");
|
||||
_balances[id][to] = _balances[id][to].add(amount);
|
||||
|
||||
emit TransferSingle(operator, from, to, id, amount);
|
||||
|
||||
_doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev See {IERC1155-safeBatchTransferFrom}.
|
||||
*/
|
||||
function safeBatchTransferFrom(
|
||||
address from,
|
||||
address to,
|
||||
uint256[] memory ids,
|
||||
uint256[] memory amounts,
|
||||
bytes memory data
|
||||
)
|
||||
public
|
||||
virtual
|
||||
override
|
||||
{
|
||||
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
|
||||
require(to != address(0), "ERC1155: transfer to the zero address");
|
||||
require(
|
||||
from == _msgSender() || isApprovedForAll(from, _msgSender()),
|
||||
"ERC1155: transfer caller is not owner nor approved"
|
||||
);
|
||||
|
||||
address operator = _msgSender();
|
||||
|
||||
_beforeTokenTransfer(operator, from, to, ids, amounts, data);
|
||||
|
||||
for (uint256 i = 0; i < ids.length; ++i) {
|
||||
uint256 id = ids[i];
|
||||
uint256 amount = amounts[i];
|
||||
|
||||
_balances[id][from] = _balances[id][from].sub(
|
||||
amount,
|
||||
"ERC1155: insufficient balance for transfer"
|
||||
);
|
||||
_balances[id][to] = _balances[id][to].add(amount);
|
||||
}
|
||||
|
||||
emit TransferBatch(operator, from, to, ids, amounts);
|
||||
|
||||
_doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sets a new URI for all token types, by relying on the token type ID
|
||||
* substitution mechanism
|
||||
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
|
||||
*
|
||||
* By this mechanism, any occurrence of the `\{id\}` substring in either the
|
||||
* URI or any of the amounts in the JSON file at said URI will be replaced by
|
||||
* clients with the token type ID.
|
||||
*
|
||||
* For example, the `https://token-cdn-domain/\{id\}.json` URI would be
|
||||
* interpreted by clients as
|
||||
* `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
|
||||
* for token type ID 0x4cce0.
|
||||
*
|
||||
* See {uri}.
|
||||
*
|
||||
* Because these URIs cannot be meaningfully represented by the {URI} event,
|
||||
* this function emits no events.
|
||||
*/
|
||||
function _setURI(string memory newuri) internal virtual {
|
||||
_uri = newuri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Creates `amount` tokens of token type `id`, and assigns them to `account`.
|
||||
*
|
||||
* Emits a {TransferSingle} event.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `account` cannot be the zero address.
|
||||
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
|
||||
* acceptance magic value.
|
||||
*/
|
||||
function _mint(address account, uint256 id, uint256 amount, bytes memory data) internal virtual {
|
||||
require(account != address(0), "ERC1155: mint to the zero address");
|
||||
|
||||
address operator = _msgSender();
|
||||
|
||||
_beforeTokenTransfer(operator, address(0), account, _asSingletonArray(id), _asSingletonArray(amount), data);
|
||||
|
||||
_balances[id][account] = _balances[id][account].add(amount);
|
||||
emit TransferSingle(operator, address(0), account, id, amount);
|
||||
|
||||
_doSafeTransferAcceptanceCheck(operator, address(0), account, id, amount, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `ids` and `amounts` must have the same length.
|
||||
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
|
||||
* acceptance magic value.
|
||||
*/
|
||||
function _mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) internal virtual {
|
||||
require(to != address(0), "ERC1155: mint to the zero address");
|
||||
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
|
||||
|
||||
address operator = _msgSender();
|
||||
|
||||
_beforeTokenTransfer(operator, address(0), to, ids, amounts, data);
|
||||
|
||||
for (uint i = 0; i < ids.length; i++) {
|
||||
_balances[ids[i]][to] = amounts[i].add(_balances[ids[i]][to]);
|
||||
}
|
||||
|
||||
emit TransferBatch(operator, address(0), to, ids, amounts);
|
||||
|
||||
_doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Destroys `amount` tokens of token type `id` from `account`
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `account` cannot be the zero address.
|
||||
* - `account` must have at least `amount` tokens of token type `id`.
|
||||
*/
|
||||
function _burn(address account, uint256 id, uint256 amount) internal virtual {
|
||||
require(account != address(0), "ERC1155: burn from the zero address");
|
||||
|
||||
address operator = _msgSender();
|
||||
|
||||
_beforeTokenTransfer(operator, account, address(0), _asSingletonArray(id), _asSingletonArray(amount), "");
|
||||
|
||||
_balances[id][account] = _balances[id][account].sub(
|
||||
amount,
|
||||
"ERC1155: burn amount exceeds balance"
|
||||
);
|
||||
|
||||
emit TransferSingle(operator, account, address(0), id, amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `ids` and `amounts` must have the same length.
|
||||
*/
|
||||
function _burnBatch(address account, uint256[] memory ids, uint256[] memory amounts) internal virtual {
|
||||
require(account != address(0), "ERC1155: burn from the zero address");
|
||||
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
|
||||
|
||||
address operator = _msgSender();
|
||||
|
||||
_beforeTokenTransfer(operator, account, address(0), ids, amounts, "");
|
||||
|
||||
for (uint i = 0; i < ids.length; i++) {
|
||||
_balances[ids[i]][account] = _balances[ids[i]][account].sub(
|
||||
amounts[i],
|
||||
"ERC1155: burn amount exceeds balance"
|
||||
);
|
||||
}
|
||||
|
||||
emit TransferBatch(operator, account, address(0), ids, amounts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Hook that is called before any token transfer. This includes minting
|
||||
* and burning, as well as batched variants.
|
||||
*
|
||||
* The same hook is called on both single and batched variants. For single
|
||||
* transfers, the length of the `id` and `amount` arrays will be 1.
|
||||
*
|
||||
* Calling conditions (for each `id` and `amount` pair):
|
||||
*
|
||||
* - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
|
||||
* of token type `id` will be transferred to `to`.
|
||||
* - When `from` is zero, `amount` tokens of token type `id` will be minted
|
||||
* for `to`.
|
||||
* - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
|
||||
* will be burned.
|
||||
* - `from` and `to` are never both zero.
|
||||
* - `ids` and `amounts` have the same, non-zero length.
|
||||
*
|
||||
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
|
||||
*/
|
||||
function _beforeTokenTransfer(
|
||||
address operator,
|
||||
address from,
|
||||
address to,
|
||||
uint256[] memory ids,
|
||||
uint256[] memory amounts,
|
||||
bytes memory data
|
||||
)
|
||||
internal virtual
|
||||
{ }
|
||||
|
||||
function _doSafeTransferAcceptanceCheck(
|
||||
address operator,
|
||||
address from,
|
||||
address to,
|
||||
uint256 id,
|
||||
uint256 amount,
|
||||
bytes memory data
|
||||
)
|
||||
internal
|
||||
{
|
||||
if (to.isContract()) {
|
||||
try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {
|
||||
if (response != IERC1155Receiver(to).onERC1155Received.selector) {
|
||||
revert("ERC1155: ERC1155Receiver rejected tokens");
|
||||
}
|
||||
} catch Error(string memory reason) {
|
||||
revert(reason);
|
||||
} catch {
|
||||
revert("ERC1155: transfer to non ERC1155Receiver implementer");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _doSafeBatchTransferAcceptanceCheck(
|
||||
address operator,
|
||||
address from,
|
||||
address to,
|
||||
uint256[] memory ids,
|
||||
uint256[] memory amounts,
|
||||
bytes memory data
|
||||
)
|
||||
internal
|
||||
{
|
||||
if (to.isContract()) {
|
||||
try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (bytes4 response) {
|
||||
if (response != IERC1155Receiver(to).onERC1155BatchReceived.selector) {
|
||||
revert("ERC1155: ERC1155Receiver rejected tokens");
|
||||
}
|
||||
} catch Error(string memory reason) {
|
||||
revert(reason);
|
||||
} catch {
|
||||
revert("ERC1155: transfer to non ERC1155Receiver implementer");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {
|
||||
uint256[] memory array = new uint256[](1);
|
||||
array[0] = element;
|
||||
|
||||
return array;
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
pragma solidity ^0.7.1;
|
||||
|
||||
import "./IERC1155TokenReceiver.sol";
|
||||
import "@openzeppelin/contracts/introspection/ERC165.sol";
|
||||
|
||||
abstract contract ERC1155TokenReceiver is ERC165, IERC1155TokenReceiver {
|
||||
constructor() {
|
||||
_registerInterface(
|
||||
ERC1155TokenReceiver(0).onERC1155Received.selector ^
|
||||
ERC1155TokenReceiver(0).onERC1155BatchReceived.selector
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
pragma solidity ^0.7.1;
|
||||
import "@openzeppelin/contracts/math/SafeMath.sol";
|
||||
import { ERC1155 } from "./ERC1155.sol";
|
||||
|
||||
/// @title A base contract for an ERC-1155 contract with calculation of totals.
|
||||
abstract contract ERC1155WithTotals is ERC1155 {
|
||||
using SafeMath for uint256;
|
||||
|
||||
// Mapping (token => total).
|
||||
mapping(uint256 => uint256) private totalBalances;
|
||||
|
||||
/// Construct a token contract with given description URI.
|
||||
/// @param uri_ Description URI.
|
||||
constructor (string memory uri_) ERC1155(uri_) { }
|
||||
|
||||
// Overrides //
|
||||
|
||||
// Need also update totals - commented out
|
||||
// function _mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) internal virtual override {
|
||||
// return super._mintBatch(_originalAddress(to), ids, amounts, data);
|
||||
// }
|
||||
|
||||
// Need also update totals - commented out
|
||||
// function _burnBatch(address account, uint256[] memory ids, uint256[] memory amounts) internal virtual override {
|
||||
// return super._burnBatch(_originalAddress(account), ids, amounts);
|
||||
// }
|
||||
|
||||
/// Total supply of a token (conforms to `IERC1155Views`).
|
||||
/// @param id Token ID.
|
||||
/// @return Total supply.
|
||||
function totalSupply(uint256 id) public view returns (uint256) {
|
||||
return totalBalances[id];
|
||||
}
|
||||
|
||||
/// Mint a token.
|
||||
/// @param to Whom to mint to.
|
||||
/// @param id Token ID.
|
||||
/// @param value Amount to mint.
|
||||
/// @param data Additional data.
|
||||
function _mint(address to, uint256 id, uint256 value, bytes memory data) internal override {
|
||||
require(to != address(0), "ERC1155: mint to the zero address");
|
||||
|
||||
_doMint(to, id, value);
|
||||
emit TransferSingle(msg.sender, address(0), to, id, value);
|
||||
|
||||
_doSafeTransferAcceptanceCheck(msg.sender, address(0), to, id, value, data);
|
||||
}
|
||||
|
||||
/// Mint zero or more tokens.
|
||||
/// @param to Whom to mint to.
|
||||
/// @param ids Token IDs.
|
||||
/// @param values Amounts to mint.
|
||||
/// @param data Additional data.
|
||||
function _batchMint(address to, uint256[] memory ids, uint256[] memory values, bytes memory data) internal {
|
||||
require(to != address(0), "ERC1155: batch mint to the zero address");
|
||||
require(ids.length == values.length, "ERC1155: IDs and values must have same lengths");
|
||||
|
||||
for(uint i = 0; i < ids.length; i++) {
|
||||
_doMint(to, ids[i], values[i]);
|
||||
}
|
||||
|
||||
emit TransferBatch(msg.sender, address(0), to, ids, values);
|
||||
|
||||
_doSafeBatchTransferAcceptanceCheck(msg.sender, address(0), to, ids, values, data);
|
||||
}
|
||||
|
||||
/// Burn a token.
|
||||
/// @param owner Whose tokens to burn.
|
||||
/// @param id Token ID.
|
||||
/// @param value Amount to mint.
|
||||
function _burn(address owner, uint256 id, uint256 value) internal override {
|
||||
_doBurn(owner, id, value);
|
||||
emit TransferSingle(msg.sender, owner, address(0), id, value);
|
||||
}
|
||||
|
||||
/// Burn zero or more tokens.
|
||||
/// @param owner Whose tokens to burn.
|
||||
/// @param ids Token IDs.
|
||||
/// @param values Amounts to mint.
|
||||
function _batchBurn(address owner, uint256[] memory ids, uint256[] memory values) internal {
|
||||
require(ids.length == values.length, "ERC1155: IDs and values must have same lengths");
|
||||
|
||||
for(uint i = 0; i < ids.length; i++) {
|
||||
_doBurn(owner, ids[i], values[i]);
|
||||
}
|
||||
|
||||
emit TransferBatch(msg.sender, owner, address(0), ids, values);
|
||||
}
|
||||
|
||||
function _doMint(address to, uint256 id, uint256 value) private {
|
||||
totalBalances[id] = totalBalances[id].add(value);
|
||||
_balances[id][to] = _balances[id][to] + value; // The previous didn't overflow, therefore this doesn't overflow.
|
||||
}
|
||||
|
||||
function _doBurn(address from, uint256 id, uint256 value) private {
|
||||
_balances[id][from] = _balances[id][from].sub(value);
|
||||
totalBalances[id] = totalBalances[id] - value; // The previous didn't overflow, therefore this doesn't overflow.
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
pragma solidity ^0.7.1;
|
||||
|
||||
import "@openzeppelin/contracts/introspection/IERC165.sol";
|
||||
|
||||
/**
|
||||
@title ERC-1155 Multi Token Standard basic interface
|
||||
@dev See https://eips.ethereum.org/EIPS/eip-1155
|
||||
*/
|
||||
abstract contract IERC1155 is IERC165 {
|
||||
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
|
||||
|
||||
event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values);
|
||||
|
||||
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
|
||||
|
||||
event URI(string value, uint256 indexed id);
|
||||
|
||||
function balanceOf(address owner, uint256 id) public view virtual returns (uint256);
|
||||
|
||||
function balanceOfBatch(address[] memory owners, uint256[] memory ids) public view virtual returns (uint256[] memory);
|
||||
|
||||
function setApprovalForAll(address operator, bool approved) external virtual;
|
||||
|
||||
function isApprovedForAll(address owner, address operator) external view virtual returns (bool);
|
||||
|
||||
function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external virtual;
|
||||
|
||||
function safeBatchTransferFrom(address from, address to, uint256[] calldata ids, uint256[] calldata values, bytes calldata data) external virtual;
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
pragma solidity ^0.7.1;
|
||||
|
||||
import "@openzeppelin/contracts/introspection/IERC165.sol";
|
||||
|
||||
/**
|
||||
@title ERC-1155 Multi Token Receiver Interface
|
||||
@dev See https://eips.ethereum.org/EIPS/eip-1155
|
||||
*/
|
||||
abstract contract IERC1155TokenReceiver is IERC165 {
|
||||
|
||||
/**
|
||||
@dev Handles the receipt of a single ERC1155 token type. This function is
|
||||
called at the end of a `safeTransferFrom` after the balance has been updated.
|
||||
To accept the transfer, this must return
|
||||
`bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
|
||||
(i.e. 0xf23a6e61, or its own function selector).
|
||||
@param operator The address which initiated the transfer (i.e. msg.sender)
|
||||
@param from The address which previously owned the token
|
||||
@param id The ID of the token being transferred
|
||||
@param value The amount of tokens being transferred
|
||||
@param data Additional data with no specified format
|
||||
@return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
|
||||
*/
|
||||
function onERC1155Received(
|
||||
address operator,
|
||||
address from,
|
||||
uint256 id,
|
||||
uint256 value,
|
||||
bytes calldata data
|
||||
)
|
||||
external virtual
|
||||
returns(bytes4);
|
||||
|
||||
/**
|
||||
@dev Handles the receipt of a multiple ERC1155 token types. This function
|
||||
is called at the end of a `safeBatchTransferFrom` after the balances have
|
||||
been updated. To accept the transfer(s), this must return
|
||||
`bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
|
||||
(i.e. 0xbc197c81, or its own function selector).
|
||||
@param operator The address which initiated the batch transfer (i.e. msg.sender)
|
||||
@param from The address which previously owned the token
|
||||
@param ids An array containing ids of each token being transferred (order and length must match values array)
|
||||
@param values An array containing amounts of each token being transferred (order and length must match ids array)
|
||||
@param data Additional data with no specified format
|
||||
@return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
|
||||
*/
|
||||
function onERC1155BatchReceived(
|
||||
address operator,
|
||||
address from,
|
||||
uint256[] calldata ids,
|
||||
uint256[] calldata values,
|
||||
bytes calldata data
|
||||
)
|
||||
external virtual
|
||||
returns(bytes4);
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
---
|
||||
sections:
|
||||
- title: Core
|
||||
contracts:
|
||||
- IERC1155
|
||||
- ERC1155
|
||||
- IERC1155TokenReceiver
|
||||
---
|
||||
|
||||
This set of interfaces and contracts are all related to the [ERC1155 Multi Token Standard](https://eips.ethereum.org/EIPS/eip-1155).
|
||||
|
||||
The EIP consists of two interfaces which fulfill different roles, found here as `IERC1155` and `IERC1155TokenReceiver`. Only `IERC1155` is required for a contract to be ERC1155 compliant. The basic functionality is implemented in `ERC1155`.
|
|
@ -1,31 +0,0 @@
|
|||
This directory contains contract sources for EIP 3267 draft.
|
||||
|
||||
The audit of the contracts was paid for, now it is in progress.
|
||||
(There are some FIXME/TODO comments for the auditors.)
|
||||
|
||||
The contracts are to be compiled with Solidity 0.7.6.
|
||||
|
||||
Dependencies (Node.js packages):
|
||||
|
||||
- @openzeppelin/contracts 3.3.0
|
||||
- abdk-libraries-solidity 2.4.0
|
||||
|
||||
The contracts to be deployed are:
|
||||
- SalaryWithDAO
|
||||
- DefaultDAOInterface
|
||||
|
||||
The sources:
|
||||
- [ERC1155/ERC1155.sol](./ERC1155/ERC1155.sol)
|
||||
- [ERC1155/ERC1155TokenReceiver.sol](./ERC1155/ERC1155TokenReceiver.sol)
|
||||
- [ERC1155/ERC1155WithTotals.sol](./ERC1155/ERC1155WithTotals.sol)
|
||||
- [ERC1155/IERC1155.sol](./ERC1155/IERC1155.sol)
|
||||
- [ERC1155/IERC1155TokenReceiver.sol](./ERC1155/IERC1155TokenReceiver.sol)
|
||||
- [BaseBidOnAddresses.sol](./BaseBidOnAddresses.sol)
|
||||
- [BaseLock.sol](./BaseLock.sol)
|
||||
- [BaseRestorableSalary.sol](./BaseRestorableSalary.sol)
|
||||
- [BaseSalary.sol](./BaseSalary.sol)
|
||||
- [BidOnAddresses.sol](./BidOnAddresses.sol)
|
||||
- [DAOInterface.sol](./DAOInterface.sol)
|
||||
- [DefaultDAOInterface.sol](./DefaultDAOInterface.sol)
|
||||
- [Salary.sol](./Salary.sol)
|
||||
- [SalaryWithDAO.sol](./SalaryWithDAO.sol)
|
|
@ -1,28 +0,0 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
pragma solidity ^0.7.1;
|
||||
import "./BaseSalary.sol";
|
||||
|
||||
/// @title "Salary" that is paid one token per second using minted conditionals.
|
||||
/// @author Victor Porton
|
||||
/// @notice Not audited, not enough tested.
|
||||
contract Salary is BaseSalary {
|
||||
/// @param _uri The ERC-1155 token URI.
|
||||
constructor(string memory _uri) BaseSalary(_uri) { }
|
||||
|
||||
/// Register a salary recipient.
|
||||
///
|
||||
/// Can be called both before or after the oracle finish. However registering after the finish is useless.
|
||||
///
|
||||
/// Anyone can register anyone (useful for robots registering a person).
|
||||
///
|
||||
/// Registering another person is giving him money against his will (forcing to hire bodyguards, etc.),
|
||||
/// but if one does not want, he can just not associate this address with his identity in his publications.
|
||||
/// @param _customer The original address.
|
||||
/// @param _oracleId The oracle ID.
|
||||
/// @param _data The current data.
|
||||
function registerCustomer(address _customer, uint64 _oracleId, bytes calldata _data)
|
||||
virtual public returns (uint256)
|
||||
{
|
||||
return _registerCustomer(_customer, _oracleId, _data);
|
||||
}
|
||||
}
|
|
@ -1,126 +0,0 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
pragma solidity ^0.7.1;
|
||||
import { ABDKMath64x64 } from "abdk-libraries-solidity/ABDKMath64x64.sol";
|
||||
import "./BaseRestorableSalary.sol";
|
||||
import "./DAOInterface.sol";
|
||||
|
||||
/// Salary system with a "DAO" that can assign attorneys to restore lost Ethereum accounts.
|
||||
/// @author Victor Porton
|
||||
/// @notice Not audited, not enough tested.
|
||||
contract SalaryWithDAO is BaseRestorableSalary {
|
||||
using ABDKMath64x64 for int128;
|
||||
|
||||
/// The DAO interface.
|
||||
DAOInterface public daoPlugin;
|
||||
|
||||
/// When set to true, your account can't be moved to new address (by the DAO).
|
||||
///
|
||||
/// By default new users are not under DAO control to avoid front-running of resigning control
|
||||
/// by an evil DAO.
|
||||
///
|
||||
/// Mapping (current address => under control)
|
||||
mapping (address => bool) public underDAOControl;
|
||||
|
||||
/// Mapping (current address => account has at least one salary).
|
||||
mapping (address => bool) public accountHasSalary;
|
||||
|
||||
// DAO share will be zero to prevent theft by voters and because it can be done instead by future voting.
|
||||
// int128 public daoShare = int128(0).div(1); // zero by default
|
||||
|
||||
/// Constructor.
|
||||
/// @param _daoPlugin The DAO interface.
|
||||
/// @param _uri The ERC-1155 token URI.
|
||||
constructor(DAOInterface _daoPlugin, string memory _uri)
|
||||
BaseRestorableSalary(_uri)
|
||||
{
|
||||
daoPlugin = _daoPlugin;
|
||||
}
|
||||
|
||||
/// Create an oracle for caclcualting salary amounts.
|
||||
function createOracle() external returns (uint64) {
|
||||
return _createOracle();
|
||||
}
|
||||
|
||||
/// Register a salary recipient.
|
||||
///
|
||||
/// Can be called both before or after the oracle finish. However registering after the finish is useless.
|
||||
///
|
||||
/// Anyone can register anyone (useful for robots registering a person).
|
||||
///
|
||||
/// Registering another person is giving him money against his will (forcing to hire bodyguards, etc.),
|
||||
/// but if one does not want, he can just not associate this address with his identity in his publications.
|
||||
/// @param _customer The original address.
|
||||
/// @param _oracleId The oracle ID.
|
||||
/// @param _underDAOControl If the registered address will be under DAO control.
|
||||
/// @param _data The current data.
|
||||
function registerCustomer(address _customer, uint64 _oracleId, bool _underDAOControl, bytes calldata _data)
|
||||
virtual public returns (uint256)
|
||||
{
|
||||
address _orig = _originalAddress(_customer);
|
||||
// Auditor: Check that this value is set to false, when (and if) necessary.
|
||||
accountHasSalary[_customer] = true;
|
||||
underDAOControl[_customer] = _underDAOControl; // We don't trigger and event to reduce gas usage.
|
||||
return super._registerCustomer(_orig, _oracleId, _data);
|
||||
}
|
||||
|
||||
/// A user can agree for DAO control. Then his account can be restored by DAO for the expense
|
||||
/// of the DAO assigned personnel or software being able to steal his funds.
|
||||
///
|
||||
/// Be exteremely careful calling this method: If you refuse and lose your key, your funds are lost!
|
||||
///
|
||||
/// Fishers may trick one to resign mistakenly. However, it's no much worse than just fishing for
|
||||
/// withdrawing the salary token, because a user could just register anew and notify traders/oracles
|
||||
/// that it's the same person.
|
||||
function setDAOControl(bool _underControl) public {
|
||||
address _orig = _originalAddress(msg.sender);
|
||||
require(accountHasSalary[_orig], "Cannot resign account receiving a salary.");
|
||||
underDAOControl[_orig] = _underControl; // We don't trigger and event to reduce gas usage.
|
||||
}
|
||||
|
||||
/// The DAO can replace itself.
|
||||
function setDAO(DAOInterface _daoPlugin) public onlyDAO {
|
||||
daoPlugin = _daoPlugin;
|
||||
}
|
||||
|
||||
/// Set the token URI.
|
||||
function setURI(string memory _newuri) public onlyDAO {
|
||||
_setURI(_newuri);
|
||||
}
|
||||
|
||||
// Overrides ///
|
||||
|
||||
function checkAllowedRestoreAccount(address _oldAccount, address _newAccount)
|
||||
public virtual override isUnderDAOControl(_oldAccount)
|
||||
{
|
||||
daoPlugin.checkAllowedRestoreAccount(_oldAccount, _newAccount);
|
||||
}
|
||||
|
||||
/// Allow the user to unrestore by himself?
|
||||
/// We won't not allow it to `_oldAccount` because it may be a stolen private key.
|
||||
/// We could allow it to `_newAccount`, but this makes no much sense, because
|
||||
/// it would only prevent the user to do a theft by himself, let only DAO could be allowed to do.
|
||||
function checkAllowedUnrestoreAccount(address _oldAccount, address _newAccount)
|
||||
public virtual override isUnderDAOControl(_oldAccount)
|
||||
{
|
||||
daoPlugin.checkAllowedUnrestoreAccount(_oldAccount, _newAccount);
|
||||
}
|
||||
|
||||
// Internal //
|
||||
|
||||
function _isDAO() internal view returns (bool) {
|
||||
return msg.sender == address(daoPlugin);
|
||||
}
|
||||
|
||||
// Modifiers //
|
||||
|
||||
modifier onlyDAO() {
|
||||
require(_isDAO(), "Only DAO can do.");
|
||||
_;
|
||||
}
|
||||
|
||||
/// @param _customer The current address.
|
||||
modifier isUnderDAOControl(address _customer) {
|
||||
require(underDAOControl[_customer], "Not under DAO control.");
|
||||
_;
|
||||
}
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
pragma solidity >=0.7.6;
|
||||
|
||||
contract MetaProxyFactory {
|
||||
/// @dev Creates a new proxy for `targetContract` with metadata from calldata.
|
||||
/// Copies everything from calldata except the first 4 bytes.
|
||||
/// @return addr A non-zero address if successful.
|
||||
function _metaProxyFromCalldata (address targetContract) internal returns (address addr) {
|
||||
// the following assembly code (init code + contract code) constructs a metaproxy.
|
||||
assembly {
|
||||
// load free memory pointer as per solidity convention
|
||||
let start := mload(64)
|
||||
// copy
|
||||
let ptr := start
|
||||
// deploy code (11 bytes) + first part of the proxy (21 bytes)
|
||||
mstore(ptr, 0x600b380380600b3d393df3363d3d373d3d3d3d60368038038091363936013d73)
|
||||
ptr := add(ptr, 32)
|
||||
|
||||
// store the address of the contract to be called
|
||||
mstore(ptr, shl(96, targetContract))
|
||||
// 20 bytes
|
||||
ptr := add(ptr, 20)
|
||||
|
||||
// the remaining proxy code...
|
||||
mstore(ptr, 0x5af43d3d93803e603457fd5bf300000000000000000000000000000000000000)
|
||||
// ...13 bytes
|
||||
ptr := add(ptr, 13)
|
||||
|
||||
// now calculdate the size and copy the metadata
|
||||
// - 4 bytes function signature
|
||||
let size := sub(calldatasize(), 4)
|
||||
// copy
|
||||
calldatacopy(ptr, 4, size)
|
||||
ptr := add(ptr, size)
|
||||
// store the size of the metadata at the end of the bytecode
|
||||
mstore(ptr, size)
|
||||
ptr := add(ptr, 32)
|
||||
|
||||
// The size is deploy code + contract code + calldatasize - 4 + 32.
|
||||
addr := create(0, start, sub(ptr, start))
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Creates a proxy for `targetContract` with metadata from `metadata`.
|
||||
/// @return A non-zero address if successful.
|
||||
function _metaProxyFromBytes (address targetContract, bytes memory metadata) internal returns (address) {
|
||||
uint256 ptr;
|
||||
assembly {
|
||||
ptr := add(metadata, 32)
|
||||
}
|
||||
return _metaProxyFromMemory(targetContract, ptr, metadata.length);
|
||||
}
|
||||
|
||||
/// @dev Creates a new proxy for `targetContract` with metadata from memory starting at `offset` and `length` bytes.
|
||||
/// @return addr A non-zero address if successful.
|
||||
function _metaProxyFromMemory (address targetContract, uint256 offset, uint256 length) internal returns (address addr) {
|
||||
// the following assembly code (init code + contract code) constructs a metaproxy.
|
||||
assembly {
|
||||
// load free memory pointer as per solidity convention
|
||||
let start := mload(64)
|
||||
// keep a copy
|
||||
let ptr := start
|
||||
// deploy code (11 bytes) + first part of the proxy (21 bytes)
|
||||
mstore(ptr, 0x600b380380600b3d393df3363d3d373d3d3d3d60368038038091363936013d73)
|
||||
ptr := add(ptr, 32)
|
||||
|
||||
// store the address of the contract to be called
|
||||
mstore(ptr, shl(96, targetContract))
|
||||
// 20 bytes
|
||||
ptr := add(ptr, 20)
|
||||
|
||||
// the remaining proxy code...
|
||||
mstore(ptr, 0x5af43d3d93803e603457fd5bf300000000000000000000000000000000000000)
|
||||
// ...13 bytes
|
||||
ptr := add(ptr, 13)
|
||||
|
||||
// copy the metadata
|
||||
{
|
||||
for { let i := 0 } lt(i, length) { i := add(i, 32) } {
|
||||
mstore(add(ptr, i), mload(add(offset, i)))
|
||||
}
|
||||
}
|
||||
ptr := add(ptr, length)
|
||||
// store the size of the metadata at the end of the bytecode
|
||||
mstore(ptr, length)
|
||||
ptr := add(ptr, 32)
|
||||
|
||||
// The size is deploy code + contract code + calldatasize - 4 + 32.
|
||||
addr := create(0, start, sub(ptr, start))
|
||||
}
|
||||
}
|
||||
}
|