Address Contract Partially Verified
Address
0x5D2cAAd2B7f851dcb001E7D1156fdc3B4936666c
Balance
0 ETH
Nonce
1
Code Size
19279 bytes
Creator
0x3FdFdCE9...3b7E at tx 0xc2960e0a...786b2c
Indexed Transactions
0
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
Token Balances (2)
View Transfers →Recent Transactions
No transactions found for this address