Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0x183636e8611766Aea2a92a7ad8a29079873e2E04
Balance 0 ETH
Nonce 1
Code Size 18223 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

18223 bytes
0x608060405234801561001057600080fd5b50600436106103615760003560e01c806387989f6e116101c8578063c8d7624411610104578063e6116cfd116100a2578063eddd0d9c1161007c578063eddd0d9c1461089f578063f195341e146108b2578063f2fde38b146108c5578063f5f92a6f146108d857600080fd5b8063e6116cfd14610859578063ec8469b71461086c578063edd41e0a1461088c57600080fd5b8063ce3dca77116100de578063ce3dca77146107e5578063d3c03c00146107f8578063dade41551461081b578063e162b3671461084657600080fd5b8063c8d7624414610797578063cb301971146107aa578063cc25ac55146107bd57600080fd5b8063a2fbaff411610171578063b6c571701161014b578063b6c571701461073d578063ba28987314610750578063bc1c0fb61461077b578063c115bef51461078457600080fd5b8063a2fbaff4146106e4578063b24fdf4e146106f7578063b60e73db1461071757600080fd5b80638baa353b116101a25780638baa353b1461069e5780638da5cb5b146106be5780639c5b2eea146106d157600080fd5b806387989f6e1461066557806389a302711461066e57806389b8db551461069557600080fd5b8063455fd5d2116102a257806359ac83251161024057806366c863081161021a57806366c86308146105ca57806367e1af00146105dd57806369dc9ff3146105f057806382eaa2c91461065257600080fd5b806359ac83251461058b5780635e5f7ea0146105ae578063663ef651146105b757600080fd5b806350ab331b1161027c57806350ab331b1461053d578063533c0c42146105455780635386a71d1461055857806358b1f29c1461057857600080fd5b8063455fd5d2146104a157806347f9aa9f146104aa57806350729e6b146104ff57600080fd5b806331b35ea51161030f5780633adc8360116102e95780633adc83601461044b5780633b58f49a146104545780633b72e42c146104675780633f680e451461048e57600080fd5b806331b35ea5146103d95780633751954f146103f957806338e14c4b1461043857600080fd5b80631c318adf116103405780631c318adf146103aa5780631dcb573a146103b35780632e7cc7b2146103c657600080fd5b806281d2ef146103665780630a1022261461037b5780630e3a7d2c14610397575b600080fd5b610379610374366004614010565b6108e0565b005b61038460045481565b6040519081526020015b60405180910390f35b6103796103a536600461403e565b610982565b61038460085481565b6103796103c1366004614076565b610d90565b6103796103d4366004614010565b610e09565b6103846103e7366004614010565b60126020526000908152604090205481565b6104207f0000000000000000000000006c302e35a5de6ae6de9bc4c186255dd1d92bde4881565b6040516001600160a01b03909116815260200161038e565b610384610446366004614093565b610e7a565b61038460025481565b610379610462366004614010565b610eb9565b6104207f0000000000000000000000006373c7a7a5168ee5c377a44f09f9b20f6ed2e21a81565b61037961049c366004614010565b610f19565b61038460035481565b6104df6104b8366004614076565b600f6020526000908152604090208054600182015460028301546003909301549192909184565b60408051948552602085019390935291830152606082015260800161038e565b61052d61050d3660046140bf565b601760209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161038e565b6103846111c7565b6104206105533660046140ef565b61139c565b61056b610566366004614076565b6113d4565b60405161038e9190614149565b610379610586366004614010565b61144b565b61052d610599366004614010565b601a6020526000908152604090205460ff1681565b61038460065481565b6103796105c5366004614010565b6117e1565b6103796105d836600461415d565b61196e565b600a54610420906001600160a01b031681565b61062d6105fe366004614076565b600d60205260009081526040902080546001909101546001600160a01b03821691600160a01b900460ff169083565b604080516001600160a01b03909416845291151560208401529082015260600161038e565b610379610660366004614010565b611b94565b61038460015481565b6104207f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b61038460075481565b6106b16106ac366004614076565b611bfd565b60405161038e9190614196565b600954610420906001600160a01b031681565b6103846106df3660046141c7565b611c4f565b6103796106f2366004614076565b61211c565b610384610705366004614010565b60116020526000908152604090205481565b61072a610725366004614010565b61234e565b60405161038e97969594939291906142a1565b600b54610420906001600160a01b031681565b61038461075e3660046140bf565b601860209081526000928352604080842090915290825290205481565b61038460055481565b6103846107923660046140ef565b61242d565b6103796107a5366004614307565b61245e565b6103796107b8366004614342565b612782565b6107d06107cb366004614010565b612be2565b6040805192835260208301919091520161038e565b6103796107f3366004614010565b612cff565b61052d610806366004614076565b60106020526000908152604090205460ff1681565b6103846108293660046140bf565b601660209081526000928352604080842090915290825290205481565b6103796108543660046140bf565b612d5f565b610379610867366004614076565b612f16565b61038461087a366004614010565b60136020526000908152604090205481565b61037961089a366004614010565b612f92565b6103796108ad366004614010565b612ff2565b6104206108c03660046140ef565b613052565b6103796108d3366004614076565b61306e565b6103796130eb565b6009546001600160a01b0316331461090b576040516330cd747160e01b815260040160405180910390fd5b6019811115610946576040517f58d620b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018190556040518181527f131e1261c6b52e80038b6ec8bc9eebb015e73beeb5a966ad823d01c888c07c64906020015b60405180910390a150565b6000838152600e60209081526040808320815181546101209481028201850190935261010081018381529093919284928491908401828280156109ee57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116109d0575b505050918352505060018201546001600160a01b03908116602083015260028301549081166040830152606090910190600160a01b900460ff166004811115610a3957610a39614111565b6004811115610a4a57610a4a614111565b8152602001600382018054610a5e90614413565b80601f0160208091040260200160405190810160405280929190818152602001828054610a8a90614413565b8015610ad75780601f10610aac57610100808354040283529160200191610ad7565b820191906000526020600020905b815481529060010190602001808311610aba57829003601f168201915b5050509183525050600482015460208201526005820154604082015260069091015460ff1615156060909101529050600181606001516004811115610b1e57610b1e614111565b14610b3c57604051631458625d60e11b815260040160405180910390fd5b60208101516001600160a01b03163314610b695760405163f87c866960e01b815260040160405180910390fd5b6001600160a01b03831660009081526010602052604090205460ff16610ba257604051638775fd1d60e01b815260040160405180910390fd5b600084815260116020526040902054606490610bbf90849061445d565b1115610bf7576040517ff287e19000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316331480610c23575080604001516001600160a01b0316836001600160a01b0316145b15610c5a576040517ff984d43b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008481526016602090815260408083206001600160a01b03871684529091529020548015610cb5576040517f4c3a3ec000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008581526016602090815260408083206001600160a01b03881684528252808320869055878352601190915281208054859290610cf490849061445d565b909155505060008581526014602090815260408083208054600180820183559185528385200180546001600160a01b0319166001600160a01b038a16908117909155898552601584528285208054928301815585529383902001869055805192835290820185905286917f3b0c3ce2408727dbca95180acaf270c88dfac5acc91e20a692bdd67c40797b0d910160405180910390a25050505050565b6009546001600160a01b03163314610dbb576040516330cd747160e01b815260040160405180910390fd5b600a80546001600160a01b0319166001600160a01b0383169081179091556040519081527fd144c9fa3b9a42323743289b36210c130953eb0290854e07e2d3b38a972b987390602001610977565b6009546001600160a01b03163314610e34576040516330cd747160e01b815260040160405180910390fd5b600580549082905560408051828152602081018490527f085570e45e5089c87296fe3ddc21ebd69b73d6d8e168d71162d0b7507580dc1691015b60405180910390a15050565b6009546000906001600160a01b03163314610ea8576040516330cd747160e01b815260040160405180910390fd5b610eb28383613270565b9392505050565b6009546001600160a01b03163314610ee4576040516330cd747160e01b815260040160405180910390fd5b60078190556040518181527fa5324cc7956c4d8e6e433de4d6a5e735c98fa2f3af113a918f33a0f94e22a96790602001610977565b610f216134e1565b6000818152600e6020908152604080832081518154610120948102820185019093526101008101838152909391928492849190840182828015610f8d57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610f6f575b505050918352505060018201546001600160a01b03908116602083015260028301549081166040830152606090910190600160a01b900460ff166004811115610fd857610fd8614111565b6004811115610fe957610fe9614111565b8152602001600382018054610ffd90614413565b80601f016020809104026020016040519081016040528092919081815260200182805461102990614413565b80156110765780601f1061104b57610100808354040283529160200191611076565b820191906000526020600020905b81548152906001019060200180831161105957829003601f168201915b5050509183525050600482015460208201526005820154604082015260069091015460ff16151560609091015290506003816060015160048111156110bd576110bd614111565b146110f4576040517f24161af600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208101516001600160a01b031633146111215760405163f87c866960e01b815260040160405180910390fd5b600082815260126020526040902054421015611169576040517fbec5f0d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260136020526040902054156111af576040517fc2c7c2cf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111b88261353f565b50506111c46001600055565b50565b6002546000901561121457600a54600254611214916001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48811692339291909116906139c0565b6040516370a0823160e01b81523360048201526000907f0000000000000000000000006c302e35a5de6ae6de9bc4c186255dd1d92bde486001600160a01b0316906370a0823190602401602060405180830381865afa15801561127b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061129f9190614475565b11156112d7576040517f6ae387e100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516335313c2160e11b81523360048201527f0000000000000000000000006c302e35a5de6ae6de9bc4c186255dd1d92bde486001600160a01b031690636a627842906024016020604051808303816000875af115801561133d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113619190614475565b60405181815290915033907f6b3849217980a0c0ca50eb90017e531044f102c347eebcaafd2dc4ec751ef3b79060200160405180910390a290565b601960205281600052604060002081815481106113b857600080fd5b6000918252602090912001546001600160a01b03169150829050565b6001600160a01b038181166000908152600d60209081526040808320815160608101835281549586168152600160a01b90950460ff16158015938601939093526001015490840152909190611445576040818101516000908152600e6020522060020154600160a01b900460ff1691505b50919050565b6114536134e1565b6000818152600e60209081526040808320815181546101209481028201850190935261010081018381529093919284928491908401828280156114bf57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116114a1575b505050918352505060018201546001600160a01b03908116602083015260028301549081166040830152606090910190600160a01b900460ff16600481111561150a5761150a614111565b600481111561151b5761151b614111565b815260200160038201805461152f90614413565b80601f016020809104026020016040519081016040528092919081815260200182805461155b90614413565b80156115a85780601f1061157d576101008083540402835291602001916115a8565b820191906000526020600020905b81548152906001019060200180831161158b57829003601f168201915b505050918352505060048201546020820152600582015460408083019190915260069092015460ff1615156060909101528101519091506001600160a01b0316331461160657604051627013f760e31b815260040160405180910390fd5b60208101516001600160a01b0316158015906116255750428160a00151115b80611646575060018160600151600481111561164357611643614111565b14155b8061166a575060208101516001600160a01b031615801561166a5750428160c00151115b156116a1576040517f58f00bd300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208101516001600160a01b0316156116e3576020808201516001600160a01b03166000908152600f909152604081208054916116dd8361448e565b91905055505b6000828152600e60205260408120600201805460ff60a01b1916740400000000000000000000000000000000000000001790555b6000838152601960205260409020548110156117a857600083815260196020526040812080548390811061174d5761174d6144a5565b6000918252602080832091909101548683526018825260408084206001600160a01b039092168085529190925281832080549390559085015190925061179590839083613a77565b5050806117a1906144bb565b9050611717565b50604051829033907fc85508b437f67f29a4e18870f0631c52ceee4a66c63eccf4f11188ee8cc09c0190600090a3506111c46001600055565b60016000828152600e6020526040902060020154600160a01b900460ff16600481111561181057611810614111565b1461182e57604051631458625d60e11b815260040160405180910390fd5b6000818152600e60205260409020600101546001600160a01b0316156118675760405163047d97a960e31b815260040160405180910390fd5b3360009081526010602052604090205460ff1661189757604051638775fd1d60e01b815260040160405180910390fd5b336000908152600f6020526040902054600454116118c85760405163745219b360e01b815260040160405180910390fd5b600081815260176020908152604080832033845290915290205460ff161515600103611920576040517f5303ed8200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152601760209081526040808320338085529252808320805460ff191660011790555183927fdbd322a3337532a13c9b421a6a2866dc81fd0c07eba453d21e5b1ce2a824a02f91a350565b6119766134e1565b6000838152600e60209081526040808320815181546101209481028201850190935261010081018381529093919284928491908401828280156119e257602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116119c4575b505050918352505060018201546001600160a01b03908116602083015260028301549081166040830152606090910190600160a01b900460ff166004811115611a2d57611a2d614111565b6004811115611a3e57611a3e614111565b8152602001600382018054611a5290614413565b80601f0160208091040260200160405190810160405280929190818152602001828054611a7e90614413565b8015611acb5780601f10611aa057610100808354040283529160200191611acb565b820191906000526020600020905b815481529060010190602001808311611aae57829003601f168201915b505050918352505060048201546020820152600582015460408083019190915260069092015460ff1615156060909101528101519091506001600160a01b03163314611b43576040517f8858596300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600181606001516004811115611b5b57611b5b614111565b14611b7957604051631458625d60e11b815260040160405180910390fd5b611b84848484613ac0565b50611b8f6001600055565b505050565b6009546001600160a01b03163314611bbf576040516330cd747160e01b815260040160405180910390fd5b600480549082905560408051828152602081018490527f648ffb12430ecbe2df85de53f1e896e7f07ff56ea8b721c9abf91bcc06133f3d9101610e6e565b611c05613e71565b6001600160a01b0382166000908152600c602052604090819020815160808101928390529160049082845b815481526020019060010190808311611c305750505050509050919050565b6000611c596134e1565b6040516370a0823160e01b81523360048201527f0000000000000000000000006c302e35a5de6ae6de9bc4c186255dd1d92bde486001600160a01b0316906370a0823190602401602060405180830381865afa158015611cbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ce19190614475565b600003611cf257611cf06111c7565b505b600754821015611d2e576040517fa8b9c37100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600860008154611d3d906144bb565b909155505060085483156120385760005b84811015611ed9576000600d6000888885818110611d6e57611d6e6144a5565b9050602002016020810190611d839190614076565b6001600160a01b0390811682526020808301939093526040918201600020825160608101845281549283168152600160a01b90920460ff161580159483019490945260010154918101919091529150611def576040516364748e3960e11b815260040160405180910390fd5b80516001600160a01b03163314611e1857604051627013f760e31b815260040160405180910390fd5b6001600d6000898986818110611e3057611e306144a5565b9050602002016020810190611e459190614076565b6001600160a01b03166001600160a01b0316815260200190815260200160002060000160146101000a81548160ff02191690831515021790555082600d6000898986818110611e9657611e966144a5565b9050602002016020810190611eab9190614076565b6001600160a01b0316815260208101919091526040016000206001015550611ed2816144bb565b9050611d4e565b50821561201d5760008381526012602052604090205442101580611f1757506000838152600e60205260409020600201546001600160a01b03163314155b15611f4e576040517f78a7fb4e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600e60205260408082206001908101548484529190922090910180546001600160a01b0319166001600160a01b03909216919091179055600354611f97904261445d565b6000828152600e6020908152604080832060040193909355858252601490528181208382529190208154611fcb9290613e8f565b5060008381526015602052604080822083835291208154611fec9290613e8f565b50600083815260116020908152604080832054848452818420558583526013909152902081905561201d8382613bb2565b6000818152600e60205260409020612036908686613edf565b505b6000818152600e60205260409020600201805474ffffffffffffffffffffffffffffffffffffffffff19163360ff60a01b191617600160a01b17905560065461208290429061445d565b6000828152600e602052604090206005015581156120c5576120c581837f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48613ac0565b336001600160a01b031683827f3d364f58fd792583625c7fbc2f4f24f77d3d2df986e7f6c4de06ba1ba02e59cf88886040516121029291906144d4565b60405180910390a46121146001600055565b949350505050565b6009546001600160a01b03163314612147576040516330cd747160e01b815260040160405180910390fd5b600b546001600160a01b03161561218a576040517fa741a04500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b80546001600160a01b0319166001600160a01b03831617905560005b600b60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061221f9190614475565b81101561234a57600b546040517f6352211e00000000000000000000000000000000000000000000000000000000815260048101839052612339916001600160a01b031690636352211e90602401602060405180830381865afa15801561228a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122ae9190614522565b600b546040517f05c58df2000000000000000000000000000000000000000000000000000000008152600481018590526001600160a01b03909116906305c58df290602401602060405180830381865afa158015612310573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123349190614475565b613270565b50612343816144bb565b90506121a8565b5050565b600e602052600090815260409020600181015460028201546003830180546001600160a01b039384169493831693600160a01b90930460ff1692919061239390614413565b80601f01602080910402602001604051908101604052809291908181526020018280546123bf90614413565b801561240c5780601f106123e15761010080835404028352916020019161240c565b820191906000526020600020905b8154815290600101906020018083116123ef57829003601f168201915b50505050600483015460058401546006909401549293909290915060ff1687565b6015602052816000526040600020818154811061244957600080fd5b90600052602060002001600091509150505481565b6000828152600e60209081526040808320815181546101209481028201850190935261010081018381529093919284928491908401828280156124ca57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116124ac575b505050918352505060018201546001600160a01b03908116602083015260028301549081166040830152606090910190600160a01b900460ff16600481111561251557612515614111565b600481111561252657612526614111565b815260200160038201805461253a90614413565b80601f016020809104026020016040519081016040528092919081815260200182805461256690614413565b80156125b35780601f10612588576101008083540402835291602001916125b3565b820191906000526020600020905b81548152906001019060200180831161259657829003601f168201915b5050509183525050600482015460208201526005820154604082015260069091015460ff16151560609091015290506002816060015160048111156125fa576125fa614111565b14612631576040517fb26b5a6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408101516001600160a01b0316331461265d57604051627013f760e31b815260040160405180910390fd5b8060e0015115612699576040517f5a4af0c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600e60205260409020600601805460ff1916600117905581156126f2576020808201516001600160a01b03166000908152600f9091526040812060010180549091906126e9906144bb565b90915550612725565b6020808201516001600160a01b03166000908152600f909152604081206002018054909190612720906144bb565b909155505b80604001516001600160a01b031681602001516001600160a01b0316847f841c5619cbe34128658a6ac2bb5abb9a6eebb47950d4667514efe8b67ce907c585604051612775911515815260200190565b60405180910390a4505050565b61278a6134e1565b6000838152600e60209081526040808320815181546101209481028201850190935261010081018381529093919284928491908401828280156127f657602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116127d8575b505050918352505060018201546001600160a01b03908116602083015260028301549081166040830152606090910190600160a01b900460ff16600481111561284157612841614111565b600481111561285257612852614111565b815260200160038201805461286690614413565b80601f016020809104026020016040519081016040528092919081815260200182805461289290614413565b80156128df5780601f106128b4576101008083540402835291602001916128df565b820191906000526020600020905b8154815290600101906020018083116128c257829003601f168201915b5050509183525050600482015460208201526005820154604082015260069091015460ff161515606090910152905060018160600151600481111561292657612926614111565b1461294457604051631458625d60e11b815260040160405180910390fd5b60208101516001600160a01b031633146129715760405163f87c866960e01b815260040160405180910390fd5b600283600481111561298557612985614111565b141580156129a5575060038360048111156129a2576129a2614111565b14155b156129dc576040517f7c599f8000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606081018360048111156129f2576129f2614111565b90816004811115612a0557612a05614111565b905250608081018290526000848152600e60209081526040909120825180518493612a34928492910190613f32565b5060208201516001820180546001600160a01b03199081166001600160a01b039384161790915560408401516002840180549283169190931690811783556060850151929174ffffffffffffffffffffffffffffffffffffffffff191617600160a01b836004811115612aa957612aa9614111565b021790555060808201518051612ac9916003840191602090910190613f87565b5060a0820151600482015560c0820151600582015560e0909101516006909101805460ff19169115159190911790556002836004811115612b0c57612b0c614111565b03612b66576000612b1c8561353f565b6020808401516001600160a01b03166000908152600c909152604090209091508160048110612b4d57612b4d6144a5565b0160008154612b5b906144bb565b90915550612b839050565b600554612b73904261445d565b6000858152601260205260409020555b8381604001516001600160a01b031682602001516001600160a01b03167ffb5bb8637cebbfe3f455d9317d5356931f835691d8ee63bc8cbfd7571177d12486604051612bcf9190614149565b60405180910390a450611b8f6001600055565b60008181526018602090815260408083206001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48168085529083528184205482517f313ce56700000000000000000000000000000000000000000000000000000000815292519093859363313ce56792600480830193928290030181865afa158015612c78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c9c919061453f565b612ca790600a614646565b9050612cb5816103e8614655565b8210612cf957612cc781612710614655565b821015612cd75760019250612cf9565b612ce481620186a0614655565b821015612cf45760029250612cf9565b600392505b50915091565b6009546001600160a01b03163314612d2a576040516330cd747160e01b815260040160405180910390fd5b60068190556040518181527fce6e22835ebf356cf3a20deb5a407d543dffeedb59411be3daa147410760288390602001610977565b6000828152600e60205260409020600201546001600160a01b03163314612d9857604051627013f760e31b815260040160405180910390fd5b6000828152600e60205260409020600101546001600160a01b031615612dd15760405163047d97a960e31b815260040160405180910390fd5b6001600160a01b0381166000908152600f602052604090205460045411612e0b5760405163745219b360e01b815260040160405180910390fd5b60008281526017602090815260408083206001600160a01b038516845290915290205460ff16612e67576040517f807ef7a700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0381166000908152600f602052604081208054909190612e8d906144bb565b909155506000828152600e6020526040902060010180546001600160a01b0319166001600160a01b038316179055600354612ec8904261445d565b6000838152600e602052604080822060040192909255905183916001600160a01b0384169133917f4b0bed974df4459d53356182bc0966683bea5a9eba848cd3095b855459a517bf91a45050565b6009546001600160a01b03163314612f41576040516330cd747160e01b815260040160405180910390fd5b6001600160a01b038116600081815260106020908152604091829020805460ff1916905590519182527fd3e803f2dfdacd206b7d19aa46d847206386d84e3dc6b8de0926e54affa6fddc9101610977565b6009546001600160a01b03163314612fbd576040516330cd747160e01b815260040160405180910390fd5b60038190556040518181527f3dfb4a74af4c292af6b1354e17f1a5383cc3403798e5a3465a12812a308399c390602001610977565b6009546001600160a01b0316331461301d576040516330cd747160e01b815260040160405180910390fd5b60028190556040518181527f97aee230ba41961438e908e115df76fa8113f85a0586d85b19ba5be50e6a227490602001610977565b601460205281600052604060002081815481106113b857600080fd5b6009546001600160a01b03163314613099576040516330cd747160e01b815260040160405180910390fd5b600980546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6040516370a0823160e01b81523260048201527f0000000000000000000000006c302e35a5de6ae6de9bc4c186255dd1d92bde486001600160a01b0316906370a0823190602401602060405180830381865afa15801561314f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131739190614475565b6000036131ac576040517f15fce27a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3233036131e5576040517f09ee12d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600d6020908152604091829020825160608101845281546001600160a01b038116808352600160a01b90910460ff16151593820193909352600190910154928101929092521561324e576040516364748e3960e11b815260040160405180910390fd5b50336000908152600d6020526040902080546001600160a01b03191632179055565b600060038211156132ad576040517fd1459f7900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516370a0823160e01b81526001600160a01b0384811660048301527f0000000000000000000000006373c7a7a5168ee5c377a44f09f9b20f6ed2e21a16906370a0823190602401602060405180830381865afa158015613313573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133379190614475565b6000036133d1576040516335313c2160e11b81526001600160a01b0384811660048301527f0000000000000000000000006373c7a7a5168ee5c377a44f09f9b20f6ed2e21a1690636a627842906024016020604051808303816000875af11580156133a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133ca9190614475565b9050613477565b6040517f03199b250000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301527f0000000000000000000000006373c7a7a5168ee5c377a44f09f9b20f6ed2e21a16906303199b2590602401602060405180830381865afa158015613450573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134749190614475565b90505b6001600160a01b0383166000818152600f602090815260408083206003018690556010825291829020805460ff1916600117905590519182527f2c31044378cc14466459f09320dd4057d7ad6e99b194c0800c78227383a25296910160405180910390a192915050565b6002600054036135385760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b6002600055565b6000818152601a602052604081205460ff1615613588576040517f0e92da9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152601460209081526040808320805482518185028101850190935280835291929091908301828280156135e857602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116135ca575b5050505050905060006015600085815260200190815260200160002080548060200260200160405190810160405280929190818152602001828054801561364e57602002820191906000526020600020905b81548152602001906001019080831161363a575b5050506000878152601a60209081526040808320805460ff19166001179055600e825280832081518154610120948102820185019093526101008101838152979850939693955093508492918491908401828280156136d657602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116136b8575b505050918352505060018201546001600160a01b03908116602083015260028301549081166040830152606090910190600160a01b900460ff16600481111561372157613721614111565b600481111561373257613732614111565b815260200160038201805461374690614413565b80601f016020809104026020016040519081016040528092919081815260200182805461377290614413565b80156137bf5780601f10613794576101008083540402835291602001916137bf565b820191906000526020600020905b8154815290600101906020018083116137a257829003601f168201915b5050509183525050600482015460208201526005820154604082015260069091015460ff16151560609091015290506137f785612be2565b50935060005b600086815260196020526040902054811015613995576000868152601960205260408120805483908110613833576138336144a5565b6000918252602080832091909101548983526018825260408084206001600160a01b0390921680855291909252908220805490839055600154919350919060649061387e9082614674565b6138889084614655565b613892919061468b565b905060006138a08284614674565b600a549091506138bd906001600160a01b03868116911683613a77565b6000805b895181101561395457600060648a83815181106138e0576138e06144a5565b6020026020010151866138f39190614655565b6138fd919061468b565b90506139368b8381518110613914576139146144a5565b602002602001015182896001600160a01b0316613a779092919063ffffffff16565b613940818461445d565b9250508061394d906144bb565b90506138c1565b5060006139618285614674565b602089015190915061397e906001600160a01b0388169083613a77565b5050505050508061398e906144bb565b90506137fd565b50336000908152600f6020526040812080549091906139b39061448e565b9091555092949350505050565b6040516001600160a01b0380851660248301528316604482015260648101829052613a719085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152613c66565b50505050565b6040516001600160a01b038316602482015260448101829052611b8f9084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401613a0d565b613ad56001600160a01b0382163330856139c0565b60008381526018602090815260408083206001600160a01b03851684529091528120549003613b365760008381526019602090815260408220805460018101825590835291200180546001600160a01b0319166001600160a01b0383161790555b60008381526018602090815260408083206001600160a01b038516845290915281208054849290613b6890849061445d565b909155505060405182815283906001600160a01b038316907f05fd9f298229187174fe5cb048a207631aa73738f574b2c2a7b8dcd6da9957e69060200160405180910390a3505050565b60005b600083815260196020526040902054811015613c45576000838152601960205260408120805483908110613beb57613beb6144a5565b6000918252602080832090910154868352601880835260408085206001600160a01b03909316808652928452808520805490869055888652918452808520928552919092529091205550613c3e816144bb565b9050613bb5565b5060008281526019602052604080822083835291208154611b8f9290613e8f565b6000613cbb826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613d4e9092919063ffffffff16565b9050805160001480613cdc575080806020019051810190613cdc91906146ad565b611b8f5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161352f565b6060612114848460008585600080866001600160a01b03168587604051613d7591906146ca565b60006040518083038185875af1925050503d8060008114613db2576040519150601f19603f3d011682016040523d82523d6000602084013e613db7565b606091505b5091509150613dc887838387613dd3565b979650505050505050565b60608315613e42578251600003613e3b576001600160a01b0385163b613e3b5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161352f565b5081612114565b6121148383815115613e575781518083602001fd5b8060405162461bcd60e51b815260040161352f91906146e6565b60405180608001604052806004906020820280368337509192915050565b828054828255906000526020600020908101928215613ecf5760005260206000209182015b82811115613ecf578254825591600101919060010190613eb4565b50613edb929150613ffb565b5090565b828054828255906000526020600020908101928215613ecf579160200282015b82811115613ecf5781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613eff565b828054828255906000526020600020908101928215613ecf579160200282015b82811115613ecf57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613f52565b828054613f9390614413565b90600052602060002090601f016020900481019282613fb55760008555613ecf565b82601f10613fce57805160ff1916838001178555613ecf565b82800160010185558215613ecf579182015b82811115613ecf578251825591602001919060010190613fe0565b5b80821115613edb5760008155600101613ffc565b60006020828403121561402257600080fd5b5035919050565b6001600160a01b03811681146111c457600080fd5b60008060006060848603121561405357600080fd5b83359250602084013561406581614029565b929592945050506040919091013590565b60006020828403121561408857600080fd5b8135610eb281614029565b600080604083850312156140a657600080fd5b82356140b181614029565b946020939093013593505050565b600080604083850312156140d257600080fd5b8235915060208301356140e481614029565b809150509250929050565b6000806040838503121561410257600080fd5b50508035926020909101359150565b634e487b7160e01b600052602160045260246000fd5b6005811061414557634e487b7160e01b600052602160045260246000fd5b9052565b602081016141578284614127565b92915050565b60008060006060848603121561417257600080fd5b8335925060208401359150604084013561418b81614029565b809150509250925092565b60808101818360005b60048110156141be57815183526020928301929091019060010161419f565b50505092915050565b600080600080606085870312156141dd57600080fd5b843567ffffffffffffffff808211156141f557600080fd5b818701915087601f83011261420957600080fd5b81358181111561421857600080fd5b8860208260051b850101111561422d57600080fd5b6020928301999098509187013596604001359550909350505050565b60005b8381101561426457818101518382015260200161424c565b83811115613a715750506000910152565b6000815180845261428d816020860160208601614249565b601f01601f19169290920160200192915050565b6001600160a01b0388811682528716602082015260006142c46040830188614127565b60e060608301526142d860e0830187614275565b60808301959095525060a0810192909252151560c090910152949350505050565b80151581146111c457600080fd5b6000806040838503121561431a57600080fd5b8235915060208301356140e4816142f9565b634e487b7160e01b600052604160045260246000fd5b60008060006060848603121561435757600080fd5b8335925060208401356005811061436d57600080fd5b9150604084013567ffffffffffffffff8082111561438a57600080fd5b818601915086601f83011261439e57600080fd5b8135818111156143b0576143b061432c565b604051601f8201601f19908116603f011681019083821181831017156143d8576143d861432c565b816040528281528960208487010111156143f157600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b600181811c9082168061442757607f821691505b60208210810361144557634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000821982111561447057614470614447565b500190565b60006020828403121561448757600080fd5b5051919050565b60008161449d5761449d614447565b506000190190565b634e487b7160e01b600052603260045260246000fd5b6000600182016144cd576144cd614447565b5060010190565b60208082528181018390526000908460408401835b868110156145175782356144fc81614029565b6001600160a01b0316825291830191908301906001016144e9565b509695505050505050565b60006020828403121561453457600080fd5b8151610eb281614029565b60006020828403121561455157600080fd5b815160ff81168114610eb257600080fd5b600181815b8085111561459d57816000190482111561458357614583614447565b8085161561459057918102915b93841c9390800290614567565b509250929050565b6000826145b457506001614157565b816145c157506000614157565b81600181146145d757600281146145e1576145fd565b6001915050614157565b60ff8411156145f2576145f2614447565b50506001821b614157565b5060208310610133831016604e8410600b8410161715614620575081810a614157565b61462a8383614562565b806000190482111561463e5761463e614447565b029392505050565b6000610eb260ff8416836145a5565b600081600019048311821515161561466f5761466f614447565b500290565b60008282101561468657614686614447565b500390565b6000826146a857634e487b7160e01b600052601260045260246000fd5b500490565b6000602082840312156146bf57600080fd5b8151610eb2816142f9565b600082516146dc818460208701614249565b9190910192915050565b602081526000610eb2602083018461427556fea2646970667358221220db92e4e0ca39f9cd80c7dea75860806aebd3afce5bd0d0bf1734cd063b15848a64736f6c634300080e0033

Verified Source Code Full Match

Compiler: v0.8.14+commit.80d49f37 EVM: london Optimization: Yes (1000 runs)
Database.sol 778 lines
pragma solidity 0.8.14;

import "./interface/IProofOfDeveloper.sol";
import "./interface/IProofOfAuditor.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

/// @title   Hyacinth Database
/// @notice  Contract that keeps track of pending and completed audits
/// @author  Hyacinth
contract HyacinthDatabase is ReentrancyGuard {
    /// DEPENDENCIES ///

    using SafeERC20 for IERC20;

    /// EVENTS ///

    /// @notice        Emitted after Hyacinth fee has been updated
    /// @param newFee  New Hyacinth fee
    event HyacinthFeeSet(uint256 newFee);

    /// @notice              Emitted after min bounty has been set
    /// @param newMinBounty  New min bounty
    event MinBountySet(uint256 newMinBounty);

    /// @notice            Emittd after mint fee amount has been updated
    /// @param newMintFee  New mint fee amount
    event MintFeeSet(uint256 newMintFee);

    /// @notice             Emitted after deadline time has been updated
    /// @param newDeadline  New deadline time
    event AuditDeadlineUpdated(uint256 newDeadline);

    /// @notice           Emitted after Hyacinth wallet has been updated
    /// @param newWallet  Address of new Hyacinth wallet
    event HyacinthWalletUpdated(address newWallet);

    /// @notice           Emitted after new escrow withdraw buffer has been set
    /// @param newBuffer  New buffer time
    event EscrowWithdrawBufferSet(uint256 newBuffer);

    /// @notice             Emitted after bounty has been added to
    /// @param token        Address of token added to bounty
    /// @param auditId      Audit id of audit bounty is being added to
    /// @param amountAdded  Amount added to bounty
    event AddedToBounty(address indexed token, uint256 indexed auditId, uint256 amountAdded);

    /// @notice          Emitted after audit has been created
    /// @param auditId   Audit id
    /// @param previous  Audit id of previous audit
    /// @param developer Address of developer
    /// @param contracts Address of conrtacts being audited (Off chain audit if empty)
    event AuditCreated(
        uint256 indexed auditId, uint256 indexed previous, address indexed developer, address[] contracts
    );

    /// @notice           Emitted after pod has been minted
    /// @param developer  Address of developer
    /// @param id         Id of POD minted
    event PODMinted(address indexed developer, uint256 id);

    /// @notice           Emitted after audit result has been submitted
    /// @param auditor    Address of auditor
    /// @param developer  Developer of contracts
    /// @param auditId    Id of audit
    /// @param result     Result of audit
    event ResultSubmitted(address indexed auditor, address indexed developer, uint256 indexed auditId, STATUS result);

    /// @notice           Emitted after audit result has been submitted
    /// @param auditId    Id of audit
    /// @param auditor    Address of auditor
    /// @param developer  Developer of `auditId`
    /// @param positive   Bool if positive feedback
    event AuditFeedBackGiven(
        uint256 indexed auditId, address indexed auditor, address indexed developer, bool positive
    );

    /// @notice           Emitted after bounty has been refunded
    /// @param developer  Address of developer being refunded
    /// @param auditId    Id of audit being refunded
    event BountyRefunded(address indexed developer, uint256 indexed auditId);

    /// @notice         Emitted after auditor request has been sent
    /// @param auditor  Address of auditor requesting
    /// @param auditId  Audit id of audit request
    event AuditorRequest(address indexed auditor, uint256 indexed auditId);

    /// @notice           Emitted after auditor has been accepted
    /// @param developer  Address of developer of audit
    /// @param auditor    Address of auditor accepted
    /// @param auditId    Audit id auditor has been accepted for
    event AuditorAccepted(address indexed developer, address indexed auditor, uint256 indexed auditId);

    /// @notice                 Emitted after collaboration has been created
    /// @param auditId          Audit id collaborator is being added to
    /// @param collaborator     Address of collaborator
    /// @param percentOfBounty  Percent of bounty given to collaborator
    event CollaborationCreated(uint256 indexed auditId, address collaborator, uint256 percentOfBounty);

    /// @notice        Emitted after max number of audits for auditor set
    /// @param oldMax  Old max audits for auditor
    /// @param newMax  New max audits for auditor
    event MaxAuditsSet(uint256 oldMax, uint256 newMax);

    /// @notice           Emitted after time to roll over is updated
    /// @param oldPeriod  Old roll over period
    /// @param newPeriod  New roll over period
    event TimeToRollOverSet(uint256 oldPeriod, uint256 newPeriod);

    /// @notice         Emitted after auditor has been added
    /// @param auditor  Address of auditor being added
    event AuditorAdded(address auditor);

    /// @notice         Emitted after auditor has been removed
    /// @param auditor  Address of auditor being removed
    event AuditorRemoved(address auditor);

    /// @notice               Emitted after ownership has been transfered
    /// @param previousOwner  Address of previous owner
    /// @param newOwner       Address of new owner
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /// ERRORS ///

    /// @notice Error for if contrac was not developed by developer
    error NotDeveloper();
    /// @notice Error for if bounty has been paid out already
    error BountyPaid();
    /// @notice Error for if auditor already requested to audit
    error AlreadyRequested();
    /// @notice Error for if address already set
    error AlreadySet();
    /// @notice Error for if invalid level
    error InvalidLevel();
    /// @notice Error for if auditor has already been assigned
    error AuditorAssigned();
    /// @notice Error for if audit has not been failed
    error AuditNotFailed();
    /// @notice Error for if audit has been rolled over
    error AuditRolledOver();
    /// @notice Error for if refund condition not met
    error CanNotRefund();
    /// @notice Error for if the address is not the owner
    error NotOwner();
    /// @notice Error for if not approved auditor
    error NotApprovedAuditor();
    /// @notice Error for if not requested auditor
    error NotRequestedAuditor();
    /// @notice Error for only auditor
    error OnlyAuditor();
    /// @notice Error for only developer
    error OnlyDeveloper();
    /// @notice Error for if contract is not being audited
    error NotBeingAudited();
    /// @notice Error for if audit has not been passed
    error NotPassed();
    /// @notice Error for if feedback has already been given
    error FeedbackGiven();
    /// @notice Error for if contract is already in system
    error AlreadyInSystem();
    /// @notice Error for invalid audit result
    error InvalidResult();
    /// @notice Error for if address is not a contact
    error NotAContract();
    /// @notice Error for if collaboration has already been created
    error CollaborationAlreadyCreated();
    /// @notice Error for if invalid collaborator
    error InvalidCollaborator();
    /// @notice Error for if trying to give away more of bounty than available
    error MoreThanCanGiveAway();
    /// @notice Error for if address already owns POD NFT
    error AlreadyOwnPOD();
    /// @notice Error for if submitting audit and does not own POD NFT
    error DoesNotOwnPODNFT();
    /// @notice Error for if auditor has max amount of audits
    error MaxAuditsInProgress();
    /// @notice Error for if roll over period is still active
    error RollOverStillActive();
    /// @notice Error for if invalid fee
    error InvalidFee();
    /// @notice Error for if invalid previous
    error InvalidPrevious();
    /// @notice Error for if less than min bounty
    error LessThanMinBounty();

    /// STRUCTS ///

    enum STATUS {
        NOTAUDITED,
        PENDING,
        PASSED,
        FAILED,
        REFUNDED
    }

    /// @notice           Details of contract
    /// @param contracts  Address of contract developer
    /// @param audited    Bool if has been add to audit
    /// @param auditId    Audit id
    struct Contract {
        address developer;
        bool audited;
        uint256 auditId;
    }

    /// @notice                         Details of audited contracts
    /// @param contracts                Contracts being audited
    /// @param auditor                  Address of auditor
    /// @param developer                Address of developer
    /// @param status                   Status of audit
    /// @param auditDescription         Description of audit results
    /// @param deadline                 Deadline auditor has to complete audit
    /// @param escrowWithdrawTimestamp  Timestamp escrow can be withdrawn from
    /// @param feedback                 Bool if feedback has been given to auditor
    struct Audit {
        address[] contracts;
        address auditor;
        address developer;
        STATUS status;
        string auditDescription;
        uint256 deadline;
        uint256 escrowWithdrawTimestamp;
        bool feedback;
    }

    /// @notice                  Details of auditor
    /// @param auditsInProgress  Number of audits in progress
    /// @param positiveFeedback  Number of positive feedback for auditor
    /// @param negativeFeedbac   Number of negative feedback for auditor
    /// @param mintedLevel       Minted level for auditor
    struct Auditor {
        uint256 auditsInProgress;
        uint256 positiveFeedback;
        uint256 negativeFeedback;
        uint256 mintedLevel;
    }

    /// STATE VARIABLES ///

    /// @notice Fee percent for Hyacinth
    uint256 public hyacinthFee;
    /// @notice Fee amount to mint POD NFT
    uint256 public podMintFee;
    /// @notice time to complete audit or can refund
    uint256 public auditDeadline;
    /// @notice Max number of audits an auditor can pick up at one time
    uint256 public maxAuditsForAuditor;
    /// @notice Amount of time dev has to roll over audit until auditor can claim bounty
    uint256 public timeToRollOver;
    /// @notice Buffer before can withdraw from escrow
    uint256 public escrowWithdrawBuffer;
    /// @notice Amount of min bounty
    uint256 public minBounty;
    /// @notice Amount of audits in system
    uint256 public auditId;

    /// @notice Address of owner
    address public owner;
    /// @notice Address of hyacinth wallet
    address public hyacinthWallet;

    /// @notice Address of previous POA
    IProofOfAuditor public previousPOA;

    /// @notice Address of USDC
    address public immutable USDC;
    /// @notice Address of proof of developer NFT
    IProofOfDeveloper public immutable proofOfDeveloper;
    /// @notice Address of proof of auditor NFT
    IProofOfAuditor public immutable proofOfAuditor;

    /// @notice Amount of audits completed at each level for auditor
    mapping(address => uint256[4]) internal _levelsCompleted;

    /// @notice Contract details for contract address
    mapping(address => Contract) public contracts;
    /// @notice Audit details of address
    mapping(uint256 => Audit) public audits;
    /// @notice Auditor details of auditor
    mapping(address => Auditor) public auditors;
    /// @notice Bool if address is an approved auditor
    mapping(address => bool) public approvedAuditor;
    /// @notice Percent of bounty given to collaborators
    mapping(uint256 => uint256) public percentGivenForCollab;
    /// @notice Time rollover of bounty is active till
    mapping(uint256 => uint256) public timeRollOverActive;
    /// @notice Address failed audit rolled over to
    mapping(uint256 => uint256) public rolledOverAudit;
    /// @notice Array of collaborators for audit id
    mapping(uint256 => address[]) public collaborators;
    /// @notice Array of fees collaborators receive
    mapping(uint256 => uint256[]) public collaboratorsPercentOfBounty;
    /// @notice Bounty percent for collaberation of an audit id of a collaborator
    mapping(uint256 => mapping(address => uint256)) public collaborationPercent;
    /// @notice Bool if address requested to be auditor of audit id
    mapping(uint256 => mapping(address => bool)) public requestToBeAuditor;
    /// @notice Bounty amount of token on audit
    mapping(uint256 => mapping(address => uint256)) public bountyOnContract;
    /// @notice Token addresses on bounty
    mapping(uint256 => address[]) public tokenAddressOnBounty;
    /// @notice Bool if bounty has been paid out
    mapping(uint256 => bool) public bountyPaidOut;

    /// CONSTRUCTOR ///

    /// @param hyacinthWallet_  Address of hyacinth wallet
    /// @param owner_           Address of owner
    /// @param pod_             Address of proof of developer NFT
    /// @param poa_             Address of proof of auditor NFT
    /// @param usdc_            Address of USDC
    constructor(address hyacinthWallet_, address owner_, address pod_, address poa_, address usdc_) {
        hyacinthWallet = hyacinthWallet_;
        owner = owner_;
        proofOfDeveloper = IProofOfDeveloper(pod_);
        proofOfAuditor = IProofOfAuditor(poa_);
        USDC = usdc_;
    }

    /// AUDIT FUNCTION ///

    /// @notice               Function that creates audit
    /// @param beingAudited_  Array of addresses to have be audited (If 0 - Off chain audit)
    /// @param previous_      Previous audit id if rolling over
    /// @param bountyAmount_  Starting bounty amount
    /// @return auditId_      Id of audit created
    function createAudit(address[] calldata beingAudited_, uint256 previous_, uint256 bountyAmount_)
        external
        nonReentrant
        returns (uint256 auditId_)
    {
        if (proofOfDeveloper.balanceOf(msg.sender) == 0) mintPOD();
        if (bountyAmount_ < minBounty) revert LessThanMinBounty();

        ++auditId;
        auditId_ = auditId;

        if (beingAudited_.length > 0) {
            for (uint256 i; i < beingAudited_.length; ++i) {
                Contract memory contract_ = contracts[beingAudited_[i]];
                if (contract_.audited) revert AlreadyInSystem();
                if (contract_.developer != msg.sender) revert OnlyDeveloper();
                contracts[beingAudited_[i]].audited = true;
                contracts[beingAudited_[i]].auditId = auditId_;
            }

            if (previous_ != 0) {
                if (timeRollOverActive[previous_] <= block.timestamp || audits[previous_].developer != msg.sender) {
                    revert InvalidPrevious();
                }

                audits[auditId_].auditor = audits[previous_].auditor;
                audits[auditId_].deadline = block.timestamp + auditDeadline;
                collaborators[auditId_] = collaborators[previous_];
                collaboratorsPercentOfBounty[auditId_] = collaboratorsPercentOfBounty[previous_];
                percentGivenForCollab[auditId_] = percentGivenForCollab[previous_];
                rolledOverAudit[previous_] = auditId_;
                _rollOverBounty(previous_, auditId_);
            }

            audits[auditId_].contracts = beingAudited_;
        }

        audits[auditId_].developer = msg.sender;
        audits[auditId_].status = STATUS.PENDING;
        audits[auditId_].escrowWithdrawTimestamp = escrowWithdrawBuffer + block.timestamp;

        if (bountyAmount_ > 0) {
            _addToBounty(auditId_, bountyAmount_, USDC);
        }

        emit AuditCreated(auditId_, previous_, msg.sender, beingAudited_);
    }

    /// @notice  Called upon contract being deployed to be audited
    function beingAudited() external {
        if (proofOfDeveloper.balanceOf(tx.origin) == 0) revert DoesNotOwnPODNFT();
        if (msg.sender == tx.origin) revert NotAContract();
        Contract memory contract_ = contracts[msg.sender];
        if (contract_.developer != address(0)) revert AlreadyInSystem();
        contracts[msg.sender].developer = tx.origin;
    }

    /// DEVELOPER FUNCTION ///

    /// @notice           Add to bounty of `auditId_`
    /// @param auditId_   Audit id to add bounty to
    /// @param amount_    Amount of stable to add to bounty
    /// @param token_     Address of token on bounty
    function addToBounty(uint256 auditId_, uint256 amount_, address token_) external nonReentrant {
        Audit memory audit_ = audits[auditId_];

        if (audit_.developer != msg.sender) revert NotDeveloper();
        if (audit_.status != STATUS.PENDING) revert NotBeingAudited();
        _addToBounty(auditId_, amount_, token_);
    }

    /// @notice      Function that allow address to mint POD NFT
    /// @return id_  POD id minted
    function mintPOD() public returns (uint256 id_) {
        if (podMintFee > 0) {
            IERC20(USDC).safeTransferFrom(msg.sender, hyacinthWallet, podMintFee);
        }
        if (proofOfDeveloper.balanceOf(msg.sender) > 0) revert AlreadyOwnPOD();
        else (id_) = proofOfDeveloper.mint(msg.sender);

        emit PODMinted(msg.sender, id_);
    }

    /// @notice           Function that allows developer to give feedback to auditor
    /// @param auditId_   Audit id feedback given for
    /// @param positive_  Bool if positive or negative feedback
    function giveAuditorFeedback(uint256 auditId_, bool positive_) external {
        Audit memory audit_ = audits[auditId_];

        if (audit_.status != STATUS.PASSED) revert NotPassed();
        if (audit_.developer != msg.sender) revert OnlyDeveloper();
        if (audit_.feedback) revert FeedbackGiven();

        audits[auditId_].feedback = true;

        if (positive_) ++auditors[audit_.auditor].positiveFeedback;
        else ++auditors[audit_.auditor].negativeFeedback;

        emit AuditFeedBackGiven(auditId_, audit_.auditor, audit_.developer, positive_);
    }

    /// @notice           Function that allows developer to get a refund for bounty if no auditor or past deadline
    /// @param auditId_   Audit id to get refund for
    function refundBounty(uint256 auditId_) external nonReentrant {
        Audit memory audit_ = audits[auditId_];
        if (audit_.developer != msg.sender) revert OnlyDeveloper();
        if (
            (audit_.auditor != address(0) && audit_.deadline > block.timestamp) || audit_.status != STATUS.PENDING
                || (audit_.auditor == address(0) && audit_.escrowWithdrawTimestamp > block.timestamp)
        ) {
            revert CanNotRefund();
        }

        if (audit_.auditor != address(0)) auditors[audit_.auditor].auditsInProgress--;
        audits[auditId_].status = STATUS.REFUNDED;

        for (uint256 i; i < tokenAddressOnBounty[auditId_].length; ++i) {
            address token_ = tokenAddressOnBounty[auditId_][i];
            uint256 bounty_ = bountyOnContract[auditId_][token_];
            bountyOnContract[auditId_][token_] = 0;
            IERC20(token_).safeTransfer(audit_.developer, bounty_);
        }

        emit BountyRefunded(msg.sender, auditId_);
    }

    /// @notice          Function that allows developer to accept propose auditor
    /// @param auditId_  Audit Id of audit developer is accepting `auditor_` for
    /// @param auditor_  Address being accepted as auditor for `auditId_`
    function acceptAuditor(uint256 auditId_, address auditor_) external {
        if (audits[auditId_].developer != msg.sender) revert OnlyDeveloper();
        if (audits[auditId_].auditor != address(0)) revert AuditorAssigned();
        if (maxAuditsForAuditor <= auditors[auditor_].auditsInProgress) revert MaxAuditsInProgress();
        if (!requestToBeAuditor[auditId_][auditor_]) revert NotRequestedAuditor();

        ++auditors[auditor_].auditsInProgress;
        audits[auditId_].auditor = auditor_;
        audits[auditId_].deadline = block.timestamp + auditDeadline;

        emit AuditorAccepted(msg.sender, auditor_, auditId_);
    }

    /// AUDITOR FUNCTION ///

    /// @notice          Function that allows approved auditor to request to audit
    /// @param auditId_  Audit id auditor is requesting to audit
    function requestToAudit(uint256 auditId_) external {
        if (audits[auditId_].status != STATUS.PENDING) revert NotBeingAudited();
        if (audits[auditId_].auditor != address(0)) revert AuditorAssigned();
        if (!approvedAuditor[msg.sender]) revert NotApprovedAuditor();
        if (maxAuditsForAuditor <= auditors[msg.sender].auditsInProgress) revert MaxAuditsInProgress();
        if (requestToBeAuditor[auditId_][msg.sender] == true) revert AlreadyRequested();

        requestToBeAuditor[auditId_][msg.sender] = true;

        emit AuditorRequest(msg.sender, auditId_);
    }

    /// @notice              Auditor submits the `result_` of `auditId_`
    /// @param auditId_      Audit Id of audit having `result_` submitted
    /// @param result_       Result of the audit
    /// @param description_  Desecription of the audit
    function submitResult(uint256 auditId_, STATUS result_, string memory description_) external nonReentrant {
        Audit memory audit_ = audits[auditId_];
        if (audit_.status != STATUS.PENDING) revert NotBeingAudited();
        if (audit_.auditor != msg.sender) revert OnlyAuditor();
        if (result_ != STATUS.PASSED && result_ != STATUS.FAILED) revert InvalidResult();
        audit_.status = result_;
        audit_.auditDescription = description_;
        audits[auditId_] = audit_;

        if (result_ == STATUS.PASSED) {
            uint256 level_ = _payBounty(auditId_);
            ++_levelsCompleted[audit_.auditor][level_];
        } else {
            timeRollOverActive[auditId_] = block.timestamp + timeToRollOver;
        }

        emit ResultSubmitted(audit_.auditor, audit_.developer, auditId_, result_);
    }

    /// @notice          Function that pays out bounty if roll over has expired
    /// @param auditId_  Audit id to pay out bounty for
    function rollOverExpired(uint256 auditId_) external nonReentrant {
        Audit memory audit_ = audits[auditId_];
        if (audit_.status != STATUS.FAILED) revert AuditNotFailed();
        if (audit_.auditor != msg.sender) revert OnlyAuditor();
        if (timeRollOverActive[auditId_] > block.timestamp) revert RollOverStillActive();
        if (rolledOverAudit[auditId_] != 0) revert AuditRolledOver();

        _payBounty(auditId_);
    }

    /// @notice                  Function that allows an auditor to propose a collaboration
    /// @param auditId_          Audit id
    /// @param collaborator_     Address of collaborator
    /// @param percentOfBounty_  Percent of bounty `collaborator_` will receive
    function createCollaboration(uint256 auditId_, address collaborator_, uint256 percentOfBounty_) external {
        Audit memory audit_ = audits[auditId_];
        if (audit_.status != STATUS.PENDING) revert NotBeingAudited();
        if (audit_.auditor != msg.sender) revert OnlyAuditor();
        if (!approvedAuditor[collaborator_]) revert NotApprovedAuditor();
        if (percentGivenForCollab[auditId_] + percentOfBounty_ > 100) revert MoreThanCanGiveAway();
        if (collaborator_ == msg.sender || collaborator_ == audit_.developer) revert InvalidCollaborator();

        uint256 collaborationPercent_ = collaborationPercent[auditId_][collaborator_];
        if (collaborationPercent_ > 0) revert CollaborationAlreadyCreated();

        collaborationPercent[auditId_][collaborator_] = percentOfBounty_;

        percentGivenForCollab[auditId_] += percentOfBounty_;
        collaborators[auditId_].push(collaborator_);
        collaboratorsPercentOfBounty[auditId_].push(percentOfBounty_);

        emit CollaborationCreated(auditId_, collaborator_, percentOfBounty_);
    }

    /// OWNER FUNCTION ///

    /// @notice              Add previous auditors
    /// @param previousPOA_  Previous POA address
    function addPreviousAuditors(address previousPOA_) external {
        if (msg.sender != owner) revert NotOwner();
        if (address(previousPOA) != address(0)) revert AlreadySet();

        previousPOA = IProofOfAuditor(previousPOA_);

        for (uint256 i; i < previousPOA.totalSupply(); ++i) {
            _addAuditor(previousPOA.ownerOf(i), previousPOA.level(i));
        }
    }

    /// @notice         Update audit fee
    /// @param newFee_  New Hyacinth audit fee
    function setHyacinthfee(uint256 newFee_) external {
        if (msg.sender != owner) revert NotOwner();
        if (newFee_ > 25) revert InvalidFee();
        hyacinthFee = newFee_;

        emit HyacinthFeeSet(newFee_);
    }

    /// @notice         Min USDC bounty
    /// @param newMin_  New min USDC
    function setMinBounty(uint256 newMin_) external {
        if (msg.sender != owner) revert NotOwner();
        minBounty = newMin_;

        emit MinBountySet(newMin_);
    }

    /// @notice             Set new POD mint fee
    /// @param podMintFee_  New POD mint fee
    function setMintFee(uint256 podMintFee_) external {
        if (msg.sender != owner) revert NotOwner();
        podMintFee = podMintFee_;

        emit MintFeeSet(podMintFee_);
    }

    /// @notice              Set auditor deadline
    /// @param newDeadline_  New auditor deadline
    function setAuditDeadline(uint256 newDeadline_) external {
        if (msg.sender != owner) revert NotOwner();
        auditDeadline = newDeadline_;

        emit AuditDeadlineUpdated(newDeadline_);
    }

    /// @notice                 Set Hyacinth wallet
    /// @param hyacinthWallet_  Hyacinth wallet
    function updateHyacinthWallet(address hyacinthWallet_) external {
        if (msg.sender != owner) revert NotOwner();
        hyacinthWallet = hyacinthWallet_;

        emit HyacinthWalletUpdated(hyacinthWallet_);
    }

    /// @notice                       Set escrow withdraw buffer
    /// @param escrowWithdrawBuffer_  escrow withdraw buffer
    function setEscrowWithdrawBuffer(uint256 escrowWithdrawBuffer_) external {
        if (msg.sender != owner) revert NotOwner();
        escrowWithdrawBuffer = escrowWithdrawBuffer_;

        emit EscrowWithdrawBufferSet(escrowWithdrawBuffer_);
    }

    /// @notice           Transfer ownership of contract
    /// @param newOwner_  Address of the new owner
    function transferOwnership(address newOwner_) external {
        if (msg.sender != owner) revert NotOwner();
        address oldOwner_ = owner;
        owner = newOwner_;

        emit OwnershipTransferred(oldOwner_, newOwner_);
    }

    /// @notice                 Set roll over time for failed audit
    /// @param timeToRollOver_  New roll over time for failed audit
    function setTimeToRollOver(uint256 timeToRollOver_) external {
        if (msg.sender != owner) revert NotOwner();
        uint256 oldPeriod_ = timeToRollOver;
        timeToRollOver = timeToRollOver_;

        emit TimeToRollOverSet(oldPeriod_, timeToRollOver_);
    }

    /// @notice            Set max number of audits
    /// @param maxAudits_  New max number of audits for auditor
    function setMaxAuditsForAuditor(uint256 maxAudits_) external {
        if (msg.sender != owner) revert NotOwner();
        uint256 oldMax_ = maxAuditsForAuditor;
        maxAuditsForAuditor = maxAudits_;

        emit MaxAuditsSet(oldMax_, maxAudits_);
    }

    /// @notice            Add auditor
    /// @param auditor_    Address to add as auditor
    /// @param baseLevel_  Base level to give `auditor_`
    /// @return id_        Id of POA for `auditor_`
    function addAuditor(address auditor_, uint256 baseLevel_) external returns (uint256 id_) {
        if (msg.sender != owner) revert NotOwner();

        id_ = _addAuditor(auditor_, baseLevel_);
    }

    /// @notice          Remove auditor
    /// @param auditor_  Address to remove as auditor
    function removeAuditor(address auditor_) external {
        if (msg.sender != owner) revert NotOwner();
        approvedAuditor[auditor_] = false;

        emit AuditorRemoved(auditor_);
    }

    /// INTERNAL FUNCTIONS ///

    /// @notice            Add auditor
    /// @param auditor_    Address to add as auditor
    /// @param baseLevel_  Base level to give `auditor_`
    /// @return id_        Id of POA for `auditor_`
    function _addAuditor(address auditor_, uint256 baseLevel_) internal returns (uint256 id_) {
        if (baseLevel_ > 3) revert InvalidLevel();

        if (proofOfAuditor.balanceOf(auditor_) == 0) {
            id_ = proofOfAuditor.mint(auditor_);
        } else {
            id_ = proofOfAuditor.idHeld(auditor_);
        }

        auditors[auditor_].mintedLevel = baseLevel_;
        approvedAuditor[auditor_] = true;

        emit AuditorAdded(auditor_);
    }

    /// @notice                  Internal function that pays out bounty
    /// @param auditId_          Bounty Id to pay bounty out for
    function _payBounty(uint256 auditId_) internal returns (uint256 level_) {
        if (bountyPaidOut[auditId_]) revert BountyPaid();
        address[] memory collaborators_ = collaborators[auditId_];
        uint256[] memory percentsOfBounty_ = collaboratorsPercentOfBounty[auditId_];

        bountyPaidOut[auditId_] = true;

        Audit memory audit_ = audits[auditId_];

        (level_,) = currentBountyLevel(auditId_);

        for (uint256 i; i < tokenAddressOnBounty[auditId_].length; ++i) {
            address token_ = tokenAddressOnBounty[auditId_][i];
            uint256 bounty_ = bountyOnContract[auditId_][token_];
            bountyOnContract[auditId_][token_] = 0;
            uint256 bountyToDistribute_ = ((bounty_ * (100 - hyacinthFee)) / 100);
            uint256 hyacinthReceives_ = bounty_ - bountyToDistribute_;
            IERC20(token_).safeTransfer(hyacinthWallet, hyacinthReceives_);

            uint256 collaboratorsReceived_;
            for (uint256 n; n < collaborators_.length; ++n) {
                uint256 collaboratorsReceives_ = (bountyToDistribute_ * percentsOfBounty_[n]) / 100;
                IERC20(token_).safeTransfer(collaborators_[n], collaboratorsReceives_);
                collaboratorsReceived_ += collaboratorsReceives_;
            }

            uint256 auditorReceives_ = bountyToDistribute_ - collaboratorsReceived_;
            IERC20(token_).safeTransfer(audit_.auditor, auditorReceives_);
        }

        --auditors[msg.sender].auditsInProgress;
    }

    /// @notice           Add to bounty of `auditId_`
    /// @param auditId_   Audit id to add bounty to
    /// @param amount_    Amount of stable to add to bounty
    /// @param token_     Address of token on bounty
    function _addToBounty(uint256 auditId_, uint256 amount_, address token_) internal {
        IERC20(token_).safeTransferFrom(msg.sender, address(this), amount_);

        if (bountyOnContract[auditId_][token_] == 0) tokenAddressOnBounty[auditId_].push(token_);
        bountyOnContract[auditId_][token_] += amount_;

        emit AddedToBounty(token_, auditId_, amount_);
    }

    /// @notice           Rolls over bounty of `previous_` to `new_`
    /// @param previous_  Audit id of roll overed audit
    /// @param new_       Audsit id of new audit after roll over
    function _rollOverBounty(uint256 previous_, uint256 new_) internal {
        for (uint256 i; i < tokenAddressOnBounty[previous_].length; ++i) {
            address token_ = tokenAddressOnBounty[previous_][i];
            uint256 bounty_ = bountyOnContract[previous_][token_];

            bountyOnContract[previous_][token_] = 0;
            bountyOnContract[new_][token_] = bounty_;
        }

        tokenAddressOnBounty[new_] = tokenAddressOnBounty[previous_];
    }

    /// EXTERNAL VIEW FUNCTIONS ///

    /// @notice                   Returns amount of audits completed at each level for `auditorAdderss_`
    /// @param auditorAddress_    Address of auditor
    /// @return levelsCompleted_  Array of levels of audits completed for `auditorAddress_`
    function levelsCompleted(address auditorAddress_) external view returns (uint256[4] memory levelsCompleted_) {
        return (_levelsCompleted[auditorAddress_]);
    }

    /// @notice                   Returns audit status for `contractAddress_`
    /// @param contractAddress_   Contract address to check audit status for
    /// @return status_           Audit status of `contractAddress_`
    function auditStatus(address contractAddress_) external view returns (STATUS status_) {
        Contract memory contract_ = contracts[contractAddress_];
        if (contract_.audited) status_ = audits[contract_.auditId].status;
    }

    /// @notice          Returns current `level_` and `bounty_` of `auditId_`
    /// @param auditId_  Audit to check bounty for
    /// @return level_   Current level of `contract_` bounty
    /// @return bounty_  Current bouty of `contract_`
    function currentBountyLevel(uint256 auditId_) public view returns (uint256 level_, uint256 bounty_) {
        bounty_ = bountyOnContract[auditId_][USDC];

        uint256 decimals_ = 10 ** IERC20Metadata(USDC).decimals();
        if (bounty_ >= 1000 * decimals_) {
            if (bounty_ < 10000 * decimals_) level_ = 1;
            else if (bounty_ < 100000 * decimals_) level_ = 2;
            else level_ = 3;
        }
    }
}
IProofOfAuditor.sol 13 lines
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/IERC721.sol";

interface IProofOfAuditor is IERC721 {
    function mint(address auditor_) external returns (uint256 id_);

    function idHeld(address auditor_) external view returns (uint256 id_);

    function level(uint256 tokenId_) external view returns (uint256 level_);

    function totalSupply() external view returns (uint256 totalSupply_);
}
Address.sol 244 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}
IProofOfDeveloper.sol 9 lines
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/IERC721.sol";

interface IProofOfDeveloper is IERC721 {
    function mint(address developer_) external returns (uint256 id_);

    function idHeld(address developer_) external view returns (uint256 id_);
}
IERC20.sol 78 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
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 amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` 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 amount) external returns (bool);
}
IERC721.sol 132 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}
ReentrancyGuard.sol 77 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
 * @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 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].
 */
abstract contract ReentrancyGuard {
    // 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;

    uint256 private _status;

    constructor() {
        _status = _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();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _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 _status == _ENTERED;
    }
}
SafeERC20.sol 143 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 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 {
    using Address for address;

    /**
     * @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 {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    /**
     * @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 {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
        }
    }

    /**
     * @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.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
     * Revert on invalid signature.
     */
    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), 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 data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), 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 data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return
            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
    }
}
IERC165.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * 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[EIP 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);
}
IERC20Permit.sol 90 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     *
     * CAUTION: See Security Considerations above.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}
IERC20Metadata.sol 28 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
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);
}

Read Contract

USDC 0x89a30271 → address
approvedAuditor 0xd3c03c00 → bool
auditDeadline 0x455fd5d2 → uint256
auditId 0x1c318adf → uint256
auditStatus 0x5386a71d → uint8
auditors 0x47f9aa9f → uint256, uint256, uint256, uint256
audits 0xb60e73db → address, address, uint8, string, uint256, uint256, bool
bountyOnContract 0xba289873 → uint256
bountyPaidOut 0x59ac8325 → bool
collaborationPercent 0xdade4155 → uint256
collaborators 0xf195341e → address
collaboratorsPercentOfBounty 0xc115bef5 → uint256
contracts 0x69dc9ff3 → address, bool, uint256
currentBountyLevel 0xcc25ac55 → uint256, uint256
escrowWithdrawBuffer 0x5e5f7ea0 → uint256
hyacinthFee 0x87989f6e → uint256
hyacinthWallet 0x67e1af00 → address
levelsCompleted 0x8baa353b → uint256[4]
maxAuditsForAuditor 0x0a102226 → uint256
minBounty 0x89b8db55 → uint256
owner 0x8da5cb5b → address
percentGivenForCollab 0xb24fdf4e → uint256
podMintFee 0x3adc8360 → uint256
previousPOA 0xb6c57170 → address
proofOfAuditor 0x3b72e42c → address
proofOfDeveloper 0x3751954f → address
requestToBeAuditor 0x50729e6b → bool
rolledOverAudit 0xec8469b7 → uint256
timeRollOverActive 0x31b35ea5 → uint256
timeToRollOver 0xbc1c0fb6 → uint256
tokenAddressOnBounty 0x533c0c42 → address

Write Contract 23 functions

These functions modify contract state and require a wallet transaction to execute.

acceptAuditor 0xe162b367
uint256 auditId_
address auditor_
addAuditor 0x38e14c4b
address auditor_
uint256 baseLevel_
returns: uint256
addPreviousAuditors 0xa2fbaff4
address previousPOA_
addToBounty 0x66c86308
uint256 auditId_
uint256 amount_
address token_
beingAudited 0xf5f92a6f
No parameters
createAudit 0x9c5b2eea
address[] beingAudited_
uint256 previous_
uint256 bountyAmount_
returns: uint256
createCollaboration 0x0e3a7d2c
uint256 auditId_
address collaborator_
uint256 percentOfBounty_
giveAuditorFeedback 0xc8d76244
uint256 auditId_
bool positive_
mintPOD 0x50ab331b
No parameters
returns: uint256
refundBounty 0x58b1f29c
uint256 auditId_
removeAuditor 0xe6116cfd
address auditor_
requestToAudit 0x663ef651
uint256 auditId_
rollOverExpired 0x3f680e45
uint256 auditId_
setAuditDeadline 0xedd41e0a
uint256 newDeadline_
setEscrowWithdrawBuffer 0xce3dca77
uint256 escrowWithdrawBuffer_
setHyacinthfee 0x0081d2ef
uint256 newFee_
setMaxAuditsForAuditor 0x82eaa2c9
uint256 maxAudits_
setMinBounty 0x3b58f49a
uint256 newMin_
setMintFee 0xeddd0d9c
uint256 podMintFee_
setTimeToRollOver 0x2e7cc7b2
uint256 timeToRollOver_
submitResult 0xcb301971
uint256 auditId_
uint8 result_
string description_
transferOwnership 0xf2fde38b
address newOwner_
updateHyacinthWallet 0x1dcb573a
address hyacinthWallet_

Recent Transactions

No transactions found for this address