Cryo Explorer Ethereum Mainnet

Address Contract Partially Verified

Address 0x5D2cAAd2B7f851dcb001E7D1156fdc3B4936666c
Balance 0 ETH
Nonce 1
Code Size 19279 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

19279 bytes
0x608060405234801561001057600080fd5b506004361061038e5760003560e01c80638c28cbe8116101de578063ba9530a61161010f578063e5a583a9116100ad578063f699a3911161007c578063f699a39114610ae5578063f77c479114610b02578063f8b2cb4f14610b0a578063f8d6aed414610b305761038e565b8063e5a583a914610a92578063e755f7ea14610aaf578063ec09302114610ab7578063f1b8a9b714610abf5761038e565b8063cd2ed8fb116100e9578063cd2ed8fb14610a30578063cd669be014610a38578063dd62ed3e14610a64578063e4a28a521461046f5761038e565b8063ba9530a61461099d578063be3bbd2e146109d8578063c36596a6146105485761038e565b8063992e2a921161017c578063b02f0b7311610156578063b02f0b731461090e578063b0e0d13614610985578063b3f05b971461098d578063b7b800a4146109955761038e565b8063992e2a92146108ae5780639c649fee146108b6578063a9059cbb146108e25761038e565b80639381cd2b116101b85780639381cd2b14610870578063938b5f3214610878578063948d8ce61461088057806395d89b41146108a65761038e565b80638c28cbe81461081c57806392eefe9b14610842578063936c3477146108685761038e565b80632f37b624116102c35780636a7f63fa116102615780637c5e9ea4116102305780637c5e9ea41461074c57806381efd24a1461078c5780638201aa3f146107d4578063867378c5146108145761038e565b80636a7f63fa146106b557806370a08231146106bd57806371cbfdca146106e35780637ae05237146106eb5761038e565b80634f69c0d41161029d5780634f69c0d4146105fc57806354cf2aeb146106735780635db342771461067b5780636284ae41146106ad5761038e565b80632f37b62414610586578063313ce567146105ac57806346ab38f1146105ca5761038e565b80631446a7ff1161033057806318160ddd1161030a57806318160ddd146105215780631ca22ea514610529578063218b53821461054857806323b872dd146105505761038e565b80631446a7ff146104bd57806315e84af9146104eb57806317ab06e1146105195761038e565b806309a3bbe41161036c57806309a3bbe41461046f5780630d8e6e2c146104895780630dbc6b3e1461049157806311b42b1e146104b55761038e565b806305261aea1461039357806306fdde03146103b2578063095ea7b31461042f575b600080fd5b6103b0600480360360208110156103a957600080fd5b5035610b6b565b005b6103ba610e84565b6040805160208082528351818301528351919283929083019185019080838360005b838110156103f45781810151838201526020016103dc565b50505050905090810190601f1680156104215780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61045b6004803603604081101561044557600080fd5b506001600160a01b038135169060200135610eae565b604080519115158252519081900360200190f35b610477610f14565b60408051918252519081900360200190f35b610477610f21565b610499610f2e565b604080516001600160a01b039092168252519081900360200190f35b610477610f3d565b610477600480360360408110156104d357600080fd5b506001600160a01b0381358116916020013516610f42565b6104776004803603604081101561050157600080fd5b506001600160a01b038135811691602001351661111d565b6104776112c7565b6104776112cf565b6103b06004803603602081101561053f57600080fd5b503515156112d5565b61047761136f565b61045b6004803603606081101561056657600080fd5b506001600160a01b0381358116916020810135909116906040013561137b565b61045b6004803603602081101561059c57600080fd5b50356001600160a01b03166114ed565b6105b461150b565b6040805160ff9092168252519081900360200190f35b610477600480360360608110156105e057600080fd5b506001600160a01b038135169060208101359060400135611510565b6103b06004803603604081101561061257600080fd5b8135919081019060408101602082013564010000000081111561063457600080fd5b82018360208201111561064657600080fd5b8035906020019184602083028401116401000000008311171561066857600080fd5b509092509050611999565b610477611c9f565b6104776004803603606081101561069157600080fd5b506001600160a01b038135169060208101359060400135611ca5565b61047761200f565b610499612015565b610477600480360360208110156106d357600080fd5b50356001600160a01b0316612024565b61047761203f565b610733600480360360c081101561070157600080fd5b506001600160a01b038135811691602081013591604082013581169160608101359160808201359160a0013516612045565b6040805192835260208301919091528051918290030190f35b610733600480360360a081101561076257600080fd5b506001600160a01b038135811691602081013591604082013516906060810135906080013561277e565b610733600480360360c08110156107a257600080fd5b506001600160a01b038135811691602081013591604082013581169160608101359160808201359160a001351661279e565b610733600480360360a08110156107ea57600080fd5b506001600160a01b0381358116916020810135916040820135169060608101359060800135612eba565b610477612ecc565b6103b06004803603602081101561083257600080fd5b50356001600160a01b0316612ed3565b6103b06004803603602081101561085857600080fd5b50356001600160a01b031661307f565b6104776131d6565b610477613226565b610499613233565b6104776004803603602081101561089657600080fd5b50356001600160a01b0316613242565b6103ba613307565b610477613324565b6103b0600480360360408110156108cc57600080fd5b506001600160a01b038135169060200135613330565b61045b600480360360408110156108f857600080fd5b506001600160a01b03813516906020013561384d565b6103b06004803603604081101561092457600080fd5b8135919081019060408101602082013564010000000081111561094657600080fd5b82018360208201111561095857600080fd5b8035906020019184602083028401116401000000008311171561097a57600080fd5b509092509050613863565b610477613c17565b61045b613c1c565b610477613c2c565b610477600480360360c08110156109b357600080fd5b5080359060208101359060408101359060608101359060808101359060a00135613c31565b6109e0613ce1565b60408051602080825283518183015283519192839290830191858101910280838360005b83811015610a1c578181015183820152602001610a04565b505050509050019250505060405180910390f35b610477613ddc565b6103b060048036036040811015610a4e57600080fd5b506001600160a01b038135169060200135613de2565b61047760048036036040811015610a7a57600080fd5b506001600160a01b0381358116916020013516613ed8565b6103b060048036036020811015610aa857600080fd5b5035613f03565b61045b6140aa565b6104776140b3565b61047760048036036020811015610ad557600080fd5b50356001600160a01b03166140bf565b61047760048036036020811015610afb57600080fd5b503561419c565b6104996141b0565b61047760048036036020811015610b2057600080fd5b50356001600160a01b03166141c4565b610477600480360360c0811015610b4657600080fd5b5080359060208101359060408101359060608101359060808101359060a00135614289565b60085460ff1615610bb1576040805162461bcd60e51b815260206004820152600b60248201526a4552525f5245454e54525960a81b604482015290519081900360640190fd5b60088054600160ff19909116179081905561010090046001600160a01b03163314610c18576040805162461bcd60e51b815260206004820152601260248201527122a9292fa727aa2fa1a7a72a2927a62622a960711b604482015290519081900360640190fd5b600854600160a81b900460ff1615610c6a576040805162461bcd60e51b815260206004820152601060248201526f11549497d254d7d1925390531256915160821b604482015290519081900360640190fd5b600e5460021115610cb3576040805162461bcd60e51b815260206004820152600e60248201526d4552525f4d494e5f544f4b454e5360901b604482015290519081900360640190fd5b600e5460081015610cfc576040805162461bcd60e51b815260206004820152600e60248201526d4552525f4d41585f544f4b454e5360901b604482015290519081900360640190fd5b600354811015610d41576040805162461bcd60e51b815260206004820152600b60248201526a4552525f4d494e5f46454560a81b604482015290519081900360640190fd5b600754811115610d86576040805162461bcd60e51b815260206004820152600b60248201526a4552525f4d41585f46454560a81b604482015290519081900360640190fd5b6000805b6005811015610dba5760038160058110610da057fe5b0154831415610db25760019150610dba565b600101610d8a565b5080610e04576040805162461bcd60e51b81526020600482015260146024820152734552525f494e56414c49445f535741505f46454560601b604482015290519081900360640190fd5b60098290556008805460ff60a81b1916600160a81b179055610e2e68056bc75e2d63100000614302565b610e413368056bc75e2d6310000061430e565b60095460408051918252517f385682b698dbab9a6c443fd4594a08df31e60958fa2369566cc3a76c0072a7fe9181900360200190a150506008805460ff19169055565b60408051808201909152601081526f2c2232a334902837b7b6102a37b5b2b760811b602082015290565b3360008181526001602090815260408083206001600160a01b038716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a350600192915050565b6802b5e3af16b188000081565b6541504f4c4c4f60d01b90565b600b546001600160a01b031681565b600081565b60085460009060ff1615610f8b576040805162461bcd60e51b815260206004820152600b60248201526a4552525f5245454e54525960a81b604482015290519081900360640190fd5b6001600160a01b0383166000908152600f602052604090205460ff16610fe8576040805162461bcd60e51b815260206004820152600d60248201526c11549497d393d517d093d55391609a1b604482015290519081900360640190fd5b6001600160a01b0382166000908152600f602052604090205460ff16611045576040805162461bcd60e51b815260206004820152600d60248201526c11549497d393d517d093d55391609a1b604482015290519081900360640190fd5b6001600160a01b038084166000908152600f6020908152604080832093861683528083206003808601546002808801549284015490840154855163a221ee4960e01b81526004810193909352602483019390935260448201526064810191909152608481019490945290519092734f8d1c6dabbb379134272cb1273638cc98212a449263a221ee499260a480840193829003018186803b1580156110e857600080fd5b505af41580156110fc573d6000803e3d6000fd5b505050506040513d602081101561111257600080fd5b505195945050505050565b60085460009060ff1615611166576040805162461bcd60e51b815260206004820152600b60248201526a4552525f5245454e54525960a81b604482015290519081900360640190fd5b6001600160a01b0383166000908152600f602052604090205460ff166111c3576040805162461bcd60e51b815260206004820152600d60248201526c11549497d393d517d093d55391609a1b604482015290519081900360640190fd5b6001600160a01b0382166000908152600f602052604090205460ff16611220576040805162461bcd60e51b815260206004820152600d60248201526c11549497d393d517d093d55391609a1b604482015290519081900360640190fd5b6001600160a01b038084166000908152600f602090815260408083209386168352918290206003808501546002808701549284015490840154600954875163a221ee4960e01b81526004810194909452602484019490945260448301919091526064820152608481019190915292519092734f8d1c6dabbb379134272cb1273638cc98212a449263a221ee499260a480840193829003018186803b1580156110e857600080fd5b6305f5e10081565b60025490565b6011546001600160a01b03163314611325576040805162461bcd60e51b815260206004820152600e60248201526d4552525f4e4f545f434f4e46494760901b604482015290519081900360640190fd5b600d805482151560ff199091168117909155604080519182525133917f1c37382de11fec2ccd27d010eaa40491f045ea806bc44380827628e4f767040d919081900360200190a250565b670de0b6b3a764000081565b6000336001600160a01b03851614806113b757506001600160a01b03841660009081526001602090815260408083203384529091529020548211155b611400576040805162461bcd60e51b815260206004820152601560248201527422a9292fa12a27a5a2a72fa120a22fa1a0a62622a960591b604482015290519081900360640190fd5b61140b84848461431d565b336001600160a01b0385161480159061144957506001600160a01b038416600090815260016020908152604080832033845290915290205460001914155b156114e3576001600160a01b0384166000908152600160209081526040808320338452909152902054611482908363ffffffff61443916565b6001600160a01b03858116600090815260016020908152604080832033808552908352928190208590558051948552519287169391927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a35b5060019392505050565b6001600160a01b03166000908152600f602052604090205460ff1690565b601290565b6000336001600160a01b03166000356001600160e01b0319166001600160e01b03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a260085460ff16156115b9576040805162461bcd60e51b815260206004820152600b60248201526a4552525f5245454e54525960a81b604482015290519081900360640190fd5b6008805460ff191660011790819055600160a81b900460ff16611617576040805162461bcd60e51b815260206004820152601160248201527011549497d393d517d19253905312569151607a1b604482015290519081900360640190fd5b6001600160a01b0384166000908152600f602052604090205460ff16611674576040805162461bcd60e51b815260206004820152600d60248201526c11549497d393d517d093d55391609a1b604482015290519081900360640190fd5b6305f5e1008310156116be576040805162461bcd60e51b815260206004820152600e60248201526d11549497d3525397d05353d5539560921b604482015290519081900360640190fd5b6116c8338461449b565b6000600a541180156116e557506012546001600160a01b03163314155b1561172e576000611701600a54856144a690919063ffffffff16565b60125490915061171a906001600160a01b03168261430e565b61172a848263ffffffff61443916565b9350505b6117378361456f565b6001600160a01b0384166000908152600f6020908152604091829020600381015460028083015490546010546009548751634494c00960e11b815260048101959095526024850193909352604484019190915260648301526084820188905260a482015292519092734f8d1c6dabbb379134272cb1273638cc98212a449263892980129260c480840193829003018186803b1580156117d557600080fd5b505af41580156117e9573d6000803e3d6000fd5b505050506040513d60208110156117ff57600080fd5b5051915082821015611848576040805162461bcd60e51b815260206004820152600d60248201526c11549497d31253525517d3d555609a1b604482015290519081900360640190fd5b6001600160a01b0385166000908152600f6020526040902060030154611876906704a03ce68d2155566144a6565b8211156118be576040805162461bcd60e51b81526020600482015260116024820152704552525f4d41585f4f55545f524154494f60781b604482015290519081900360640190fd5b60038101546118d3908363ffffffff61443916565b6003820155600c546000906118ef90849063ffffffff6144a616565b600d5490915060ff16156119145760095461191190849063ffffffff6144a616565b90505b6040805184815290516001600160a01b0388169133917fe74c91552b64c2e2e7bd255639e004e693bd3e1d01cc33e65610b86afcc1ffed9181900360200190a3600b5461196c9087906001600160a01b031683614578565b6119868633611981868563ffffffff61443916565b614578565b50506008805460ff191690559392505050565b60085460ff16156119df576040805162461bcd60e51b815260206004820152600b60248201526a4552525f5245454e54525960a81b604482015290519081900360640190fd5b6008805460ff191660011790819055600160a81b900460ff16611a3d576040805162461bcd60e51b815260206004820152601160248201527011549497d393d517d19253905312569151607a1b604482015290519081900360640190fd5b600e548114611a89576040805162461bcd60e51b815260206004820152601360248201527208aa4a4be988a9c8ea890be9a92a69a82a8869606b1b604482015290519081900360640190fd5b6000611a936112cf565b90506000611aa7858363ffffffff6146da16565b905080611aed576040805162461bcd60e51b815260206004820152600f60248201526e08aa4a4be9a82a890be82a0a0a49eb608b1b604482015290519081900360640190fd5b60005b600e54811015611c7a576000600e8281548110611b0957fe5b60009182526020808320909101546001600160a01b0316808352600f909152604082206003015490925090611b44858363ffffffff6144a616565b905080611b8a576040805162461bcd60e51b815260206004820152600f60248201526e08aa4a4be9a82a890be82a0a0a49eb608b1b604482015290519081900360640190fd5b878785818110611b9657fe5b90506020020135811115611be0576040805162461bcd60e51b815260206004820152600c60248201526b22a9292fa624a6a4aa2fa4a760a11b604482015290519081900360640190fd5b6001600160a01b0383166000908152600f6020526040902060030154611c0c908263ffffffff6147e216565b6001600160a01b0384166000818152600f60209081526040918290206003019390935580518481529051919233927f63982df10efd8dfaaaa0fcc7f50b2d93b7cba26ccc48adee2873220d485dc39a9281900390910190a3611c6f83338361482f565b505050600101611af0565b50611c8485614302565b611c8e338661430e565b50506008805460ff19169055505050565b60095481565b60085460009060ff1615611cee576040805162461bcd60e51b815260206004820152600b60248201526a4552525f5245454e54525960a81b604482015290519081900360640190fd5b6008805460ff191660011790819055600160a81b900460ff16611d4c576040805162461bcd60e51b815260206004820152601160248201527011549497d393d517d19253905312569151607a1b604482015290519081900360640190fd5b6001600160a01b0384166000908152600f602052604090205460ff16611da9576040805162461bcd60e51b815260206004820152600d60248201526c11549497d393d517d093d55391609a1b604482015290519081900360640190fd5b6001600160a01b0384166000908152600f6020526040902060030154611dd7906706f05b59d3b200006144a6565b831115611e1e576040805162461bcd60e51b815260206004820152601060248201526f4552525f4d41585f494e5f524154494f60801b604482015290519081900360640190fd5b611e2984338561482f565b6000611e40600c54856144a690919063ffffffff16565b600d5490915060ff1615611e6557600954611e6290859063ffffffff6144a616565b90505b611e75848263ffffffff61443916565b6001600160a01b0386166000908152600f6020908152604091829020600381015460028083015490546010546009548751638656b65360e01b815260048101959095526024850193909352604484019190915260648301526084820186905260a4820152925193975092734f8d1c6dabbb379134272cb1273638cc98212a4492638656b6539260c4808301939192829003018186803b158015611f1757600080fd5b505af4158015611f2b573d6000803e3d6000fd5b505050506040513d6020811015611f4157600080fd5b5051925083831015611f8a576040805162461bcd60e51b815260206004820152600d60248201526c11549497d31253525517d3d555609a1b604482015290519081900360640190fd5b6003810154611f9f908663ffffffff6147e216565b6003820155600b54611fbc9087906001600160a01b031684614578565b6040805186815290516001600160a01b0388169133917f63982df10efd8dfaaaa0fcc7f50b2d93b7cba26ccc48adee2873220d485dc39a9181900360200190a361200583614302565b611986338461430e565b600a5481565b6011546001600160a01b031681565b6001600160a01b031660009081526020819052604090205490565b600c5481565b600854600090819060ff1615612090576040805162461bcd60e51b815260206004820152600b60248201526a4552525f5245454e54525960a81b604482015290519081900360640190fd5b6008805460ff191660011790556001600160a01b0388166000908152600f602052604090205460ff166120fa576040805162461bcd60e51b815260206004820152600d60248201526c11549497d393d517d093d55391609a1b604482015290519081900360640190fd5b6001600160a01b0386166000908152600f602052604090205460ff16612157576040805162461bcd60e51b815260206004820152600d60248201526c11549497d393d517d093d55391609a1b604482015290519081900360640190fd5b600854600160a81b900460ff166121a9576040805162461bcd60e51b815260206004820152601160248201527011549497d393d517d19253905312569151607a1b604482015290519081900360640190fd5b6001600160a01b038881166000908152600f60205260408082209289168252902060038201546121e1906706f05b59d3b200006144a6565b891115612228576040805162461bcd60e51b815260206004820152601060248201526f4552525f4d41585f494e5f524154494f60801b604482015290519081900360640190fd5b6000734f8d1c6dabbb379134272cb1273638cc98212a4463a221ee4984600301548560020154856003015486600201546009546040518663ffffffff1660e01b8152600401808681526020018581526020018481526020018381526020018281526020019550505050505060206040518083038186803b1580156122ab57600080fd5b505af41580156122bf573d6000803e3d6000fd5b505050506040513d60208110156122d557600080fd5b5051905086811115612324576040805162461bcd60e51b81526020600482015260136024820152724552525f4241445f4c494d49545f505249434560681b604482015290519081900360640190fd5b61234483600301548460020154846003015485600201548e600954613c31565b94508785101561238b576040805162461bcd60e51b815260206004820152600d60248201526c11549497d31253525517d3d555609a1b604482015290519081900360640190fd5b61239b8a8663ffffffff6146da16565b8111156123e1576040805162461bcd60e51b815260206004820152600f60248201526e08aa4a4be9a82a890be82a0a0a49eb608b1b604482015290519081900360640190fd5b60038301546123f6908b63ffffffff6147e216565b600380850191909155820154612412908663ffffffff61443916565b8260030181905550734f8d1c6dabbb379134272cb1273638cc98212a4463a221ee4984600301548560020154856003015486600201546009546040518663ffffffff1660e01b8152600401808681526020018581526020018481526020018381526020018281526020019550505050505060206040518083038186803b15801561249b57600080fd5b505af41580156124af573d6000803e3d6000fd5b505050506040513d60208110156124c557600080fd5b5051935080841015612510576040805162461bcd60e51b815260206004820152600f60248201526e08aa4a4be9a82a890be82a0a0a49eb608b1b604482015290519081900360640190fd5b86841115612557576040805162461bcd60e51b815260206004820152600f60248201526e4552525f4c494d49545f505249434560881b604482015290519081900360640190fd5b886001600160a01b03168b6001600160a01b0316336001600160a01b03167f908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d433788d89604051808381526020018281526020019250505060405180910390a46125bf8b338c61482f565b60006125d66009548c6144a690919063ffffffff16565b905060006001600160a01b038816158015906125fb57506001600160a01b0388163314155b801561261057506001600160a01b0388163214155b156126985750600581046126258d8983614578565b600385015461263a908263ffffffff61443916565b85600301819055508c6001600160a01b0316886001600160a01b0316336001600160a01b03167f2fa8f551635bc74da38059e0b4294901eedc1258f4dab545bbc85a3b809eb076846040518082815260200191505060405180910390a45b60006126af600c548e6144a690919063ffffffff16565b600d5490915060ff16156126d0576126cd838363ffffffff61443916565b90505b826126e1828463ffffffff6147e216565b1115612724576040805162461bcd60e51b815260206004820152600d60248201526c11549497d1915157d312535255609a1b604482015290519081900360640190fd5b600b5461273c908f906001600160a01b031683614578565b6003860154612751908263ffffffff61443916565b60038701556127618c338a614578565b5050505050506008805460ff191690559097909650945050505050565b6000806127908787878787600061279e565b915091509550959350505050565b600854600090819060ff16156127e9576040805162461bcd60e51b815260206004820152600b60248201526a4552525f5245454e54525960a81b604482015290519081900360640190fd5b6008805460ff191660011790556001600160a01b0388166000908152600f602052604090205460ff16612853576040805162461bcd60e51b815260206004820152600d60248201526c11549497d393d517d093d55391609a1b604482015290519081900360640190fd5b6001600160a01b0386166000908152600f602052604090205460ff166128b0576040805162461bcd60e51b815260206004820152600d60248201526c11549497d393d517d093d55391609a1b604482015290519081900360640190fd5b600854600160a81b900460ff16612902576040805162461bcd60e51b815260206004820152601160248201527011549497d393d517d19253905312569151607a1b604482015290519081900360640190fd5b6001600160a01b038881166000908152600f602052604080822092891682529020600381015461293a906704a03ce68d2155566144a6565b871115612982576040805162461bcd60e51b81526020600482015260116024820152704552525f4d41585f4f55545f524154494f60781b604482015290519081900360640190fd5b6000734f8d1c6dabbb379134272cb1273638cc98212a4463a221ee4984600301548560020154856003015486600201546009546040518663ffffffff1660e01b8152600401808681526020018581526020018481526020018381526020018281526020019550505050505060206040518083038186803b158015612a0557600080fd5b505af4158015612a19573d6000803e3d6000fd5b505050506040513d6020811015612a2f57600080fd5b5051905086811115612a7e576040805162461bcd60e51b81526020600482015260136024820152724552525f4241445f4c494d49545f505249434560681b604482015290519081900360640190fd5b612a9e83600301548460020154846003015485600201548c600954614289565b945089851115612ae4576040805162461bcd60e51b815260206004820152600c60248201526b22a9292fa624a6a4aa2fa4a760a11b604482015290519081900360640190fd5b612af4858963ffffffff6146da16565b811115612b3a576040805162461bcd60e51b815260206004820152600f60248201526e08aa4a4be9a82a890be82a0a0a49eb608b1b604482015290519081900360640190fd5b6003830154612b4f908663ffffffff6147e216565b600380850191909155820154612b6b908963ffffffff61443916565b8260030181905550734f8d1c6dabbb379134272cb1273638cc98212a4463a221ee4984600301548560020154856003015486600201546009546040518663ffffffff1660e01b8152600401808681526020018581526020018481526020018381526020018281526020019550505050505060206040518083038186803b158015612bf457600080fd5b505af4158015612c08573d6000803e3d6000fd5b505050506040513d6020811015612c1e57600080fd5b5051935080841015612c69576040805162461bcd60e51b815260206004820152600f60248201526e08aa4a4be9a82a890be82a0a0a49eb608b1b604482015290519081900360640190fd5b86841115612cb0576040805162461bcd60e51b815260206004820152600f60248201526e4552525f4c494d49545f505249434560881b604482015290519081900360640190fd5b886001600160a01b03168b6001600160a01b0316336001600160a01b03167f908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378888c604051808381526020018281526020019250505060405180910390a4612d188b338761482f565b6000612d2f600954876144a690919063ffffffff16565b905060006001600160a01b03881615801590612d5457506001600160a01b0388163314155b8015612d6957506001600160a01b0388163214155b15612df1575060058104612d7e8d8983614578565b6003850154612d93908263ffffffff61443916565b85600301819055508c6001600160a01b0316886001600160a01b0316336001600160a01b03167f2fa8f551635bc74da38059e0b4294901eedc1258f4dab545bbc85a3b809eb076846040518082815260200191505060405180910390a45b6000612e08600c54896144a690919063ffffffff16565b600d5490915060ff1615612e2957612e26838363ffffffff61443916565b90505b82612e3a828463ffffffff6147e216565b1115612e7d576040805162461bcd60e51b815260206004820152600d60248201526c11549497d1915157d312535255609a1b604482015290519081900360640190fd5b600b54612e95908f906001600160a01b031683614578565b6003860154612eaa908263ffffffff61443916565b60038701556127618c338d614578565b60008061279087878787876000612045565b620f424081565b336001600160a01b03166000356001600160e01b0319166001600160e01b03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a260085460ff1615612f7a576040805162461bcd60e51b815260206004820152600b60248201526a4552525f5245454e54525960a81b604482015290519081900360640190fd5b6008805460ff191660011790556001600160a01b0381166000908152600f602052604090205460ff16612fe4576040805162461bcd60e51b815260206004820152600d60248201526c11549497d393d517d093d55391609a1b604482015290519081900360640190fd5b604080516370a0823160e01b815230600482015290516001600160a01b038316916370a08231916024808301926020929190829003018186803b15801561302a57600080fd5b505afa15801561303e573d6000803e3d6000fd5b505050506040513d602081101561305457600080fd5b50516001600160a01b039091166000908152600f60205260409020600301556008805460ff19169055565b336001600160a01b03166000356001600160e01b0319166001600160e01b03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a260085461010090046001600160a01b03163314613139576040805162461bcd60e51b815260206004820152601260248201527122a9292fa727aa2fa1a7a72a2927a62622a960711b604482015290519081900360640190fd5b6001600160a01b038116613184576040805162461bcd60e51b815260206004820152600d60248201526c22a9292fad22a927afa0a2222960991b604482015290519081900360640190fd5b60088054610100600160a81b0319166101006001600160a01b038416908102919091179091556040517f37f86e4777739e0dbc5682f53e26f091cac39f3d134742d5431c06cbe0a58dff90600090a250565b60085460009060ff161561321f576040805162461bcd60e51b815260206004820152600b60248201526a4552525f5245454e54525960a81b604482015290519081900360640190fd5b5060105490565b68056bc75e2d6310000081565b6012546001600160a01b031681565b60085460009060ff161561328b576040805162461bcd60e51b815260206004820152600b60248201526a4552525f5245454e54525960a81b604482015290519081900360640190fd5b6001600160a01b0382166000908152600f602052604090205460ff166132e8576040805162461bcd60e51b815260206004820152600d60248201526c11549497d393d517d093d55391609a1b604482015290519081900360640190fd5b506001600160a01b03166000908152600f602052604090206002015490565b60408051808201909152600381526216141560ea1b602082015290565b6704a03ce68d21555681565b60085460ff1615613376576040805162461bcd60e51b815260206004820152600b60248201526a4552525f5245454e54525960a81b604482015290519081900360640190fd5b60088054600160ff19909116179081905561010090046001600160a01b031633146133dd576040805162461bcd60e51b815260206004820152601260248201527122a9292fa727aa2fa1a7a72a2927a62622a960711b604482015290519081900360640190fd5b6001600160a01b0382166000908152600f602052604090205460ff161561343a576040805162461bcd60e51b815260206004820152600c60248201526b11549497d254d7d093d5539160a21b604482015290519081900360640190fd5b600854600160a81b900460ff161561348c576040805162461bcd60e51b815260206004820152601060248201526f11549497d254d7d1925390531256915160821b604482015290519081900360640190fd5b600e546008116134d4576040805162461bcd60e51b815260206004820152600e60248201526d4552525f4d41585f544f4b454e5360901b604482015290519081900360640190fd5b670de0b6b3a7640000811015613522576040805162461bcd60e51b815260206004820152600e60248201526d11549497d3525397d5d15251d21560921b604482015290519081900360640190fd5b6802b5e3af16b1880000811115613571576040805162461bcd60e51b815260206004820152600e60248201526d11549497d3505617d5d15251d21560921b604482015290519081900360640190fd5b604080516370a0823160e01b815230600482015290516000916001600160a01b038516916370a0823191602480820192602092909190829003018186803b1580156135bb57600080fd5b505afa1580156135cf573d6000803e3d6000fd5b505050506040513d60208110156135e557600080fd5b50516040805163313ce56760e01b815290519192506000916001600160a01b0386169163313ce567916004808301926020929190829003018186803b15801561362d57600080fd5b505afa158015613641573d6000803e3d6000fd5b505050506040513d602081101561365757600080fd5b505160ff16600a0a9050620f42408110156136a9576040805162461bcd60e51b815260206004820152600d60248201526c11549497d513d3d7d4d3505313609a1b604482015290519081900360640190fd5b620f424081048210156136f5576040805162461bcd60e51b815260206004820152600f60248201526e4552525f4d494e5f42414c414e434560881b604482015290519081900360640190fd5b601054613708908463ffffffff6147e216565b60108190556802b5e3af16b18800001015613761576040805162461bcd60e51b815260206004820152601460248201527311549497d3505617d513d5105317d5d15251d21560621b604482015290519081900360640190fd5b604080516080810182526001808252600e80546020808501918252848601898152606086018981526001600160a01b038c166000818152600f85528981209851895460ff19169015151789559451888801559151600288015551600390960195909555825493840183559190527fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd90910180546001600160a01b0319168317905582518681529081018590528251919233927f5deb8656732bee68a74ef874b834356bfc2936842bd13b816ec4c219e362a71e9281900390910190a350506008805460ff191690555050565b600061385a33848461431d565b50600192915050565b60085460ff16156138a9576040805162461bcd60e51b815260206004820152600b60248201526a4552525f5245454e54525960a81b604482015290519081900360640190fd5b6008805460ff191660011790819055600160a81b900460ff16613907576040805162461bcd60e51b815260206004820152601160248201527011549497d393d517d19253905312569151607a1b604482015290519081900360640190fd5b600e548114613953576040805162461bcd60e51b815260206004820152601360248201527208aa4a4be988a9c8ea890be9a92a69a82a8869606b1b604482015290519081900360640190fd5b6305f5e10083101561399d576040805162461bcd60e51b815260206004820152600e60248201526d11549497d3525397d05353d5539560921b604482015290519081900360640190fd5b60006139a76112cf565b905060006139c0600a54866144a690919063ffffffff16565b6012549091506001600160a01b03163314156139da575060005b60006139ec868363ffffffff61443916565b90506000613a00828563ffffffff6146da16565b905080613a46576040805162461bcd60e51b815260206004820152600f60248201526e08aa4a4be9a82a890be82a0a0a49eb608b1b604482015290519081900360640190fd5b613a50338861449b565b8215613a6c57601254613a6c906001600160a01b03168461430e565b613a758261456f565b60005b600e54811015613c03576000600e8281548110613a9157fe5b60009182526020808320909101546001600160a01b0316808352600f909152604082206003015490925090613acc858363ffffffff6144a616565b905080613b12576040805162461bcd60e51b815260206004820152600f60248201526e08aa4a4be9a82a890be82a0a0a49eb608b1b604482015290519081900360640190fd5b898985818110613b1e57fe5b90506020020135811015613b69576040805162461bcd60e51b815260206004820152600d60248201526c11549497d31253525517d3d555609a1b604482015290519081900360640190fd5b6001600160a01b0383166000908152600f6020526040902060030154613b95908263ffffffff61443916565b6001600160a01b0384166000818152600f60209081526040918290206003019390935580518481529051919233927fe74c91552b64c2e2e7bd255639e004e693bd3e1d01cc33e65610b86afcc1ffed9281900390910190a3613bf8833383614578565b505050600101613a78565b50506008805460ff19169055505050505050565b600881565b600854600160a81b900460ff1681565b600281565b60408051635d4a985360e11b8152600481018890526024810187905260448101869052606481018590526084810184905260a481018390529051600091734f8d1c6dabbb379134272cb1273638cc98212a449163ba9530a69160c480820192602092909190829003018186803b158015613caa57600080fd5b505af4158015613cbe573d6000803e3d6000fd5b505050506040513d6020811015613cd457600080fd5b5051979650505050505050565b60085460609060ff1615613d2a576040805162461bcd60e51b815260206004820152600b60248201526a4552525f5245454e54525960a81b604482015290519081900360640190fd5b600854600160a81b900460ff16613d7c576040805162461bcd60e51b815260206004820152601160248201527011549497d393d517d19253905312569151607a1b604482015290519081900360640190fd5b600e805480602002602001604051908101604052809291908181526020018280548015613dd257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613db4575b5050505050905090565b600e5490565b6011546001600160a01b03163314613e32576040805162461bcd60e51b815260206004820152600e60248201526d4552525f4e4f545f434f4e46494760901b604482015290519081900360640190fd5b6001600160a01b038216613e7d576040805162461bcd60e51b815260206004820152600d60248201526c22a9292fad22a927afa0a2222960991b604482015290519081900360640190fd5b600b80546001600160a01b0384166001600160a01b03199091168117909155600c8290556040805183815290517fccaa809140cb901df601f6c5eae0a0d30849c3b29378df0886f660270c9735e99181900360200190a25050565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600854600160a81b900460ff1615613f55576040805162461bcd60e51b815260206004820152601060248201526f11549497d254d7d1925390531256915160821b604482015290519081900360640190fd5b60085461010090046001600160a01b03163314613fae576040805162461bcd60e51b815260206004820152601260248201527122a9292fa727aa2fa1a7a72a2927a62622a960711b604482015290519081900360640190fd5b601160009054906101000a90046001600160a01b03166001600160a01b031663ff42517d6040518163ffffffff1660e01b815260040160206040518083038186803b158015613ffc57600080fd5b505afa158015614010573d6000803e3d6000fd5b505050506040513d602081101561402657600080fd5b505181111561406f576040805162461bcd60e51b815260206004820152601060248201526f494e56414c49445f455849545f46454560801b604482015290519081900360640190fd5b600a8190556040805182815290517f09ea89c001139a826eedf1b1b3a690524db01249f803b62c0f6a30b09f4976fc9181900360200190a150565b600d5460ff1681565b6706f05b59d3b2000081565b60085460009060ff1615614108576040805162461bcd60e51b815260206004820152600b60248201526a4552525f5245454e54525960a81b604482015290519081900360640190fd5b6001600160a01b0382166000908152600f602052604090205460ff16614165576040805162461bcd60e51b815260206004820152600d60248201526c11549497d393d517d093d55391609a1b604482015290519081900360640190fd5b6001600160a01b0382166000908152600f602052604090206002015460105461419590829063ffffffff6146da16565b9392505050565b600381600581106141a957fe5b0154905081565b60085461010090046001600160a01b031681565b60085460009060ff161561420d576040805162461bcd60e51b815260206004820152600b60248201526a4552525f5245454e54525960a81b604482015290519081900360640190fd5b6001600160a01b0382166000908152600f602052604090205460ff1661426a576040805162461bcd60e51b815260206004820152600d60248201526c11549497d393d517d093d55391609a1b604482015290519081900360640190fd5b506001600160a01b03166000908152600f602052604090206003015490565b60408051633e35abb560e21b8152600481018890526024810187905260448101869052606481018590526084810184905260a481018390529051600091734f8d1c6dabbb379134272cb1273638cc98212a449163f8d6aed49160c480820192602092909190829003018186803b158015613caa57600080fd5b61430b81614998565b50565b61431930838361431d565b5050565b6001600160a01b038316600090815260208190526040902054811115614381576040805162461bcd60e51b815260206004820152601460248201527311549497d25394d551919250d251539517d0905360621b604482015290519081900360640190fd5b6001600160a01b0383166000908152602081905260409020546143aa908263ffffffff61443916565b6001600160a01b0380851660009081526020819052604080822093909355908416815220546143df908263ffffffff6147e216565b6001600160a01b038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b60008060006144488585614a19565b915091508015614493576040805162461bcd60e51b81526020600482015260116024820152704552525f5355425f554e444552464c4f5760781b604482015290519081900360640190fd5b509392505050565b61431982308361431d565b60008282028315806144c05750828482816144bd57fe5b04145b614504576040805162461bcd60e51b815260206004820152601060248201526f4552525f4d554c5f4f564552464c4f5760801b604482015290519081900360640190fd5b6706f05b59d3b20000810181811015614557576040805162461bcd60e51b815260206004820152601060248201526f4552525f4d554c5f4f564552464c4f5760801b604482015290519081900360640190fd5b6000670de0b6b3a7640000825b049695505050505050565b61430b81614a3e565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b178152925182516000946060949389169392918291908083835b602083106145f55780518252601f1990920191602091820191016145d6565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114614657576040519150601f19603f3d011682016040523d82523d6000602084013e61465c565b606091505b509150915081801561468a57508051158061468a575080806020019051602081101561468757600080fd5b50515b6146d3576040805162461bcd60e51b8152602060048201526015602482015274115490cc8c17d514905394d1915497d19052531151605a1b604482015290519081900360640190fd5b5050505050565b60008161471d576040805162461bcd60e51b815260206004820152600c60248201526b4552525f4449565f5a45524f60a01b604482015290519081900360640190fd5b670de0b6b3a764000083028315806147455750670de0b6b3a764000084828161474257fe5b04145b614789576040805162461bcd60e51b815260206004820152601060248201526f11549497d1125597d25395115493905360821b604482015290519081900360640190fd5b600283048101818110156147d7576040805162461bcd60e51b815260206004820152601060248201526f11549497d1125597d25395115493905360821b604482015290519081900360640190fd5b600084828161456457fe5b600082820183811015614195576040805162461bcd60e51b815260206004820152601060248201526f4552525f4144445f4f564552464c4f5760801b604482015290519081900360640190fd5b604080516001600160a01b038481166024830152306044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b178152925182516000946060949389169392918291908083835b602083106148b25780518252601f199092019160209182019101614893565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114614914576040519150601f19603f3d011682016040523d82523d6000602084013e614919565b606091505b5091509150818015614947575080511580614947575080806020019051602081101561494457600080fd5b50515b6146d3576040805162461bcd60e51b815260206004820152601a60248201527f45524332305f5452414e534645525f46524f4d5f4641494c4544000000000000604482015290519081900360640190fd5b306000908152602081905260409020546149b8908263ffffffff6147e216565b306000908152602081905260409020556002546149db908263ffffffff6147e216565b60025560408051828152905130916000917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a350565b600080828410614a2f5750508082036000614a37565b505081810360015b9250929050565b30600090815260208190526040902054811115614a99576040805162461bcd60e51b815260206004820152601460248201527311549497d25394d551919250d251539517d0905360621b604482015290519081900360640190fd5b30600090815260208190526040902054614ab9908263ffffffff61443916565b30600090815260208190526040902055600254614adc908263ffffffff61443916565b60025560408051828152905160009130917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35056fea265627a7a72315820e4bc0b79265b34f3071fc12ee0e04d56963a3285dc6081942b73e464bfc1c8b064736f6c63430005110032

Verified Source Code Partial Match

Compiler: v0.5.17+commit.d19bba13 EVM: istanbul Optimization: Yes (200 runs)
XPool.sol 1343 lines
// File: contracts/XVersion.sol

pragma solidity 0.5.17;

contract XVersion {
    function getVersion() external view returns (bytes32);
}

contract XApollo is XVersion {
    function getVersion() external view returns (bytes32) {
        return bytes32("APOLLO");
    }
}

// File: contracts/XConst.sol

pragma solidity 0.5.17;

contract XConst {
    uint256 public constant BONE = 10**18;

    uint256 public constant MIN_BOUND_TOKENS = 2;
    uint256 public constant MAX_BOUND_TOKENS = 8;

    uint256 public constant EXIT_ZERO_FEE = 0;

    uint256 public constant MIN_WEIGHT = BONE;
    uint256 public constant MAX_WEIGHT = BONE * 50;
    uint256 public constant MAX_TOTAL_WEIGHT = BONE * 50;

    // min effective value: 0.000001 TOKEN
    uint256 public constant MIN_BALANCE = 10**6;

    // BONE/(10**10) XPT
    uint256 public constant MIN_POOL_AMOUNT = 10**8;

    uint256 public constant INIT_POOL_SUPPLY = BONE * 100;

    uint256 public constant MAX_IN_RATIO = BONE / 2;
    uint256 public constant MAX_OUT_RATIO = (BONE / 3) + 1 wei;
}

// File: contracts/lib/XNum.sol

pragma solidity 0.5.17;

library XNum {
    uint256 public constant BONE = 10**18;
    uint256 public constant MIN_BPOW_BASE = 1 wei;
    uint256 public constant MAX_BPOW_BASE = (2 * BONE) - 1 wei;
    uint256 public constant BPOW_PRECISION = BONE / 10**10;

    function btoi(uint256 a) internal pure returns (uint256) {
        return a / BONE;
    }

    function bfloor(uint256 a) internal pure returns (uint256) {
        return btoi(a) * BONE;
    }

    function badd(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "ERR_ADD_OVERFLOW");
        return c;
    }

    function bsub(uint256 a, uint256 b) internal pure returns (uint256) {
        (uint256 c, bool flag) = bsubSign(a, b);
        require(!flag, "ERR_SUB_UNDERFLOW");
        return c;
    }

    function bsubSign(uint256 a, uint256 b)
        internal
        pure
        returns (uint256, bool)
    {
        if (a >= b) {
            return (a - b, false);
        } else {
            return (b - a, true);
        }
    }

    function bmul(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c0 = a * b;
        require(a == 0 || c0 / a == b, "ERR_MUL_OVERFLOW");
        uint256 c1 = c0 + (BONE / 2);
        require(c1 >= c0, "ERR_MUL_OVERFLOW");
        uint256 c2 = c1 / BONE;
        return c2;
    }

    function bdiv(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0, "ERR_DIV_ZERO");
        uint256 c0 = a * BONE;
        require(a == 0 || c0 / a == BONE, "ERR_DIV_INTERNAL"); // bmul overflow
        uint256 c1 = c0 + (b / 2);
        require(c1 >= c0, "ERR_DIV_INTERNAL"); //  badd require
        uint256 c2 = c1 / b;
        return c2;
    }

    // DSMath.wpow
    function bpowi(uint256 a, uint256 n) internal pure returns (uint256) {
        uint256 z = n % 2 != 0 ? a : BONE;

        for (n /= 2; n != 0; n /= 2) {
            a = bmul(a, a);

            if (n % 2 != 0) {
                z = bmul(z, a);
            }
        }
        return z;
    }

    // Compute b^(e.w) by splitting it into (b^e)*(b^0.w).
    // Use `bpowi` for `b^e` and `bpowK` for k iterations
    // of approximation of b^0.w
    function bpow(uint256 base, uint256 exp) internal pure returns (uint256) {
        require(base >= MIN_BPOW_BASE, "ERR_BPOW_BASE_TOO_LOW");
        require(base <= MAX_BPOW_BASE, "ERR_BPOW_BASE_TOO_HIGH");

        uint256 whole = bfloor(exp);
        uint256 remain = bsub(exp, whole);

        uint256 wholePow = bpowi(base, btoi(whole));

        if (remain == 0) {
            return wholePow;
        }

        uint256 partialResult = bpowApprox(base, remain, BPOW_PRECISION);
        return bmul(wholePow, partialResult);
    }

    function bpowApprox(
        uint256 base,
        uint256 exp,
        uint256 precision
    ) internal pure returns (uint256) {
        // term 0:
        uint256 a = exp;
        (uint256 x, bool xneg) = bsubSign(base, BONE);
        uint256 term = BONE;
        uint256 sum = term;
        bool negative = false;

        // term(k) = numer / denom
        //         = (product(a - i + 1, i=1-->k) * x^k) / (k!)
        // each iteration, multiply previous term by (a-(k-1)) * x / k
        // continue until term is less than precision
        for (uint256 i = 1; term >= precision; i++) {
            uint256 bigK = i * BONE;
            (uint256 c, bool cneg) = bsubSign(a, bsub(bigK, BONE));
            term = bmul(term, bmul(c, x));
            term = bdiv(term, bigK);
            if (term == 0) break;

            if (xneg) negative = !negative;
            if (cneg) negative = !negative;
            if (negative) {
                sum = bsub(sum, term);
            } else {
                sum = badd(sum, term);
            }
        }

        return sum;
    }
}

// File: contracts/interface/IERC20.sol

pragma solidity 0.5.17;

interface IERC20 {
    function name() external view returns (string memory);

    function symbol() external view returns (string memory);

    function decimals() external view returns (uint8);

    function totalSupply() external view returns (uint256);

    function balanceOf(address _owner) external view returns (uint256 balance);

    function transfer(address _to, uint256 _value)
        external
        returns (bool success);

    function transferFrom(
        address _from,
        address _to,
        uint256 _value
    ) external returns (bool success);

    function approve(address _spender, uint256 _value)
        external
        returns (bool success);

    function allowance(address _owner, address _spender)
        external
        view
        returns (uint256 remaining);
}

// File: contracts/XPToken.sol

pragma solidity 0.5.17;




// Highly opinionated token implementation
contract XTokenBase {
    using XNum for uint256;

    mapping(address => uint256) internal _balance;
    mapping(address => mapping(address => uint256)) internal _allowance;
    uint256 internal _totalSupply;

    event Approval(address indexed src, address indexed dst, uint256 amt);
    event Transfer(address indexed src, address indexed dst, uint256 amt);

    function _mint(uint256 amt) internal {
        _balance[address(this)] = (_balance[address(this)]).badd(amt);
        _totalSupply = _totalSupply.badd(amt);
        emit Transfer(address(0), address(this), amt);
    }

    function _burn(uint256 amt) internal {
        require(_balance[address(this)] >= amt, "ERR_INSUFFICIENT_BAL");
        _balance[address(this)] = (_balance[address(this)]).bsub(amt);
        _totalSupply = _totalSupply.bsub(amt);
        emit Transfer(address(this), address(0), amt);
    }

    function _move(
        address src,
        address dst,
        uint256 amt
    ) internal {
        require(_balance[src] >= amt, "ERR_INSUFFICIENT_BAL");
        _balance[src] = (_balance[src]).bsub(amt);
        _balance[dst] = (_balance[dst]).badd(amt);
        emit Transfer(src, dst, amt);
    }
}

contract XPToken is XTokenBase, IERC20, XApollo {
    using XNum for uint256;

    string private constant _name = "XDeFi Pool Token";
    string private constant _symbol = "XPT";
    uint8 private constant _decimals = 18;

    function name() external view returns (string memory) {
        return _name;
    }

    function symbol() external view returns (string memory) {
        return _symbol;
    }

    function decimals() external view returns (uint8) {
        return _decimals;
    }

    function allowance(address src, address dst)
        external
        view
        returns (uint256)
    {
        return _allowance[src][dst];
    }

    function balanceOf(address whom) external view returns (uint256) {
        return _balance[whom];
    }

    function totalSupply() public view returns (uint256) {
        return _totalSupply;
    }

    function approve(address dst, uint256 amt) external returns (bool) {
        _allowance[msg.sender][dst] = amt;
        emit Approval(msg.sender, dst, amt);
        return true;
    }

    function transfer(address dst, uint256 amt) external returns (bool) {
        _move(msg.sender, dst, amt);
        return true;
    }

    function transferFrom(
        address src,
        address dst,
        uint256 amt
    ) external returns (bool) {
        require(
            msg.sender == src || amt <= _allowance[src][msg.sender],
            "ERR_BTOKEN_BAD_CALLER"
        );
        _move(src, dst, amt);
        if (msg.sender != src && _allowance[src][msg.sender] != uint256(-1)) {
            _allowance[src][msg.sender] = (_allowance[src][msg.sender]).bsub(
                amt
            );
            emit Approval(msg.sender, dst, _allowance[src][msg.sender]);
        }
        return true;
    }
}

// File: contracts/lib/XMath.sol

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity 0.5.17;


library XMath {
    using XNum for uint256;

    uint256 public constant BONE = 10**18;
    uint256 public constant EXIT_ZERO_FEE = 0;

    /**********************************************************************************************
    // calcSpotPrice                                                                             //
    // sP = spotPrice                                                                            //
    // bI = tokenBalanceIn                ( bI / wI )         1                                  //
    // bO = tokenBalanceOut         sP =  -----------  *  ----------                             //
    // wI = tokenWeightIn                 ( bO / wO )     ( 1 - sF )                             //
    // wO = tokenWeightOut                                                                       //
    // sF = swapFee                                                                              //
    **********************************************************************************************/
    function calcSpotPrice(
        uint256 tokenBalanceIn,
        uint256 tokenWeightIn,
        uint256 tokenBalanceOut,
        uint256 tokenWeightOut,
        uint256 swapFee
    ) public pure returns (uint256 spotPrice) {
        uint256 numer = tokenBalanceIn.bdiv(tokenWeightIn);
        uint256 denom = tokenBalanceOut.bdiv(tokenWeightOut);
        uint256 ratio = numer.bdiv(denom);
        uint256 scale = BONE.bdiv(BONE.bsub(swapFee));
        return (spotPrice = ratio.bmul(scale));
    }

    /**********************************************************************************************
    // calcOutGivenIn                                                                            //
    // aO = tokenAmountOut                                                                       //
    // bO = tokenBalanceOut                                                                      //
    // bI = tokenBalanceIn              /      /            bI             \    (wI / wO) \      //
    // aI = tokenAmountIn    aO = bO * |  1 - | --------------------------  | ^            |     //
    // wI = tokenWeightIn               \      \ ( bI + ( aI * ( 1 - sF )) /              /      //
    // wO = tokenWeightOut                                                                       //
    // sF = swapFee                                                                              //
    **********************************************************************************************/
    function calcOutGivenIn(
        uint256 tokenBalanceIn,
        uint256 tokenWeightIn,
        uint256 tokenBalanceOut,
        uint256 tokenWeightOut,
        uint256 tokenAmountIn,
        uint256 swapFee
    ) public pure returns (uint256 tokenAmountOut) {
        uint256 weightRatio;
        if (tokenWeightIn == tokenWeightOut) {
            weightRatio = 1 * BONE;
        } else if (tokenWeightIn >> 1 == tokenWeightOut) {
            weightRatio = 2 * BONE;
        } else {
            weightRatio = tokenWeightIn.bdiv(tokenWeightOut);
        }
        uint256 adjustedIn = BONE.bsub(swapFee);
        adjustedIn = tokenAmountIn.bmul(adjustedIn);
        uint256 y = tokenBalanceIn.bdiv(tokenBalanceIn.badd(adjustedIn));
        uint256 foo;
        if (tokenWeightIn == tokenWeightOut) {
            foo = y;
        } else if (tokenWeightIn >> 1 == tokenWeightOut) {
            foo = y.bmul(y);
        } else {
            foo = y.bpow(weightRatio);
        }
        uint256 bar = BONE.bsub(foo);
        tokenAmountOut = tokenBalanceOut.bmul(bar);
        return tokenAmountOut;
    }

    /**********************************************************************************************
    // calcInGivenOut                                                                            //
    // aI = tokenAmountIn                                                                        //
    // bO = tokenBalanceOut               /  /     bO      \    (wO / wI)      \                 //
    // bI = tokenBalanceIn          bI * |  | ------------  | ^            - 1  |                //
    // aO = tokenAmountOut    aI =        \  \ ( bO - aO ) /                   /                 //
    // wI = tokenWeightIn           --------------------------------------------                 //
    // wO = tokenWeightOut                          ( 1 - sF )                                   //
    // sF = swapFee                                                                              //
    **********************************************************************************************/
    function calcInGivenOut(
        uint256 tokenBalanceIn,
        uint256 tokenWeightIn,
        uint256 tokenBalanceOut,
        uint256 tokenWeightOut,
        uint256 tokenAmountOut,
        uint256 swapFee
    ) public pure returns (uint256 tokenAmountIn) {
        uint256 weightRatio;
        if (tokenWeightOut == tokenWeightIn) {
            weightRatio = 1 * BONE;
        } else if (tokenWeightOut >> 1 == tokenWeightIn) {
            weightRatio = 2 * BONE;
        } else {
            weightRatio = tokenWeightOut.bdiv(tokenWeightIn);
        }
        uint256 diff = tokenBalanceOut.bsub(tokenAmountOut);
        uint256 y = tokenBalanceOut.bdiv(diff);
        uint256 foo;
        if (tokenWeightOut == tokenWeightIn) {
            foo = y;
        } else if (tokenWeightOut >> 1 == tokenWeightIn) {
            foo = y.bmul(y);
        } else {
            foo = y.bpow(weightRatio);
        }
        foo = foo.bsub(BONE);
        tokenAmountIn = BONE.bsub(swapFee);
        tokenAmountIn = tokenBalanceIn.bmul(foo).bdiv(tokenAmountIn);
        return tokenAmountIn;
    }

    /**********************************************************************************************
    // calcPoolOutGivenSingleIn                                                                  //
    // pAo = poolAmountOut         /                                              \              //
    // tAi = tokenAmountIn        ///      /     //    wI \      \\       \     wI \             //
    // wI = tokenWeightIn        //| tAi *| 1 - || 1 - --  | * sF || + tBi \    --  \            //
    // tW = totalWeight     pAo=||  \      \     \\    tW /      //         | ^ tW   | * pS - pS //
    // tBi = tokenBalanceIn      \\  ------------------------------------- /        /            //
    // pS = poolSupply            \\                    tBi               /        /             //
    // sF = swapFee                \                                              /              //
    **********************************************************************************************/
    function calcPoolOutGivenSingleIn(
        uint256 tokenBalanceIn,
        uint256 tokenWeightIn,
        uint256 poolSupply,
        uint256 totalWeight,
        uint256 tokenAmountIn,
        uint256 swapFee
    ) public pure returns (uint256 poolAmountOut) {
        // Charge the trading fee for the proportion of tokenAi
        ///  which is implicitly traded to the other pool tokens.
        // That proportion is (1- weightTokenIn)
        // tokenAiAfterFee = tAi * (1 - (1-weightTi) * poolFee);
        uint256 normalizedWeight = tokenWeightIn.bdiv(totalWeight);
        uint256 zaz = BONE.bsub(normalizedWeight).bmul(swapFee);
        uint256 tokenAmountInAfterFee = tokenAmountIn.bmul(BONE.bsub(zaz));

        uint256 newTokenBalanceIn = tokenBalanceIn.badd(tokenAmountInAfterFee);
        uint256 tokenInRatio = newTokenBalanceIn.bdiv(tokenBalanceIn);

        // uint newPoolSupply = (ratioTi ^ weightTi) * poolSupply;
        uint256 poolRatio = tokenInRatio.bpow(normalizedWeight);
        uint256 newPoolSupply = poolRatio.bmul(poolSupply);
        poolAmountOut = newPoolSupply.bsub(poolSupply);
        return poolAmountOut;
    }

    /**********************************************************************************************
    // calcSingleOutGivenPoolIn                                                                  //
    // tAo = tokenAmountOut            /      /                                             \\   //
    // bO = tokenBalanceOut           /      // pS - (pAi * (1 - eF)) \     /    1    \      \\  //
    // pAi = poolAmountIn            | bO - || ----------------------- | ^ | --------- | * b0 || //
    // ps = poolSupply                \      \\          pS           /     \(wO / tW)/      //  //
    // wI = tokenWeightIn      tAo =   \      \                                             //   //
    // tW = totalWeight                    /     /      wO \       \                             //
    // sF = swapFee                    *  | 1 - |  1 - ---- | * sF  |                            //
    // eF = exitFee                        \     \      tW /       /                             //
    **********************************************************************************************/
    function calcSingleOutGivenPoolIn(
        uint256 tokenBalanceOut,
        uint256 tokenWeightOut,
        uint256 poolSupply,
        uint256 totalWeight,
        uint256 poolAmountIn,
        uint256 swapFee
    ) public pure returns (uint256 tokenAmountOut) {
        uint256 normalizedWeight = tokenWeightOut.bdiv(totalWeight);
        // charge exit fee on the pool token side
        // pAiAfterExitFee = pAi*(1-exitFee)
        uint256 poolAmountInAfterExitFee =
            poolAmountIn.bmul(BONE.bsub(EXIT_ZERO_FEE));
        uint256 newPoolSupply = poolSupply.bsub(poolAmountInAfterExitFee);
        uint256 poolRatio = newPoolSupply.bdiv(poolSupply);

        // newBalTo = poolRatio^(1/weightTo) * balTo;
        uint256 tokenOutRatio = poolRatio.bpow(BONE.bdiv(normalizedWeight));
        uint256 newTokenBalanceOut = tokenOutRatio.bmul(tokenBalanceOut);

        uint256 tokenAmountOutBeforeSwapFee =
            tokenBalanceOut.bsub(newTokenBalanceOut);

        // charge swap fee on the output token side
        //uint tAo = tAoBeforeSwapFee * (1 - (1-weightTo) * swapFee)
        uint256 zaz = BONE.bsub(normalizedWeight).bmul(swapFee);
        tokenAmountOut = tokenAmountOutBeforeSwapFee.bmul(BONE.bsub(zaz));
        return tokenAmountOut;
    }
}

// File: contracts/interface/IXConfig.sol

pragma solidity 0.5.17;

interface IXConfig {
    function getCore() external view returns (address);

    function getSAFU() external view returns (address);

    function getMaxExitFee() external view returns (uint256);

    function getSafuFee() external view returns (uint256);

    function getSwapProxy() external view returns (address);

    function dedupPool(address[] calldata tokens, uint256[] calldata denorms)
        external
        returns (bool exist, bytes32 sig);

    function addPoolSig(bytes32 sig, address pool) external;
}

// File: contracts/XPool.sol

pragma solidity 0.5.17;







contract XPool is XApollo, XPToken, XConst {
    using XNum for uint256;

    //Swap Fees: 0.1%, 0.25%, 1%, 2.5%, 10%
    uint256[5] public SWAP_FEES = [
        BONE / 1000,
        (25 * BONE) / 10000,
        BONE / 100,
        (25 * BONE) / 1000,
        BONE / 10
    ];

    struct Record {
        bool bound; // is token bound to pool
        uint256 index; // private
        uint256 denorm; // denormalized weight
        uint256 balance;
    }

    event LOG_SWAP(
        address indexed caller,
        address indexed tokenIn,
        address indexed tokenOut,
        uint256 tokenAmountIn,
        uint256 tokenAmountOut
    );

    event LOG_REFER(
        address indexed caller,
        address indexed ref,
        address indexed tokenIn,
        uint256 fee
    );

    event LOG_JOIN(
        address indexed caller,
        address indexed tokenIn,
        uint256 tokenAmountIn
    );

    event LOG_EXIT(
        address indexed caller,
        address indexed tokenOut,
        uint256 tokenAmountOut
    );

    event LOG_BIND(
        address indexed caller,
        address indexed token,
        uint256 denorm,
        uint256 balance
    );

    event LOG_UPDATE_SAFU(address indexed safu, uint256 fee);

    event LOG_EXIT_FEE(uint256 fee);

    event LOG_FINAL(uint256 swapFee);

    event SET_CONTROLLER(address indexed manager);

    event UPDATE_FARM(address indexed caller, bool isFarm);

    // anonymous event
    event LOG_CALL(
        bytes4 indexed sig,
        address indexed caller,
        bytes data
    ) anonymous;

    modifier _logs_() {
        emit LOG_CALL(msg.sig, msg.sender, msg.data);
        _;
    }

    modifier _lock_() {
        require(!_mutex, "ERR_REENTRY");
        _mutex = true;
        _;
        _mutex = false;
    }

    modifier _viewlock_() {
        require(!_mutex, "ERR_REENTRY");
        _;
    }

    bool private _mutex;

    address public controller; // has CONTROL role

    // `finalize` require CONTROL, `finalize` sets `can SWAP and can JOIN`
    bool public finalized;

    uint256 public swapFee;
    uint256 public exitFee;

    // Pool Governance
    address public SAFU;
    uint256 public safuFee;
    bool public isFarmPool;

    address[] internal _tokens;
    mapping(address => Record) internal _records;
    uint256 private _totalWeight;

    IXConfig public xconfig;
    address public origin;

    constructor(address _xconfig, address _controller) public {
        controller = _controller;
        origin = tx.origin;
        swapFee = SWAP_FEES[1];
        exitFee = EXIT_ZERO_FEE;
        finalized = false;
        xconfig = IXConfig(_xconfig);
        SAFU = xconfig.getSAFU();
        safuFee = xconfig.getSafuFee();
    }

    function isBound(address t) external view returns (bool) {
        return _records[t].bound;
    }

    function getNumTokens() external view returns (uint256) {
        return _tokens.length;
    }

    function getFinalTokens()
        external
        view
        _viewlock_
        returns (address[] memory tokens)
    {
        require(finalized, "ERR_NOT_FINALIZED");
        return _tokens;
    }

    function getDenormalizedWeight(address token)
        external
        view
        _viewlock_
        returns (uint256)
    {
        require(_records[token].bound, "ERR_NOT_BOUND");
        return _records[token].denorm;
    }

    function getTotalDenormalizedWeight()
        external
        view
        _viewlock_
        returns (uint256)
    {
        return _totalWeight;
    }

    function getNormalizedWeight(address token)
        external
        view
        _viewlock_
        returns (uint256)
    {
        require(_records[token].bound, "ERR_NOT_BOUND");
        uint256 denorm = _records[token].denorm;
        return denorm.bdiv(_totalWeight);
    }

    function getBalance(address token)
        external
        view
        _viewlock_
        returns (uint256)
    {
        require(_records[token].bound, "ERR_NOT_BOUND");
        return _records[token].balance;
    }

    function setController(address manager) external _logs_ {
        require(msg.sender == controller, "ERR_NOT_CONTROLLER");
        require(manager != address(0), "ERR_ZERO_ADDR");
        controller = manager;
        emit SET_CONTROLLER(manager);
    }

    function setExitFee(uint256 fee) external {
        require(!finalized, "ERR_IS_FINALIZED");
        require(msg.sender == controller, "ERR_NOT_CONTROLLER");
        require(fee <= xconfig.getMaxExitFee(), "INVALID_EXIT_FEE");
        exitFee = fee;
        emit LOG_EXIT_FEE(fee);
    }

    // allow SAFU address and SAFE FEE be updated by xconfig
    function updateSafu(address safu, uint256 fee) external {
        require(msg.sender == address(xconfig), "ERR_NOT_CONFIG");
        require(safu != address(0), "ERR_ZERO_ADDR");
        SAFU = safu;
        safuFee = fee;

        emit LOG_UPDATE_SAFU(safu, fee);
    }

    // allow isFarmPool be updated by xconfig
    function updateFarm(bool isFarm) external {
        require(msg.sender == address(xconfig), "ERR_NOT_CONFIG");
        isFarmPool = isFarm;
        emit UPDATE_FARM(msg.sender, isFarm);
    }

    function bind(address token, uint256 denorm) external _lock_ {
        require(msg.sender == controller, "ERR_NOT_CONTROLLER");
        require(!_records[token].bound, "ERR_IS_BOUND");
        require(!finalized, "ERR_IS_FINALIZED");

        require(_tokens.length < MAX_BOUND_TOKENS, "ERR_MAX_TOKENS");

        require(denorm >= MIN_WEIGHT, "ERR_MIN_WEIGHT");
        require(denorm <= MAX_WEIGHT, "ERR_MAX_WEIGHT");

        uint256 balance = IERC20(token).balanceOf(address(this));

        uint256 decimal = 10**uint256(IERC20(token).decimals());
        require(decimal >= 10**6, "ERR_TOO_SMALL");

        // 0.000001 TOKEN
        require(balance >= decimal / MIN_BALANCE, "ERR_MIN_BALANCE");

        _totalWeight = _totalWeight.badd(denorm);
        require(_totalWeight <= MAX_TOTAL_WEIGHT, "ERR_MAX_TOTAL_WEIGHT");

        _records[token] = Record({
            bound: true,
            index: _tokens.length,
            denorm: denorm,
            balance: balance
        });
        _tokens.push(token);

        emit LOG_BIND(msg.sender, token, denorm, balance);
    }

    // _swapFee must be one of SWAP_FEES
    function finalize(uint256 _swapFee) external _lock_ {
        require(msg.sender == controller, "ERR_NOT_CONTROLLER");
        require(!finalized, "ERR_IS_FINALIZED");
        require(_tokens.length >= MIN_BOUND_TOKENS, "ERR_MIN_TOKENS");
        require(_tokens.length <= MAX_BOUND_TOKENS, "ERR_MAX_TOKENS");

        require(_swapFee >= SWAP_FEES[0], "ERR_MIN_FEE");
        require(_swapFee <= SWAP_FEES[SWAP_FEES.length - 1], "ERR_MAX_FEE");

        bool found = false;
        for (uint256 i = 0; i < SWAP_FEES.length; i++) {
            if (_swapFee == SWAP_FEES[i]) {
                found = true;
                break;
            }
        }
        require(found, "ERR_INVALID_SWAP_FEE");
        swapFee = _swapFee;

        finalized = true;

        _mintPoolShare(INIT_POOL_SUPPLY);
        _pushPoolShare(msg.sender, INIT_POOL_SUPPLY);

        emit LOG_FINAL(swapFee);
    }

    // Absorb any tokens that have been sent to this contract into the pool
    function gulp(address token) external _logs_ _lock_ {
        require(_records[token].bound, "ERR_NOT_BOUND");
        _records[token].balance = IERC20(token).balanceOf(address(this));
    }

    function getSpotPrice(address tokenIn, address tokenOut)
        external
        view
        _viewlock_
        returns (uint256 spotPrice)
    {
        require(_records[tokenIn].bound, "ERR_NOT_BOUND");
        require(_records[tokenOut].bound, "ERR_NOT_BOUND");
        Record storage inRecord = _records[tokenIn];
        Record storage outRecord = _records[tokenOut];
        return
            XMath.calcSpotPrice(
                inRecord.balance,
                inRecord.denorm,
                outRecord.balance,
                outRecord.denorm,
                swapFee
            );
    }

    function getSpotPriceSansFee(address tokenIn, address tokenOut)
        external
        view
        _viewlock_
        returns (uint256 spotPrice)
    {
        require(_records[tokenIn].bound, "ERR_NOT_BOUND");
        require(_records[tokenOut].bound, "ERR_NOT_BOUND");
        Record storage inRecord = _records[tokenIn];
        Record storage outRecord = _records[tokenOut];
        return
            XMath.calcSpotPrice(
                inRecord.balance,
                inRecord.denorm,
                outRecord.balance,
                outRecord.denorm,
                0
            );
    }

    function joinPool(uint256 poolAmountOut, uint256[] calldata maxAmountsIn)
        external
        _lock_
    {
        require(finalized, "ERR_NOT_FINALIZED");
        require(maxAmountsIn.length == _tokens.length, "ERR_LENGTH_MISMATCH");

        uint256 poolTotal = totalSupply();
        uint256 ratio = poolAmountOut.bdiv(poolTotal);
        require(ratio != 0, "ERR_MATH_APPROX");

        for (uint256 i = 0; i < _tokens.length; i++) {
            address t = _tokens[i];
            uint256 bal = _records[t].balance;
            uint256 tokenAmountIn = ratio.bmul(bal);
            require(tokenAmountIn != 0, "ERR_MATH_APPROX");
            require(tokenAmountIn <= maxAmountsIn[i], "ERR_LIMIT_IN");
            _records[t].balance = (_records[t].balance).badd(tokenAmountIn);
            emit LOG_JOIN(msg.sender, t, tokenAmountIn);
            _pullUnderlying(t, msg.sender, tokenAmountIn);
        }
        _mintPoolShare(poolAmountOut);
        _pushPoolShare(msg.sender, poolAmountOut);
    }

    function exitPool(uint256 poolAmountIn, uint256[] calldata minAmountsOut)
        external
        _lock_
    {
        require(finalized, "ERR_NOT_FINALIZED");
        require(minAmountsOut.length == _tokens.length, "ERR_LENGTH_MISMATCH");

        // min pool amount
        require(poolAmountIn >= MIN_POOL_AMOUNT, "ERR_MIN_AMOUNT");

        uint256 poolTotal = totalSupply();
        uint256 _exitFee = poolAmountIn.bmul(exitFee);

        // never charge exitFee to pool origin
        if (msg.sender == origin) {
            _exitFee = 0;
        }
        uint256 pAiAfterExitFee = poolAmountIn.bsub(_exitFee);
        uint256 ratio = pAiAfterExitFee.bdiv(poolTotal);
        require(ratio != 0, "ERR_MATH_APPROX");

        _pullPoolShare(msg.sender, poolAmountIn);
        // send exitFee to origin
        if (_exitFee > 0) {
            _pushPoolShare(origin, _exitFee);
        }
        _burnPoolShare(pAiAfterExitFee);

        for (uint256 i = 0; i < _tokens.length; i++) {
            address t = _tokens[i];
            uint256 bal = _records[t].balance;
            uint256 tokenAmountOut = ratio.bmul(bal);
            require(tokenAmountOut != 0, "ERR_MATH_APPROX");
            require(tokenAmountOut >= minAmountsOut[i], "ERR_LIMIT_OUT");
            _records[t].balance = (_records[t].balance).bsub(tokenAmountOut);
            emit LOG_EXIT(msg.sender, t, tokenAmountOut);
            _pushUnderlying(t, msg.sender, tokenAmountOut);
        }
    }

    function swapExactAmountIn(
        address tokenIn,
        uint256 tokenAmountIn,
        address tokenOut,
        uint256 minAmountOut,
        uint256 maxPrice
    ) external returns (uint256 tokenAmountOut, uint256 spotPriceAfter) {
        return
            swapExactAmountInRefer(
                tokenIn,
                tokenAmountIn,
                tokenOut,
                minAmountOut,
                maxPrice,
                address(0x0)
            );
    }

    function swapExactAmountInRefer(
        address tokenIn,
        uint256 tokenAmountIn,
        address tokenOut,
        uint256 minAmountOut,
        uint256 maxPrice,
        address referrer
    ) public _lock_ returns (uint256 tokenAmountOut, uint256 spotPriceAfter) {
        require(_records[tokenIn].bound, "ERR_NOT_BOUND");
        require(_records[tokenOut].bound, "ERR_NOT_BOUND");
        require(finalized, "ERR_NOT_FINALIZED");

        Record storage inRecord = _records[address(tokenIn)];
        Record storage outRecord = _records[address(tokenOut)];

        require(
            tokenAmountIn <= (inRecord.balance).bmul(MAX_IN_RATIO),
            "ERR_MAX_IN_RATIO"
        );

        uint256 spotPriceBefore =
            XMath.calcSpotPrice(
                inRecord.balance,
                inRecord.denorm,
                outRecord.balance,
                outRecord.denorm,
                swapFee
            );
        require(spotPriceBefore <= maxPrice, "ERR_BAD_LIMIT_PRICE");

        tokenAmountOut = calcOutGivenIn(
            inRecord.balance,
            inRecord.denorm,
            outRecord.balance,
            outRecord.denorm,
            tokenAmountIn,
            swapFee
        );
        require(tokenAmountOut >= minAmountOut, "ERR_LIMIT_OUT");
        require(
            spotPriceBefore <= tokenAmountIn.bdiv(tokenAmountOut),
            "ERR_MATH_APPROX"
        );

        inRecord.balance = (inRecord.balance).badd(tokenAmountIn);
        outRecord.balance = (outRecord.balance).bsub(tokenAmountOut);

        spotPriceAfter = XMath.calcSpotPrice(
            inRecord.balance,
            inRecord.denorm,
            outRecord.balance,
            outRecord.denorm,
            swapFee
        );
        require(spotPriceAfter >= spotPriceBefore, "ERR_MATH_APPROX");
        require(spotPriceAfter <= maxPrice, "ERR_LIMIT_PRICE");

        emit LOG_SWAP(
            msg.sender,
            tokenIn,
            tokenOut,
            tokenAmountIn,
            tokenAmountOut
        );

        _pullUnderlying(tokenIn, msg.sender, tokenAmountIn);

        uint256 _swapFee = tokenAmountIn.bmul(swapFee);

        // to referral
        uint256 _referFee = 0;
        if (
            referrer != address(0) &&
            referrer != msg.sender &&
            referrer != tx.origin
        ) {
            _referFee = _swapFee / 5; // 20% to referrer
            _pushUnderlying(tokenIn, referrer, _referFee);
            inRecord.balance = (inRecord.balance).bsub(_referFee);
            emit LOG_REFER(msg.sender, referrer, tokenIn, _referFee);
        }

        // to SAFU
        uint256 _safuFee = tokenAmountIn.bmul(safuFee);
        if (isFarmPool) {
            _safuFee = _swapFee.bsub(_referFee);
        }
        require(_safuFee.badd(_referFee) <= _swapFee, "ERR_FEE_LIMIT");
        _pushUnderlying(tokenIn, SAFU, _safuFee);
        inRecord.balance = (inRecord.balance).bsub(_safuFee);

        _pushUnderlying(tokenOut, msg.sender, tokenAmountOut);
        return (tokenAmountOut, spotPriceAfter);
    }

    function swapExactAmountOut(
        address tokenIn,
        uint256 maxAmountIn,
        address tokenOut,
        uint256 tokenAmountOut,
        uint256 maxPrice
    ) external returns (uint256 tokenAmountIn, uint256 spotPriceAfter) {
        return
            swapExactAmountOutRefer(
                tokenIn,
                maxAmountIn,
                tokenOut,
                tokenAmountOut,
                maxPrice,
                address(0x0)
            );
    }

    function swapExactAmountOutRefer(
        address tokenIn,
        uint256 maxAmountIn,
        address tokenOut,
        uint256 tokenAmountOut,
        uint256 maxPrice,
        address referrer
    ) public _lock_ returns (uint256 tokenAmountIn, uint256 spotPriceAfter) {
        require(_records[tokenIn].bound, "ERR_NOT_BOUND");
        require(_records[tokenOut].bound, "ERR_NOT_BOUND");
        require(finalized, "ERR_NOT_FINALIZED");

        Record storage inRecord = _records[address(tokenIn)];
        Record storage outRecord = _records[address(tokenOut)];

        require(
            tokenAmountOut <= (outRecord.balance).bmul(MAX_OUT_RATIO),
            "ERR_MAX_OUT_RATIO"
        );

        uint256 spotPriceBefore =
            XMath.calcSpotPrice(
                inRecord.balance,
                inRecord.denorm,
                outRecord.balance,
                outRecord.denorm,
                swapFee
            );
        require(spotPriceBefore <= maxPrice, "ERR_BAD_LIMIT_PRICE");

        tokenAmountIn = calcInGivenOut(
            inRecord.balance,
            inRecord.denorm,
            outRecord.balance,
            outRecord.denorm,
            tokenAmountOut,
            swapFee
        );
        require(tokenAmountIn <= maxAmountIn, "ERR_LIMIT_IN");
        require(
            spotPriceBefore <= tokenAmountIn.bdiv(tokenAmountOut),
            "ERR_MATH_APPROX"
        );

        inRecord.balance = (inRecord.balance).badd(tokenAmountIn);
        outRecord.balance = (outRecord.balance).bsub(tokenAmountOut);

        spotPriceAfter = XMath.calcSpotPrice(
            inRecord.balance,
            inRecord.denorm,
            outRecord.balance,
            outRecord.denorm,
            swapFee
        );
        require(spotPriceAfter >= spotPriceBefore, "ERR_MATH_APPROX");
        require(spotPriceAfter <= maxPrice, "ERR_LIMIT_PRICE");

        emit LOG_SWAP(
            msg.sender,
            tokenIn,
            tokenOut,
            tokenAmountIn,
            tokenAmountOut
        );

        _pullUnderlying(tokenIn, msg.sender, tokenAmountIn);

        uint256 _swapFee = tokenAmountIn.bmul(swapFee);
        // to referral
        uint256 _referFee = 0;
        if (
            referrer != address(0) &&
            referrer != msg.sender &&
            referrer != tx.origin
        ) {
            _referFee = _swapFee / 5; // 20% to referrer
            _pushUnderlying(tokenIn, referrer, _referFee);
            inRecord.balance = (inRecord.balance).bsub(_referFee);
            emit LOG_REFER(msg.sender, referrer, tokenIn, _referFee);
        }

        // to SAFU
        uint256 _safuFee = tokenAmountIn.bmul(safuFee);
        if (isFarmPool) {
            _safuFee = _swapFee.bsub(_referFee);
        }
        require(_safuFee.badd(_referFee) <= _swapFee, "ERR_FEE_LIMIT");
        _pushUnderlying(tokenIn, SAFU, _safuFee);
        inRecord.balance = (inRecord.balance).bsub(_safuFee);

        _pushUnderlying(tokenOut, msg.sender, tokenAmountOut);
        return (tokenAmountIn, spotPriceAfter);
    }

    function joinswapExternAmountIn(
        address tokenIn,
        uint256 tokenAmountIn,
        uint256 minPoolAmountOut
    ) external _lock_ returns (uint256 poolAmountOut) {
        require(finalized, "ERR_NOT_FINALIZED");
        require(_records[tokenIn].bound, "ERR_NOT_BOUND");
        require(
            tokenAmountIn <= (_records[tokenIn].balance).bmul(MAX_IN_RATIO),
            "ERR_MAX_IN_RATIO"
        );

        _pullUnderlying(tokenIn, msg.sender, tokenAmountIn);

        // to SAFU
        uint256 _safuFee = tokenAmountIn.bmul(safuFee);
        if (isFarmPool) {
            _safuFee = tokenAmountIn.bmul(swapFee);
        }
        tokenAmountIn = tokenAmountIn.bsub(_safuFee);

        Record storage inRecord = _records[tokenIn];
        poolAmountOut = XMath.calcPoolOutGivenSingleIn(
            inRecord.balance,
            inRecord.denorm,
            _totalSupply,
            _totalWeight,
            tokenAmountIn,
            swapFee
        );
        require(poolAmountOut >= minPoolAmountOut, "ERR_LIMIT_OUT");

        inRecord.balance = (inRecord.balance).badd(tokenAmountIn);

        _pushUnderlying(tokenIn, SAFU, _safuFee);
        emit LOG_JOIN(msg.sender, tokenIn, tokenAmountIn);
        _mintPoolShare(poolAmountOut);
        _pushPoolShare(msg.sender, poolAmountOut);
        return poolAmountOut;
    }

    function exitswapPoolAmountIn(
        address tokenOut,
        uint256 poolAmountIn,
        uint256 minAmountOut
    ) external _logs_ _lock_ returns (uint256 tokenAmountOut) {
        require(finalized, "ERR_NOT_FINALIZED");
        require(_records[tokenOut].bound, "ERR_NOT_BOUND");
        require(poolAmountIn >= MIN_POOL_AMOUNT, "ERR_MIN_AMOUNT");

        _pullPoolShare(msg.sender, poolAmountIn);

        // exit fee to origin
        if (exitFee > 0 && msg.sender != origin) {
            uint256 _exitFee = poolAmountIn.bmul(exitFee);
            _pushPoolShare(origin, _exitFee);
            poolAmountIn = poolAmountIn.bsub(_exitFee);
        }

        _burnPoolShare(poolAmountIn);

        Record storage outRecord = _records[tokenOut];
        tokenAmountOut = XMath.calcSingleOutGivenPoolIn(
            outRecord.balance,
            outRecord.denorm,
            _totalSupply,
            _totalWeight,
            poolAmountIn,
            swapFee
        );

        require(tokenAmountOut >= minAmountOut, "ERR_LIMIT_OUT");
        require(
            tokenAmountOut <= (_records[tokenOut].balance).bmul(MAX_OUT_RATIO),
            "ERR_MAX_OUT_RATIO"
        );

        outRecord.balance = (outRecord.balance).bsub(tokenAmountOut);

        // to SAFU
        uint256 _safuFee = tokenAmountOut.bmul(safuFee);
        if (isFarmPool) {
            _safuFee = tokenAmountOut.bmul(swapFee);
        }

        emit LOG_EXIT(msg.sender, tokenOut, tokenAmountOut);
        _pushUnderlying(tokenOut, SAFU, _safuFee);
        _pushUnderlying(tokenOut, msg.sender, tokenAmountOut.bsub(_safuFee));
        return tokenAmountOut;
    }

    function calcOutGivenIn(
        uint256 tokenBalanceIn,
        uint256 tokenWeightIn,
        uint256 tokenBalanceOut,
        uint256 tokenWeightOut,
        uint256 tokenAmountIn,
        uint256 _swapFee
    ) public pure returns (uint256) {
        return
            XMath.calcOutGivenIn(
                tokenBalanceIn,
                tokenWeightIn,
                tokenBalanceOut,
                tokenWeightOut,
                tokenAmountIn,
                _swapFee
            );
    }

    function calcInGivenOut(
        uint256 tokenBalanceIn,
        uint256 tokenWeightIn,
        uint256 tokenBalanceOut,
        uint256 tokenWeightOut,
        uint256 tokenAmountOut,
        uint256 _swapFee
    ) public pure returns (uint256) {
        return
            XMath.calcInGivenOut(
                tokenBalanceIn,
                tokenWeightIn,
                tokenBalanceOut,
                tokenWeightOut,
                tokenAmountOut,
                _swapFee
            );
    }

    // ==
    // 'Underlying' token-manipulation functions make external calls but are NOT locked
    // You must `_lock_` or otherwise ensure reentry-safety
    // Fixed ERC-20 transfer revert for some special token such as USDT
    function _pullUnderlying(
        address erc20,
        address from,
        uint256 amount
    ) internal {
        // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
        (bool success, bytes memory data) =
            erc20.call(
                abi.encodeWithSelector(0x23b872dd, from, address(this), amount)
            );
        require(
            success && (data.length == 0 || abi.decode(data, (bool))),
            "ERC20_TRANSFER_FROM_FAILED"
        );
    }

    function _pushUnderlying(
        address erc20,
        address to,
        uint256 amount
    ) internal {
        // bytes4(keccak256(bytes('transfer(address,uint256)')));
        (bool success, bytes memory data) =
            erc20.call(abi.encodeWithSelector(0xa9059cbb, to, amount));
        require(
            success && (data.length == 0 || abi.decode(data, (bool))),
            "ERC20_TRANSFER_FAILED"
        );
    }

    function _pullPoolShare(address from, uint256 amount) internal {
        _move(from, address(this), amount);
    }

    function _pushPoolShare(address to, uint256 amount) internal {
        _move(address(this), to, amount);
    }

    function _mintPoolShare(uint256 amount) internal {
        _mint(amount);
    }

    function _burnPoolShare(uint256 amount) internal {
        _burn(amount);
    }
}

Read Contract

BONE 0xc36596a6 → uint256
EXIT_ZERO_FEE 0x11b42b1e → uint256
INIT_POOL_SUPPLY 0x9381cd2b → uint256
MAX_BOUND_TOKENS 0xb0e0d136 → uint256
MAX_IN_RATIO 0xec093021 → uint256
MAX_OUT_RATIO 0x992e2a92 → uint256
MAX_TOTAL_WEIGHT 0x09a3bbe4 → uint256
MAX_WEIGHT 0xe4a28a52 → uint256
MIN_BALANCE 0x867378c5 → uint256
MIN_BOUND_TOKENS 0xb7b800a4 → uint256
MIN_POOL_AMOUNT 0x17ab06e1 → uint256
MIN_WEIGHT 0x218b5382 → uint256
SAFU 0x0dbc6b3e → address
SWAP_FEES 0xf699a391 → uint256
allowance 0xdd62ed3e → uint256
balanceOf 0x70a08231 → uint256
calcInGivenOut 0xf8d6aed4 → uint256
calcOutGivenIn 0xba9530a6 → uint256
controller 0xf77c4791 → address
decimals 0x313ce567 → uint8
exitFee 0x6284ae41 → uint256
finalized 0xb3f05b97 → bool
getBalance 0xf8b2cb4f → uint256
getDenormalizedWeight 0x948d8ce6 → uint256
getFinalTokens 0xbe3bbd2e → address[]
getNormalizedWeight 0xf1b8a9b7 → uint256
getNumTokens 0xcd2ed8fb → uint256
getSpotPrice 0x15e84af9 → uint256
getSpotPriceSansFee 0x1446a7ff → uint256
getTotalDenormalizedWeight 0x936c3477 → uint256
getVersion 0x0d8e6e2c → bytes32
isBound 0x2f37b624 → bool
isFarmPool 0xe755f7ea → bool
name 0x06fdde03 → string
origin 0x938b5f32 → address
safuFee 0x71cbfdca → uint256
swapFee 0x54cf2aeb → uint256
symbol 0x95d89b41 → string
totalSupply 0x18160ddd → uint256
xconfig 0x6a7f63fa → address

Write Contract 18 functions

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

approve 0x095ea7b3
address dst
uint256 amt
returns: bool
bind 0x9c649fee
address token
uint256 denorm
exitPool 0xb02f0b73
uint256 poolAmountIn
uint256[] minAmountsOut
exitswapPoolAmountIn 0x46ab38f1
address tokenOut
uint256 poolAmountIn
uint256 minAmountOut
returns: uint256
finalize 0x05261aea
uint256 _swapFee
gulp 0x8c28cbe8
address token
joinPool 0x4f69c0d4
uint256 poolAmountOut
uint256[] maxAmountsIn
joinswapExternAmountIn 0x5db34277
address tokenIn
uint256 tokenAmountIn
uint256 minPoolAmountOut
returns: uint256
setController 0x92eefe9b
address manager
setExitFee 0xe5a583a9
uint256 fee
swapExactAmountIn 0x8201aa3f
address tokenIn
uint256 tokenAmountIn
address tokenOut
uint256 minAmountOut
uint256 maxPrice
returns: uint256, uint256
swapExactAmountInRefer 0x7ae05237
address tokenIn
uint256 tokenAmountIn
address tokenOut
uint256 minAmountOut
uint256 maxPrice
address referrer
returns: uint256, uint256
swapExactAmountOut 0x7c5e9ea4
address tokenIn
uint256 maxAmountIn
address tokenOut
uint256 tokenAmountOut
uint256 maxPrice
returns: uint256, uint256
swapExactAmountOutRefer 0x81efd24a
address tokenIn
uint256 maxAmountIn
address tokenOut
uint256 tokenAmountOut
uint256 maxPrice
address referrer
returns: uint256, uint256
transfer 0xa9059cbb
address dst
uint256 amt
returns: bool
transferFrom 0x23b872dd
address src
address dst
uint256 amt
returns: bool
updateFarm 0x1ca22ea5
bool isFarm
updateSafu 0xcd669be0
address safu
uint256 fee

Recent Transactions

No transactions found for this address