Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- RWATokenV2
- Optimization enabled
- false
- Compiler version
- v0.8.24+commit.e11b9ed9
- EVM Version
- Verified at
- 2026-10-20T10:04:38.399079Z
Constructor Arguments
0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000d3c21bcecceda10000000000000000000000000000000eb5556032f9ca9ab629439afaecd79c40aab863000000000000000000000000f119beb1b343e46c4ed0e78362cd3f87e87ef4cc00000000000000000000000076e388cf49d12262808651e35d6fd296c1d4433f000000000000000000000000d37d29526d271770f42c2553faae7f282effc1630000000000000000000000005a5db3d01a38d640a81182b1769a9f1e4d1f0f7400000000000000000000000016eeba545a07a88cdf21cfdde973ee67cdc3200000000000000000000000000091991f58804cc5aceca5e87d4667e68d22e0824800000000000000000000000000000000000000000000000000000000000000055257415f3100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064d445445535400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042697066733a2f2f6261666b726569613566676970727837706672756b6661373275756a377876676b776d7663697a646d686f36656e327a76376335346c3565793271000000000000000000000000000000000000000000000000000000000000
contracts/RWATokenV2.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "./AdminZamik.sol";
interface IKYCWhitelistV2 {
function isWhitelisted(address account) external view returns (bool);
}
interface IUORSRegistryV2 {
function authorizedUORS(address operater) external view returns (bool);
}
/// @notice Kar zeton bere z RWA Marketplace v2.
interface ITrgV2 {
function usdc() external view returns (address);
function feeRecipient() external view returns (address);
function placanaProvizija(address zeton) external view returns (uint256);
}
/**
* @notice Nastavitve novega zetona v2 v eni strukturi (glej RWAToken: "stack too deep").
*/
struct NastavitveZetonaV2 {
string ime;
string simbol;
string metapodatkiCID;
uint256 vrednostUSD;
address zkVerifier;
address entropyOracle;
address trg; // RWA Marketplace v2 — edina pot za obicajno prodajo
address kyc; // 0x0 = brez omejitve, a mora biti napisano izrecno
address lastnik;
address uors;
address overitelj;
}
/**
* @title RWATokenV2
* @notice Delez realnega sredstva. Razlike proti RWAToken:
*
* 1. PROVIZIJE SAMO V USDC. Zeton nima provizije v enotah — ne ob kovanju ne ob
* prenosu. Platforma tako nikoli ni solastnica sredstva. Provizija za izdajo
* (0,5 % cenitve) je zapisana v USDC in jo RWA Marketplace v2 zadrzi od
* kupnine prvih prodaj prvotnega lastnika, dokler ni poravnana.
*
* 2. PRENOS SAMO PREK TRGA. Obicajen prenos gre samo v hrambo trga ali iz nje.
* Prenos mimo trga (dedovanje, darilo, sodna odlocba) izvede overitelj z
* odtisom listine, skozi javno napoved in zamik.
*
* 3. RAZDRUZITEV. Imetnik vsaj 90 % enot lahko zahteva, da se sredstvo sprosti
* iz zetona. Manjsina dobi USDC po ceni, ki ni nizja od nove neodvisne
* cenitve; ima pravico do ugovora in druge cenitve. Potek je opisan pri
* funkcijah spodaj.
*
* @dev ZDRUZLJIVOST Z ZKVerifierjem: obstojeci ZKVerifier skuje `amount - 0,5 %`
* prejemniku in nato poklice `mintFee(feeRecipient(), 0,5 %)`. Ta zeton vrne
* kot `feeRecipient()` prvotnega lastnika, zato lastnik dobi VSE enote,
* ZKVerifierja pa ni treba menjati. Dogodek `MintFeeCollected` v ZKVerifierju
* pri tem zetonu pomeni "drugi del kovanja lastniku", ne provizije.
*/
contract RWATokenV2 is ERC20, Ownable, ReentrancyGuard, AdminZamik {
using SafeERC20 for IERC20;
// ── Sredstvo ──────────────────────────────────────────────────────────────
string public assetMetadataCID; // nespremenljiv (glej RWAToken)
uint256 public assetValueUSD; // 18 decimalk
address public immutable zkVerifier;
address public immutable entropyOracle;
address public immutable trg;
address public immutable uors;
address public immutable overitelj;
uint256 public immutable aktivenOd;
address public kyc;
address public prvotniLastnik;
bool public zamrznjen;
mapping(bytes32 => bool) public usedProofs;
bool private provizijaOdprta;
uint256 private skovanoLastniku;
bool private prenosOdobren;
// ── Provizija za izdajo (USDC, 6 decimalk) ─────────────────────────────────
uint256 public constant PROVIZIJA_IZDAJE_BPS = 50; // 0,5 % cenitve ob kovanju
/// @notice Celotna provizija za izdajo v USDC; zapise se ob kovanju in se ne spreminja.
uint256 public provizijaIzdaje;
// ── Razdruzitev ───────────────────────────────────────────────────────────
uint256 public constant PRAG_BPS = 9_000; // 90 % vseh enot
uint256 public constant PRAG_UGOVORA_BPS = 500; // druga cenitev vsaj 5 % visja
uint256 public constant POLOG_UGOVORA = 500e6; // 500 USDC
uint256 public constant DNI_CENITEV = 30; // overitelj vpise cenitev
uint256 public constant DNI_POLOG = 14; // sprozitelj polozi USDC
uint256 public constant DNI_UGOVOR = 30; // rok za ugovor / za drugo cenitev
uint256 public constant DNI_DOPLACILO = 14; // sprozitelj doplaca po uspesnem ugovoru
uint256 public constant DNI_POTRDITEV = 30; // overitelj potrdi; sicer preklic
uint256 public constant DNI_PAVZA = 30; // po preklicu do nove zahteve
enum Faza { Ni, Zahtevano, Ocenjeno, Polozeno, Ugovor, Doplacilo, Razdruzeno }
Faza public faza;
uint256 public krog; // zaporedna stevilka postopka
address public sprozitelj;
address public placilniZeton; // USDC, zapisan ob zahtevi
uint256 public rok; // rok trenutne faze (unix cas)
uint256 public cenitevRazdruzitve; // nova cenitev, 18 decimalk
uint256 public drugaCenitev; // cenitev po ugovoru, 18 decimalk (0 = je ni)
uint256 public trznaCena; // USDC za enoto (6 decimalk), 0 = ni prodaj
uint256 public cenaNaEnoto; // USDC za 1e18 enote — po tej se odkupi
bytes32 public odtisCenitve;
bytes32 public odtisDrugeCenitve;
bytes32 public odtisListine;
uint256 public enotSprozitelja; // zapisano ob pologu
uint256 public enotManjsine; // zapisano ob pologu
uint256 public polozeno; // USDC v hrambi za manjsino (+ provizija pred potrditvijo)
uint256 public provizijaVPologu; // neporavnana provizija za izdajo, zajeta v pologu
/// @notice Pred tem casom nove zahteve ni. Brez pavze bi lahko vecinski imetnik
/// z zaporednimi zahtevami in preklici trgovanje zamrznil za nedolocen cas.
uint256 public naslednjaZahtevaOd;
/// @dev Izid ugovora po krogu. `vracilo`: 0 = se odprto, 1 = polno, 2 = strosek deljen.
struct Ugovor { uint256 stevilo; uint8 vracilo; bool ugovorOpravljen; }
mapping(uint256 => Ugovor) public ugovori;
mapping(uint256 => mapping(address => bool)) public ugovarjal;
// ── Dogodki ───────────────────────────────────────────────────────────────
event Zamrznjeno(address indexed kdo);
event Odmrznjeno(address indexed kdo);
event AssetValueUpdated(uint256 newValueUSD);
event TokensMinted(address indexed to, uint256 amount, bytes32 proofHash);
event PrvotniLastnikZapisan(address indexed lastnik);
event KycUpdated(address indexed newKyc);
event PrenosZOdobritvijo(address indexed od, address indexed komu, uint256 kolicina, bytes32 odtisListine);
event RazdruzitevZahtevana(uint256 indexed krog, address indexed sprozitelj, uint256 enot);
event CenitevVpisana(uint256 indexed krog, uint256 cenitevUSD, uint256 trznaCena, uint256 cenaNaEnoto, bytes32 odtis);
event Polozeno(uint256 indexed krog, uint256 znesek, uint256 enotManjsine);
event UgovorVlozen(uint256 indexed krog, address indexed kdo);
event DrugaCenitevVpisana(uint256 indexed krog, uint256 cenitevUSD, bool uspel, uint256 cenaNaEnoto, bytes32 odtis);
event Doplacano(uint256 indexed krog, uint256 znesek);
event RazdruzitevPreklicana(uint256 indexed krog, address indexed kdo);
event Razdruzeno(uint256 indexed krog, bytes32 odtisListine);
event Dvignjeno(address indexed kdo, uint256 enot, uint256 usdc);
event PologUgovoraVrnjen(uint256 indexed krog, address indexed kdo, uint256 znesek);
constructor(NastavitveZetonaV2 memory n)
ERC20(n.ime, n.simbol)
Ownable(n.lastnik)
{
require(n.zkVerifier != address(0), "ZKVerifier je nujen");
require(n.trg != address(0), "Trg je nujen");
require(n.lastnik != address(0), "Lastnik je nujen");
require(n.uors != address(0), "UORSRegistry je nujen");
assetMetadataCID = n.metapodatkiCID;
assetValueUSD = n.vrednostUSD;
zkVerifier = n.zkVerifier;
entropyOracle = n.entropyOracle;
trg = n.trg;
kyc = n.kyc;
uors = n.uors;
overitelj = n.overitelj;
aktivenOd = block.timestamp + Omrezja.zamik();
}
// ── Dovoljenja ────────────────────────────────────────────────────────────
modifier samoUORS() {
require(IUORSRegistryV2(uors).authorizedUORS(msg.sender), "Samo UORS operater");
_;
}
modifier samoOveritelj() {
require(overitelj != address(0), "Sredstvo nima zapisanega overitelja");
require(msg.sender == overitelj, "Samo overitelj tega sredstva");
require(IUORSRegistryV2(uors).authorizedUORS(msg.sender), "Overitelj ni vec pooblascen");
_;
}
/// @dev Rok v dneh. Na testnih verigah (Omrezja.jeTestno) je en "dan" ena minuta,
/// da je postopek mogoce pokazati v eni seji — enako nacelo kot `zamik()`.
function _dni(uint256 d) internal view returns (uint256) {
return Omrezja.jeTestno(block.chainid) ? d * 1 minutes : d * 1 days;
}
/// @notice Dolzina enega "dneva" v rokih razdruzitve na tej verigi (sekunde).
function dan() external view returns (uint256) { return _dni(1); }
function zaporaPrenosa() external view returns (uint256) { return Omrezja.zamik(); }
function jePrenosMogoc() external view returns (bool mogoc, uint256 odKdaj, bool zamrznjeno) {
return (block.timestamp >= aktivenOd && !zamrznjen && faza == Faza.Ni, aktivenOd, zamrznjen);
}
/// @notice Ali razdruzitev tece (ali je koncana) — trg takrat ne sprejema poslov.
function razdruzitevVTeku() external view returns (bool) { return faza != Faza.Ni; }
function zamrzni() external samoUORS { zamrznjen = true; emit Zamrznjeno(msg.sender); }
function odmrzni() external samoUORS { zamrznjen = false; emit Odmrznjeno(msg.sender); }
// ── Kovanje ───────────────────────────────────────────────────────────────
function mintWithProof(address to, uint256 amount, bytes32 proofHash) external {
require(msg.sender == zkVerifier, "Only ZK verifier");
require(!usedProofs[proofHash], "Proof already used");
require(prvotniLastnik == address(0), "Sredstvo je ze skovano");
usedProofs[proofHash] = true;
prvotniLastnik = to;
provizijaOdprta = true;
skovanoLastniku = amount;
// 18 decimalk USD → 6 decimalk USDC
provizijaIzdaje = assetValueUSD * PROVIZIJA_IZDAJE_BPS / 10_000 / 1e12;
_mint(to, amount);
emit TokensMinted(to, amount, proofHash);
emit PrvotniLastnikZapisan(to);
}
/**
* @notice Drugi del kovanja (glej opombo o zdruzljivosti zgoraj). Enote gredo
* prvotnemu lastniku, ne platformi.
*/
function mintFee(address to, uint256 amount) external {
require(msg.sender == zkVerifier, "Only ZK verifier");
require(provizijaOdprta, "Provizija brez kovanja");
require(to == prvotniLastnik, "Enote gredo samo prvotnemu lastniku");
require(amount * 199 <= skovanoLastniku, "Provizija previsoka");
provizijaOdprta = false;
_mint(to, amount);
}
/// @notice Za ZKVerifier: kam gre drugi del kovanja. Pri tem zetonu je to lastnik.
function feeRecipient() external view returns (address) { return prvotniLastnik; }
// ── Prenos ────────────────────────────────────────────────────────────────
function _update(address from, address to, uint256 amount) internal override {
bool isMint = (from == address(0));
bool isBurn = (to == address(0));
// Unicenje (dvig po razdruzitvi) je izvzeto iz KYC namerno: imetnik,
// ki mu je bil KYC odvzet, mora se vedno priti do svojega USDC.
if (kyc != address(0) && !isBurn) {
require(IKYCWhitelistV2(kyc).isWhitelisted(to), "Prejemnik ni KYC preverjen");
if (!isMint) require(IKYCWhitelistV2(kyc).isWhitelisted(from), "Posiljatelj ni KYC preverjen");
}
if (!isMint) {
require(!zamrznjen, "Sredstvo je zamrznjeno");
require(block.timestamp >= aktivenOd, "Sredstvo se ni aktivno za prenos");
if (!isBurn) {
if (faza != Faza.Ni) {
// Med razdruzitvijo se enote ne premikajo. Izjema je vracilo iz
// hrambe trga (preklic oglasa), da lahko prodajalec dvigne USDC.
require(from == trg, "Razdruzitev v teku: prenos ni mogoc");
} else {
require(from == trg || to == trg || prenosOdobren,
"Prenos samo prek RWA Marketplace");
}
}
}
super._update(from, to, amount);
}
/**
* @notice Prenos mimo trga (dedovanje, darilo, sodna odlocba) — 1. korak: javna napoved.
* @dev Overitelj s tem premakne tuje enote, zato gre skozi napoved in zamik: imetnik
* vidi, kaj prihaja, skrbnik pa lahko napoved prekliče (`prekliciSpremembo`).
*/
function napoviPrenesiZOdobritvijo(address od, address komu, uint256 kolicina, bytes32 odtis)
external samoOveritelj
{
require(odtis != bytes32(0), "Odtis listine je nujen");
_napovej(keccak256(abi.encode("prenos", od, komu, kolicina, odtis)), "RWATokenV2.prenos");
}
/// @notice 2. korak: izvedba po zamiku. Velja samo za napovedane podatke.
function prenesiZOdobritvijo(address od, address komu, uint256 kolicina, bytes32 odtis)
external samoOveritelj
{
require(faza == Faza.Ni, "Razdruzitev v teku");
_porabi(keccak256(abi.encode("prenos", od, komu, kolicina, odtis)), "RWATokenV2.prenos");
prenosOdobren = true;
_transfer(od, komu, kolicina);
prenosOdobren = false;
emit PrenosZOdobritvijo(od, komu, kolicina, odtis);
}
// ── Razdruzitev ───────────────────────────────────────────────────────────
/**
* @notice 1. Imetnik vsaj 90 % vseh enot zahteva razdruzitev. Trgovanje se zamrzne.
* @dev Kdorkoli, ne samo prvotni lastnik: enote so lastnistvo.
*/
function zahtevajRazdruzitev() external {
require(faza == Faza.Ni, "Razdruzitev ze tece");
require(prvotniLastnik != address(0), "Sredstvo se ni skovano");
require(!zamrznjen, "Sredstvo je zamrznjeno");
require(block.timestamp >= naslednjaZahtevaOd, "Po preklicu nova zahteva se ni mogoca");
uint256 enot = balanceOf(msg.sender);
require(enot * 10_000 >= totalSupply() * PRAG_BPS, "Potrebnih je vsaj 90 % enot");
krog++;
faza = Faza.Zahtevano;
sprozitelj = msg.sender;
placilniZeton = ITrgV2(trg).usdc();
rok = block.timestamp + _dni(DNI_CENITEV);
cenitevRazdruzitve = 0;
drugaCenitev = 0;
trznaCena = 0;
cenaNaEnoto = 0;
odtisCenitve = bytes32(0);
odtisDrugeCenitve = bytes32(0);
enotSprozitelja = 0;
enotManjsine = 0;
polozeno = 0;
provizijaVPologu = 0;
emit RazdruzitevZahtevana(krog, msg.sender, enot);
}
/// @dev cena = najvecja od (cenitev na enoto; povprecje cenitve in trzne cene).
function _cena(uint256 cenitevUSD, uint256 trzna) internal view returns (uint256) {
uint256 naEnoto = cenitevUSD * 1e6 / totalSupply();
if (trzna == 0) return naEnoto;
uint256 povp = (naEnoto + trzna) / 2;
return povp > naEnoto ? povp : naEnoto;
}
/**
* @notice 2. Overitelj vpise NOVO neodvisno cenitev, trzno ceno in odtis porocila.
* @param cenitevUSD cenitev celotnega sredstva, 18 decimalk
* @param trznaNaEnoto povprecna cena prodaj na RWA Marketplace v zadnjih 90 dneh,
* utezena s kolicino, v USDC za enoto (6 decimalk); 0 = prodaj ni bilo.
* Izracun iz javnih dogodkov trga lahko preveri vsak.
*/
function vpisiCenitev(uint256 cenitevUSD, uint256 trznaNaEnoto, bytes32 odtis) external samoOveritelj {
require(faza == Faza.Zahtevano, "Ni zahteve za razdruzitev");
require(cenitevUSD > 0, "Cenitev je nujna");
require(odtis != bytes32(0), "Odtis porocila je nujen");
cenitevRazdruzitve = cenitevUSD;
trznaCena = trznaNaEnoto;
odtisCenitve = odtis;
cenaNaEnoto = _cena(cenitevUSD, trznaNaEnoto);
faza = Faza.Ocenjeno;
rok = block.timestamp + _dni(DNI_POLOG);
emit CenitevVpisana(krog, cenitevUSD, trznaNaEnoto, cenaNaEnoto, odtis);
}
/// @notice Neporavnani del provizije za izdajo (USDC).
function neporavnanaProvizija() public view returns (uint256) {
uint256 p = ITrgV2(trg).placanaProvizija(address(this));
return p >= provizijaIzdaje ? 0 : provizijaIzdaje - p;
}
/// @notice Koliko USDC mora sprozitelj polozit zdaj.
function potrebenPolog() public view returns (uint256) {
uint256 manjsina = totalSupply() - balanceOf(sprozitelj);
return manjsina * cenaNaEnoto / 1e18 + neporavnanaProvizija();
}
/**
* @notice 3. Sprozitelj polozi ves USDC za enote manjsine in neporavnano provizijo.
* Zacne tece rok za ugovor.
*/
function polozi() external nonReentrant {
require(faza == Faza.Ocenjeno, "Ni casa za polog");
require(msg.sender == sprozitelj, "Samo sprozitelj");
require(block.timestamp <= rok, "Rok za polog je potekel");
enotSprozitelja = balanceOf(sprozitelj);
enotManjsine = totalSupply() - enotSprozitelja;
provizijaVPologu = neporavnanaProvizija();
uint256 znesek = enotManjsine * cenaNaEnoto / 1e18 + provizijaVPologu;
polozeno = znesek;
faza = Faza.Polozeno;
rok = block.timestamp + _dni(DNI_UGOVOR);
IERC20(placilniZeton).safeTransferFrom(msg.sender, address(this), znesek);
emit Polozeno(krog, znesek, enotManjsine);
}
/**
* @notice 4. Imetnik manjsinskih enot ugovarja ceni in polozi 500 USDC za drugo cenitev.
* @dev En ugovor velja za vse. Kdor se pridruzi pred drugo cenitvijo, prav tako
* polozi 500 USDC; ob neuspehu si stroske ene cenitve delijo enako.
*/
function ugovor() external nonReentrant {
Ugovor storage u = ugovori[krog];
if (faza == Faza.Polozeno) {
require(!u.ugovorOpravljen, "Ugovor je ze bil obravnavan");
require(block.timestamp < rok, "Rok za ugovor je potekel");
faza = Faza.Ugovor;
rok = block.timestamp + _dni(DNI_UGOVOR);
} else {
require(faza == Faza.Ugovor, "Ni casa za ugovor");
}
require(msg.sender != sprozitelj, "Sprozitelj ne ugovarja");
require(balanceOf(msg.sender) > 0, "Ugovarja lahko imetnik enot");
require(!ugovarjal[krog][msg.sender], "Ze ugovarjal");
ugovarjal[krog][msg.sender] = true;
u.stevilo++;
IERC20(placilniZeton).safeTransferFrom(msg.sender, address(this), POLOG_UGOVORA);
emit UgovorVlozen(krog, msg.sender);
}
/**
* @notice 5. Overitelj vpise drugo cenitev (drug cenilec).
* Vsaj 5 % visja → ugovor uspe: nova cena, sprozitelj doplaca razliko in
* strosek cenitve, ugovarjalci dobijo polog nazaj v celoti.
* Sicer ostane prva cena, 500 USDC dobi overitelj za cenilca.
*/
function vpisiDrugoCenitev(uint256 cenitevUSD, bytes32 odtis) external samoOveritelj nonReentrant {
require(faza == Faza.Ugovor, "Ni ugovora");
require(cenitevUSD > 0, "Cenitev je nujna");
require(odtis != bytes32(0), "Odtis porocila je nujen");
Ugovor storage u = ugovori[krog];
u.ugovorOpravljen = true;
drugaCenitev = cenitevUSD;
odtisDrugeCenitve = odtis;
bool uspel = cenitevUSD * 10_000 >= cenitevRazdruzitve * (10_000 + PRAG_UGOVORA_BPS);
if (uspel) {
uint256 nova = _cena(cenitevUSD, trznaCena);
if (nova > cenaNaEnoto) cenaNaEnoto = nova;
u.vracilo = 1;
faza = Faza.Doplacilo;
rok = block.timestamp + _dni(DNI_DOPLACILO);
} else {
u.vracilo = 2;
faza = Faza.Polozeno;
rok = block.timestamp; // ugovor je bil, novega ni — potrditev je mogoca
IERC20(placilniZeton).safeTransfer(overitelj, POLOG_UGOVORA);
}
emit DrugaCenitevVpisana(krog, cenitevUSD, uspel, cenaNaEnoto, odtis);
}
/// @notice Koliko mora sprozitelj doplacati po uspesnem ugovoru (razlika + cenitev).
function potrebnoDoplacilo() public view returns (uint256) {
if (faza != Faza.Doplacilo) return 0;
uint256 manjsina = enotManjsine * cenaNaEnoto / 1e18 + provizijaVPologu;
return manjsina - polozeno + POLOG_UGOVORA;
}
/// @notice 6. Doplacilo po uspesnem ugovoru.
function doplacaj() external nonReentrant {
require(faza == Faza.Doplacilo, "Doplacilo ni potrebno");
require(msg.sender == sprozitelj, "Samo sprozitelj");
require(block.timestamp <= rok, "Rok za doplacilo je potekel");
uint256 znesek = potrebnoDoplacilo();
polozeno += znesek - POLOG_UGOVORA;
faza = Faza.Polozeno;
rok = block.timestamp;
IERC20(placilniZeton).safeTransferFrom(msg.sender, address(this), znesek);
IERC20(placilniZeton).safeTransfer(overitelj, POLOG_UGOVORA);
emit Doplacano(krog, znesek);
}
/**
* @notice 7. Overitelj potrdi razdruzitev z odtisom notarske listine. Enote
* sprozitelja se unicijo, provizija za izdajo gre platformi.
*/
function potrdiRazdruzitev(bytes32 odtis) external samoOveritelj nonReentrant {
require(faza == Faza.Polozeno, "Ni pripravljeno za potrditev");
require(block.timestamp >= rok || enotManjsine == 0, "Rok za ugovor se tece");
require(odtis != bytes32(0), "Odtis listine je nujen");
faza = Faza.Razdruzeno;
odtisListine = odtis;
_burn(sprozitelj, enotSprozitelja);
uint256 p = provizijaVPologu;
if (p > 0) {
polozeno -= p;
IERC20(placilniZeton).safeTransfer(ITrgV2(trg).feeRecipient(), p);
}
emit Razdruzeno(krog, odtis);
}
/// @notice 8. Imetnik po razdruzitvi dvigne USDC; njegove enote se unicijo.
function dvigni() external nonReentrant {
require(faza == Faza.Razdruzeno, "Sredstvo ni razdruzeno");
uint256 enot = balanceOf(msg.sender);
require(enot > 0, "Ni enot");
uint256 znesek = enot * cenaNaEnoto / 1e18;
_burn(msg.sender, enot);
polozeno -= znesek;
IERC20(placilniZeton).safeTransfer(msg.sender, znesek);
emit Dvignjeno(msg.sender, enot, znesek);
}
/// @notice Ugovarjalec dvigne polog: v celoti, ce je ugovor uspel ali je bil postopek
/// preklican; sicer zmanjsan za svoj delez stroska ene cenitve.
function dvigniPologUgovora(uint256 k) external nonReentrant {
Ugovor storage u = ugovori[k];
require(ugovarjal[k][msg.sender], "Ni ugovarjal ali je ze dvignil");
require(u.vracilo != 0, "Ugovor se ni razresen");
ugovarjal[k][msg.sender] = false;
uint256 znesek = POLOG_UGOVORA;
if (u.vracilo == 2) {
uint256 delez = (POLOG_UGOVORA + u.stevilo - 1) / u.stevilo; // zaokrozeno navzgor
znesek -= delez;
}
if (znesek > 0) IERC20(placilniZeton).safeTransfer(msg.sender, znesek);
emit PologUgovoraVrnjen(k, msg.sender, znesek);
}
/**
* @notice Preklic razdruzitve. Trgovanje se odmrzne, sprozitelj dobi polog nazaj.
* @dev Sprozitelj lahko preklice pred potrditvijo kadarkoli. Kdorkoli lahko
* preklice, ko je rok faze potekel in tisti, ki je na vrsti, ni ukrepal —
* tako nihce ne more zamrzniti trgovanja za nedolocen cas.
* Ob preklicu v fazi Doplacilo gre 500 USDC iz pologa overitelju za cenilca.
*/
function preklici() external nonReentrant {
Faza f = faza;
require(f != Faza.Ni && f != Faza.Razdruzeno, "Ni postopka za preklic");
if (msg.sender != sprozitelj) {
uint256 meja = f == Faza.Polozeno ? rok + _dni(DNI_POTRDITEV) : rok;
require(block.timestamp > meja, "Rok se ni potekel");
}
Ugovor storage u = ugovori[krog];
uint256 vrni = polozeno;
if (f == Faza.Doplacilo) {
vrni -= POLOG_UGOVORA;
IERC20(placilniZeton).safeTransfer(overitelj, POLOG_UGOVORA);
}
if (u.stevilo > 0 && u.vracilo == 0) u.vracilo = 1;
address s = sprozitelj;
uint256 k = krog;
faza = Faza.Ni;
polozeno = 0;
naslednjaZahtevaOd = block.timestamp + _dni(DNI_PAVZA);
sprozitelj = address(0);
if (vrni > 0) IERC20(placilniZeton).safeTransfer(s, vrni);
emit RazdruzitevPreklicana(k, msg.sender);
}
// ── Admin (skozi napoved in zamik) ────────────────────────────────────────
function napoviSetKyc(address _kyc) external onlyOwner {
_napovej(keccak256(abi.encode("setKyc", _kyc)), "RWATokenV2.setKyc");
}
function setKyc(address _kyc) external onlyOwner {
_porabi(keccak256(abi.encode("setKyc", _kyc)), "RWATokenV2.setKyc");
kyc = _kyc;
emit KycUpdated(_kyc);
}
function napoviUpdateAssetValue(uint256 newValueUSD) external samoOveritelj {
_napovej(keccak256(abi.encode("updateAssetValue", newValueUSD)), "RWATokenV2.updateAssetValue");
}
function updateAssetValue(uint256 newValueUSD) external samoOveritelj {
_porabi(keccak256(abi.encode("updateAssetValue", newValueUSD)), "RWATokenV2.updateAssetValue");
assetValueUSD = newValueUSD;
emit AssetValueUpdated(newValueUSD);
}
function renounceOwnership() public pure override {
revert("Renounce onemogocen");
}
}
@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity >=0.6.2;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC-20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
@openzeppelin/contracts/utils/ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
import {StorageSlot} from "./StorageSlot.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
* consider using {ReentrancyGuardTransient} instead.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*
* IMPORTANT: Deprecated. This storage-based reentrancy guard will be removed and replaced
* by the {ReentrancyGuardTransient} variant in v6.0.
*
* @custom:stateless
*/
abstract contract ReentrancyGuard {
using StorageSlot for bytes32;
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant REENTRANCY_GUARD_STORAGE =
0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
constructor() {
_reentrancyGuardStorageSlot().getUint256Slot().value = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
/**
* @dev A `view` only version of {nonReentrant}. Use to block view functions
* from being called, preventing reading from inconsistent contract state.
*
* CAUTION: This is a "view" modifier and does not change the reentrancy
* status. Use it only on view functions. For payable or non-payable functions,
* use the standard {nonReentrant} modifier instead.
*/
modifier nonReentrantView() {
_nonReentrantBeforeView();
_;
}
function _nonReentrantBeforeView() private view {
if (_reentrancyGuardEntered()) {
revert ReentrancyGuardReentrantCall();
}
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
_nonReentrantBeforeView();
// Any calls to nonReentrant after this point will fail
_reentrancyGuardStorageSlot().getUint256Slot().value = ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_reentrancyGuardStorageSlot().getUint256Slot().value = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _reentrancyGuardStorageSlot().getUint256Slot().value == ENTERED;
}
function _reentrancyGuardStorageSlot() internal pure virtual returns (bytes32) {
return REENTRANCY_GUARD_STORAGE;
}
}
contracts/Omrezja.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/**
* @title Omrezja
* @notice Katere verige so TESTNE. Vse druge, tudi neznane, veljajo za produkcijske.
*
* Seznam je izrecen in kratek. Napaka je zato mogoca samo v varno smer: na
* novem, se ne nastetem testnem omrezju dobi pogodba produkcijski (dolg) zamik,
* nikoli obratno. Produkcijske verige ni treba nikjer nasteti, zato je ni mogoce
* pozabiti — ista bajtna koda je na kateri koli EVM produkcijski verigi zascitena.
*/
library Omrezja {
/// @notice true samo za nastete testne verige in lokalni razvojni vozel.
function jeTestno(uint256 id) internal pure returns (bool) {
return id == 943 // PulseChain Testnet v4
|| id == 11155111 // Ethereum Sepolia
|| id == 560048 // Ethereum Hoodi
|| id == 84532 // Base Sepolia
|| id == 421614 // Arbitrum Sepolia
|| id == 31337; // lokalni razvojni vozel (Hardhat)
}
/// @notice Zamik za spremembe in zapore: produkcija 48 ur, testno 10 minut.
function zamik() internal view returns (uint256) {
return jeTestno(block.chainid) ? 10 minutes : 48 hours;
}
}
@openzeppelin/contracts/interfaces/draft-IERC6093.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.0) (interfaces/draft-IERC6093.sol)
pragma solidity >=0.8.4;
/**
* @dev Standard ERC-20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC-721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-721.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC-1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}
@openzeppelin/contracts/interfaces/IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)
pragma solidity >=0.4.16;
import {IERC165} from "../utils/introspection/IERC165.sol";
contracts/AdminZamik.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "./Omrezja.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
/**
* @title AdminZamik
* @notice Casovni zamik na nevarne admin spremembe.
*
* ZAKAJ TO OBSTAJA
* ----------------
* Owner kljuc na tej platformi NE more krasti: ne more kovati zetonov, ne more
* premikati tujih zetonov in ne more v escrow. Kar PA lahko, je tiho zamenjati
* nastavitve pod nogami uporabnikov — KYC listo, placilni token, prijavljeno
* vrednost sredstva.
*
* Vsi trije so napadi, ki jih je mogoce VIDETI VNAPREJ. Zato jih ne branimo z
* multisigom (ki varuje lastnika kljuca), ampak s casovnim zamikom (ki varuje
* UPORABNIKA): sprememba se mora najprej javno napovedati, sele po zamiku jo je
* mogoce izvesti. Uporabnik ima ves ta cas, da spremembo vidi in izstopi.
*
* Namenoma NI zunanje timelock pogodbe kot lastnika. Tak vzorec doda tveganje
* nedosegljivosti: ce lastniku kdaj ne uspe sestaviti transakcije skozi tujo
* pogodbo, so kontrakti zamrznjeni za vedno. Tu je zamik vgrajen, lastnik pa
* ostane navadna denarnica.
*
* KAJ ZAMIK NE POKRIVA (namerno)
* ------------------------------
* - pause() — zasilna zavora mora biti takojsnja, sicer ni zavora
* - unpause() — vrnitev v obratovanje naj bo hitra
* - odvzem pravice zaustavljalca — ob razkritem kljucu ga moras vreci TAKOJ
* Nevarnost caka, zasilna zavora ne.
*/
abstract contract AdminZamik is Ownable {
/// @notice Rok, v katerem je napoved uporabna. Po njem potece.
/// @dev Brez tega bi stara napoved lezala na verigi kot nabita puska:
/// napoves nekaj neopaznega danes, izvedes cez pol leta, ko nihce vec
/// ne gleda. Napoved, ki ni bila izvedena v roku, je treba ponoviti.
uint256 public constant ROK = 7 days;
/// @notice id napovedi → cas, od katerega je izvedljiva (0 = ni napovedi)
mapping(bytes32 => uint256) public izvedljivoOd;
event SpremembaNapovedana(bytes32 indexed id, string kaj, uint256 izvedljivoOd, uint256 potece);
event SpremembaIzvedena(bytes32 indexed id, string kaj);
event SpremembaPreklicana(bytes32 indexed id, string kaj);
/// @notice Koliko casa mora napovedana sprememba cakati, preden je izvedljiva.
///
/// produkcijske verige 48 ur imetnik ima cas spremembo videti in izstopiti
/// testne verige 10 minut razvojno okolje (seznam v Omrezja.sol)
///
/// @dev Vrednost doloca `block.chainid`, ne nastavitev ob postavitvi. Ista
/// bajtna koda tako na vsaki produkcijski verigi vedno vrne 48 ur: testne
/// verige so nastete, vse druge (tudi neznane) so produkcijske.
/// @dev `virtual` zato, da lahko posamezna testna pogodba vrednost povozi.
function zamik() public view virtual returns (uint256) {
return Omrezja.zamik();
}
// ── Notranje ────────────────────────────────────────────────────────────
/// @dev id MORA vsebovati tocne parametre spremembe, sicer bi lahko
/// napovedal nedolzno vrednost in izvedel skodljivo.
function _napovej(bytes32 id, string memory kaj) internal {
require(izvedljivoOd[id] == 0, "Ze napovedano");
uint256 od = block.timestamp + zamik();
izvedljivoOd[id] = od;
emit SpremembaNapovedana(id, kaj, od, od + ROK);
}
function _porabi(bytes32 id, string memory kaj) internal {
uint256 od = izvedljivoOd[id];
require(od != 0, "Ni napovedano");
require(block.timestamp >= od, "Zamik se ni potekel");
require(block.timestamp <= od + ROK, "Napoved je potekla");
delete izvedljivoOd[id];
emit SpremembaIzvedena(id, kaj);
}
// ── Javno ───────────────────────────────────────────────────────────────
/// @notice Preklic napovedane spremembe. Takojsen — premisliti se mora biti
/// mogoce hitreje, kot se izvede.
function prekliciSpremembo(bytes32 id, string calldata kaj) external onlyOwner {
require(izvedljivoOd[id] != 0, "Ni napovedano");
delete izvedljivoOd[id];
emit SpremembaPreklicana(id, kaj);
}
/// @notice Stanje napovedi — da ga stran in nadzorni sistem lahko prikazeta.
function stanjeNapovedi(bytes32 id)
external
view
returns (bool napovedana, uint256 od, uint256 potece, bool izvedljivaZdaj)
{
uint256 t = izvedljivoOd[id];
if (t == 0) return (false, 0, 0, false);
return (true, t, t + ROK, block.timestamp >= t && block.timestamp <= t + ROK);
}
}
@openzeppelin/contracts/token/ERC20/ERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC-20
* applications.
*/
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
mapping(address account => uint256) private _balances;
mapping(address account => mapping(address spender => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* Both values are immutable: they can only be set once during construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual returns (uint8) {
return 18;
}
/// @inheritdoc IERC20
function totalSupply() public view virtual returns (uint256) {
return _totalSupply;
}
/// @inheritdoc IERC20
function balanceOf(address account) public view virtual returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `value`.
*/
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
/// @inheritdoc IERC20
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Skips emitting an {Approval} event indicating an allowance update. This is not
* required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve].
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `value`.
* - the caller must have allowance for ``from``'s tokens of at least
* `value`.
*/
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
/**
* @dev Moves a `value` amount of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
/**
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
* this function.
*
* Emits a {Transfer} event.
*/
function _update(address from, address to, uint256 value) internal virtual {
if (from == address(0)) {
// Overflow check required: The rest of the code assumes that totalSupply never overflows
_totalSupply += value;
} else {
uint256 fromBalance = _balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
// Overflow not possible: value <= fromBalance <= totalSupply.
_balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
// Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
_totalSupply -= value;
}
} else {
unchecked {
// Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
_balances[to] += value;
}
}
emit Transfer(from, to, value);
}
/**
* @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
* Relies on the `_update` mechanism
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
/**
* @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead
*/
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
/**
* @dev Sets `value` as the allowance of `spender` over the `owner`'s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
/**
* @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
*
* By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
* `_spendAllowance` during the `transferFrom` operation sets the flag to false. This saves gas by not emitting any
* `Approval` event during `transferFrom` operations.
*
* Anyone who wishes to continue emitting `Approval` events on the `transferFrom` operation can force the flag to
* true using the following override:
*
* ```solidity
* function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
* super._approve(owner, spender, value, true);
* }
* ```
*
* Requirements are the same as {_approve}.
*/
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
/**
* @dev Updates `owner`'s allowance for `spender` based on spent `value`.
*
* Does not update the allowance value in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Does not emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance < type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}
@openzeppelin/contracts/interfaces/IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)
pragma solidity >=0.4.16;
import {IERC20} from "../token/ERC20/IERC20.sol";
@openzeppelin/contracts/utils/StorageSlot.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC-1967 implementation slot:
* ```solidity
* contract ERC1967 {
* // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* TIP: Consider using this library along with {SlotDerivation}.
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct Int256Slot {
int256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Int256Slot` with member `value` located at `slot`.
*/
function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
assembly ("memory-safe") {
r.slot := store.slot
}
}
/**
* @dev Returns a `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
assembly ("memory-safe") {
r.slot := store.slot
}
}
}
@openzeppelin/contracts/interfaces/IERC1363.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)
pragma solidity >=0.6.2;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}
@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
if (!_safeTransfer(token, to, value, true)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
if (!_safeTransferFrom(token, from, to, value, true)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
return _safeTransfer(token, to, value, false);
}
/**
* @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
return _safeTransferFrom(token, from, to, value, false);
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
if (!_safeApprove(token, spender, value, false)) {
if (!_safeApprove(token, spender, 0, true)) revert SafeERC20FailedOperation(address(token));
if (!_safeApprove(token, spender, value, true)) revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that relies on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that relies on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Oppositely, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity `token.transfer(to, value)` call, relaxing the requirement on the return value: the
* return value is optional (but if data is returned, it must not be false).
*
* @param token The token targeted by the call.
* @param to The recipient of the tokens
* @param value The amount of token to transfer
* @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.
*/
function _safeTransfer(IERC20 token, address to, uint256 value, bool bubble) private returns (bool success) {
bytes4 selector = IERC20.transfer.selector;
assembly ("memory-safe") {
let fmp := mload(0x40)
mstore(0x00, selector)
mstore(0x04, and(to, shr(96, not(0))))
mstore(0x24, value)
success := call(gas(), token, 0, 0x00, 0x44, 0x00, 0x20)
// if call success and return is true, all is good.
// otherwise (not success or return is not true), we need to perform further checks
if iszero(and(success, eq(mload(0x00), 1))) {
// if the call was a failure and bubble is enabled, bubble the error
if and(iszero(success), bubble) {
returndatacopy(fmp, 0x00, returndatasize())
revert(fmp, returndatasize())
}
// if the return value is not true, then the call is only successful if:
// - the token address has code
// - the returndata is empty
success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))
}
mstore(0x40, fmp)
}
}
/**
* @dev Imitates a Solidity `token.transferFrom(from, to, value)` call, relaxing the requirement on the return
* value: the return value is optional (but if data is returned, it must not be false).
*
* @param token The token targeted by the call.
* @param from The sender of the tokens
* @param to The recipient of the tokens
* @param value The amount of token to transfer
* @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.
*/
function _safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value,
bool bubble
) private returns (bool success) {
bytes4 selector = IERC20.transferFrom.selector;
assembly ("memory-safe") {
let fmp := mload(0x40)
mstore(0x00, selector)
mstore(0x04, and(from, shr(96, not(0))))
mstore(0x24, and(to, shr(96, not(0))))
mstore(0x44, value)
success := call(gas(), token, 0, 0x00, 0x64, 0x00, 0x20)
// if call success and return is true, all is good.
// otherwise (not success or return is not true), we need to perform further checks
if iszero(and(success, eq(mload(0x00), 1))) {
// if the call was a failure and bubble is enabled, bubble the error
if and(iszero(success), bubble) {
returndatacopy(fmp, 0x00, returndatasize())
revert(fmp, returndatasize())
}
// if the return value is not true, then the call is only successful if:
// - the token address has code
// - the returndata is empty
success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))
}
mstore(0x40, fmp)
mstore(0x60, 0)
}
}
/**
* @dev Imitates a Solidity `token.approve(spender, value)` call, relaxing the requirement on the return value:
* the return value is optional (but if data is returned, it must not be false).
*
* @param token The token targeted by the call.
* @param spender The spender of the tokens
* @param value The amount of token to transfer
* @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.
*/
function _safeApprove(IERC20 token, address spender, uint256 value, bool bubble) private returns (bool success) {
bytes4 selector = IERC20.approve.selector;
assembly ("memory-safe") {
let fmp := mload(0x40)
mstore(0x00, selector)
mstore(0x04, and(spender, shr(96, not(0))))
mstore(0x24, value)
success := call(gas(), token, 0, 0x00, 0x44, 0x00, 0x20)
// if call success and return is true, all is good.
// otherwise (not success or return is not true), we need to perform further checks
if iszero(and(success, eq(mload(0x00), 1))) {
// if the call was a failure and bubble is enabled, bubble the error
if and(iszero(success), bubble) {
returndatacopy(fmp, 0x00, returndatasize())
revert(fmp, returndatasize())
}
// if the return value is not true, then the call is only successful if:
// - the token address has code
// - the returndata is empty
success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))
}
mstore(0x40, fmp)
}
}
}
@openzeppelin/contracts/access/Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
@openzeppelin/contracts/token/ERC20/IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
@openzeppelin/contracts/utils/Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
@openzeppelin/contracts/utils/introspection/IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
Compiler Settings
{"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"],"":["ast"]}},"optimizer":{"runs":1,"enabled":true},"evmVersion":"paris"}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"tuple","name":"n","internalType":"struct NastavitveZetonaV2","components":[{"type":"string","name":"ime","internalType":"string"},{"type":"string","name":"simbol","internalType":"string"},{"type":"string","name":"metapodatkiCID","internalType":"string"},{"type":"uint256","name":"vrednostUSD","internalType":"uint256"},{"type":"address","name":"zkVerifier","internalType":"address"},{"type":"address","name":"entropyOracle","internalType":"address"},{"type":"address","name":"trg","internalType":"address"},{"type":"address","name":"kyc","internalType":"address"},{"type":"address","name":"lastnik","internalType":"address"},{"type":"address","name":"uors","internalType":"address"},{"type":"address","name":"overitelj","internalType":"address"}]}]},{"type":"error","name":"ERC20InsufficientAllowance","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"allowance","internalType":"uint256"},{"type":"uint256","name":"needed","internalType":"uint256"}]},{"type":"error","name":"ERC20InsufficientBalance","inputs":[{"type":"address","name":"sender","internalType":"address"},{"type":"uint256","name":"balance","internalType":"uint256"},{"type":"uint256","name":"needed","internalType":"uint256"}]},{"type":"error","name":"ERC20InvalidApprover","inputs":[{"type":"address","name":"approver","internalType":"address"}]},{"type":"error","name":"ERC20InvalidReceiver","inputs":[{"type":"address","name":"receiver","internalType":"address"}]},{"type":"error","name":"ERC20InvalidSender","inputs":[{"type":"address","name":"sender","internalType":"address"}]},{"type":"error","name":"ERC20InvalidSpender","inputs":[{"type":"address","name":"spender","internalType":"address"}]},{"type":"error","name":"OwnableInvalidOwner","inputs":[{"type":"address","name":"owner","internalType":"address"}]},{"type":"error","name":"OwnableUnauthorizedAccount","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"error","name":"ReentrancyGuardReentrantCall","inputs":[]},{"type":"error","name":"SafeERC20FailedOperation","inputs":[{"type":"address","name":"token","internalType":"address"}]},{"type":"event","name":"Approval","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"address","name":"spender","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"AssetValueUpdated","inputs":[{"type":"uint256","name":"newValueUSD","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"CenitevVpisana","inputs":[{"type":"uint256","name":"krog","internalType":"uint256","indexed":true},{"type":"uint256","name":"cenitevUSD","internalType":"uint256","indexed":false},{"type":"uint256","name":"trznaCena","internalType":"uint256","indexed":false},{"type":"uint256","name":"cenaNaEnoto","internalType":"uint256","indexed":false},{"type":"bytes32","name":"odtis","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"Doplacano","inputs":[{"type":"uint256","name":"krog","internalType":"uint256","indexed":true},{"type":"uint256","name":"znesek","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"DrugaCenitevVpisana","inputs":[{"type":"uint256","name":"krog","internalType":"uint256","indexed":true},{"type":"uint256","name":"cenitevUSD","internalType":"uint256","indexed":false},{"type":"bool","name":"uspel","internalType":"bool","indexed":false},{"type":"uint256","name":"cenaNaEnoto","internalType":"uint256","indexed":false},{"type":"bytes32","name":"odtis","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"Dvignjeno","inputs":[{"type":"address","name":"kdo","internalType":"address","indexed":true},{"type":"uint256","name":"enot","internalType":"uint256","indexed":false},{"type":"uint256","name":"usdc","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"KycUpdated","inputs":[{"type":"address","name":"newKyc","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Odmrznjeno","inputs":[{"type":"address","name":"kdo","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"PologUgovoraVrnjen","inputs":[{"type":"uint256","name":"krog","internalType":"uint256","indexed":true},{"type":"address","name":"kdo","internalType":"address","indexed":true},{"type":"uint256","name":"znesek","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Polozeno","inputs":[{"type":"uint256","name":"krog","internalType":"uint256","indexed":true},{"type":"uint256","name":"znesek","internalType":"uint256","indexed":false},{"type":"uint256","name":"enotManjsine","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"PrenosZOdobritvijo","inputs":[{"type":"address","name":"od","internalType":"address","indexed":true},{"type":"address","name":"komu","internalType":"address","indexed":true},{"type":"uint256","name":"kolicina","internalType":"uint256","indexed":false},{"type":"bytes32","name":"odtisListine","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"PrvotniLastnikZapisan","inputs":[{"type":"address","name":"lastnik","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Razdruzeno","inputs":[{"type":"uint256","name":"krog","internalType":"uint256","indexed":true},{"type":"bytes32","name":"odtisListine","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"RazdruzitevPreklicana","inputs":[{"type":"uint256","name":"krog","internalType":"uint256","indexed":true},{"type":"address","name":"kdo","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RazdruzitevZahtevana","inputs":[{"type":"uint256","name":"krog","internalType":"uint256","indexed":true},{"type":"address","name":"sprozitelj","internalType":"address","indexed":true},{"type":"uint256","name":"enot","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SpremembaIzvedena","inputs":[{"type":"bytes32","name":"id","internalType":"bytes32","indexed":true},{"type":"string","name":"kaj","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"SpremembaNapovedana","inputs":[{"type":"bytes32","name":"id","internalType":"bytes32","indexed":true},{"type":"string","name":"kaj","internalType":"string","indexed":false},{"type":"uint256","name":"izvedljivoOd","internalType":"uint256","indexed":false},{"type":"uint256","name":"potece","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SpremembaPreklicana","inputs":[{"type":"bytes32","name":"id","internalType":"bytes32","indexed":true},{"type":"string","name":"kaj","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"TokensMinted","inputs":[{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"bytes32","name":"proofHash","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"UgovorVlozen","inputs":[{"type":"uint256","name":"krog","internalType":"uint256","indexed":true},{"type":"address","name":"kdo","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Zamrznjeno","inputs":[{"type":"address","name":"kdo","internalType":"address","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"DNI_CENITEV","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"DNI_DOPLACILO","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"DNI_PAVZA","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"DNI_POLOG","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"DNI_POTRDITEV","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"DNI_UGOVOR","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"POLOG_UGOVORA","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"PRAG_BPS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"PRAG_UGOVORA_BPS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"PROVIZIJA_IZDAJE_BPS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"ROK","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"aktivenOd","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"allowance","inputs":[{"type":"address","name":"owner","internalType":"address"},{"type":"address","name":"spender","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"approve","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"assetMetadataCID","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"assetValueUSD","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"balanceOf","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"cenaNaEnoto","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"cenitevRazdruzitve","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"dan","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"decimals","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"doplacaj","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"drugaCenitev","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"dvigni","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"dvigniPologUgovora","inputs":[{"type":"uint256","name":"k","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"enotManjsine","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"enotSprozitelja","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"entropyOracle","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"enum RWATokenV2.Faza"}],"name":"faza","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"feeRecipient","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"izvedljivoOd","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"mogoc","internalType":"bool"},{"type":"uint256","name":"odKdaj","internalType":"uint256"},{"type":"bool","name":"zamrznjeno","internalType":"bool"}],"name":"jePrenosMogoc","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"krog","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"kyc","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"mintFee","inputs":[{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"mintWithProof","inputs":[{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"bytes32","name":"proofHash","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"name","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"napoviPrenesiZOdobritvijo","inputs":[{"type":"address","name":"od","internalType":"address"},{"type":"address","name":"komu","internalType":"address"},{"type":"uint256","name":"kolicina","internalType":"uint256"},{"type":"bytes32","name":"odtis","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"napoviSetKyc","inputs":[{"type":"address","name":"_kyc","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"napoviUpdateAssetValue","inputs":[{"type":"uint256","name":"newValueUSD","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"naslednjaZahtevaOd","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"neporavnanaProvizija","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"odmrzni","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"odtisCenitve","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"odtisDrugeCenitve","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"odtisListine","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"overitelj","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"placilniZeton","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"polozeno","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"polozi","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"potrdiRazdruzitev","inputs":[{"type":"bytes32","name":"odtis","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"potrebenPolog","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"potrebnoDoplacilo","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"preklici","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"prekliciSpremembo","inputs":[{"type":"bytes32","name":"id","internalType":"bytes32"},{"type":"string","name":"kaj","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"prenesiZOdobritvijo","inputs":[{"type":"address","name":"od","internalType":"address"},{"type":"address","name":"komu","internalType":"address"},{"type":"uint256","name":"kolicina","internalType":"uint256"},{"type":"bytes32","name":"odtis","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"provizijaIzdaje","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"provizijaVPologu","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"prvotniLastnik","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"razdruzitevVTeku","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rok","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setKyc","inputs":[{"type":"address","name":"_kyc","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"sprozitelj","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"napovedana","internalType":"bool"},{"type":"uint256","name":"od","internalType":"uint256"},{"type":"uint256","name":"potece","internalType":"uint256"},{"type":"bool","name":"izvedljivaZdaj","internalType":"bool"}],"name":"stanjeNapovedi","inputs":[{"type":"bytes32","name":"id","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"symbol","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalSupply","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transfer","inputs":[{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transferFrom","inputs":[{"type":"address","name":"from","internalType":"address"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"trg","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"trznaCena","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"ugovarjal","inputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"ugovor","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"stevilo","internalType":"uint256"},{"type":"uint8","name":"vracilo","internalType":"uint8"},{"type":"bool","name":"ugovorOpravljen","internalType":"bool"}],"name":"ugovori","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"uors","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateAssetValue","inputs":[{"type":"uint256","name":"newValueUSD","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"usedProofs","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"vpisiCenitev","inputs":[{"type":"uint256","name":"cenitevUSD","internalType":"uint256"},{"type":"uint256","name":"trznaNaEnoto","internalType":"uint256"},{"type":"bytes32","name":"odtis","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"vpisiDrugoCenitev","inputs":[{"type":"uint256","name":"cenitevUSD","internalType":"uint256"},{"type":"bytes32","name":"odtis","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"zahtevajRazdruzitev","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"zamik","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"zamrzni","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"zamrznjen","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"zaporaPrenosa","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"zkVerifier","inputs":[]}]
Contract Creation Code
0x6101406040523480156200001257600080fd5b50604051620050cc380380620050cc83398101604081905262000035916200049b565b61010081015181516020830151600362000050838262000689565b5060046200005f828262000689565b5050506001600160a01b0381166200009257604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b6200009d81620002ae565b5060017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005560808101516001600160a01b03166200011e5760405162461bcd60e51b815260206004820152601360248201527f5a4b5665726966696572206a65206e756a656e00000000000000000000000000604482015260640162000089565b60c08101516001600160a01b0316620001695760405162461bcd60e51b815260206004820152600c60248201526b2a393390353290373ab532b760a11b604482015260640162000089565b6101008101516001600160a01b0316620001b95760405162461bcd60e51b815260206004820152601060248201526f2630b9ba3734b590353290373ab532b760811b604482015260640162000089565b6101208101516001600160a01b0316620002165760405162461bcd60e51b815260206004820152601560248201527f554f52535265676973747279206a65206e756a656e0000000000000000000000604482015260640162000089565b60408101516007906200022a908262000689565b5060608101516008556080808201516001600160a01b0390811690915260a0808301518216905260c0808301518216905260e080830151600980546001600160a01b0319169184169190911790556101208301518216905261014082015116610100526200029762000300565b620002a3904262000755565b610120525062000777565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60006200030d466200032a565b6200031c576202a30062000320565b6102585b62ffffff16905090565b6000816103af14806200033f57508162aa36a7145b806200034d57508162088bb0145b806200035b57508162014a34145b806200036957508162066eee145b8062000376575081617a69145b92915050565b634e487b7160e01b600052604160045260246000fd5b60405161016081016001600160401b0381118282101715620003b857620003b86200037c565b60405290565b604051601f8201601f191681016001600160401b0381118282101715620003e957620003e96200037c565b604052919050565b600082601f8301126200040357600080fd5b81516001600160401b038111156200041f576200041f6200037c565b602062000435601f8301601f19168201620003be565b82815285828487010111156200044a57600080fd5b60005b838110156200046a5785810183015182820184015282016200044d565b506000928101909101919091529392505050565b80516001600160a01b03811681146200049657600080fd5b919050565b600060208284031215620004ae57600080fd5b81516001600160401b0380821115620004c657600080fd5b908301906101608286031215620004dc57600080fd5b620004e662000392565b825182811115620004f657600080fd5b6200050487828601620003f1565b8252506020830151828111156200051a57600080fd5b6200052887828601620003f1565b6020830152506040830151828111156200054157600080fd5b6200054f87828601620003f1565b604083015250606083015160608201526200056d608084016200047e565b60808201526200058060a084016200047e565b60a08201526200059360c084016200047e565b60c0820152620005a660e084016200047e565b60e08201526101009150620005bd8284016200047e565b828201526101209150620005d38284016200047e565b828201526101409150620005e98284016200047e565b91810191909152949350505050565b600181811c908216806200060d57607f821691505b6020821081036200062e57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111562000684576000816000526020600020601f850160051c810160208610156200065f5750805b601f850160051c820191505b8181101562000680578281556001016200066b565b5050505b505050565b81516001600160401b03811115620006a557620006a56200037c565b620006bd81620006b68454620005f8565b8462000634565b602080601f831160018114620006f55760008415620006dc5750858301515b600019600386901b1c1916600185901b17855562000680565b600085815260208120601f198616915b82811015620007265788860151825594840194600190910190840162000705565b5085821015620007455787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b808201808211156200037657634e487b7160e01b600052601160045260246000fd5b60805160a05160c05160e0516101005161012051614802620008ca6000396000818161097c01528181610d2a01528181610d8b0152613cd301526000818161059e01528181610f8b015281816111d901528181611228015281816114db0152818161182301528181611872015281816119f801528181611a4701528181611fe3015281816120320152818161229c0152818161255f015281816125ae01528181612868015281816128b7015281816132f8015261334701526000818161050f01528181610c190152818161127c015281816118c601528181611a9b01528181612086015281816126020152818161290b01528181612bb7015261339b0152600081816105e90152818161176f01528181612ace01528181612e8b01528181613d6601528181613df80152613e330152600061046d0152600081816108ef01528181611c6c015261233d01526148026000f3fe608060405234801561001057600080fd5b50600436106103dd5760003560e01c806302471efa146103e2578063034b3767146103fe57806306fdde031461040857806307601d271461041d5780630854eef514610425578063095ea7b3146104455780630e78931d1461046857806318160ddd1461049c578063225cbe20146104a457806323b872dd146104ad57806323eca665146104c057806325bd0f45146104e7578063263c1e61146104ef57806329a52c171461050257806329c3fe7c1461050a5780632a06cc25146105315780632bcc0bbe146105395780632f6081dc1461054d578063313ce5671461056057806333d1f5631461056f5780633504182d1461057857806336b2e3ed14610580578063404512b11461058957806340a1d3cb14610591578063418ee99d1461059957806343e9cf4b146105c057806346904840146105d3578063480ea628146105e45780634abf9c6a1461060b5780634b4fdb4f1461061e5780634c8a1b0d1461062957806355065c39146104e7578063584d525f146106315780635c57d8a8146106395780635e7f9862146104e7578063633c963a1461064c5780636783ec341461065f5780636a3b5c4d1461066857806370a082311461067b578063715018a61461068e57806376e382c814610696578063776528cd146106a95780637a347775146106e05780637b742d4c146106e85780637e92d2b3146106f15780637f5181b014610704578063853511f51461070c5780638cc9d1071461075e5780638da5cb5b1461077157806390d6b45f14610779578063944765c81461078c57806395d89b41146107ba578063988d33e0146107c25780639953ed96146107cb57806399c27206146107d45780639abe0969146107e75780639e759f94146107fa578063a023661814610803578063a27486cd1461080b578063a582665214610814578063a656212a1461081c578063a859e57714610825578063a9059cbb1461083f578063af95822c14610852578063afc1a4c01461085b578063b007d5fc14610864578063b318d3a31461086c578063bf50829d1461087f578063bfba6d5d14610892578063c1da7c97146108a5578063c30a0f25146108ad578063c71a9a1e146108d0578063cde2202a146108d8578063d1bf942a146108e1578063d48693d114610864578063d6df096d146108ea578063d7bcc5b0146104e7578063dd62ed3e14610911578063dd6b579214610924578063e29eb51b1461092c578063e787225c14610935578063e826f69a1461093e578063ec59656014610948578063f2fde38b14610951578063f7dc924314610964578063f9728ca114610977578063fa93527d14610803575b600080fd5b6103eb600f5481565b6040519081526020015b60405180910390f35b61040661099e565b005b610410610b70565b6040516103f591906140ab565b610406610c02565b6103eb6104333660046140c5565b60066020526000908152604090205481565b6104586104533660046140f3565b610ce5565b60405190151581526020016103f5565b61048f7f000000000000000000000000000000000000000000000000000000000000000081565b6040516103f5919061411f565b6002546103eb565b6103eb601f5481565b6104586104bb366004614133565b610cff565b6104c8610d23565b60408051931515845260208401929092521515908201526060016103f5565b6103eb601e81565b6104066104fd366004614174565b610dbd565b610406610e21565b61048f7f000000000000000000000000000000000000000000000000000000000000000081565b61040661107f565b600a5461045890600160a01b900460ff1681565b61040661055b366004614191565b6111d7565b604051601281526020016103f5565b6103eb601b5481565b6103eb603281565b6103eb60175481565b610406611390565b6103eb611537565b61048f7f000000000000000000000000000000000000000000000000000000000000000081565b6104066105ce3660046140c5565b6115b4565b600a546001600160a01b031661048f565b61048f7f000000000000000000000000000000000000000000000000000000000000000081565b60125461048f906001600160a01b031681565b6103eb631dcd650081565b610458611749565b6103eb61176a565b6104066106473660046140c5565b611821565b61040661065a3660046141d7565b6119f6565b6103eb60185481565b610406610676366004614203565b611c61565b6103eb610689366004614174565b611e4f565b610406611e6a565b6104066106a4366004614238565b611ea8565b6106bc6106b73660046140c5565b611f22565b604080519415158552602085019390935291830152151560608201526080016103f5565b6103eb611f8f565b6103eb60195481565b6104066106ff3660046142b3565b611fe1565b6103eb612321565b61073f61071a3660046140c5565b6021602052600090815260409020805460019091015460ff8082169161010090041683565b6040805193845260ff90921660208401521515908201526060016103f5565b61040661076c3660046140f3565b612332565b61048f612494565b60095461048f906001600160a01b031681565b61045861079a3660046142d5565b602260209081526000928352604080842090915290825290205460ff1681565b6104106124a3565b6103eb61232881565b6103eb601c5481565b6104066107e2366004614174565b6124b2565b6104066107f5366004614191565b61255d565b6103eb60165481565b6103eb600e81565b6103eb601a5481565b6104106127c0565b6103eb601d5481565b6010546108329060ff1681565b6040516103f5919061431b565b61045861084d3660046140f3565b61284e565b6103eb6101f481565b6103eb601e5481565b6103eb61285c565b61040661087a3660046140c5565b612866565b60135461048f906001600160a01b031681565b600a5461048f906001600160a01b031681565b610406612ba0565b6104586108bb3660046140c5565b600b6020526000908152604090205460ff1681565b610406612c89565b6103eb60085481565b6103eb60145481565b61048f7f000000000000000000000000000000000000000000000000000000000000000081565b6103eb61091f366004614343565b612f9f565b610406612fca565b6103eb60205481565b6103eb60155481565b6103eb62093a8081565b6103eb60115481565b61040661095f366004614174565b6132bb565b6104066109723660046140c5565b6132f6565b6103eb7f000000000000000000000000000000000000000000000000000000000000000081565b6109a6613490565b600260105460ff1660068111156109bf576109bf614305565b14610a045760405162461bcd60e51b815260206004820152601060248201526f4e692063617361207a6120706f6c6f6760801b60448201526064015b60405180910390fd5b6012546001600160a01b03163314610a2e5760405162461bcd60e51b81526004016109fb90614371565b601454421115610a7a5760405162461bcd60e51b8152602060048201526017602482015276149bdac81e98481c1bdb1bd9c81a99481c1bdd195ad95b604a1b60448201526064016109fb565b601254610a8f906001600160a01b0316611e4f565b601c819055600254610aa191906143b0565b601d55610aac61176a565b601f819055506000601f54670de0b6b3a7640000601854601d54610ad091906143c3565b610ada91906143da565b610ae491906143fc565b601e8181556010805460ff19166003179055909150610b02906134ab565b610b0c90426143fc565b601455601354610b27906001600160a01b03163330846134d7565b6011547fee0aea9ff2c1b37b651b974b61c086588b20c5ab08133a1a6c546e1563bacc9f82601d54604051610b5d92919061440f565b60405180910390a250610b6e613504565b565b606060038054610b7f9061441d565b80601f0160208091040260200160405190810160405280929190818152602001828054610bab9061441d565b8015610bf85780601f10610bcd57610100808354040283529160200191610bf8565b820191906000526020600020905b815481529060010190602001808311610bdb57829003601f168201915b5050505050905090565b6040516338260bcb60e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063704c179690610c4e90339060040161411f565b602060405180830381865afa158015610c6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c8f9190614457565b610cab5760405162461bcd60e51b81526004016109fb90614479565b600a805460ff60a01b1916905560405133907fae0ecc60019f8d35cb80c8e02e2aeb74213dfa85a8557ba667398dc103b0e77a90600090a2565b600033610cf3818585613511565b60019150505b92915050565b600033610d0d858285613523565b610d18858585613571565b506001949350505050565b60008060007f00000000000000000000000000000000000000000000000000000000000000004210158015610d625750600a54600160a01b900460ff16155b8015610d845750600060105460ff166006811115610d8257610d82614305565b145b600a5490947f00000000000000000000000000000000000000000000000000000000000000009450600160a01b90910460ff1692509050565b610dc56135d0565b610e1e81604051602001610dd991906144a5565b6040516020818303038152906040528051906020012060405180604001604052806011815260200170525741546f6b656e56322e7365744b796360781b815250613602565b50565b610e29613490565b60105460ff166000816006811115610e4357610e43614305565b14158015610e6357506006816006811115610e6057610e60614305565b14155b610ea85760405162461bcd60e51b81526020600482015260166024820152754e6920706f73746f706b61207a61207072656b6c696360501b60448201526064016109fb565b6012546001600160a01b03163314610f3b5760006003826006811115610ed057610ed0614305565b14610edd57601454610ef4565b610ee7601e6134ab565b601454610ef491906143fc565b9050804211610f395760405162461bcd60e51b8152602060048201526011602482015270149bdac81cd9481b9a481c1bdd195ad95b607a1b60448201526064016109fb565b505b6011546000908152602160205260409020601e546005836006811115610f6357610f63614305565b03610fb457610f76631dcd6500826143b0565b601354909150610fb4906001600160a01b03167f0000000000000000000000000000000000000000000000000000000000000000631dcd65006136b5565b815415801590610fc95750600182015460ff16155b15610fdf576001828101805460ff191690911790555b6012546011546010805460ff191690556000601e9081556001600160a01b039092169161100b906134ab565b61101590426143fc565b602055601280546001600160a01b0319169055821561104557601354611045906001600160a01b031683856136b5565b604051339082907fd04286d519dc9428ffae13bb4fab7e445711d8630bfea9efe333def519d6fa2b90600090a35050505050610b6e613504565b611087613490565b600660105460ff1660068111156110a0576110a0614305565b146110e65760405162461bcd60e51b8152602060048201526016602482015275537265647374766f206e692072617a6472757a656e6f60501b60448201526064016109fb565b60006110f133611e4f565b90506000811161112d5760405162461bcd60e51b8152602060048201526007602482015266139a48195b9bdd60ca1b60448201526064016109fb565b6000670de0b6b3a76400006018548361114691906143c3565b61115091906143da565b905061115c33836136e1565b80601e600082825461116e91906143b0565b909155505060135461118a906001600160a01b031633836136b5565b336001600160a01b03167f8db9b93d9d69f7759ea46adb3a7c5c9c42206c5c58e126b621cbcaae6afd3ae283836040516111c592919061440f565b60405180910390a25050610b6e613504565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661121d5760405162461bcd60e51b81526004016109fb906144d6565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146112655760405162461bcd60e51b81526004016109fb90614519565b6040516338260bcb60e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063704c1796906112b190339060040161411f565b602060405180830381865afa1580156112ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112f29190614457565b61130e5760405162461bcd60e51b81526004016109fb9061454f565b8061132b5760405162461bcd60e51b81526004016109fb90614584565b61138a8484848460405160200161134594939291906145b4565b6040516020818303038152906040528051906020012060405180604001604052806011815260200170525741546f6b656e56322e7072656e6f7360781b815250613602565b50505050565b611398613490565b600560105460ff1660068111156113b1576113b1614305565b146113f65760405162461bcd60e51b8152602060048201526015602482015274446f706c6163696c6f206e6920706f747265626e6f60581b60448201526064016109fb565b6012546001600160a01b031633146114205760405162461bcd60e51b81526004016109fb90614371565b6014544211156114705760405162461bcd60e51b815260206004820152601b60248201527a149bdac81e9848191bdc1b1858da5b1bc81a99481c1bdd195ad95b602a1b60448201526064016109fb565b600061147a611537565b905061148a631dcd6500826143b0565b601e600082825461149b91906143fc565b90915550506010805460ff19166003179055426014556013546114c9906001600160a01b03163330846134d7565b601354611504906001600160a01b03167f0000000000000000000000000000000000000000000000000000000000000000631dcd65006136b5565b6011546040518281527fd85f6e72ce972e459bcdaf47e097ebe1cc478812ddfcfbd786bda5d161f96e3690602001610b5d565b6000600560105460ff16600681111561155257611552614305565b1461155d5750600090565b6000601f54670de0b6b3a7640000601854601d5461157b91906143c3565b61158591906143da565b61158f91906143fc565b9050631dcd6500601e54826115a491906143b0565b6115ae91906143fc565b91505090565b6115bc613490565b6000818152602160209081526040808320602283528184203385529092529091205460ff1661162d5760405162461bcd60e51b815260206004820152601e60248201527f4e692075676f7661726a616c20616c69206a65207a6520647669676e696c000060448201526064016109fb565b600181015460ff1660000361167c5760405162461bcd60e51b81526020600482015260156024820152742ab3b7bb37b91039b2903734903930bd3932b9b2b760591b60448201526064016109fb565b60008281526022602090815260408083203384529091529020805460ff191690556001810154631dcd65009060ff166002036116eb57815460009060016116c782631dcd65006143fc565b6116d191906143b0565b6116db91906143da565b90506116e781836143b0565b9150505b801561170857601354611708906001600160a01b031633836136b5565b604051818152339084907f028bbf34bb50f38722a8bfaa6e366e68d05dfb2c78996a30f4e70b50ab10135e9060200160405180910390a35050610e1e613504565b60008060105460ff16600681111561176357611763614305565b1415905090565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166379c9f580306040518263ffffffff1660e01b81526004016117b9919061411f565b602060405180830381865afa1580156117d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117fa91906145fa565b9050600f548110156118195780600f5461181491906143b0565b6115ae565b600091505090565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166118675760405162461bcd60e51b81526004016109fb906144d6565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146118af5760405162461bcd60e51b81526004016109fb90614519565b6040516338260bcb60e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063704c1796906118fb90339060040161411f565b602060405180830381865afa158015611918573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061193c9190614457565b6119585760405162461bcd60e51b81526004016109fb9061454f565b6119bb8160405160200161196c9190614613565b604051602081830303815290604052805190602001206040518060400160405280601b81526020017a525741546f6b656e56322e757064617465417373657456616c756560281b815250613717565b60088190556040518181527f1cb5e221120a70c5978375b275179418e0cc46d0390597fad5b2d8757fe9eab59060200160405180910390a150565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316611a3c5760405162461bcd60e51b81526004016109fb906144d6565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611a845760405162461bcd60e51b81526004016109fb90614519565b6040516338260bcb60e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063704c179690611ad090339060040161411f565b602060405180830381865afa158015611aed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b119190614457565b611b2d5760405162461bcd60e51b81526004016109fb9061454f565b600160105460ff166006811115611b4657611b46614305565b14611b8f5760405162461bcd60e51b81526020600482015260196024820152782734903d30b43a32bb32903d30903930bd32393abd34ba32bb60391b60448201526064016109fb565b60008311611baf5760405162461bcd60e51b81526004016109fb90614645565b80611bcc5760405162461bcd60e51b81526004016109fb9061466f565b601583905560178290556019819055611be58383613820565b6018556010805460ff19166002179055611bff600e6134ab565b611c0990426143fc565b601455601154601854604080518681526020810186905290810191909152606081018390527f0bc2303f3a43f3c189cc0a59eb941fb5ab17f2ce794015a14f0f45236ffdc329906080015b60405180910390a2505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611ca95760405162461bcd60e51b81526004016109fb906146a0565b6000818152600b602052604090205460ff1615611cfd5760405162461bcd60e51b8152602060048201526012602482015271141c9bdbd988185b1c9958591e481d5cd95960721b60448201526064016109fb565b600a546001600160a01b031615611d4f5760405162461bcd60e51b8152602060048201526016602482015275537265647374766f206a65207a6520736b6f76616e6f60501b60448201526064016109fb565b6000818152600b602052604090208054600160ff199182168117909255600a80546001600160a01b0319166001600160a01b038716179055600c80549091169091179055600d82905560085464e8d4a510009061271090611db2906032906143c3565b611dbc91906143da565b611dc691906143da565b600f55611dd38383613886565b826001600160a01b03167f7369d801113c713520ca653010d32c6bcd6778f0ffb3df0bc9efb8d85b687e448383604051611e0e92919061440f565b60405180910390a26040516001600160a01b038416907fe2cdd6bfbb0efc5299e0840dd4af6d4c9a195224ebad256485e9990726fd041c90600090a2505050565b6001600160a01b031660009081526020819052604090205490565b60405162461bcd60e51b81526020600482015260136024820152722932b737bab731b29037b732b6b7b3b7b1b2b760691b60448201526064016109fb565b611eb06135d0565b6000838152600660205260408120549003611edd5760405162461bcd60e51b81526004016109fb906146ca565b600083815260066020526040808220919091555183907f72003eda7c2c39777210bccbf69141a92bbe56d746914a16f5ee3aaf5e6f7a8390611c5490859085906146f1565b600081815260066020526040812054819081908190808203611f5257600080600080945094509450945050611f88565b600181611f6262093a80826143fc565b834210158015611f7e5750611f7a62093a80856143fc565b4211155b9450945094509450505b9193509193565b6012546000908190611fa9906001600160a01b0316611e4f565b600254611fb691906143b0565b9050611fc061176a565b670de0b6b3a764000060185483611fd791906143c3565b6115a491906143da565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166120275760405162461bcd60e51b81526004016109fb906144d6565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461206f5760405162461bcd60e51b81526004016109fb90614519565b6040516338260bcb60e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063704c1796906120bb90339060040161411f565b602060405180830381865afa1580156120d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120fc9190614457565b6121185760405162461bcd60e51b81526004016109fb9061454f565b612120613490565b600460105460ff16600681111561213957612139614305565b146121735760405162461bcd60e51b815260206004820152600a6024820152694e692075676f766f726160b01b60448201526064016109fb565b600082116121935760405162461bcd60e51b81526004016109fb90614645565b806121b05760405162461bcd60e51b81526004016109fb9061466f565b601154600090815260216020526040812060018101805461ff0019166101001790556016849055601a839055906121eb6101f46127106143fc565b6015546121f891906143c3565b612204856127106143c3565b108015915061226857600061221b85601754613820565b905060185481111561222d5760188190555b6001838101805460ff199081169092179055601080549091166005179055612255600e6134ab565b61225f90426143fc565b601455506122c5565b600182018054600260ff1991821617909155601080549091166003179055426014556013546122c5906001600160a01b03167f0000000000000000000000000000000000000000000000000000000000000000631dcd65006136b5565b6011546018546040805187815284151560208201528082019290925260608201869052517f264e3ba2de740a90f8b1241378dcf3cd9e3c79649705d7ffe8506634ab181bbe9181900360800190a2505061231d613504565b5050565b600061232d60016134ab565b905090565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461237a5760405162461bcd60e51b81526004016109fb906146a0565b600c5460ff166123c55760405162461bcd60e51b815260206004820152601660248201527550726f76697a696a61206272657a206b6f76616e6a6160501b60448201526064016109fb565b600a546001600160a01b0383811691161461242e5760405162461bcd60e51b815260206004820152602360248201527f456e6f746520677265646f2073616d6f207072766f746e656d75206c6173746e604482015262696b7560e81b60648201526084016109fb565b600d5461243c8260c76143c3565b11156124805760405162461bcd60e51b815260206004820152601360248201527250726f76697a696a61207072657669736f6b6160681b60448201526064016109fb565b600c805460ff1916905561231d8282613886565b6005546001600160a01b031690565b606060048054610b7f9061441d565b6124ba6135d0565b612513816040516020016124ce91906144a5565b6040516020818303038152906040528051906020012060405180604001604052806011815260200170525741546f6b656e56322e7365744b796360781b815250613717565b600980546001600160a01b0319166001600160a01b0383169081179091556040517f9f5f8fd48aa64bb8a94c00d6adfc92b215610db623c189eb30698be4581265a490600090a250565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166125a35760405162461bcd60e51b81526004016109fb906144d6565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146125eb5760405162461bcd60e51b81526004016109fb90614519565b6040516338260bcb60e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063704c17969061263790339060040161411f565b602060405180830381865afa158015612654573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126789190614457565b6126945760405162461bcd60e51b81526004016109fb9061454f565b600060105460ff1660068111156126ad576126ad614305565b146126ef5760405162461bcd60e51b815260206004820152601260248201527152617a6472757a6974657620762074656b7560701b60448201526064016109fb565b61274e8484848460405160200161270994939291906145b4565b6040516020818303038152906040528051906020012060405180604001604052806011815260200170525741546f6b656e56322e7072656e6f7360781b815250613717565b600e805460ff19166001179055612766848484613571565b600e805460ff191690556040516001600160a01b0380851691908616907f3317fbec254084023eda084601748dbfa751fb226b84fb928b888a1905067c55906127b2908690869061440f565b60405180910390a350505050565b600780546127cd9061441d565b80601f01602080910402602001604051908101604052809291908181526020018280546127f99061441d565b80156128465780601f1061281b57610100808354040283529160200191612846565b820191906000526020600020905b81548152906001019060200180831161282957829003601f168201915b505050505081565b600033610cf3818585613571565b600061232d6138bc565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166128ac5760405162461bcd60e51b81526004016109fb906144d6565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146128f45760405162461bcd60e51b81526004016109fb90614519565b6040516338260bcb60e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063704c17969061294090339060040161411f565b602060405180830381865afa15801561295d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129819190614457565b61299d5760405162461bcd60e51b81526004016109fb9061454f565b6129a5613490565b600360105460ff1660068111156129be576129be614305565b14612a0a5760405162461bcd60e51b815260206004820152601c60248201527b273490383934b83930bb363532b737903d30903837ba393234ba32bb60211b60448201526064016109fb565b60145442101580612a1b5750601d54155b612a5f5760405162461bcd60e51b8152602060048201526015602482015274526f6b207a612075676f766f72207365207465636560581b60448201526064016109fb565b80612a7c5760405162461bcd60e51b81526004016109fb90614584565b6010805460ff19166006179055601b819055601254601c54612aa7916001600160a01b0316906136e1565b601f548015612b615780601e6000828254612ac291906143b0565b92505081905550612b617f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663469048406040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b4e9190614720565b6013546001600160a01b031690836136b5565b6011546040518381527f246b68f75a0f7ec8f7358217be89ea2805600b63529f8ca499081835d612b53f9060200160405180910390a250610e1e613504565b6040516338260bcb60e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063704c179690612bec90339060040161411f565b602060405180830381865afa158015612c09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c2d9190614457565b612c495760405162461bcd60e51b81526004016109fb90614479565b600a805460ff60a01b1916600160a01b17905560405133907f481d73db1c84a4cd0734a718818b266e3b59f2e485d8ba806e15763777d9d00690600090a2565b600060105460ff166006811115612ca257612ca2614305565b14612ce55760405162461bcd60e51b815260206004820152601360248201527252617a6472757a69746576207a65207465636560681b60448201526064016109fb565b600a546001600160a01b0316612d365760405162461bcd60e51b8152602060048201526016602482015275537265647374766f207365206e6920736b6f76616e6f60501b60448201526064016109fb565b600a54600160a01b900460ff1615612d605760405162461bcd60e51b81526004016109fb9061473d565b602054421015612dc05760405162461bcd60e51b815260206004820152602560248201527f506f207072656b6c696375206e6f7661207a616874657661207365206e69206d6044820152646f676f636160d81b60648201526084016109fb565b6000612dcb33611e4f565b9050612328612dd960025490565b612de391906143c3565b612def826127106143c3565b1015612e3b5760405162461bcd60e51b815260206004820152601b60248201527a141bdd1c99589b9a5a081a99481d9cd85a880e4c080948195b9bdd602a1b60448201526064016109fb565b60118054906000612e4b8361476d565b90915550506010805460ff1916600117905560128054336001600160a01b031990911617905560408051631f209df760e11b815290516001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691633e413bee9160048083019260209291908290030181865afa158015612ed6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612efa9190614720565b601380546001600160a01b0319166001600160a01b0392909216919091179055612f24601e6134ab565b612f2e90426143fc565b601455600060158190556016819055601781905560188190556019819055601a819055601c819055601d819055601e819055601f556011546040518281523391907f7e0520c3144535d11130bf88d1bed98f7c8a938aa78147d18d20f375a99171ba9060200160405180910390a350565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b612fd2613490565b6011546000908152602160205260409020600360105460ff166006811115612ffc57612ffc614305565b036130ce576001810154610100900460ff16156130595760405162461bcd60e51b815260206004820152601b60248201527a2ab3b7bb37b9103532903d32903134b61037b13930bb3730bb30b760291b60448201526064016109fb565b60145442106130a55760405162461bcd60e51b8152602060048201526018602482015277149bdac81e98481d59dbdd9bdc881a99481c1bdd195ad95b60421b60448201526064016109fb565b6010805460ff191660041790556130bc601e6134ab565b6130c690426143fc565b601455613128565b600460105460ff1660068111156130e7576130e7614305565b146131285760405162461bcd60e51b815260206004820152601160248201527027349031b0b9b0903d30903ab3b7bb37b960791b60448201526064016109fb565b6012546001600160a01b0316330361317b5760405162461bcd60e51b81526020600482015260166024820152755370726f7a6974656c6a206e652075676f7661726a6160501b60448201526064016109fb565b600061318633611e4f565b116131d15760405162461bcd60e51b815260206004820152601b60248201527a1559dbdd985c9a98481b185a1adbc81a5b595d1b9a5ac8195b9bdd602a1b60448201526064016109fb565b601154600090815260226020908152604080832033845290915290205460ff161561322d5760405162461bcd60e51b815260206004820152600c60248201526b1699481d59dbdd985c9a985b60a21b60448201526064016109fb565b60115460009081526022602090815260408083203384529091528120805460ff1916600117905581549082906132628361476d565b9091555050601354613283906001600160a01b03163330631dcd65006134d7565b6011546040513391907f91c60199e9bb6e772b5ba372bd886eaf70d847ebaa965a97a1acba93b87698e590600090a350610b6e613504565b6132c36135d0565b6001600160a01b0381166132ed576000604051631e4fbdf760e01b81526004016109fb919061411f565b610e1e816138e2565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661333c5760405162461bcd60e51b81526004016109fb906144d6565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146133845760405162461bcd60e51b81526004016109fb90614519565b6040516338260bcb60e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063704c1796906133d090339060040161411f565b602060405180830381865afa1580156133ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134119190614457565b61342d5760405162461bcd60e51b81526004016109fb9061454f565b610e1e816040516020016134419190614613565b604051602081830303815290604052805190602001206040518060400160405280601b81526020017a525741546f6b656e56322e757064617465417373657456616c756560281b815250613602565b613498613934565b60026134a86134a561395a565b90565b55565b60006134b64661397e565b6134cc576134c782620151806143c3565b610cf9565b610cf982603c6143c3565b6134e58484848460016139c7565b61138a5783604051635274afe760e01b81526004016109fb919061411f565b60016134a86134a561395a565b61351e8383836001613a39565b505050565b600061352f8484612f9f565b905060001981101561138a578181101561356257828183604051637dc7a0d960e11b81526004016109fb93929190614786565b61138a84848484036000613a39565b6001600160a01b03831661359b576000604051634b637e8f60e11b81526004016109fb919061411f565b6001600160a01b0382166135c557600060405163ec442f0560e01b81526004016109fb919061411f565b61351e838383613b00565b336135d9612494565b6001600160a01b031614610b6e573360405163118cdaa760e01b81526004016109fb919061411f565b6000828152600660205260409020541561364e5760405162461bcd60e51b815260206004820152600d60248201526c5a65206e61706f766564616e6f60981b60448201526064016109fb565b600061365861285c565b61366290426143fc565b60008481526006602052604090208190559050827f63a0d065f46e07e30a4f246d28eb53f839982100439173db92dbd5700ab37c1583836136a662093a80826143fc565b604051611c54939291906147a7565b6136c28383836001613ed2565b61351e5782604051635274afe760e01b81526004016109fb919061411f565b6001600160a01b03821661370b576000604051634b637e8f60e11b81526004016109fb919061411f565b61231d82600083613b00565b600082815260066020526040812054908190036137465760405162461bcd60e51b81526004016109fb906146ca565b8042101561378c5760405162461bcd60e51b815260206004820152601360248201527216985b5a5ac81cd9481b9a481c1bdd195ad95b606a1b60448201526064016109fb565b61379962093a80826143fc565b4211156137dd5760405162461bcd60e51b81526020600482015260126024820152714e61706f766564206a6520706f74656b6c6160701b60448201526064016109fb565b600083815260066020526040808220919091555183907ffac4537038ebc9eaa00d86a88a6c2e268012d306f6442966aab36014a195432390611c549085906140ab565b60008061382c60025490565b61383985620f42406143c3565b61384391906143da565b905082600003613854579050610cf9565b6000600261386285846143fc565b61386c91906143da565b905081811161387b578161387d565b805b95945050505050565b6001600160a01b0382166138b057600060405163ec442f0560e01b81526004016109fb919061411f565b61231d60008383613b00565b60006138c74661397e565b6138d4576202a3006138d8565b6102585b62ffffff16905090565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b61393c613f38565b15610b6e57604051633ee5aeb560e01b815260040160405180910390fd5b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0090565b6000816103af148061399257508162aa36a7145b8061399f57508162088bb0145b806139ac57508162014a34145b806139b957508162066eee145b80610cf9575050617a691490565b6040516323b872dd60e01b60008181526001600160a01b038781166004528616602452604485905291602083606481808c5af192506001600051148316613a27578383151615613a1a573d6000823e3d81fd5b6000883b113d1516831692505b60405250600060605295945050505050565b6001600160a01b038416613a6357600060405163e602df0560e01b81526004016109fb919061411f565b6001600160a01b038316613a8d576000604051634a1406b160e11b81526004016109fb919061411f565b6001600160a01b038085166000908152600160209081526040808320938716835292905220829055801561138a57826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040516127b291815260200190565b6009546001600160a01b03848116159184821615911615801590613b22575080155b15613ca257600954604051633af32abf60e01b81526001600160a01b0390911690633af32abf90613b5790879060040161411f565b602060405180830381865afa158015613b74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b989190614457565b613be15760405162461bcd60e51b815260206004820152601a602482015279283932b532b6b734b59037349025aca190383932bb32b93532b760311b60448201526064016109fb565b81613ca257600954604051633af32abf60e01b81526001600160a01b0390911690633af32abf90613c1690889060040161411f565b602060405180830381865afa158015613c33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c579190614457565b613ca25760405162461bcd60e51b815260206004820152601c60248201527b2837b9b4b63530ba32b6351037349025aca190383932bb32b93532b760211b60448201526064016109fb565b81613ec057600a54600160a01b900460ff1615613cd15760405162461bcd60e51b81526004016109fb9061473d565b7f0000000000000000000000000000000000000000000000000000000000000000421015613d415760405162461bcd60e51b815260206004820181905260248201527f537265647374766f207365206e6920616b7469766e6f207a61207072656e6f7360448201526064016109fb565b80613ec057600060105460ff166006811115613d5f57613d5f614305565b14613df6577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316856001600160a01b031614613df15760405162461bcd60e51b815260206004820152602360248201527f52617a6472757a6974657620762074656b753a207072656e6f73206e69206d6f604482015262676f6360e81b60648201526084016109fb565b613ec0565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316856001600160a01b03161480613e6757507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b0316145b80613e745750600e5460ff165b613ec05760405162461bcd60e51b815260206004820181905260248201527f5072656e6f732073616d6f207072656b20525741204d61726b6574706c61636560448201526064016109fb565b613ecb858585613f4e565b5050505050565b60405163a9059cbb60e01b60008181526001600160a01b038616600452602485905291602083604481808b5af192506001600051148316613f2c578383151615613f1f573d6000823e3d81fd5b6000873b113d1516831692505b60405250949350505050565b60006002613f476134a561395a565b5414919050565b6001600160a01b038316613f79578060026000828254613f6e91906143fc565b90915550613fd89050565b6001600160a01b03831660009081526020819052604090205481811015613fb95783818360405163391434e360e21b81526004016109fb93929190614786565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b038216613ff457600280548290039055614013565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161405891815260200190565b60405180910390a3505050565b6000815180845260005b8181101561408b5760208185018101518683018201520161406f565b506000602082860101526020601f19601f83011685010191505092915050565b6020815260006140be6020830184614065565b9392505050565b6000602082840312156140d757600080fd5b5035919050565b6001600160a01b0381168114610e1e57600080fd5b6000806040838503121561410657600080fd5b8235614111816140de565b946020939093013593505050565b6001600160a01b0391909116815260200190565b60008060006060848603121561414857600080fd5b8335614153816140de565b92506020840135614163816140de565b929592945050506040919091013590565b60006020828403121561418657600080fd5b81356140be816140de565b600080600080608085870312156141a757600080fd5b84356141b2816140de565b935060208501356141c2816140de565b93969395505050506040820135916060013590565b6000806000606084860312156141ec57600080fd5b505081359360208301359350604090920135919050565b60008060006060848603121561421857600080fd5b8335614223816140de565b95602085013595506040909401359392505050565b60008060006040848603121561424d57600080fd5b8335925060208401356001600160401b038082111561426b57600080fd5b818601915086601f83011261427f57600080fd5b81358181111561428e57600080fd5b8760208285010111156142a057600080fd5b6020830194508093505050509250925092565b600080604083850312156142c657600080fd5b50508035926020909101359150565b600080604083850312156142e857600080fd5b8235915060208301356142fa816140de565b809150509250929050565b634e487b7160e01b600052602160045260246000fd5b602081016007831061433d57634e487b7160e01b600052602160045260246000fd5b91905290565b6000806040838503121561435657600080fd5b8235614361816140de565b915060208301356142fa816140de565b6020808252600f908201526e29b0b6b79039b83937bd34ba32b63560891b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b81810381811115610cf957610cf961439a565b8082028115828204841417610cf957610cf961439a565b6000826143f757634e487b7160e01b600052601260045260246000fd5b500490565b80820180821115610cf957610cf961439a565b918252602082015260400190565b600181811c9082168061443157607f821691505b60208210810361445157634e487b7160e01b600052602260045260246000fd5b50919050565b60006020828403121561446957600080fd5b815180151581146140be57600080fd5b60208082526012908201527129b0b6b7902aa7a9299037b832b930ba32b960711b604082015260600190565b6040808252600690820152657365744b796360d01b60608201526001600160a01b0391909116602082015260800190565b60208082526023908201527f537265647374766f206e696d61207a61706973616e656761206f7665726974656040820152626c6a6160e81b606082015260800190565b6020808252601c908201527b53616d6f206f7665726974656c6a207465676120737265647374766160201b604082015260600190565b6020808252601b908201527a27bb32b934ba32b635103734903b32b1903837b7b13630b9b1b2b760291b604082015260600190565b60208082526016908201527527b23a34b9903634b9ba34b73290353290373ab532b760511b604082015260600190565b60a0808252600690820152657072656e6f7360d01b60c08201526001600160a01b0394851660208201529290931660408301526060820152608081019190915260e00190565b60006020828403121561460c57600080fd5b5051919050565b60408082526010908201526f757064617465417373657456616c756560801b6060820152602081019190915260800190565b60208082526010908201526f43656e69746576206a65206e756a6e6160801b604082015260600190565b60208082526017908201527627b23a34b9903837b937b1b4b63090353290373ab532b760491b604082015260600190565b60208082526010908201526f27b7363c902d25903b32b934b334b2b960811b604082015260600190565b6020808252600d908201526c4e69206e61706f766564616e6f60981b604082015260600190565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b60006020828403121561473257600080fd5b81516140be816140de565b602080825260169082015275537265647374766f206a65207a616d727a6e6a656e6f60501b604082015260600190565b60006001820161477f5761477f61439a565b5060010190565b6001600160a01b039390931683526020830191909152604082015260600190565b6060815260006147ba6060830186614065565b6020830194909452506040015291905056fea264697066735822122071e2e8c6e65414f5179909af364e1877e212c555359c2a822836fa6a392fa1c064736f6c634300081800330000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000d3c21bcecceda10000000000000000000000000000000eb5556032f9ca9ab629439afaecd79c40aab863000000000000000000000000f119beb1b343e46c4ed0e78362cd3f87e87ef4cc00000000000000000000000076e388cf49d12262808651e35d6fd296c1d4433f000000000000000000000000d37d29526d271770f42c2553faae7f282effc1630000000000000000000000005a5db3d01a38d640a81182b1769a9f1e4d1f0f7400000000000000000000000016eeba545a07a88cdf21cfdde973ee67cdc3200000000000000000000000000091991f58804cc5aceca5e87d4667e68d22e0824800000000000000000000000000000000000000000000000000000000000000055257415f3100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064d445445535400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042697066733a2f2f6261666b726569613566676970727837706672756b6661373275756a377876676b776d7663697a646d686f36656e327a76376335346c3565793271000000000000000000000000000000000000000000000000000000000000
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106103dd5760003560e01c806302471efa146103e2578063034b3767146103fe57806306fdde031461040857806307601d271461041d5780630854eef514610425578063095ea7b3146104455780630e78931d1461046857806318160ddd1461049c578063225cbe20146104a457806323b872dd146104ad57806323eca665146104c057806325bd0f45146104e7578063263c1e61146104ef57806329a52c171461050257806329c3fe7c1461050a5780632a06cc25146105315780632bcc0bbe146105395780632f6081dc1461054d578063313ce5671461056057806333d1f5631461056f5780633504182d1461057857806336b2e3ed14610580578063404512b11461058957806340a1d3cb14610591578063418ee99d1461059957806343e9cf4b146105c057806346904840146105d3578063480ea628146105e45780634abf9c6a1461060b5780634b4fdb4f1461061e5780634c8a1b0d1461062957806355065c39146104e7578063584d525f146106315780635c57d8a8146106395780635e7f9862146104e7578063633c963a1461064c5780636783ec341461065f5780636a3b5c4d1461066857806370a082311461067b578063715018a61461068e57806376e382c814610696578063776528cd146106a95780637a347775146106e05780637b742d4c146106e85780637e92d2b3146106f15780637f5181b014610704578063853511f51461070c5780638cc9d1071461075e5780638da5cb5b1461077157806390d6b45f14610779578063944765c81461078c57806395d89b41146107ba578063988d33e0146107c25780639953ed96146107cb57806399c27206146107d45780639abe0969146107e75780639e759f94146107fa578063a023661814610803578063a27486cd1461080b578063a582665214610814578063a656212a1461081c578063a859e57714610825578063a9059cbb1461083f578063af95822c14610852578063afc1a4c01461085b578063b007d5fc14610864578063b318d3a31461086c578063bf50829d1461087f578063bfba6d5d14610892578063c1da7c97146108a5578063c30a0f25146108ad578063c71a9a1e146108d0578063cde2202a146108d8578063d1bf942a146108e1578063d48693d114610864578063d6df096d146108ea578063d7bcc5b0146104e7578063dd62ed3e14610911578063dd6b579214610924578063e29eb51b1461092c578063e787225c14610935578063e826f69a1461093e578063ec59656014610948578063f2fde38b14610951578063f7dc924314610964578063f9728ca114610977578063fa93527d14610803575b600080fd5b6103eb600f5481565b6040519081526020015b60405180910390f35b61040661099e565b005b610410610b70565b6040516103f591906140ab565b610406610c02565b6103eb6104333660046140c5565b60066020526000908152604090205481565b6104586104533660046140f3565b610ce5565b60405190151581526020016103f5565b61048f7f000000000000000000000000f119beb1b343e46c4ed0e78362cd3f87e87ef4cc81565b6040516103f5919061411f565b6002546103eb565b6103eb601f5481565b6104586104bb366004614133565b610cff565b6104c8610d23565b60408051931515845260208401929092521515908201526060016103f5565b6103eb601e81565b6104066104fd366004614174565b610dbd565b610406610e21565b61048f7f00000000000000000000000016eeba545a07a88cdf21cfdde973ee67cdc3200081565b61040661107f565b600a5461045890600160a01b900460ff1681565b61040661055b366004614191565b6111d7565b604051601281526020016103f5565b6103eb601b5481565b6103eb603281565b6103eb60175481565b610406611390565b6103eb611537565b61048f7f00000000000000000000000091991f58804cc5aceca5e87d4667e68d22e0824881565b6104066105ce3660046140c5565b6115b4565b600a546001600160a01b031661048f565b61048f7f00000000000000000000000076e388cf49d12262808651e35d6fd296c1d4433f81565b60125461048f906001600160a01b031681565b6103eb631dcd650081565b610458611749565b6103eb61176a565b6104066106473660046140c5565b611821565b61040661065a3660046141d7565b6119f6565b6103eb60185481565b610406610676366004614203565b611c61565b6103eb610689366004614174565b611e4f565b610406611e6a565b6104066106a4366004614238565b611ea8565b6106bc6106b73660046140c5565b611f22565b604080519415158552602085019390935291830152151560608201526080016103f5565b6103eb611f8f565b6103eb60195481565b6104066106ff3660046142b3565b611fe1565b6103eb612321565b61073f61071a3660046140c5565b6021602052600090815260409020805460019091015460ff8082169161010090041683565b6040805193845260ff90921660208401521515908201526060016103f5565b61040661076c3660046140f3565b612332565b61048f612494565b60095461048f906001600160a01b031681565b61045861079a3660046142d5565b602260209081526000928352604080842090915290825290205460ff1681565b6104106124a3565b6103eb61232881565b6103eb601c5481565b6104066107e2366004614174565b6124b2565b6104066107f5366004614191565b61255d565b6103eb60165481565b6103eb600e81565b6103eb601a5481565b6104106127c0565b6103eb601d5481565b6010546108329060ff1681565b6040516103f5919061431b565b61045861084d3660046140f3565b61284e565b6103eb6101f481565b6103eb601e5481565b6103eb61285c565b61040661087a3660046140c5565b612866565b60135461048f906001600160a01b031681565b600a5461048f906001600160a01b031681565b610406612ba0565b6104586108bb3660046140c5565b600b6020526000908152604090205460ff1681565b610406612c89565b6103eb60085481565b6103eb60145481565b61048f7f0000000000000000000000000eb5556032f9ca9ab629439afaecd79c40aab86381565b6103eb61091f366004614343565b612f9f565b610406612fca565b6103eb60205481565b6103eb60155481565b6103eb62093a8081565b6103eb60115481565b61040661095f366004614174565b6132bb565b6104066109723660046140c5565b6132f6565b6103eb7f000000000000000000000000000000000000000000000000000000006ad5040181565b6109a6613490565b600260105460ff1660068111156109bf576109bf614305565b14610a045760405162461bcd60e51b815260206004820152601060248201526f4e692063617361207a6120706f6c6f6760801b60448201526064015b60405180910390fd5b6012546001600160a01b03163314610a2e5760405162461bcd60e51b81526004016109fb90614371565b601454421115610a7a5760405162461bcd60e51b8152602060048201526017602482015276149bdac81e98481c1bdb1bd9c81a99481c1bdd195ad95b604a1b60448201526064016109fb565b601254610a8f906001600160a01b0316611e4f565b601c819055600254610aa191906143b0565b601d55610aac61176a565b601f819055506000601f54670de0b6b3a7640000601854601d54610ad091906143c3565b610ada91906143da565b610ae491906143fc565b601e8181556010805460ff19166003179055909150610b02906134ab565b610b0c90426143fc565b601455601354610b27906001600160a01b03163330846134d7565b6011547fee0aea9ff2c1b37b651b974b61c086588b20c5ab08133a1a6c546e1563bacc9f82601d54604051610b5d92919061440f565b60405180910390a250610b6e613504565b565b606060038054610b7f9061441d565b80601f0160208091040260200160405190810160405280929190818152602001828054610bab9061441d565b8015610bf85780601f10610bcd57610100808354040283529160200191610bf8565b820191906000526020600020905b815481529060010190602001808311610bdb57829003601f168201915b5050505050905090565b6040516338260bcb60e11b81526001600160a01b037f00000000000000000000000016eeba545a07a88cdf21cfdde973ee67cdc32000169063704c179690610c4e90339060040161411f565b602060405180830381865afa158015610c6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c8f9190614457565b610cab5760405162461bcd60e51b81526004016109fb90614479565b600a805460ff60a01b1916905560405133907fae0ecc60019f8d35cb80c8e02e2aeb74213dfa85a8557ba667398dc103b0e77a90600090a2565b600033610cf3818585613511565b60019150505b92915050565b600033610d0d858285613523565b610d18858585613571565b506001949350505050565b60008060007f000000000000000000000000000000000000000000000000000000006ad504014210158015610d625750600a54600160a01b900460ff16155b8015610d845750600060105460ff166006811115610d8257610d82614305565b145b600a5490947f000000000000000000000000000000000000000000000000000000006ad504019450600160a01b90910460ff1692509050565b610dc56135d0565b610e1e81604051602001610dd991906144a5565b6040516020818303038152906040528051906020012060405180604001604052806011815260200170525741546f6b656e56322e7365744b796360781b815250613602565b50565b610e29613490565b60105460ff166000816006811115610e4357610e43614305565b14158015610e6357506006816006811115610e6057610e60614305565b14155b610ea85760405162461bcd60e51b81526020600482015260166024820152754e6920706f73746f706b61207a61207072656b6c696360501b60448201526064016109fb565b6012546001600160a01b03163314610f3b5760006003826006811115610ed057610ed0614305565b14610edd57601454610ef4565b610ee7601e6134ab565b601454610ef491906143fc565b9050804211610f395760405162461bcd60e51b8152602060048201526011602482015270149bdac81cd9481b9a481c1bdd195ad95b607a1b60448201526064016109fb565b505b6011546000908152602160205260409020601e546005836006811115610f6357610f63614305565b03610fb457610f76631dcd6500826143b0565b601354909150610fb4906001600160a01b03167f00000000000000000000000091991f58804cc5aceca5e87d4667e68d22e08248631dcd65006136b5565b815415801590610fc95750600182015460ff16155b15610fdf576001828101805460ff191690911790555b6012546011546010805460ff191690556000601e9081556001600160a01b039092169161100b906134ab565b61101590426143fc565b602055601280546001600160a01b0319169055821561104557601354611045906001600160a01b031683856136b5565b604051339082907fd04286d519dc9428ffae13bb4fab7e445711d8630bfea9efe333def519d6fa2b90600090a35050505050610b6e613504565b611087613490565b600660105460ff1660068111156110a0576110a0614305565b146110e65760405162461bcd60e51b8152602060048201526016602482015275537265647374766f206e692072617a6472757a656e6f60501b60448201526064016109fb565b60006110f133611e4f565b90506000811161112d5760405162461bcd60e51b8152602060048201526007602482015266139a48195b9bdd60ca1b60448201526064016109fb565b6000670de0b6b3a76400006018548361114691906143c3565b61115091906143da565b905061115c33836136e1565b80601e600082825461116e91906143b0565b909155505060135461118a906001600160a01b031633836136b5565b336001600160a01b03167f8db9b93d9d69f7759ea46adb3a7c5c9c42206c5c58e126b621cbcaae6afd3ae283836040516111c592919061440f565b60405180910390a25050610b6e613504565b7f00000000000000000000000091991f58804cc5aceca5e87d4667e68d22e082486001600160a01b031661121d5760405162461bcd60e51b81526004016109fb906144d6565b336001600160a01b037f00000000000000000000000091991f58804cc5aceca5e87d4667e68d22e0824816146112655760405162461bcd60e51b81526004016109fb90614519565b6040516338260bcb60e11b81526001600160a01b037f00000000000000000000000016eeba545a07a88cdf21cfdde973ee67cdc32000169063704c1796906112b190339060040161411f565b602060405180830381865afa1580156112ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112f29190614457565b61130e5760405162461bcd60e51b81526004016109fb9061454f565b8061132b5760405162461bcd60e51b81526004016109fb90614584565b61138a8484848460405160200161134594939291906145b4565b6040516020818303038152906040528051906020012060405180604001604052806011815260200170525741546f6b656e56322e7072656e6f7360781b815250613602565b50505050565b611398613490565b600560105460ff1660068111156113b1576113b1614305565b146113f65760405162461bcd60e51b8152602060048201526015602482015274446f706c6163696c6f206e6920706f747265626e6f60581b60448201526064016109fb565b6012546001600160a01b031633146114205760405162461bcd60e51b81526004016109fb90614371565b6014544211156114705760405162461bcd60e51b815260206004820152601b60248201527a149bdac81e9848191bdc1b1858da5b1bc81a99481c1bdd195ad95b602a1b60448201526064016109fb565b600061147a611537565b905061148a631dcd6500826143b0565b601e600082825461149b91906143fc565b90915550506010805460ff19166003179055426014556013546114c9906001600160a01b03163330846134d7565b601354611504906001600160a01b03167f00000000000000000000000091991f58804cc5aceca5e87d4667e68d22e08248631dcd65006136b5565b6011546040518281527fd85f6e72ce972e459bcdaf47e097ebe1cc478812ddfcfbd786bda5d161f96e3690602001610b5d565b6000600560105460ff16600681111561155257611552614305565b1461155d5750600090565b6000601f54670de0b6b3a7640000601854601d5461157b91906143c3565b61158591906143da565b61158f91906143fc565b9050631dcd6500601e54826115a491906143b0565b6115ae91906143fc565b91505090565b6115bc613490565b6000818152602160209081526040808320602283528184203385529092529091205460ff1661162d5760405162461bcd60e51b815260206004820152601e60248201527f4e692075676f7661726a616c20616c69206a65207a6520647669676e696c000060448201526064016109fb565b600181015460ff1660000361167c5760405162461bcd60e51b81526020600482015260156024820152742ab3b7bb37b91039b2903734903930bd3932b9b2b760591b60448201526064016109fb565b60008281526022602090815260408083203384529091529020805460ff191690556001810154631dcd65009060ff166002036116eb57815460009060016116c782631dcd65006143fc565b6116d191906143b0565b6116db91906143da565b90506116e781836143b0565b9150505b801561170857601354611708906001600160a01b031633836136b5565b604051818152339084907f028bbf34bb50f38722a8bfaa6e366e68d05dfb2c78996a30f4e70b50ab10135e9060200160405180910390a35050610e1e613504565b60008060105460ff16600681111561176357611763614305565b1415905090565b6000807f00000000000000000000000076e388cf49d12262808651e35d6fd296c1d4433f6001600160a01b03166379c9f580306040518263ffffffff1660e01b81526004016117b9919061411f565b602060405180830381865afa1580156117d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117fa91906145fa565b9050600f548110156118195780600f5461181491906143b0565b6115ae565b600091505090565b7f00000000000000000000000091991f58804cc5aceca5e87d4667e68d22e082486001600160a01b03166118675760405162461bcd60e51b81526004016109fb906144d6565b336001600160a01b037f00000000000000000000000091991f58804cc5aceca5e87d4667e68d22e0824816146118af5760405162461bcd60e51b81526004016109fb90614519565b6040516338260bcb60e11b81526001600160a01b037f00000000000000000000000016eeba545a07a88cdf21cfdde973ee67cdc32000169063704c1796906118fb90339060040161411f565b602060405180830381865afa158015611918573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061193c9190614457565b6119585760405162461bcd60e51b81526004016109fb9061454f565b6119bb8160405160200161196c9190614613565b604051602081830303815290604052805190602001206040518060400160405280601b81526020017a525741546f6b656e56322e757064617465417373657456616c756560281b815250613717565b60088190556040518181527f1cb5e221120a70c5978375b275179418e0cc46d0390597fad5b2d8757fe9eab59060200160405180910390a150565b7f00000000000000000000000091991f58804cc5aceca5e87d4667e68d22e082486001600160a01b0316611a3c5760405162461bcd60e51b81526004016109fb906144d6565b336001600160a01b037f00000000000000000000000091991f58804cc5aceca5e87d4667e68d22e082481614611a845760405162461bcd60e51b81526004016109fb90614519565b6040516338260bcb60e11b81526001600160a01b037f00000000000000000000000016eeba545a07a88cdf21cfdde973ee67cdc32000169063704c179690611ad090339060040161411f565b602060405180830381865afa158015611aed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b119190614457565b611b2d5760405162461bcd60e51b81526004016109fb9061454f565b600160105460ff166006811115611b4657611b46614305565b14611b8f5760405162461bcd60e51b81526020600482015260196024820152782734903d30b43a32bb32903d30903930bd32393abd34ba32bb60391b60448201526064016109fb565b60008311611baf5760405162461bcd60e51b81526004016109fb90614645565b80611bcc5760405162461bcd60e51b81526004016109fb9061466f565b601583905560178290556019819055611be58383613820565b6018556010805460ff19166002179055611bff600e6134ab565b611c0990426143fc565b601455601154601854604080518681526020810186905290810191909152606081018390527f0bc2303f3a43f3c189cc0a59eb941fb5ab17f2ce794015a14f0f45236ffdc329906080015b60405180910390a2505050565b336001600160a01b037f0000000000000000000000000eb5556032f9ca9ab629439afaecd79c40aab8631614611ca95760405162461bcd60e51b81526004016109fb906146a0565b6000818152600b602052604090205460ff1615611cfd5760405162461bcd60e51b8152602060048201526012602482015271141c9bdbd988185b1c9958591e481d5cd95960721b60448201526064016109fb565b600a546001600160a01b031615611d4f5760405162461bcd60e51b8152602060048201526016602482015275537265647374766f206a65207a6520736b6f76616e6f60501b60448201526064016109fb565b6000818152600b602052604090208054600160ff199182168117909255600a80546001600160a01b0319166001600160a01b038716179055600c80549091169091179055600d82905560085464e8d4a510009061271090611db2906032906143c3565b611dbc91906143da565b611dc691906143da565b600f55611dd38383613886565b826001600160a01b03167f7369d801113c713520ca653010d32c6bcd6778f0ffb3df0bc9efb8d85b687e448383604051611e0e92919061440f565b60405180910390a26040516001600160a01b038416907fe2cdd6bfbb0efc5299e0840dd4af6d4c9a195224ebad256485e9990726fd041c90600090a2505050565b6001600160a01b031660009081526020819052604090205490565b60405162461bcd60e51b81526020600482015260136024820152722932b737bab731b29037b732b6b7b3b7b1b2b760691b60448201526064016109fb565b611eb06135d0565b6000838152600660205260408120549003611edd5760405162461bcd60e51b81526004016109fb906146ca565b600083815260066020526040808220919091555183907f72003eda7c2c39777210bccbf69141a92bbe56d746914a16f5ee3aaf5e6f7a8390611c5490859085906146f1565b600081815260066020526040812054819081908190808203611f5257600080600080945094509450945050611f88565b600181611f6262093a80826143fc565b834210158015611f7e5750611f7a62093a80856143fc565b4211155b9450945094509450505b9193509193565b6012546000908190611fa9906001600160a01b0316611e4f565b600254611fb691906143b0565b9050611fc061176a565b670de0b6b3a764000060185483611fd791906143c3565b6115a491906143da565b7f00000000000000000000000091991f58804cc5aceca5e87d4667e68d22e082486001600160a01b03166120275760405162461bcd60e51b81526004016109fb906144d6565b336001600160a01b037f00000000000000000000000091991f58804cc5aceca5e87d4667e68d22e08248161461206f5760405162461bcd60e51b81526004016109fb90614519565b6040516338260bcb60e11b81526001600160a01b037f00000000000000000000000016eeba545a07a88cdf21cfdde973ee67cdc32000169063704c1796906120bb90339060040161411f565b602060405180830381865afa1580156120d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120fc9190614457565b6121185760405162461bcd60e51b81526004016109fb9061454f565b612120613490565b600460105460ff16600681111561213957612139614305565b146121735760405162461bcd60e51b815260206004820152600a6024820152694e692075676f766f726160b01b60448201526064016109fb565b600082116121935760405162461bcd60e51b81526004016109fb90614645565b806121b05760405162461bcd60e51b81526004016109fb9061466f565b601154600090815260216020526040812060018101805461ff0019166101001790556016849055601a839055906121eb6101f46127106143fc565b6015546121f891906143c3565b612204856127106143c3565b108015915061226857600061221b85601754613820565b905060185481111561222d5760188190555b6001838101805460ff199081169092179055601080549091166005179055612255600e6134ab565b61225f90426143fc565b601455506122c5565b600182018054600260ff1991821617909155601080549091166003179055426014556013546122c5906001600160a01b03167f00000000000000000000000091991f58804cc5aceca5e87d4667e68d22e08248631dcd65006136b5565b6011546018546040805187815284151560208201528082019290925260608201869052517f264e3ba2de740a90f8b1241378dcf3cd9e3c79649705d7ffe8506634ab181bbe9181900360800190a2505061231d613504565b5050565b600061232d60016134ab565b905090565b336001600160a01b037f0000000000000000000000000eb5556032f9ca9ab629439afaecd79c40aab863161461237a5760405162461bcd60e51b81526004016109fb906146a0565b600c5460ff166123c55760405162461bcd60e51b815260206004820152601660248201527550726f76697a696a61206272657a206b6f76616e6a6160501b60448201526064016109fb565b600a546001600160a01b0383811691161461242e5760405162461bcd60e51b815260206004820152602360248201527f456e6f746520677265646f2073616d6f207072766f746e656d75206c6173746e604482015262696b7560e81b60648201526084016109fb565b600d5461243c8260c76143c3565b11156124805760405162461bcd60e51b815260206004820152601360248201527250726f76697a696a61207072657669736f6b6160681b60448201526064016109fb565b600c805460ff1916905561231d8282613886565b6005546001600160a01b031690565b606060048054610b7f9061441d565b6124ba6135d0565b612513816040516020016124ce91906144a5565b6040516020818303038152906040528051906020012060405180604001604052806011815260200170525741546f6b656e56322e7365744b796360781b815250613717565b600980546001600160a01b0319166001600160a01b0383169081179091556040517f9f5f8fd48aa64bb8a94c00d6adfc92b215610db623c189eb30698be4581265a490600090a250565b7f00000000000000000000000091991f58804cc5aceca5e87d4667e68d22e082486001600160a01b03166125a35760405162461bcd60e51b81526004016109fb906144d6565b336001600160a01b037f00000000000000000000000091991f58804cc5aceca5e87d4667e68d22e0824816146125eb5760405162461bcd60e51b81526004016109fb90614519565b6040516338260bcb60e11b81526001600160a01b037f00000000000000000000000016eeba545a07a88cdf21cfdde973ee67cdc32000169063704c17969061263790339060040161411f565b602060405180830381865afa158015612654573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126789190614457565b6126945760405162461bcd60e51b81526004016109fb9061454f565b600060105460ff1660068111156126ad576126ad614305565b146126ef5760405162461bcd60e51b815260206004820152601260248201527152617a6472757a6974657620762074656b7560701b60448201526064016109fb565b61274e8484848460405160200161270994939291906145b4565b6040516020818303038152906040528051906020012060405180604001604052806011815260200170525741546f6b656e56322e7072656e6f7360781b815250613717565b600e805460ff19166001179055612766848484613571565b600e805460ff191690556040516001600160a01b0380851691908616907f3317fbec254084023eda084601748dbfa751fb226b84fb928b888a1905067c55906127b2908690869061440f565b60405180910390a350505050565b600780546127cd9061441d565b80601f01602080910402602001604051908101604052809291908181526020018280546127f99061441d565b80156128465780601f1061281b57610100808354040283529160200191612846565b820191906000526020600020905b81548152906001019060200180831161282957829003601f168201915b505050505081565b600033610cf3818585613571565b600061232d6138bc565b7f00000000000000000000000091991f58804cc5aceca5e87d4667e68d22e082486001600160a01b03166128ac5760405162461bcd60e51b81526004016109fb906144d6565b336001600160a01b037f00000000000000000000000091991f58804cc5aceca5e87d4667e68d22e0824816146128f45760405162461bcd60e51b81526004016109fb90614519565b6040516338260bcb60e11b81526001600160a01b037f00000000000000000000000016eeba545a07a88cdf21cfdde973ee67cdc32000169063704c17969061294090339060040161411f565b602060405180830381865afa15801561295d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129819190614457565b61299d5760405162461bcd60e51b81526004016109fb9061454f565b6129a5613490565b600360105460ff1660068111156129be576129be614305565b14612a0a5760405162461bcd60e51b815260206004820152601c60248201527b273490383934b83930bb363532b737903d30903837ba393234ba32bb60211b60448201526064016109fb565b60145442101580612a1b5750601d54155b612a5f5760405162461bcd60e51b8152602060048201526015602482015274526f6b207a612075676f766f72207365207465636560581b60448201526064016109fb565b80612a7c5760405162461bcd60e51b81526004016109fb90614584565b6010805460ff19166006179055601b819055601254601c54612aa7916001600160a01b0316906136e1565b601f548015612b615780601e6000828254612ac291906143b0565b92505081905550612b617f00000000000000000000000076e388cf49d12262808651e35d6fd296c1d4433f6001600160a01b031663469048406040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b4e9190614720565b6013546001600160a01b031690836136b5565b6011546040518381527f246b68f75a0f7ec8f7358217be89ea2805600b63529f8ca499081835d612b53f9060200160405180910390a250610e1e613504565b6040516338260bcb60e11b81526001600160a01b037f00000000000000000000000016eeba545a07a88cdf21cfdde973ee67cdc32000169063704c179690612bec90339060040161411f565b602060405180830381865afa158015612c09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c2d9190614457565b612c495760405162461bcd60e51b81526004016109fb90614479565b600a805460ff60a01b1916600160a01b17905560405133907f481d73db1c84a4cd0734a718818b266e3b59f2e485d8ba806e15763777d9d00690600090a2565b600060105460ff166006811115612ca257612ca2614305565b14612ce55760405162461bcd60e51b815260206004820152601360248201527252617a6472757a69746576207a65207465636560681b60448201526064016109fb565b600a546001600160a01b0316612d365760405162461bcd60e51b8152602060048201526016602482015275537265647374766f207365206e6920736b6f76616e6f60501b60448201526064016109fb565b600a54600160a01b900460ff1615612d605760405162461bcd60e51b81526004016109fb9061473d565b602054421015612dc05760405162461bcd60e51b815260206004820152602560248201527f506f207072656b6c696375206e6f7661207a616874657661207365206e69206d6044820152646f676f636160d81b60648201526084016109fb565b6000612dcb33611e4f565b9050612328612dd960025490565b612de391906143c3565b612def826127106143c3565b1015612e3b5760405162461bcd60e51b815260206004820152601b60248201527a141bdd1c99589b9a5a081a99481d9cd85a880e4c080948195b9bdd602a1b60448201526064016109fb565b60118054906000612e4b8361476d565b90915550506010805460ff1916600117905560128054336001600160a01b031990911617905560408051631f209df760e11b815290516001600160a01b037f00000000000000000000000076e388cf49d12262808651e35d6fd296c1d4433f1691633e413bee9160048083019260209291908290030181865afa158015612ed6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612efa9190614720565b601380546001600160a01b0319166001600160a01b0392909216919091179055612f24601e6134ab565b612f2e90426143fc565b601455600060158190556016819055601781905560188190556019819055601a819055601c819055601d819055601e819055601f556011546040518281523391907f7e0520c3144535d11130bf88d1bed98f7c8a938aa78147d18d20f375a99171ba9060200160405180910390a350565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b612fd2613490565b6011546000908152602160205260409020600360105460ff166006811115612ffc57612ffc614305565b036130ce576001810154610100900460ff16156130595760405162461bcd60e51b815260206004820152601b60248201527a2ab3b7bb37b9103532903d32903134b61037b13930bb3730bb30b760291b60448201526064016109fb565b60145442106130a55760405162461bcd60e51b8152602060048201526018602482015277149bdac81e98481d59dbdd9bdc881a99481c1bdd195ad95b60421b60448201526064016109fb565b6010805460ff191660041790556130bc601e6134ab565b6130c690426143fc565b601455613128565b600460105460ff1660068111156130e7576130e7614305565b146131285760405162461bcd60e51b815260206004820152601160248201527027349031b0b9b0903d30903ab3b7bb37b960791b60448201526064016109fb565b6012546001600160a01b0316330361317b5760405162461bcd60e51b81526020600482015260166024820152755370726f7a6974656c6a206e652075676f7661726a6160501b60448201526064016109fb565b600061318633611e4f565b116131d15760405162461bcd60e51b815260206004820152601b60248201527a1559dbdd985c9a98481b185a1adbc81a5b595d1b9a5ac8195b9bdd602a1b60448201526064016109fb565b601154600090815260226020908152604080832033845290915290205460ff161561322d5760405162461bcd60e51b815260206004820152600c60248201526b1699481d59dbdd985c9a985b60a21b60448201526064016109fb565b60115460009081526022602090815260408083203384529091528120805460ff1916600117905581549082906132628361476d565b9091555050601354613283906001600160a01b03163330631dcd65006134d7565b6011546040513391907f91c60199e9bb6e772b5ba372bd886eaf70d847ebaa965a97a1acba93b87698e590600090a350610b6e613504565b6132c36135d0565b6001600160a01b0381166132ed576000604051631e4fbdf760e01b81526004016109fb919061411f565b610e1e816138e2565b7f00000000000000000000000091991f58804cc5aceca5e87d4667e68d22e082486001600160a01b031661333c5760405162461bcd60e51b81526004016109fb906144d6565b336001600160a01b037f00000000000000000000000091991f58804cc5aceca5e87d4667e68d22e0824816146133845760405162461bcd60e51b81526004016109fb90614519565b6040516338260bcb60e11b81526001600160a01b037f00000000000000000000000016eeba545a07a88cdf21cfdde973ee67cdc32000169063704c1796906133d090339060040161411f565b602060405180830381865afa1580156133ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134119190614457565b61342d5760405162461bcd60e51b81526004016109fb9061454f565b610e1e816040516020016134419190614613565b604051602081830303815290604052805190602001206040518060400160405280601b81526020017a525741546f6b656e56322e757064617465417373657456616c756560281b815250613602565b613498613934565b60026134a86134a561395a565b90565b55565b60006134b64661397e565b6134cc576134c782620151806143c3565b610cf9565b610cf982603c6143c3565b6134e58484848460016139c7565b61138a5783604051635274afe760e01b81526004016109fb919061411f565b60016134a86134a561395a565b61351e8383836001613a39565b505050565b600061352f8484612f9f565b905060001981101561138a578181101561356257828183604051637dc7a0d960e11b81526004016109fb93929190614786565b61138a84848484036000613a39565b6001600160a01b03831661359b576000604051634b637e8f60e11b81526004016109fb919061411f565b6001600160a01b0382166135c557600060405163ec442f0560e01b81526004016109fb919061411f565b61351e838383613b00565b336135d9612494565b6001600160a01b031614610b6e573360405163118cdaa760e01b81526004016109fb919061411f565b6000828152600660205260409020541561364e5760405162461bcd60e51b815260206004820152600d60248201526c5a65206e61706f766564616e6f60981b60448201526064016109fb565b600061365861285c565b61366290426143fc565b60008481526006602052604090208190559050827f63a0d065f46e07e30a4f246d28eb53f839982100439173db92dbd5700ab37c1583836136a662093a80826143fc565b604051611c54939291906147a7565b6136c28383836001613ed2565b61351e5782604051635274afe760e01b81526004016109fb919061411f565b6001600160a01b03821661370b576000604051634b637e8f60e11b81526004016109fb919061411f565b61231d82600083613b00565b600082815260066020526040812054908190036137465760405162461bcd60e51b81526004016109fb906146ca565b8042101561378c5760405162461bcd60e51b815260206004820152601360248201527216985b5a5ac81cd9481b9a481c1bdd195ad95b606a1b60448201526064016109fb565b61379962093a80826143fc565b4211156137dd5760405162461bcd60e51b81526020600482015260126024820152714e61706f766564206a6520706f74656b6c6160701b60448201526064016109fb565b600083815260066020526040808220919091555183907ffac4537038ebc9eaa00d86a88a6c2e268012d306f6442966aab36014a195432390611c549085906140ab565b60008061382c60025490565b61383985620f42406143c3565b61384391906143da565b905082600003613854579050610cf9565b6000600261386285846143fc565b61386c91906143da565b905081811161387b578161387d565b805b95945050505050565b6001600160a01b0382166138b057600060405163ec442f0560e01b81526004016109fb919061411f565b61231d60008383613b00565b60006138c74661397e565b6138d4576202a3006138d8565b6102585b62ffffff16905090565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b61393c613f38565b15610b6e57604051633ee5aeb560e01b815260040160405180910390fd5b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0090565b6000816103af148061399257508162aa36a7145b8061399f57508162088bb0145b806139ac57508162014a34145b806139b957508162066eee145b80610cf9575050617a691490565b6040516323b872dd60e01b60008181526001600160a01b038781166004528616602452604485905291602083606481808c5af192506001600051148316613a27578383151615613a1a573d6000823e3d81fd5b6000883b113d1516831692505b60405250600060605295945050505050565b6001600160a01b038416613a6357600060405163e602df0560e01b81526004016109fb919061411f565b6001600160a01b038316613a8d576000604051634a1406b160e11b81526004016109fb919061411f565b6001600160a01b038085166000908152600160209081526040808320938716835292905220829055801561138a57826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040516127b291815260200190565b6009546001600160a01b03848116159184821615911615801590613b22575080155b15613ca257600954604051633af32abf60e01b81526001600160a01b0390911690633af32abf90613b5790879060040161411f565b602060405180830381865afa158015613b74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b989190614457565b613be15760405162461bcd60e51b815260206004820152601a602482015279283932b532b6b734b59037349025aca190383932bb32b93532b760311b60448201526064016109fb565b81613ca257600954604051633af32abf60e01b81526001600160a01b0390911690633af32abf90613c1690889060040161411f565b602060405180830381865afa158015613c33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c579190614457565b613ca25760405162461bcd60e51b815260206004820152601c60248201527b2837b9b4b63530ba32b6351037349025aca190383932bb32b93532b760211b60448201526064016109fb565b81613ec057600a54600160a01b900460ff1615613cd15760405162461bcd60e51b81526004016109fb9061473d565b7f000000000000000000000000000000000000000000000000000000006ad50401421015613d415760405162461bcd60e51b815260206004820181905260248201527f537265647374766f207365206e6920616b7469766e6f207a61207072656e6f7360448201526064016109fb565b80613ec057600060105460ff166006811115613d5f57613d5f614305565b14613df6577f00000000000000000000000076e388cf49d12262808651e35d6fd296c1d4433f6001600160a01b0316856001600160a01b031614613df15760405162461bcd60e51b815260206004820152602360248201527f52617a6472757a6974657620762074656b753a207072656e6f73206e69206d6f604482015262676f6360e81b60648201526084016109fb565b613ec0565b7f00000000000000000000000076e388cf49d12262808651e35d6fd296c1d4433f6001600160a01b0316856001600160a01b03161480613e6757507f00000000000000000000000076e388cf49d12262808651e35d6fd296c1d4433f6001600160a01b0316846001600160a01b0316145b80613e745750600e5460ff165b613ec05760405162461bcd60e51b815260206004820181905260248201527f5072656e6f732073616d6f207072656b20525741204d61726b6574706c61636560448201526064016109fb565b613ecb858585613f4e565b5050505050565b60405163a9059cbb60e01b60008181526001600160a01b038616600452602485905291602083604481808b5af192506001600051148316613f2c578383151615613f1f573d6000823e3d81fd5b6000873b113d1516831692505b60405250949350505050565b60006002613f476134a561395a565b5414919050565b6001600160a01b038316613f79578060026000828254613f6e91906143fc565b90915550613fd89050565b6001600160a01b03831660009081526020819052604090205481811015613fb95783818360405163391434e360e21b81526004016109fb93929190614786565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b038216613ff457600280548290039055614013565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161405891815260200190565b60405180910390a3505050565b6000815180845260005b8181101561408b5760208185018101518683018201520161406f565b506000602082860101526020601f19601f83011685010191505092915050565b6020815260006140be6020830184614065565b9392505050565b6000602082840312156140d757600080fd5b5035919050565b6001600160a01b0381168114610e1e57600080fd5b6000806040838503121561410657600080fd5b8235614111816140de565b946020939093013593505050565b6001600160a01b0391909116815260200190565b60008060006060848603121561414857600080fd5b8335614153816140de565b92506020840135614163816140de565b929592945050506040919091013590565b60006020828403121561418657600080fd5b81356140be816140de565b600080600080608085870312156141a757600080fd5b84356141b2816140de565b935060208501356141c2816140de565b93969395505050506040820135916060013590565b6000806000606084860312156141ec57600080fd5b505081359360208301359350604090920135919050565b60008060006060848603121561421857600080fd5b8335614223816140de565b95602085013595506040909401359392505050565b60008060006040848603121561424d57600080fd5b8335925060208401356001600160401b038082111561426b57600080fd5b818601915086601f83011261427f57600080fd5b81358181111561428e57600080fd5b8760208285010111156142a057600080fd5b6020830194508093505050509250925092565b600080604083850312156142c657600080fd5b50508035926020909101359150565b600080604083850312156142e857600080fd5b8235915060208301356142fa816140de565b809150509250929050565b634e487b7160e01b600052602160045260246000fd5b602081016007831061433d57634e487b7160e01b600052602160045260246000fd5b91905290565b6000806040838503121561435657600080fd5b8235614361816140de565b915060208301356142fa816140de565b6020808252600f908201526e29b0b6b79039b83937bd34ba32b63560891b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b81810381811115610cf957610cf961439a565b8082028115828204841417610cf957610cf961439a565b6000826143f757634e487b7160e01b600052601260045260246000fd5b500490565b80820180821115610cf957610cf961439a565b918252602082015260400190565b600181811c9082168061443157607f821691505b60208210810361445157634e487b7160e01b600052602260045260246000fd5b50919050565b60006020828403121561446957600080fd5b815180151581146140be57600080fd5b60208082526012908201527129b0b6b7902aa7a9299037b832b930ba32b960711b604082015260600190565b6040808252600690820152657365744b796360d01b60608201526001600160a01b0391909116602082015260800190565b60208082526023908201527f537265647374766f206e696d61207a61706973616e656761206f7665726974656040820152626c6a6160e81b606082015260800190565b6020808252601c908201527b53616d6f206f7665726974656c6a207465676120737265647374766160201b604082015260600190565b6020808252601b908201527a27bb32b934ba32b635103734903b32b1903837b7b13630b9b1b2b760291b604082015260600190565b60208082526016908201527527b23a34b9903634b9ba34b73290353290373ab532b760511b604082015260600190565b60a0808252600690820152657072656e6f7360d01b60c08201526001600160a01b0394851660208201529290931660408301526060820152608081019190915260e00190565b60006020828403121561460c57600080fd5b5051919050565b60408082526010908201526f757064617465417373657456616c756560801b6060820152602081019190915260800190565b60208082526010908201526f43656e69746576206a65206e756a6e6160801b604082015260600190565b60208082526017908201527627b23a34b9903837b937b1b4b63090353290373ab532b760491b604082015260600190565b60208082526010908201526f27b7363c902d25903b32b934b334b2b960811b604082015260600190565b6020808252600d908201526c4e69206e61706f766564616e6f60981b604082015260600190565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b60006020828403121561473257600080fd5b81516140be816140de565b602080825260169082015275537265647374766f206a65207a616d727a6e6a656e6f60501b604082015260600190565b60006001820161477f5761477f61439a565b5060010190565b6001600160a01b039390931683526020830191909152604082015260600190565b6060815260006147ba6060830186614065565b6020830194909452506040015291905056fea264697066735822122071e2e8c6e65414f5179909af364e1877e212c555359c2a822836fa6a392fa1c064736f6c63430008180033