Transaction Hash:
Block:
12061887 at Mar-18-2021 09:43:21 AM +UTC
Transaction Fee:
0.51454768 ETH
$1,726.64
Gas Used:
3,215,923 Gas / 160 Gwei
Emitted Events:
50 |
0x750dd34fb165be682fae445793ab9ab9729cdaa3.0xb02f0b7300000000000000000000000000000000000000000000000000000000( 0xb02f0b7300000000000000000000000000000000000000000000000000000000, 0x0000000000000000000000008da8f82d2bbdd896822de723f55d6edf416130ba, 0000000000000000000000000000000000000000000000000000000000000020, 00000000000000000000000000000000000000000000000000000000000000a4, b02f0b730000000000000000000000000000000000000000000000056bc7033a, 5295c00000000000000000000000000000000000000000000000000000000000, 0000004000000000000000000000000000000000000000000000000000000000, 0000000200000000000000000000000000000000000000000000d3c21bcecced, a100000000000000000000000000000000000000000000000000000000001230, 9ce5400000000000000000000000000000000000000000000000000000000000 )
|
51 |
BPool.0x49b5955200000000000000000000000000000000000000000000000000000000( 0x49b5955200000000000000000000000000000000000000000000000000000000, 0x000000000000000000000000750dd34fb165be682fae445793ab9ab9729cdaa3, 0000000000000000000000000000000000000000000000000000000000000020, 0000000000000000000000000000000000000000000000000000000000000024, 49b5955200000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000 )
|
52 |
0x750dd34fb165be682fae445793ab9ab9729cdaa3.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x0000000000000000000000008da8f82d2bbdd896822de723f55d6edf416130ba, 0x000000000000000000000000750dd34fb165be682fae445793ab9ab9729cdaa3, 0000000000000000000000000000000000000000000000056bc7033a5295c000 )
|
53 |
0x750dd34fb165be682fae445793ab9ab9729cdaa3.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x000000000000000000000000750dd34fb165be682fae445793ab9ab9729cdaa3, 0x0000000000000000000000009424b1412450d0f8fc2255faf6046b98213b76bd, 0000000000000000000000000000000000000000000000000000000000000000 )
|
54 |
0x750dd34fb165be682fae445793ab9ab9729cdaa3.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x000000000000000000000000750dd34fb165be682fae445793ab9ab9729cdaa3, 0x0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000056bc7033a5295c000 )
|
55 |
0x750dd34fb165be682fae445793ab9ab9729cdaa3.0xc62fc35ac75e3bff532648e2859a3e1694002cfa357614ae8e034df7f83db5e9( 0xc62fc35ac75e3bff532648e2859a3e1694002cfa357614ae8e034df7f83db5e9, 0x0000000000000000000000008da8f82d2bbdd896822de723f55d6edf416130ba, 0x00000000000000000000000031c8eacbffdd875c74b94b077895bd78cf1e64a3, 000000000000000000000000000000000000000000017123047bf9659689c1a3 )
|
56 |
BPool.0x3fdddaa200000000000000000000000000000000000000000000000000000000( 0x3fdddaa200000000000000000000000000000000000000000000000000000000, 0x000000000000000000000000750dd34fb165be682fae445793ab9ab9729cdaa3, 0000000000000000000000000000000000000000000000000000000000000020, 0000000000000000000000000000000000000000000000000000000000000064, 3fdddaa200000000000000000000000031c8eacbffdd875c74b94b077895bd78, cf1e64a300000000000000000000000000000000000000000000000018311803, 9be34ee3000000000000000000000000000000000000000000000001158e4609, 13d0000000000000000000000000000000000000000000000000000000000000 )
|
57 |
RadicleToken.Transfer( from=BPool, to=0x750dd34fb165be682fae445793ab9ab9729cdaa3, amount=1743199191347491917906339 )
|
58 |
RadicleToken.Transfer( from=BPool, to=BFactory, amount=0 )
|
59 |
RadicleToken.Transfer( from=0x750dd34fb165be682fae445793ab9ab9729cdaa3, to=Timelock, amount=1743199191347491917906339 )
|
60 |
0x750dd34fb165be682fae445793ab9ab9729cdaa3.0xc62fc35ac75e3bff532648e2859a3e1694002cfa357614ae8e034df7f83db5e9( 0xc62fc35ac75e3bff532648e2859a3e1694002cfa357614ae8e034df7f83db5e9, 0x0000000000000000000000008da8f82d2bbdd896822de723f55d6edf416130ba, 0x000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48, 00000000000000000000000000000000000000000000000000001b603cf1990d )
|
61 |
BPool.0x3fdddaa200000000000000000000000000000000000000000000000000000000( 0x3fdddaa200000000000000000000000000000000000000000000000000000000, 0x000000000000000000000000750dd34fb165be682fae445793ab9ab9729cdaa3, 0000000000000000000000000000000000000000000000000000000000000020, 0000000000000000000000000000000000000000000000000000000000000064, 3fdddaa2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce, 3606eb4800000000000000000000000000000000000000000000000000000000, 01cb4ad8000000000000000000000000000000000000000000000001158e4609, 13d0000000000000000000000000000000000000000000000000000000000000 )
|
62 |
FiatTokenProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x000000000000000000000000824603f89e27af953cab03a82017e4a74dd4df73, 0x000000000000000000000000750dd34fb165be682fae445793ab9ab9729cdaa3, 00000000000000000000000000000000000000000000000000001b603cf1990d )
|
63 |
FiatTokenProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x000000000000000000000000824603f89e27af953cab03a82017e4a74dd4df73, 0x0000000000000000000000009424b1412450d0f8fc2255faf6046b98213b76bd, 0000000000000000000000000000000000000000000000000000000000000000 )
|
64 |
FiatTokenProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x000000000000000000000000750dd34fb165be682fae445793ab9ab9729cdaa3, 0x0000000000000000000000008da8f82d2bbdd896822de723f55d6edf416130ba, 00000000000000000000000000000000000000000000000000001b603cf1990d )
|
65 |
BPool.0x49b5955200000000000000000000000000000000000000000000000000000000( 0x49b5955200000000000000000000000000000000000000000000000000000000, 0x000000000000000000000000750dd34fb165be682fae445793ab9ab9729cdaa3, 0000000000000000000000000000000000000000000000000000000000000020, 0000000000000000000000000000000000000000000000000000000000000024, 49b5955200000000000000000000000000000000000000000000000000000000, 0000000100000000000000000000000000000000000000000000000000000000 )
|
66 |
Timelock.ExecuteTransaction( txHash=B17084C1AD974D5F198DB2D396F095734BAC72846CFD7CD93CA9F3E59F770882, target=0x750dd34fb165be682fae445793ab9ab9729cdaa3, value=0, signature=exitPool(uint256,uint256[]), data=0x0000000000000000000000000000000000000000000000056BC7033A5295C0000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000D3C21BCECCEDA1000000000000000000000000000000000000000000000000000000000012309CE54000, eta=1616060132 )
|
67 |
FiatTokenProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x0000000000000000000000008da8f82d2bbdd896822de723f55d6edf416130ba, 0x000000000000000000000000055e29502153aedcfdae8fc15a710ff6fb5e10c9, 0000000000000000000000000000000000000000000000000000032ee841b800 )
|
68 |
Timelock.ExecuteTransaction( txHash=5D1878B6EAFBAAF63BBF132925562E7DEC072FB3E424E42905B86E2440B96C96, target=FiatTokenProxy, value=0, signature=transfer(address,uint256), data=0x000000000000000000000000055E29502153AEDCFDAE8FC15A710FF6FB5E10C90000000000000000000000000000000000000000000000000000032EE841B800, eta=1616060132 )
|
69 |
RadicleToken.Approval( owner=Timelock, spender=AddLiquidity, amount=500000000000000000000000 )
|
70 |
Timelock.ExecuteTransaction( txHash=87F3EF1ACC244391F68C16CCE74675D5DE25DD7F8EFAF6E0E0E1C8B4A66F9A5E, target=RadicleToken, value=0, signature=approve(address,uint256), data=0x000000000000000000000000B76FC4EBE4FC0CC34AF440AD79565A68BFCB095E0000000000000000000000000000000000000000000069E10DE76676D0800000, eta=1616060132 )
|
71 |
FiatTokenProxy.0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925( 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925, 0x0000000000000000000000008da8f82d2bbdd896822de723f55d6edf416130ba, 0x000000000000000000000000b76fc4ebe4fc0cc34af440ad79565a68bfcb095e, 0000000000000000000000000000000000000000000000000000048c27395000 )
|
72 |
Timelock.ExecuteTransaction( txHash=97FD37B2BF4F221F8AD6060F313873C48B7FCC30FD763CCC698AD4B41317564D, target=FiatTokenProxy, value=0, signature=approve(address,uint256), data=0x000000000000000000000000B76FC4EBE4FC0CC34AF440AD79565A68BFCB095E0000000000000000000000000000000000000000000000000000048C27395000, eta=1616060132 )
|
73 |
RadicleToken.Approval( owner=Timelock, spender=AddLiquidity, amount=212600000000000000000000 )
|
74 |
RadicleToken.Transfer( from=Timelock, to=AddLiquidity, amount=287400000000000000000000 )
|
75 |
FiatTokenProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x0000000000000000000000008da8f82d2bbdd896822de723f55d6edf416130ba, 0x000000000000000000000000b76fc4ebe4fc0cc34af440ad79565a68bfcb095e, 0000000000000000000000000000000000000000000000000000048c27395000 )
|
76 |
RadicleToken.Approval( owner=AddLiquidity, spender=UniswapV2Router02, amount=287400000000000000000000 )
|
77 |
FiatTokenProxy.0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925( 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925, 0x000000000000000000000000b76fc4ebe4fc0cc34af440ad79565a68bfcb095e, 0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d, 0000000000000000000000000000000000000000000000000000048c27395000 )
|
78 |
UniswapV2Factory.PairCreated( token0=RadicleToken, token1=FiatTokenProxy, pair=UniswapV2Pair, 31000 )
|
79 |
RadicleToken.Approval( owner=AddLiquidity, spender=UniswapV2Router02, amount=0 )
|
80 |
RadicleToken.Transfer( from=AddLiquidity, to=UniswapV2Pair, amount=287400000000000000000000 )
|
81 |
FiatTokenProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x000000000000000000000000b76fc4ebe4fc0cc34af440ad79565a68bfcb095e, 0x0000000000000000000000008c1c499b1796d7f3c2521ac37186b52de024e58c, 0000000000000000000000000000000000000000000000000000048c27395000 )
|
82 |
UniswapV2Pair.Transfer( from=0x0000000000000000000000000000000000000000, to=0x0000000000000000000000000000000000000000, value=1000 )
|
83 |
UniswapV2Pair.Transfer( from=0x0000000000000000000000000000000000000000, to=Timelock, value=1198749348279279609 )
|
84 |
UniswapV2Pair.Sync( reserve0=287400000000000000000000, reserve1=5000000000000 )
|
85 |
UniswapV2Pair.Mint( sender=UniswapV2Router02, amount0=287400000000000000000000, amount1=5000000000000 )
|
86 |
Timelock.ExecuteTransaction( txHash=5664E2732A831C28932275F7B55328D00FAA1E5D5BE5F86B0B1983EF96A7E674, target=AddLiquidity, value=0, signature=addLiquidity(address,address), data=0x00000000000000000000000031C8EACBFFDD875C74B94B077895BD78CF1E64A3000000000000000000000000A0B86991C6218B36C1D19D4A2E9EB0CE3606EB48, eta=1616060132 )
|
87 |
Governor.ProposalExecuted( id=4 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x055E2950...6fb5e10C9 |
3.769567097822007643 Eth
Nonce: 22
|
3.255019417822007643 Eth
Nonce: 23
| 0.51454768 | ||
0x31c8EAcB...8CF1E64A3 | |||||
0x5C69bEe7...B9cc5aA6f | (Uniswap V2: Factory Contract) | ||||
0x690e7753...39F5198eD | (Radicle: Governance) | ||||
0x750dD34F...9729CDAa3 | |||||
0x824603F8...74dd4Df73 | |||||
0x8C1c499b...De024e58c |
0 Eth
Nonce: 0
|
0 Eth
Nonce: 1
| |||
0x8dA8f82d...F416130ba | (Radicle: Timelock) | ||||
0xA0b86991...E3606eB48 | |||||
0xEA674fdD...16B898ec8
Miner
| (Ethermine) | 916.354487195844864091 Eth | 916.869034875844864091 Eth | 0.51454768 |
Execution Trace
Governor.execute( proposalId=4 )
-
Timelock.STATICCALL( )
Timelock.executeTransaction( target=0x750dD34Fb165bE682fAe445793AB9ab9729CDAa3, value=0, signature=exitPool(uint256,uint256[]), data=0x0000000000000000000000000000000000000000000000056BC7033A5295C0000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000D3C21BCECCEDA1000000000000000000000000000000000000000000000000000000000012309CE54000, eta=1616060132 ) => ( 0x )
0x750dd34fb165be682fae445793ab9ab9729cdaa3.b02f0b73( )
-
BPool.STATICCALL( )
-
BPool.setPublicSwap( public_=False )
SmartPoolManager.5471c3e4( )
-
BPool.STATICCALL( )
-
0x750dd34fb165be682fae445793ab9ab9729cdaa3.STATICCALL( )
-
BPool.getBalance( token=0x31c8EAcBFFdD875c74b94b077895Bd78CF1E64A3 ) => ( 1743200934548426466332806 )
-
BPool.getBalance( token=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 ) => ( 30100183376869 )
-
-
BPool.STATICCALL( )
-
BPool.getBalance( token=0x31c8EAcBFFdD875c74b94b077895Bd78CF1E64A3 ) => ( 1743200934548426466332806 )
-
BPool.getDenormalizedWeight( token=0x31c8EAcBFFdD875c74b94b077895Bd78CF1E64A3 ) => ( 20000000000000000000 )
BPool.rebind( token=0x31c8EAcBFFdD875c74b94b077895Bd78CF1E64A3, balance=1743200934548426467, denorm=20000000000000000000 )
-
RadicleToken.transfer( dst=0x8dA8f82d2BbDd896822de723F55D6EdF416130ba, rawAmount=1743199191347491917906339 ) => ( True )
-
BPool.getBalance( token=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 ) => ( 30100183376869 )
-
BPool.getDenormalizedWeight( token=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 ) => ( 20000000000000000000 )
BPool.rebind( token=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48, balance=30100184, denorm=20000000000000000000 )
FiatTokenProxy.a9059cbb( )
-
FiatTokenV2.transfer( to=0x8dA8f82d2BbDd896822de723F55D6EdF416130ba, value=30100153276685 ) => ( True )
-
-
BPool.setPublicSwap( public_=True )
-
Timelock.executeTransaction( target=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48, value=0, signature=transfer(address,uint256), data=0x000000000000000000000000055E29502153AEDCFDAE8FC15A710FF6FB5E10C90000000000000000000000000000000000000000000000000000032EE841B800, eta=1616060132 ) => ( 0x0000000000000000000000000000000000000000000000000000000000000001 )
FiatTokenProxy.a9059cbb( )
-
FiatTokenV2.transfer( to=0x055E29502153aEDcFDaE8Fc15a710FF6fb5e10C9, value=3500000000000 ) => ( True )
-
Timelock.executeTransaction( target=0x31c8EAcBFFdD875c74b94b077895Bd78CF1E64A3, value=0, signature=approve(address,uint256), data=0x000000000000000000000000B76FC4EBE4FC0CC34AF440AD79565A68BFCB095E0000000000000000000000000000000000000000000069E10DE76676D0800000, eta=1616060132 ) => ( 0x0000000000000000000000000000000000000000000000000000000000000001 )
-
RadicleToken.approve( spender=0xB76FC4EbE4fC0CC34AF440Ad79565A68Bfcb095e, rawAmount=500000000000000000000000 ) => ( True )
-
Timelock.executeTransaction( target=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48, value=0, signature=approve(address,uint256), data=0x000000000000000000000000B76FC4EBE4FC0CC34AF440AD79565A68BFCB095E0000000000000000000000000000000000000000000000000000048C27395000, eta=1616060132 ) => ( 0x0000000000000000000000000000000000000000000000000000000000000001 )
FiatTokenProxy.095ea7b3( )
-
FiatTokenV2.approve( spender=0xB76FC4EbE4fC0CC34AF440Ad79565A68Bfcb095e, value=5000000000000 ) => ( True )
-
Timelock.executeTransaction( target=0xB76FC4EbE4fC0CC34AF440Ad79565A68Bfcb095e, value=0, signature=addLiquidity(address,address), data=0x00000000000000000000000031C8EACBFFDD875C74B94B077895BD78CF1E64A3000000000000000000000000A0B86991C6218B36C1D19D4A2E9EB0CE3606EB48, eta=1616060132 ) => ( 0x )
AddLiquidity.addLiquidity( rad=0x31c8EAcBFFdD875c74b94b077895Bd78CF1E64A3, usdc=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 )
-
RadicleToken.transferFrom( src=0x8dA8f82d2BbDd896822de723F55D6EdF416130ba, dst=0xB76FC4EbE4fC0CC34AF440Ad79565A68Bfcb095e, rawAmount=287400000000000000000000 ) => ( True )
FiatTokenProxy.23b872dd( )
-
FiatTokenV2.transferFrom( from=0x8dA8f82d2BbDd896822de723F55D6EdF416130ba, to=0xB76FC4EbE4fC0CC34AF440Ad79565A68Bfcb095e, value=5000000000000 ) => ( True )
-
-
RadicleToken.approve( spender=0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D, rawAmount=287400000000000000000000 ) => ( True )
FiatTokenProxy.095ea7b3( )
-
FiatTokenV2.approve( spender=0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D, value=5000000000000 ) => ( True )
-
UniswapV2Router02.addLiquidity( tokenA=0x31c8EAcBFFdD875c74b94b077895Bd78CF1E64A3, tokenB=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48, amountADesired=287400000000000000000000, amountBDesired=5000000000000, amountAMin=281600000000000000000000, amountBMin=4900000000000, to=0x8dA8f82d2BbDd896822de723F55D6EdF416130ba, deadline=1616147001 ) => ( amountA=287400000000000000000000, amountB=5000000000000, liquidity=1198749348279279609 )
-
UniswapV2Factory.getPair( 0x31c8EAcBFFdD875c74b94b077895Bd78CF1E64A3, 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 ) => ( 0x0000000000000000000000000000000000000000 )
UniswapV2Factory.createPair( tokenA=0x31c8EAcBFFdD875c74b94b077895Bd78CF1E64A3, tokenB=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 ) => ( pair=0x8C1c499b1796D7F3C2521AC37186B52De024e58c )
-
UniswapV2Pair.60806040( )
-
UniswapV2Pair.initialize( _token0=0x31c8EAcBFFdD875c74b94b077895Bd78CF1E64A3, _token1=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 )
-
-
UniswapV2Pair.STATICCALL( )
-
RadicleToken.transferFrom( src=0xB76FC4EbE4fC0CC34AF440Ad79565A68Bfcb095e, dst=0x8C1c499b1796D7F3C2521AC37186B52De024e58c, rawAmount=287400000000000000000000 ) => ( True )
FiatTokenProxy.23b872dd( )
-
FiatTokenV2.transferFrom( from=0xB76FC4EbE4fC0CC34AF440Ad79565A68Bfcb095e, to=0x8C1c499b1796D7F3C2521AC37186B52De024e58c, value=5000000000000 ) => ( True )
-
UniswapV2Pair.mint( to=0x8dA8f82d2BbDd896822de723F55D6EdF416130ba ) => ( liquidity=1198749348279279609 )
-
-
execute[Governor (ln:269)]
state[Governor (ln:271)]
quorumVotes[Governor (ln:351)]
add256[Governor (ln:358)]
gracePeriod[Governor (ln:358)]
executeTransaction[Governor (ln:277)]
ProposalExecuted[Governor (ln:285)]
File 1 of 12: Governor
File 2 of 12: BPool
File 3 of 12: RadicleToken
File 4 of 12: BFactory
File 5 of 12: Timelock
File 6 of 12: FiatTokenProxy
File 7 of 12: AddLiquidity
File 8 of 12: UniswapV2Factory
File 9 of 12: UniswapV2Pair
File 10 of 12: SmartPoolManager
File 11 of 12: FiatTokenV2
File 12 of 12: UniswapV2Router02
// SPDX-License-Identifier: GPL-3.0-only // Copyright 2020 Compound Labs, Inc. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // 3. Neither the name of the copyright holder nor the names of its // contributors may be used to endorse or promote products derived from this // software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. pragma solidity ^0.7.5; pragma experimental ABIEncoderV2; contract Governor { /// @notice The name of this contract string public constant NAME = "Radicle Governor"; /// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed function quorumVotes() public pure returns (uint256) { return 4000000e18; } // 4,000,000 = 4% of Token /// @notice The number of votes required in order for a voter to become a proposer function proposalThreshold() public pure returns (uint256) { return 1000000e18; } // 1,000,000 = 1% of Token /// @notice The maximum number of actions that can be included in a proposal function proposalMaxOperations() public pure returns (uint256) { return 10; } // 10 actions /// @notice The delay before voting on a proposal may take place, once proposed function votingDelay() public pure returns (uint256) { return 1; } // 1 block /// @notice The duration of voting on a proposal, in blocks function votingPeriod() public pure returns (uint256) { return 17280; } // ~3 days in blocks (assuming 15s blocks) /// @notice The address of the Radicle Protocol Timelock TimelockInterface public immutable timelock; /// @notice The address of the Radicle governance token TokenInterface public immutable token; /// @notice The address of the Governor Guardian address public guardian; /// @notice The total number of proposals uint256 public proposalCount; /// @notice Change proposal struct Proposal { // Creator of the proposal address proposer; // The timestamp that the proposal will be available for execution, set once the vote succeeds uint256 eta; // the ordered list of target addresses for calls to be made address[] targets; // The ordered list of values (i.e. msg.value) to be passed to the calls to be made uint256[] values; // The ordered list of function signatures to be called string[] signatures; // The ordered list of calldata to be passed to each call bytes[] calldatas; // The block at which voting begins: holders must delegate their votes prior to this block uint256 startBlock; // The block at which voting ends: votes must be cast prior to this block uint256 endBlock; // Current number of votes in favor of this proposal uint256 forVotes; // Current number of votes in opposition to this proposal uint256 againstVotes; // Flag marking whether the proposal has been canceled bool canceled; // Flag marking whether the proposal has been executed bool executed; // Receipts of ballots for the entire set of voters mapping(address => Receipt) receipts; } /// @notice Ballot receipt record for a voter struct Receipt { // Whether or not a vote has been cast bool hasVoted; // Whether or not the voter supports the proposal bool support; // The number of votes the voter had, which were cast uint96 votes; } /// @notice Possible states that a proposal may be in enum ProposalState {Pending, Active, Canceled, Defeated, Succeeded, Queued, Expired, Executed} /// @notice The official record of all proposals ever proposed mapping(uint256 => Proposal) public proposals; /// @notice The latest proposal for each proposer mapping(address => uint256) public latestProposalIds; /// @notice The EIP-712 typehash for the contract's domain bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)"); /// @notice The EIP-712 typehash for the ballot struct used by the contract bytes32 public constant BALLOT_TYPEHASH = keccak256("Ballot(uint256 proposalId,bool support)"); /// @notice An event emitted when a new proposal is created event ProposalCreated( uint256 id, address proposer, address[] targets, uint256[] values, string[] signatures, bytes[] calldatas, uint256 startBlock, uint256 endBlock, string description ); /// @notice An event emitted when a vote has been cast on a proposal event VoteCast(address voter, uint256 proposalId, bool support, uint256 votes); /// @notice An event emitted when a proposal has been canceled event ProposalCanceled(uint256 id); /// @notice An event emitted when a proposal has been queued in the Timelock event ProposalQueued(uint256 id, uint256 eta); /// @notice An event emitted when a proposal has been executed in the Timelock event ProposalExecuted(uint256 id); constructor( address timelock_, address token_, address guardian_ ) { timelock = TimelockInterface(timelock_); token = TokenInterface(token_); guardian = guardian_; } function propose( address[] memory targets, uint256[] memory values, string[] memory signatures, bytes[] memory calldatas, string memory description ) public returns (uint256) { require( token.getPriorVotes(msg.sender, sub256(block.number, 1)) >= proposalThreshold(), "Governor::propose: proposer votes below proposal threshold" ); require( targets.length == values.length && targets.length == signatures.length && targets.length == calldatas.length, "Governor::propose: proposal function information arity mismatch" ); require(targets.length != 0, "Governor::propose: must provide actions"); require(targets.length <= proposalMaxOperations(), "Governor::propose: too many actions"); uint256 latestProposalId = latestProposalIds[msg.sender]; if (latestProposalId != 0) { ProposalState proposersLatestProposalState = state(latestProposalId); require( proposersLatestProposalState != ProposalState.Active, "Governor::propose: one live proposal per proposer, found an already active proposal" ); require( proposersLatestProposalState != ProposalState.Pending, "Governor::propose: one live proposal per proposer, found an already pending proposal" ); } uint256 startBlock = add256(block.number, votingDelay()); uint256 endBlock = add256(startBlock, votingPeriod()); proposalCount++; Proposal storage newProposal = proposals[proposalCount]; uint256 proposalId = proposalCount; newProposal.proposer = msg.sender; newProposal.eta = 0; newProposal.targets = targets; newProposal.values = values; newProposal.signatures = signatures; newProposal.calldatas = calldatas; newProposal.startBlock = startBlock; newProposal.endBlock = endBlock; newProposal.forVotes = 0; newProposal.againstVotes = 0; newProposal.canceled = false; newProposal.executed = false; latestProposalIds[newProposal.proposer] = proposalId; emit ProposalCreated( proposalId, msg.sender, targets, values, signatures, calldatas, startBlock, endBlock, description ); return proposalId; } function queue(uint256 proposalId) public { require( state(proposalId) == ProposalState.Succeeded, "Governor::queue: proposal can only be queued if it is succeeded" ); Proposal storage proposal = proposals[proposalId]; uint256 eta = add256(block.timestamp, timelock.delay()); for (uint256 i = 0; i < proposal.targets.length; i++) { _queueOrRevert( proposal.targets[i], proposal.values[i], proposal.signatures[i], proposal.calldatas[i], eta ); } proposal.eta = eta; emit ProposalQueued(proposalId, eta); } function _queueOrRevert( address target, uint256 value, string memory signature, bytes memory data, uint256 eta ) internal { require( !timelock.queuedTransactions( keccak256(abi.encode(target, value, signature, data, eta)) ), "Governor::_queueOrRevert: proposal action already queued at eta" ); timelock.queueTransaction(target, value, signature, data, eta); } function execute(uint256 proposalId) public payable { require( state(proposalId) == ProposalState.Queued, "Governor::execute: proposal can only be executed if it is queued" ); Proposal storage proposal = proposals[proposalId]; proposal.executed = true; for (uint256 i = 0; i < proposal.targets.length; i++) { timelock.executeTransaction{value: proposal.values[i]}( proposal.targets[i], proposal.values[i], proposal.signatures[i], proposal.calldatas[i], proposal.eta ); } emit ProposalExecuted(proposalId); } function cancel(uint256 proposalId) public { ProposalState _state = state(proposalId); require( _state != ProposalState.Executed, "Governor::cancel: cannot cancel executed proposal" ); Proposal storage proposal = proposals[proposalId]; require( msg.sender == guardian || // Allows anyone to cancel a proposal if the voting power of the // proposer dropped below the threshold after the proposal was // submitted. token.getPriorVotes(proposal.proposer, sub256(block.number, 1)) < proposalThreshold(), "Governor::cancel: cannot cancel unless proposer is below threhsold" ); proposal.canceled = true; for (uint256 i = 0; i < proposal.targets.length; i++) { timelock.cancelTransaction( proposal.targets[i], proposal.values[i], proposal.signatures[i], proposal.calldatas[i], proposal.eta ); } emit ProposalCanceled(proposalId); } function getActions(uint256 proposalId) public view returns ( address[] memory targets, uint256[] memory values, string[] memory signatures, bytes[] memory calldatas ) { Proposal storage p = proposals[proposalId]; return (p.targets, p.values, p.signatures, p.calldatas); } function getReceipt(uint256 proposalId, address voter) public view returns (Receipt memory) { return proposals[proposalId].receipts[voter]; } function state(uint256 proposalId) public view returns (ProposalState) { require( proposalCount >= proposalId && proposalId > 0, "Governor::state: invalid proposal id" ); Proposal storage proposal = proposals[proposalId]; if (proposal.canceled) { return ProposalState.Canceled; } else if (block.number <= proposal.startBlock) { return ProposalState.Pending; } else if (block.number <= proposal.endBlock) { return ProposalState.Active; } else if ( proposal.forVotes <= proposal.againstVotes || proposal.forVotes < quorumVotes() ) { return ProposalState.Defeated; } else if (proposal.eta == 0) { return ProposalState.Succeeded; } else if (proposal.executed) { return ProposalState.Executed; } else if (block.timestamp >= add256(proposal.eta, timelock.gracePeriod())) { return ProposalState.Expired; } else { return ProposalState.Queued; } } function castVote(uint256 proposalId, bool support) public { return _castVote(msg.sender, proposalId, support); } function castVoteBySig( uint256 proposalId, bool support, uint8 v, bytes32 r, bytes32 s ) public { bytes32 domainSeparator = keccak256( abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(NAME)), getChainId(), address(this)) ); bytes32 structHash = keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support)); bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); address signatory = ecrecover(digest, v, r, s); require(signatory != address(0), "Governor::castVoteBySig: invalid signature"); return _castVote(signatory, proposalId, support); } function _castVote( address voter, uint256 proposalId, bool support ) internal { require(state(proposalId) == ProposalState.Active, "Governor::_castVote: voting is closed"); Proposal storage proposal = proposals[proposalId]; Receipt storage receipt = proposal.receipts[voter]; require(receipt.hasVoted == false, "Governor::_castVote: voter already voted"); uint96 votes = token.getPriorVotes(voter, proposal.startBlock); if (support) { proposal.forVotes = add256(proposal.forVotes, votes); } else { proposal.againstVotes = add256(proposal.againstVotes, votes); } receipt.hasVoted = true; receipt.support = support; receipt.votes = votes; emit VoteCast(voter, proposalId, support, votes); } function __acceptAdmin() public { require(msg.sender == guardian, "Governor::__acceptAdmin: sender must be gov guardian"); timelock.acceptAdmin(); } function __abdicate() public { require(msg.sender == guardian, "Governor::__abdicate: sender must be gov guardian"); guardian = address(0); } function __queueSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) public { require( msg.sender == guardian, "Governor::__queueSetTimelockPendingAdmin: sender must be gov guardian" ); timelock.queueTransaction( address(timelock), 0, "setPendingAdmin(address)", abi.encode(newPendingAdmin), eta ); } function __executeSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) public { require( msg.sender == guardian, "Governor::__executeSetTimelockPendingAdmin: sender must be gov guardian" ); timelock.executeTransaction( address(timelock), 0, "setPendingAdmin(address)", abi.encode(newPendingAdmin), eta ); } function add256(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "addition overflow"); return c; } function sub256(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "subtraction underflow"); return a - b; } function getChainId() internal pure returns (uint256) { uint256 chainId; // solhint-disable no-inline-assembly assembly { chainId := chainid() } return chainId; } } interface TimelockInterface { function delay() external view returns (uint256); function gracePeriod() external view returns (uint256); function acceptAdmin() external; function queuedTransactions(bytes32 hash) external view returns (bool); function queueTransaction( address target, uint256 value, string calldata signature, bytes calldata data, uint256 eta ) external returns (bytes32); function cancelTransaction( address target, uint256 value, string calldata signature, bytes calldata data, uint256 eta ) external; function executeTransaction( address target, uint256 value, string calldata signature, bytes calldata data, uint256 eta ) external payable returns (bytes memory); } interface TokenInterface { function getPriorVotes(address account, uint256 blockNumber) external view returns (uint96); }
File 2 of 12: BPool
{"BColor.sol":{"content":"// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see \u003chttp://www.gnu.org/licenses/\u003e.\n\npragma solidity 0.5.12;\n\ncontract BColor {\n function getColor()\n external view\n returns (bytes32);\n}\n\ncontract BBronze is BColor {\n function getColor()\n external view\n returns (bytes32) {\n return bytes32(\"BRONZE\");\n }\n}\n"},"BConst.sol":{"content":"// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see \u003chttp://www.gnu.org/licenses/\u003e.\n\npragma solidity 0.5.12;\n\nimport \"./BColor.sol\";\n\ncontract BConst is BBronze {\n uint public constant BONE = 10**18;\n\n uint public constant MIN_BOUND_TOKENS = 2;\n uint public constant MAX_BOUND_TOKENS = 8;\n\n uint public constant MIN_FEE = BONE / 10**6;\n uint public constant MAX_FEE = BONE / 10;\n uint public constant EXIT_FEE = 0;\n\n uint public constant MIN_WEIGHT = BONE;\n uint public constant MAX_WEIGHT = BONE * 50;\n uint public constant MAX_TOTAL_WEIGHT = BONE * 50;\n uint public constant MIN_BALANCE = BONE / 10**12;\n\n uint public constant INIT_POOL_SUPPLY = BONE * 100;\n\n uint public constant MIN_BPOW_BASE = 1 wei;\n uint public constant MAX_BPOW_BASE = (2 * BONE) - 1 wei;\n uint public constant BPOW_PRECISION = BONE / 10**10;\n\n uint public constant MAX_IN_RATIO = BONE / 2;\n uint public constant MAX_OUT_RATIO = (BONE / 3) + 1 wei;\n}\n"},"BMath.sol":{"content":"// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see \u003chttp://www.gnu.org/licenses/\u003e.\n\npragma solidity 0.5.12;\n\nimport \"./BNum.sol\";\n\ncontract BMath is BBronze, BConst, BNum {\n /**********************************************************************************************\n // calcSpotPrice //\n // sP = spotPrice //\n // bI = tokenBalanceIn ( bI / wI ) 1 //\n // bO = tokenBalanceOut sP = ----------- * ---------- //\n // wI = tokenWeightIn ( bO / wO ) ( 1 - sF ) //\n // wO = tokenWeightOut //\n // sF = swapFee //\n **********************************************************************************************/\n function calcSpotPrice(\n uint tokenBalanceIn,\n uint tokenWeightIn,\n uint tokenBalanceOut,\n uint tokenWeightOut,\n uint swapFee\n )\n public pure\n returns (uint spotPrice)\n {\n uint numer = bdiv(tokenBalanceIn, tokenWeightIn);\n uint denom = bdiv(tokenBalanceOut, tokenWeightOut);\n uint ratio = bdiv(numer, denom);\n uint scale = bdiv(BONE, bsub(BONE, swapFee));\n return (spotPrice = bmul(ratio, scale));\n }\n\n /**********************************************************************************************\n // calcOutGivenIn //\n // aO = tokenAmountOut //\n // bO = tokenBalanceOut //\n // bI = tokenBalanceIn / / bI \\ (wI / wO) \\ //\n // aI = tokenAmountIn aO = bO * | 1 - | -------------------------- | ^ | //\n // wI = tokenWeightIn \\ \\ ( bI + ( aI * ( 1 - sF )) / / //\n // wO = tokenWeightOut //\n // sF = swapFee //\n **********************************************************************************************/\n function calcOutGivenIn(\n uint tokenBalanceIn,\n uint tokenWeightIn,\n uint tokenBalanceOut,\n uint tokenWeightOut,\n uint tokenAmountIn,\n uint swapFee\n )\n public pure\n returns (uint tokenAmountOut)\n {\n uint weightRatio = bdiv(tokenWeightIn, tokenWeightOut);\n uint adjustedIn = bsub(BONE, swapFee);\n adjustedIn = bmul(tokenAmountIn, adjustedIn);\n uint y = bdiv(tokenBalanceIn, badd(tokenBalanceIn, adjustedIn));\n uint foo = bpow(y, weightRatio);\n uint bar = bsub(BONE, foo);\n tokenAmountOut = bmul(tokenBalanceOut, bar);\n return tokenAmountOut;\n }\n\n /**********************************************************************************************\n // calcInGivenOut //\n // aI = tokenAmountIn //\n // bO = tokenBalanceOut / / bO \\ (wO / wI) \\ //\n // bI = tokenBalanceIn bI * | | ------------ | ^ - 1 | //\n // aO = tokenAmountOut aI = \\ \\ ( bO - aO ) / / //\n // wI = tokenWeightIn -------------------------------------------- //\n // wO = tokenWeightOut ( 1 - sF ) //\n // sF = swapFee //\n **********************************************************************************************/\n function calcInGivenOut(\n uint tokenBalanceIn,\n uint tokenWeightIn,\n uint tokenBalanceOut,\n uint tokenWeightOut,\n uint tokenAmountOut,\n uint swapFee\n )\n public pure\n returns (uint tokenAmountIn)\n {\n uint weightRatio = bdiv(tokenWeightOut, tokenWeightIn);\n uint diff = bsub(tokenBalanceOut, tokenAmountOut);\n uint y = bdiv(tokenBalanceOut, diff);\n uint foo = bpow(y, weightRatio);\n foo = bsub(foo, BONE);\n tokenAmountIn = bsub(BONE, swapFee);\n tokenAmountIn = bdiv(bmul(tokenBalanceIn, foo), tokenAmountIn);\n return tokenAmountIn;\n }\n\n /**********************************************************************************************\n // calcPoolOutGivenSingleIn //\n // pAo = poolAmountOut / \\ //\n // tAi = tokenAmountIn /// / // wI \\ \\\\ \\ wI \\ //\n // wI = tokenWeightIn //| tAi *| 1 - || 1 - -- | * sF || + tBi \\ -- \\ //\n // tW = totalWeight pAo=|| \\ \\ \\\\ tW / // | ^ tW | * pS - pS //\n // tBi = tokenBalanceIn \\\\ ------------------------------------- / / //\n // pS = poolSupply \\\\ tBi / / //\n // sF = swapFee \\ / //\n **********************************************************************************************/\n function calcPoolOutGivenSingleIn(\n uint tokenBalanceIn,\n uint tokenWeightIn,\n uint poolSupply,\n uint totalWeight,\n uint tokenAmountIn,\n uint swapFee\n )\n public pure\n returns (uint poolAmountOut)\n {\n // Charge the trading fee for the proportion of tokenAi\n /// which is implicitly traded to the other pool tokens.\n // That proportion is (1- weightTokenIn)\n // tokenAiAfterFee = tAi * (1 - (1-weightTi) * poolFee);\n uint normalizedWeight = bdiv(tokenWeightIn, totalWeight);\n uint zaz = bmul(bsub(BONE, normalizedWeight), swapFee); \n uint tokenAmountInAfterFee = bmul(tokenAmountIn, bsub(BONE, zaz));\n\n uint newTokenBalanceIn = badd(tokenBalanceIn, tokenAmountInAfterFee);\n uint tokenInRatio = bdiv(newTokenBalanceIn, tokenBalanceIn);\n\n // uint newPoolSupply = (ratioTi ^ weightTi) * poolSupply;\n uint poolRatio = bpow(tokenInRatio, normalizedWeight);\n uint newPoolSupply = bmul(poolRatio, poolSupply);\n poolAmountOut = bsub(newPoolSupply, poolSupply);\n return poolAmountOut;\n }\n\n /**********************************************************************************************\n // calcSingleInGivenPoolOut //\n // tAi = tokenAmountIn //(pS + pAo)\\ / 1 \\\\ //\n // pS = poolSupply || --------- | ^ | --------- || * bI - bI //\n // pAo = poolAmountOut \\\\ pS / \\(wI / tW)// //\n // bI = balanceIn tAi = -------------------------------------------- //\n // wI = weightIn / wI \\ //\n // tW = totalWeight | 1 - ---- | * sF //\n // sF = swapFee \\ tW / //\n **********************************************************************************************/\n function calcSingleInGivenPoolOut(\n uint tokenBalanceIn,\n uint tokenWeightIn,\n uint poolSupply,\n uint totalWeight,\n uint poolAmountOut,\n uint swapFee\n )\n public pure\n returns (uint tokenAmountIn)\n {\n uint normalizedWeight = bdiv(tokenWeightIn, totalWeight);\n uint newPoolSupply = badd(poolSupply, poolAmountOut);\n uint poolRatio = bdiv(newPoolSupply, poolSupply);\n \n //uint newBalTi = poolRatio^(1/weightTi) * balTi;\n uint boo = bdiv(BONE, normalizedWeight); \n uint tokenInRatio = bpow(poolRatio, boo);\n uint newTokenBalanceIn = bmul(tokenInRatio, tokenBalanceIn);\n uint tokenAmountInAfterFee = bsub(newTokenBalanceIn, tokenBalanceIn);\n // Do reverse order of fees charged in joinswap_ExternAmountIn, this way \n // ``` pAo == joinswap_ExternAmountIn(Ti, joinswap_PoolAmountOut(pAo, Ti)) ```\n //uint tAi = tAiAfterFee / (1 - (1-weightTi) * swapFee) ;\n uint zar = bmul(bsub(BONE, normalizedWeight), swapFee);\n tokenAmountIn = bdiv(tokenAmountInAfterFee, bsub(BONE, zar));\n return tokenAmountIn;\n }\n\n /**********************************************************************************************\n // calcSingleOutGivenPoolIn //\n // tAo = tokenAmountOut / / \\\\ //\n // bO = tokenBalanceOut / // pS - (pAi * (1 - eF)) \\ / 1 \\ \\\\ //\n // pAi = poolAmountIn | bO - || ----------------------- | ^ | --------- | * b0 || //\n // ps = poolSupply \\ \\\\ pS / \\(wO / tW)/ // //\n // wI = tokenWeightIn tAo = \\ \\ // //\n // tW = totalWeight / / wO \\ \\ //\n // sF = swapFee * | 1 - | 1 - ---- | * sF | //\n // eF = exitFee \\ \\ tW / / //\n **********************************************************************************************/\n function calcSingleOutGivenPoolIn(\n uint tokenBalanceOut,\n uint tokenWeightOut,\n uint poolSupply,\n uint totalWeight,\n uint poolAmountIn,\n uint swapFee\n )\n public pure\n returns (uint tokenAmountOut)\n {\n uint normalizedWeight = bdiv(tokenWeightOut, totalWeight);\n // charge exit fee on the pool token side\n // pAiAfterExitFee = pAi*(1-exitFee)\n uint poolAmountInAfterExitFee = bmul(poolAmountIn, bsub(BONE, EXIT_FEE));\n uint newPoolSupply = bsub(poolSupply, poolAmountInAfterExitFee);\n uint poolRatio = bdiv(newPoolSupply, poolSupply);\n \n // newBalTo = poolRatio^(1/weightTo) * balTo;\n uint tokenOutRatio = bpow(poolRatio, bdiv(BONE, normalizedWeight));\n uint newTokenBalanceOut = bmul(tokenOutRatio, tokenBalanceOut);\n\n uint tokenAmountOutBeforeSwapFee = bsub(tokenBalanceOut, newTokenBalanceOut);\n\n // charge swap fee on the output token side \n //uint tAo = tAoBeforeSwapFee * (1 - (1-weightTo) * swapFee)\n uint zaz = bmul(bsub(BONE, normalizedWeight), swapFee); \n tokenAmountOut = bmul(tokenAmountOutBeforeSwapFee, bsub(BONE, zaz));\n return tokenAmountOut;\n }\n\n /**********************************************************************************************\n // calcPoolInGivenSingleOut //\n // pAi = poolAmountIn // / tAo \\\\ / wO \\ \\ //\n // bO = tokenBalanceOut // | bO - -------------------------- |\\ | ---- | \\ //\n // tAo = tokenAmountOut pS - || \\ 1 - ((1 - (tO / tW)) * sF)/ | ^ \\ tW / * pS | //\n // ps = poolSupply \\\\ -----------------------------------/ / //\n // wO = tokenWeightOut pAi = \\\\ bO / / //\n // tW = totalWeight ------------------------------------------------------------- //\n // sF = swapFee ( 1 - eF ) //\n // eF = exitFee //\n **********************************************************************************************/\n function calcPoolInGivenSingleOut(\n uint tokenBalanceOut,\n uint tokenWeightOut,\n uint poolSupply,\n uint totalWeight,\n uint tokenAmountOut,\n uint swapFee\n )\n public pure\n returns (uint poolAmountIn)\n {\n\n // charge swap fee on the output token side \n uint normalizedWeight = bdiv(tokenWeightOut, totalWeight);\n //uint tAoBeforeSwapFee = tAo / (1 - (1-weightTo) * swapFee) ;\n uint zoo = bsub(BONE, normalizedWeight);\n uint zar = bmul(zoo, swapFee); \n uint tokenAmountOutBeforeSwapFee = bdiv(tokenAmountOut, bsub(BONE, zar));\n\n uint newTokenBalanceOut = bsub(tokenBalanceOut, tokenAmountOutBeforeSwapFee);\n uint tokenOutRatio = bdiv(newTokenBalanceOut, tokenBalanceOut);\n\n //uint newPoolSupply = (ratioTo ^ weightTo) * poolSupply;\n uint poolRatio = bpow(tokenOutRatio, normalizedWeight);\n uint newPoolSupply = bmul(poolRatio, poolSupply);\n uint poolAmountInAfterExitFee = bsub(poolSupply, newPoolSupply);\n\n // charge exit fee on the pool token side\n // pAi = pAiAfterExitFee/(1-exitFee)\n poolAmountIn = bdiv(poolAmountInAfterExitFee, bsub(BONE, EXIT_FEE));\n return poolAmountIn;\n }\n\n\n}\n"},"BNum.sol":{"content":"// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see \u003chttp://www.gnu.org/licenses/\u003e.\n\npragma solidity 0.5.12;\n\nimport \"./BConst.sol\";\n\ncontract BNum is BConst {\n\n function btoi(uint a)\n internal pure \n returns (uint)\n {\n return a / BONE;\n }\n\n function bfloor(uint a)\n internal pure\n returns (uint)\n {\n return btoi(a) * BONE;\n }\n\n function badd(uint a, uint b)\n internal pure\n returns (uint)\n {\n uint c = a + b;\n require(c \u003e= a, \"ERR_ADD_OVERFLOW\");\n return c;\n }\n\n function bsub(uint a, uint b)\n internal pure\n returns (uint)\n {\n (uint c, bool flag) = bsubSign(a, b);\n require(!flag, \"ERR_SUB_UNDERFLOW\");\n return c;\n }\n\n function bsubSign(uint a, uint b)\n internal pure\n returns (uint, bool)\n {\n if (a \u003e= b) {\n return (a - b, false);\n } else {\n return (b - a, true);\n }\n }\n\n function bmul(uint a, uint b)\n internal pure\n returns (uint)\n {\n uint c0 = a * b;\n require(a == 0 || c0 / a == b, \"ERR_MUL_OVERFLOW\");\n uint c1 = c0 + (BONE / 2);\n require(c1 \u003e= c0, \"ERR_MUL_OVERFLOW\");\n uint c2 = c1 / BONE;\n return c2;\n }\n\n function bdiv(uint a, uint b)\n internal pure\n returns (uint)\n {\n require(b != 0, \"ERR_DIV_ZERO\");\n uint c0 = a * BONE;\n require(a == 0 || c0 / a == BONE, \"ERR_DIV_INTERNAL\"); // bmul overflow\n uint c1 = c0 + (b / 2);\n require(c1 \u003e= c0, \"ERR_DIV_INTERNAL\"); // badd require\n uint c2 = c1 / b;\n return c2;\n }\n\n // DSMath.wpow\n function bpowi(uint a, uint n)\n internal pure\n returns (uint)\n {\n uint z = n % 2 != 0 ? a : BONE;\n\n for (n /= 2; n != 0; n /= 2) {\n a = bmul(a, a);\n\n if (n % 2 != 0) {\n z = bmul(z, a);\n }\n }\n return z;\n }\n\n // Compute b^(e.w) by splitting it into (b^e)*(b^0.w).\n // Use `bpowi` for `b^e` and `bpowK` for k iterations\n // of approximation of b^0.w\n function bpow(uint base, uint exp)\n internal pure\n returns (uint)\n {\n require(base \u003e= MIN_BPOW_BASE, \"ERR_BPOW_BASE_TOO_LOW\");\n require(base \u003c= MAX_BPOW_BASE, \"ERR_BPOW_BASE_TOO_HIGH\");\n\n uint whole = bfloor(exp); \n uint remain = bsub(exp, whole);\n\n uint wholePow = bpowi(base, btoi(whole));\n\n if (remain == 0) {\n return wholePow;\n }\n\n uint partialResult = bpowApprox(base, remain, BPOW_PRECISION);\n return bmul(wholePow, partialResult);\n }\n\n function bpowApprox(uint base, uint exp, uint precision)\n internal pure\n returns (uint)\n {\n // term 0:\n uint a = exp;\n (uint x, bool xneg) = bsubSign(base, BONE);\n uint term = BONE;\n uint sum = term;\n bool negative = false;\n\n\n // term(k) = numer / denom \n // = (product(a - i - 1, i=1--\u003ek) * x^k) / (k!)\n // each iteration, multiply previous term by (a-(k-1)) * x / k\n // continue until term is less than precision\n for (uint i = 1; term \u003e= precision; i++) {\n uint bigK = i * BONE;\n (uint c, bool cneg) = bsubSign(a, bsub(bigK, BONE));\n term = bmul(term, bmul(c, x));\n term = bdiv(term, bigK);\n if (term == 0) break;\n\n if (xneg) negative = !negative;\n if (cneg) negative = !negative;\n if (negative) {\n sum = bsub(sum, term);\n } else {\n sum = badd(sum, term);\n }\n }\n\n return sum;\n }\n\n}\n"},"BPool.sol":{"content":"// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see \u003chttp://www.gnu.org/licenses/\u003e.\n\npragma solidity 0.5.12;\n\nimport \"./BToken.sol\";\nimport \"./BMath.sol\";\n\ncontract BPool is BBronze, BToken, BMath {\n\n struct Record {\n bool bound; // is token bound to pool\n uint index; // private\n uint denorm; // denormalized weight\n uint balance;\n }\n\n event LOG_SWAP(\n address indexed caller,\n address indexed tokenIn,\n address indexed tokenOut,\n uint256 tokenAmountIn,\n uint256 tokenAmountOut\n );\n\n event LOG_JOIN(\n address indexed caller,\n address indexed tokenIn,\n uint256 tokenAmountIn\n );\n\n event LOG_EXIT(\n address indexed caller,\n address indexed tokenOut,\n uint256 tokenAmountOut\n );\n\n event LOG_CALL(\n bytes4 indexed sig,\n address indexed caller,\n bytes data\n ) anonymous;\n\n modifier _logs_() {\n emit LOG_CALL(msg.sig, msg.sender, msg.data);\n _;\n }\n\n modifier _lock_() {\n require(!_mutex, \"ERR_REENTRY\");\n _mutex = true;\n _;\n _mutex = false;\n }\n\n modifier _viewlock_() {\n require(!_mutex, \"ERR_REENTRY\");\n _;\n }\n\n bool private _mutex;\n\n address private _factory; // BFactory address to push token exitFee to\n address private _controller; // has CONTROL role\n bool private _publicSwap; // true if PUBLIC can call SWAP functions\n\n // `setSwapFee` and `finalize` require CONTROL\n // `finalize` sets `PUBLIC can SWAP`, `PUBLIC can JOIN`\n uint private _swapFee;\n bool private _finalized;\n\n address[] private _tokens;\n mapping(address=\u003eRecord) private _records;\n uint private _totalWeight;\n\n constructor() public {\n _controller = msg.sender;\n _factory = msg.sender;\n _swapFee = MIN_FEE;\n _publicSwap = false;\n _finalized = false;\n }\n\n function isPublicSwap()\n external view\n returns (bool)\n {\n return _publicSwap;\n }\n\n function isFinalized()\n external view\n returns (bool)\n {\n return _finalized;\n }\n\n function isBound(address t)\n external view\n returns (bool)\n {\n return _records[t].bound;\n }\n\n function getNumTokens()\n external view\n returns (uint) \n {\n return _tokens.length;\n }\n\n function getCurrentTokens()\n external view _viewlock_\n returns (address[] memory tokens)\n {\n return _tokens;\n }\n\n function getFinalTokens()\n external view\n _viewlock_\n returns (address[] memory tokens)\n {\n require(_finalized, \"ERR_NOT_FINALIZED\");\n return _tokens;\n }\n\n function getDenormalizedWeight(address token)\n external view\n _viewlock_\n returns (uint)\n {\n\n require(_records[token].bound, \"ERR_NOT_BOUND\");\n return _records[token].denorm;\n }\n\n function getTotalDenormalizedWeight()\n external view\n _viewlock_\n returns (uint)\n {\n return _totalWeight;\n }\n\n function getNormalizedWeight(address token)\n external view\n _viewlock_\n returns (uint)\n {\n\n require(_records[token].bound, \"ERR_NOT_BOUND\");\n uint denorm = _records[token].denorm;\n return bdiv(denorm, _totalWeight);\n }\n\n function getBalance(address token)\n external view\n _viewlock_\n returns (uint)\n {\n\n require(_records[token].bound, \"ERR_NOT_BOUND\");\n return _records[token].balance;\n }\n\n function getSwapFee()\n external view\n _viewlock_\n returns (uint)\n {\n return _swapFee;\n }\n\n function getController()\n external view\n _viewlock_\n returns (address)\n {\n return _controller;\n }\n\n function setSwapFee(uint swapFee)\n external\n _logs_\n _lock_\n { \n require(!_finalized, \"ERR_IS_FINALIZED\");\n require(msg.sender == _controller, \"ERR_NOT_CONTROLLER\");\n require(swapFee \u003e= MIN_FEE, \"ERR_MIN_FEE\");\n require(swapFee \u003c= MAX_FEE, \"ERR_MAX_FEE\");\n _swapFee = swapFee;\n }\n\n function setController(address manager)\n external\n _logs_\n _lock_\n {\n require(msg.sender == _controller, \"ERR_NOT_CONTROLLER\");\n _controller = manager;\n }\n\n function setPublicSwap(bool public_)\n external\n _logs_\n _lock_\n {\n require(!_finalized, \"ERR_IS_FINALIZED\");\n require(msg.sender == _controller, \"ERR_NOT_CONTROLLER\");\n _publicSwap = public_;\n }\n\n function finalize()\n external\n _logs_\n _lock_\n {\n require(msg.sender == _controller, \"ERR_NOT_CONTROLLER\");\n require(!_finalized, \"ERR_IS_FINALIZED\");\n require(_tokens.length \u003e= MIN_BOUND_TOKENS, \"ERR_MIN_TOKENS\");\n\n _finalized = true;\n _publicSwap = true;\n\n _mintPoolShare(INIT_POOL_SUPPLY);\n _pushPoolShare(msg.sender, INIT_POOL_SUPPLY);\n }\n\n\n function bind(address token, uint balance, uint denorm)\n external\n _logs_\n // _lock_ Bind does not lock because it jumps to `rebind`, which does\n {\n require(msg.sender == _controller, \"ERR_NOT_CONTROLLER\");\n require(!_records[token].bound, \"ERR_IS_BOUND\");\n require(!_finalized, \"ERR_IS_FINALIZED\");\n\n require(_tokens.length \u003c MAX_BOUND_TOKENS, \"ERR_MAX_TOKENS\");\n\n _records[token] = Record({\n bound: true,\n index: _tokens.length,\n denorm: 0, // balance and denorm will be validated\n balance: 0 // and set by `rebind`\n });\n _tokens.push(token);\n rebind(token, balance, denorm);\n }\n\n function rebind(address token, uint balance, uint denorm)\n public\n _logs_\n _lock_\n {\n\n require(msg.sender == _controller, \"ERR_NOT_CONTROLLER\");\n require(_records[token].bound, \"ERR_NOT_BOUND\");\n require(!_finalized, \"ERR_IS_FINALIZED\");\n\n require(denorm \u003e= MIN_WEIGHT, \"ERR_MIN_WEIGHT\");\n require(denorm \u003c= MAX_WEIGHT, \"ERR_MAX_WEIGHT\");\n require(balance \u003e= MIN_BALANCE, \"ERR_MIN_BALANCE\");\n\n // Adjust the denorm and totalWeight\n uint oldWeight = _records[token].denorm;\n if (denorm \u003e oldWeight) {\n _totalWeight = badd(_totalWeight, bsub(denorm, oldWeight));\n require(_totalWeight \u003c= MAX_TOTAL_WEIGHT, \"ERR_MAX_TOTAL_WEIGHT\");\n } else if (denorm \u003c oldWeight) {\n _totalWeight = bsub(_totalWeight, bsub(oldWeight, denorm));\n } \n _records[token].denorm = denorm;\n\n // Adjust the balance record and actual token balance\n uint oldBalance = _records[token].balance;\n _records[token].balance = balance;\n if (balance \u003e oldBalance) {\n _pullUnderlying(token, msg.sender, bsub(balance, oldBalance));\n } else if (balance \u003c oldBalance) {\n // In this case liquidity is being withdrawn, so charge EXIT_FEE\n uint tokenBalanceWithdrawn = bsub(oldBalance, balance);\n uint tokenExitFee = bmul(tokenBalanceWithdrawn, EXIT_FEE);\n _pushUnderlying(token, msg.sender, bsub(tokenBalanceWithdrawn, tokenExitFee));\n _pushUnderlying(token, _factory, tokenExitFee);\n }\n }\n\n function unbind(address token)\n external\n _logs_\n _lock_\n {\n\n require(msg.sender == _controller, \"ERR_NOT_CONTROLLER\");\n require(_records[token].bound, \"ERR_NOT_BOUND\");\n require(!_finalized, \"ERR_IS_FINALIZED\");\n\n uint tokenBalance = _records[token].balance;\n uint tokenExitFee = bmul(tokenBalance, EXIT_FEE);\n\n _totalWeight = bsub(_totalWeight, _records[token].denorm);\n\n // Swap the token-to-unbind with the last token,\n // then delete the last token\n uint index = _records[token].index;\n uint last = _tokens.length - 1;\n _tokens[index] = _tokens[last];\n _records[_tokens[index]].index = index;\n _tokens.pop();\n _records[token] = Record({\n bound: false,\n index: 0,\n denorm: 0,\n balance: 0\n });\n\n _pushUnderlying(token, msg.sender, bsub(tokenBalance, tokenExitFee));\n _pushUnderlying(token, _factory, tokenExitFee);\n }\n\n // Absorb any tokens that have been sent to this contract into the pool\n function gulp(address token)\n external\n _logs_\n _lock_\n {\n require(_records[token].bound, \"ERR_NOT_BOUND\");\n _records[token].balance = IERC20(token).balanceOf(address(this));\n }\n\n function getSpotPrice(address tokenIn, address tokenOut)\n external view\n _viewlock_\n returns (uint spotPrice)\n {\n require(_records[tokenIn].bound, \"ERR_NOT_BOUND\");\n require(_records[tokenOut].bound, \"ERR_NOT_BOUND\");\n Record storage inRecord = _records[tokenIn];\n Record storage outRecord = _records[tokenOut];\n return calcSpotPrice(inRecord.balance, inRecord.denorm, outRecord.balance, outRecord.denorm, _swapFee);\n }\n\n function getSpotPriceSansFee(address tokenIn, address tokenOut)\n external view\n _viewlock_\n returns (uint spotPrice)\n {\n require(_records[tokenIn].bound, \"ERR_NOT_BOUND\");\n require(_records[tokenOut].bound, \"ERR_NOT_BOUND\");\n Record storage inRecord = _records[tokenIn];\n Record storage outRecord = _records[tokenOut];\n return calcSpotPrice(inRecord.balance, inRecord.denorm, outRecord.balance, outRecord.denorm, 0);\n }\n\n function joinPool(uint poolAmountOut, uint[] calldata maxAmountsIn)\n external\n _logs_\n _lock_\n {\n require(_finalized, \"ERR_NOT_FINALIZED\");\n\n uint poolTotal = totalSupply();\n uint ratio = bdiv(poolAmountOut, poolTotal);\n require(ratio != 0, \"ERR_MATH_APPROX\");\n\n for (uint i = 0; i \u003c _tokens.length; i++) {\n address t = _tokens[i];\n uint bal = _records[t].balance;\n uint tokenAmountIn = bmul(ratio, bal);\n require(tokenAmountIn != 0, \"ERR_MATH_APPROX\");\n require(tokenAmountIn \u003c= maxAmountsIn[i], \"ERR_LIMIT_IN\");\n _records[t].balance = badd(_records[t].balance, tokenAmountIn);\n emit LOG_JOIN(msg.sender, t, tokenAmountIn);\n _pullUnderlying(t, msg.sender, tokenAmountIn);\n }\n _mintPoolShare(poolAmountOut);\n _pushPoolShare(msg.sender, poolAmountOut);\n }\n\n function exitPool(uint poolAmountIn, uint[] calldata minAmountsOut)\n external\n _logs_\n _lock_\n {\n require(_finalized, \"ERR_NOT_FINALIZED\");\n\n uint poolTotal = totalSupply();\n uint exitFee = bmul(poolAmountIn, EXIT_FEE);\n uint pAiAfterExitFee = bsub(poolAmountIn, exitFee);\n uint ratio = bdiv(pAiAfterExitFee, poolTotal);\n require(ratio != 0, \"ERR_MATH_APPROX\");\n\n _pullPoolShare(msg.sender, poolAmountIn);\n _pushPoolShare(_factory, exitFee);\n _burnPoolShare(pAiAfterExitFee);\n\n for (uint i = 0; i \u003c _tokens.length; i++) {\n address t = _tokens[i];\n uint bal = _records[t].balance;\n uint tokenAmountOut = bmul(ratio, bal);\n require(tokenAmountOut != 0, \"ERR_MATH_APPROX\");\n require(tokenAmountOut \u003e= minAmountsOut[i], \"ERR_LIMIT_OUT\");\n _records[t].balance = bsub(_records[t].balance, tokenAmountOut);\n emit LOG_EXIT(msg.sender, t, tokenAmountOut);\n _pushUnderlying(t, msg.sender, tokenAmountOut);\n }\n\n }\n\n\n function swapExactAmountIn(\n address tokenIn,\n uint tokenAmountIn,\n address tokenOut,\n uint minAmountOut,\n uint maxPrice\n )\n external\n _logs_\n _lock_\n returns (uint tokenAmountOut, uint spotPriceAfter)\n {\n\n require(_records[tokenIn].bound, \"ERR_NOT_BOUND\");\n require(_records[tokenOut].bound, \"ERR_NOT_BOUND\");\n require(_publicSwap, \"ERR_SWAP_NOT_PUBLIC\");\n\n Record storage inRecord = _records[address(tokenIn)];\n Record storage outRecord = _records[address(tokenOut)];\n\n require(tokenAmountIn \u003c= bmul(inRecord.balance, MAX_IN_RATIO), \"ERR_MAX_IN_RATIO\");\n\n uint spotPriceBefore = calcSpotPrice(\n inRecord.balance,\n inRecord.denorm,\n outRecord.balance,\n outRecord.denorm,\n _swapFee\n );\n require(spotPriceBefore \u003c= maxPrice, \"ERR_BAD_LIMIT_PRICE\");\n\n tokenAmountOut = calcOutGivenIn(\n inRecord.balance,\n inRecord.denorm,\n outRecord.balance,\n outRecord.denorm,\n tokenAmountIn,\n _swapFee\n );\n require(tokenAmountOut \u003e= minAmountOut, \"ERR_LIMIT_OUT\");\n\n inRecord.balance = badd(inRecord.balance, tokenAmountIn);\n outRecord.balance = bsub(outRecord.balance, tokenAmountOut);\n\n spotPriceAfter = calcSpotPrice(\n inRecord.balance,\n inRecord.denorm,\n outRecord.balance,\n outRecord.denorm,\n _swapFee\n );\n require(spotPriceAfter \u003e= spotPriceBefore, \"ERR_MATH_APPROX\"); \n require(spotPriceAfter \u003c= maxPrice, \"ERR_LIMIT_PRICE\");\n require(spotPriceBefore \u003c= bdiv(tokenAmountIn, tokenAmountOut), \"ERR_MATH_APPROX\");\n\n emit LOG_SWAP(msg.sender, tokenIn, tokenOut, tokenAmountIn, tokenAmountOut);\n\n _pullUnderlying(tokenIn, msg.sender, tokenAmountIn);\n _pushUnderlying(tokenOut, msg.sender, tokenAmountOut);\n\n return (tokenAmountOut, spotPriceAfter);\n }\n\n function swapExactAmountOut(\n address tokenIn,\n uint maxAmountIn,\n address tokenOut,\n uint tokenAmountOut,\n uint maxPrice\n )\n external\n _logs_\n _lock_ \n returns (uint tokenAmountIn, uint spotPriceAfter)\n {\n require(_records[tokenIn].bound, \"ERR_NOT_BOUND\");\n require(_records[tokenOut].bound, \"ERR_NOT_BOUND\");\n require(_publicSwap, \"ERR_SWAP_NOT_PUBLIC\");\n\n Record storage inRecord = _records[address(tokenIn)];\n Record storage outRecord = _records[address(tokenOut)];\n\n require(tokenAmountOut \u003c= bmul(outRecord.balance, MAX_OUT_RATIO), \"ERR_MAX_OUT_RATIO\");\n\n uint spotPriceBefore = calcSpotPrice(\n inRecord.balance,\n inRecord.denorm,\n outRecord.balance,\n outRecord.denorm,\n _swapFee\n );\n require(spotPriceBefore \u003c= maxPrice, \"ERR_BAD_LIMIT_PRICE\");\n\n tokenAmountIn = calcInGivenOut(\n inRecord.balance,\n inRecord.denorm,\n outRecord.balance,\n outRecord.denorm,\n tokenAmountOut,\n _swapFee\n );\n require(tokenAmountIn \u003c= maxAmountIn, \"ERR_LIMIT_IN\");\n\n inRecord.balance = badd(inRecord.balance, tokenAmountIn);\n outRecord.balance = bsub(outRecord.balance, tokenAmountOut);\n\n spotPriceAfter = calcSpotPrice(\n inRecord.balance,\n inRecord.denorm,\n outRecord.balance,\n outRecord.denorm,\n _swapFee\n );\n require(spotPriceAfter \u003e= spotPriceBefore, \"ERR_MATH_APPROX\");\n require(spotPriceAfter \u003c= maxPrice, \"ERR_LIMIT_PRICE\");\n require(spotPriceBefore \u003c= bdiv(tokenAmountIn, tokenAmountOut), \"ERR_MATH_APPROX\");\n\n emit LOG_SWAP(msg.sender, tokenIn, tokenOut, tokenAmountIn, tokenAmountOut);\n\n _pullUnderlying(tokenIn, msg.sender, tokenAmountIn);\n _pushUnderlying(tokenOut, msg.sender, tokenAmountOut);\n\n return (tokenAmountIn, spotPriceAfter);\n }\n\n\n function joinswapExternAmountIn(address tokenIn, uint tokenAmountIn, uint minPoolAmountOut)\n external\n _logs_\n _lock_\n returns (uint poolAmountOut)\n\n { \n require(_finalized, \"ERR_NOT_FINALIZED\");\n require(_records[tokenIn].bound, \"ERR_NOT_BOUND\");\n require(tokenAmountIn \u003c= bmul(_records[tokenIn].balance, MAX_IN_RATIO), \"ERR_MAX_IN_RATIO\");\n\n Record storage inRecord = _records[tokenIn];\n\n poolAmountOut = calcPoolOutGivenSingleIn(\n inRecord.balance,\n inRecord.denorm,\n _totalSupply,\n _totalWeight,\n tokenAmountIn,\n _swapFee\n );\n\n require(poolAmountOut \u003e= minPoolAmountOut, \"ERR_LIMIT_OUT\");\n\n inRecord.balance = badd(inRecord.balance, tokenAmountIn);\n\n emit LOG_JOIN(msg.sender, tokenIn, tokenAmountIn);\n\n _mintPoolShare(poolAmountOut);\n _pushPoolShare(msg.sender, poolAmountOut);\n _pullUnderlying(tokenIn, msg.sender, tokenAmountIn);\n\n return poolAmountOut;\n }\n\n function joinswapPoolAmountOut(address tokenIn, uint poolAmountOut, uint maxAmountIn)\n external\n _logs_\n _lock_\n returns (uint tokenAmountIn)\n {\n require(_finalized, \"ERR_NOT_FINALIZED\");\n require(_records[tokenIn].bound, \"ERR_NOT_BOUND\");\n\n Record storage inRecord = _records[tokenIn];\n\n tokenAmountIn = calcSingleInGivenPoolOut(\n inRecord.balance,\n inRecord.denorm,\n _totalSupply,\n _totalWeight,\n poolAmountOut,\n _swapFee\n );\n\n require(tokenAmountIn != 0, \"ERR_MATH_APPROX\");\n require(tokenAmountIn \u003c= maxAmountIn, \"ERR_LIMIT_IN\");\n \n require(tokenAmountIn \u003c= bmul(_records[tokenIn].balance, MAX_IN_RATIO), \"ERR_MAX_IN_RATIO\");\n\n inRecord.balance = badd(inRecord.balance, tokenAmountIn);\n\n emit LOG_JOIN(msg.sender, tokenIn, tokenAmountIn);\n\n _mintPoolShare(poolAmountOut);\n _pushPoolShare(msg.sender, poolAmountOut);\n _pullUnderlying(tokenIn, msg.sender, tokenAmountIn);\n\n return tokenAmountIn;\n }\n\n function exitswapPoolAmountIn(address tokenOut, uint poolAmountIn, uint minAmountOut)\n external\n _logs_\n _lock_\n returns (uint tokenAmountOut)\n {\n require(_finalized, \"ERR_NOT_FINALIZED\");\n require(_records[tokenOut].bound, \"ERR_NOT_BOUND\");\n\n Record storage outRecord = _records[tokenOut];\n\n tokenAmountOut = calcSingleOutGivenPoolIn(\n outRecord.balance,\n outRecord.denorm,\n _totalSupply,\n _totalWeight,\n poolAmountIn,\n _swapFee\n );\n\n require(tokenAmountOut \u003e= minAmountOut, \"ERR_LIMIT_OUT\");\n \n require(tokenAmountOut \u003c= bmul(_records[tokenOut].balance, MAX_OUT_RATIO), \"ERR_MAX_OUT_RATIO\");\n\n outRecord.balance = bsub(outRecord.balance, tokenAmountOut);\n\n uint exitFee = bmul(poolAmountIn, EXIT_FEE);\n\n emit LOG_EXIT(msg.sender, tokenOut, tokenAmountOut);\n\n _pullPoolShare(msg.sender, poolAmountIn);\n _burnPoolShare(bsub(poolAmountIn, exitFee));\n _pushPoolShare(_factory, exitFee);\n _pushUnderlying(tokenOut, msg.sender, tokenAmountOut);\n\n return tokenAmountOut;\n }\n\n function exitswapExternAmountOut(address tokenOut, uint tokenAmountOut, uint maxPoolAmountIn)\n external\n _logs_\n _lock_\n returns (uint poolAmountIn)\n {\n require(_finalized, \"ERR_NOT_FINALIZED\");\n require(_records[tokenOut].bound, \"ERR_NOT_BOUND\");\n require(tokenAmountOut \u003c= bmul(_records[tokenOut].balance, MAX_OUT_RATIO), \"ERR_MAX_OUT_RATIO\");\n\n Record storage outRecord = _records[tokenOut];\n\n poolAmountIn = calcPoolInGivenSingleOut(\n outRecord.balance,\n outRecord.denorm,\n _totalSupply,\n _totalWeight,\n tokenAmountOut,\n _swapFee\n );\n\n require(poolAmountIn != 0, \"ERR_MATH_APPROX\");\n require(poolAmountIn \u003c= maxPoolAmountIn, \"ERR_LIMIT_IN\");\n\n outRecord.balance = bsub(outRecord.balance, tokenAmountOut);\n\n uint exitFee = bmul(poolAmountIn, EXIT_FEE);\n\n emit LOG_EXIT(msg.sender, tokenOut, tokenAmountOut);\n\n _pullPoolShare(msg.sender, poolAmountIn);\n _burnPoolShare(bsub(poolAmountIn, exitFee));\n _pushPoolShare(_factory, exitFee);\n _pushUnderlying(tokenOut, msg.sender, tokenAmountOut); \n\n return poolAmountIn;\n }\n\n\n // ==\n // \u0027Underlying\u0027 token-manipulation functions make external calls but are NOT locked\n // You must `_lock_` or otherwise ensure reentry-safety\n\n function _pullUnderlying(address erc20, address from, uint amount)\n internal\n {\n bool xfer = IERC20(erc20).transferFrom(from, address(this), amount);\n require(xfer, \"ERR_ERC20_FALSE\");\n }\n\n function _pushUnderlying(address erc20, address to, uint amount)\n internal\n {\n bool xfer = IERC20(erc20).transfer(to, amount);\n require(xfer, \"ERR_ERC20_FALSE\");\n }\n\n function _pullPoolShare(address from, uint amount)\n internal\n {\n _pull(from, amount);\n }\n\n function _pushPoolShare(address to, uint amount)\n internal\n {\n _push(to, amount);\n }\n\n function _mintPoolShare(uint amount)\n internal\n {\n _mint(amount);\n }\n\n function _burnPoolShare(uint amount)\n internal\n {\n _burn(amount);\n }\n\n}\n"},"BToken.sol":{"content":"// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see \u003chttp://www.gnu.org/licenses/\u003e.\n\npragma solidity 0.5.12;\n\nimport \"./BNum.sol\";\n\n// Highly opinionated token implementation\n\ninterface IERC20 {\n event Approval(address indexed src, address indexed dst, uint amt);\n event Transfer(address indexed src, address indexed dst, uint amt);\n\n function totalSupply() external view returns (uint);\n function balanceOf(address whom) external view returns (uint);\n function allowance(address src, address dst) external view returns (uint);\n\n function approve(address dst, uint amt) external returns (bool);\n function transfer(address dst, uint amt) external returns (bool);\n function transferFrom(\n address src, address dst, uint amt\n ) external returns (bool);\n}\n\ncontract BTokenBase is BNum {\n\n mapping(address =\u003e uint) internal _balance;\n mapping(address =\u003e mapping(address=\u003euint)) internal _allowance;\n uint internal _totalSupply;\n\n event Approval(address indexed src, address indexed dst, uint amt);\n event Transfer(address indexed src, address indexed dst, uint amt);\n\n function _mint(uint amt) internal {\n _balance[address(this)] = badd(_balance[address(this)], amt);\n _totalSupply = badd(_totalSupply, amt);\n emit Transfer(address(0), address(this), amt);\n }\n\n function _burn(uint amt) internal {\n require(_balance[address(this)] \u003e= amt, \"ERR_INSUFFICIENT_BAL\");\n _balance[address(this)] = bsub(_balance[address(this)], amt);\n _totalSupply = bsub(_totalSupply, amt);\n emit Transfer(address(this), address(0), amt);\n }\n\n function _move(address src, address dst, uint amt) internal {\n require(_balance[src] \u003e= amt, \"ERR_INSUFFICIENT_BAL\");\n _balance[src] = bsub(_balance[src], amt);\n _balance[dst] = badd(_balance[dst], amt);\n emit Transfer(src, dst, amt);\n }\n\n function _push(address to, uint amt) internal {\n _move(address(this), to, amt);\n }\n\n function _pull(address from, uint amt) internal {\n _move(from, address(this), amt);\n }\n}\n\ncontract BToken is BTokenBase, IERC20 {\n\n string private _name = \"Balancer Pool Token\";\n string private _symbol = \"BPT\";\n uint8 private _decimals = 18;\n\n function name() public view returns (string memory) {\n return _name;\n }\n\n function symbol() public view returns (string memory) {\n return _symbol;\n }\n\n function decimals() public view returns(uint8) {\n return _decimals;\n }\n\n function allowance(address src, address dst) external view returns (uint) {\n return _allowance[src][dst];\n }\n\n function balanceOf(address whom) external view returns (uint) {\n return _balance[whom];\n }\n\n function totalSupply() public view returns (uint) {\n return _totalSupply;\n }\n\n function approve(address dst, uint amt) external returns (bool) {\n _allowance[msg.sender][dst] = amt;\n emit Approval(msg.sender, dst, amt);\n return true;\n }\n\n function increaseApproval(address dst, uint amt) external returns (bool) {\n _allowance[msg.sender][dst] = badd(_allowance[msg.sender][dst], amt);\n emit Approval(msg.sender, dst, _allowance[msg.sender][dst]);\n return true;\n }\n\n function decreaseApproval(address dst, uint amt) external returns (bool) {\n uint oldValue = _allowance[msg.sender][dst];\n if (amt \u003e oldValue) {\n _allowance[msg.sender][dst] = 0;\n } else {\n _allowance[msg.sender][dst] = bsub(oldValue, amt);\n }\n emit Approval(msg.sender, dst, _allowance[msg.sender][dst]);\n return true;\n }\n\n function transfer(address dst, uint amt) external returns (bool) {\n _move(msg.sender, dst, amt);\n return true;\n }\n\n function transferFrom(address src, address dst, uint amt) external returns (bool) {\n require(msg.sender == src || amt \u003c= _allowance[src][msg.sender], \"ERR_BTOKEN_BAD_CALLER\");\n _move(src, dst, amt);\n if (msg.sender != src \u0026\u0026 _allowance[src][msg.sender] != uint256(-1)) {\n _allowance[src][msg.sender] = bsub(_allowance[src][msg.sender], amt);\n emit Approval(msg.sender, dst, _allowance[src][msg.sender]);\n }\n return true;\n }\n}\n"}}
File 3 of 12: RadicleToken
// SPDX-License-Identifier: GPL-3.0-only // Copyright 2020 Compound Labs, Inc. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // 3. Neither the name of the copyright holder nor the names of its // contributors may be used to endorse or promote products derived from this // software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. pragma solidity ^0.7.5; pragma experimental ABIEncoderV2; contract RadicleToken { /// @notice EIP-20 token name for this token string public constant NAME = "Radicle"; /// @notice EIP-20 token symbol for this token string public constant SYMBOL = "RAD"; /// @notice EIP-20 token decimals for this token uint8 public constant DECIMALS = 18; /// @notice Total number of tokens in circulation uint256 public totalSupply = 100000000e18; // 100 million tokens // Allowance amounts on behalf of others mapping(address => mapping(address => uint96)) internal allowances; // Official record of token balances for each account mapping(address => uint96) internal balances; /// @notice A record of each accounts delegate mapping(address => address) public delegates; /// @notice A checkpoint for marking number of votes from a given block struct Checkpoint { uint32 fromBlock; uint96 votes; } /// @notice A record of votes checkpoints for each account, by index mapping(address => mapping(uint32 => Checkpoint)) public checkpoints; /// @notice The number of checkpoints for each account mapping(address => uint32) public numCheckpoints; /// @notice The EIP-712 typehash for the contract's domain bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)"); /// @notice The EIP-712 typehash for the delegation struct used by the contract bytes32 public constant DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); /// @notice The EIP-712 typehash for EIP-2612 permit bytes32 public constant PERMIT_TYPEHASH = keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ); /// @notice A record of states for signing / validating signatures mapping(address => uint256) public nonces; /// @notice An event thats emitted when an account changes its delegate event DelegateChanged( address indexed delegator, address indexed fromDelegate, address indexed toDelegate ); /// @notice An event thats emitted when a delegate account's vote balance changes event DelegateVotesChanged( address indexed delegate, uint256 previousBalance, uint256 newBalance ); /// @notice The standard EIP-20 transfer event event Transfer(address indexed from, address indexed to, uint256 amount); /// @notice The standard EIP-20 approval event event Approval(address indexed owner, address indexed spender, uint256 amount); /** * @notice Construct a new token * @param account The initial account to grant all the tokens */ constructor(address account) { balances[account] = uint96(totalSupply); emit Transfer(address(0), account, totalSupply); } /* @notice Token name */ function name() public pure returns (string memory) { return NAME; } /* @notice Token symbol */ function symbol() public pure returns (string memory) { return SYMBOL; } /* @notice Token decimals */ function decimals() public pure returns (uint8) { return DECIMALS; } /* @notice domainSeparator */ // solhint-disable func-name-mixedcase function DOMAIN_SEPARATOR() public view returns (bytes32) { return keccak256( abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(NAME)), getChainId(), address(this)) ); } /** * @notice Get the number of tokens `spender` is approved to spend on behalf of `account` * @param account The address of the account holding the funds * @param spender The address of the account spending the funds * @return The number of tokens approved */ function allowance(address account, address spender) external view returns (uint256) { return allowances[account][spender]; } /** * @notice Approve `spender` to transfer up to `amount` from `src` * @dev This will overwrite the approval amount for `spender` * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) * @param spender The address of the account which may transfer tokens * @param rawAmount The number of tokens that are approved (2^256-1 means infinite) * @return Whether or not the approval succeeded */ function approve(address spender, uint256 rawAmount) external returns (bool) { _approve(msg.sender, spender, rawAmount); return true; } function _approve( address owner, address spender, uint256 rawAmount ) internal { uint96 amount; if (rawAmount == uint256(-1)) { amount = uint96(-1); } else { amount = safe96(rawAmount, "RadicleToken::approve: amount exceeds 96 bits"); } allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @notice Get the number of tokens held by the `account` * @param account The address of the account to get the balance of * @return The number of tokens held */ function balanceOf(address account) external view returns (uint256) { return balances[account]; } /** * @notice Transfer `amount` tokens from `msg.sender` to `dst` * @param dst The address of the destination account * @param rawAmount The number of tokens to transfer * @return Whether or not the transfer succeeded */ function transfer(address dst, uint256 rawAmount) external returns (bool) { uint96 amount = safe96(rawAmount, "RadicleToken::transfer: amount exceeds 96 bits"); _transferTokens(msg.sender, dst, amount); return true; } /** * @notice Transfer `amount` tokens from `src` to `dst` * @param src The address of the source account * @param dst The address of the destination account * @param rawAmount The number of tokens to transfer * @return Whether or not the transfer succeeded */ function transferFrom( address src, address dst, uint256 rawAmount ) external returns (bool) { address spender = msg.sender; uint96 spenderAllowance = allowances[src][spender]; uint96 amount = safe96(rawAmount, "RadicleToken::approve: amount exceeds 96 bits"); if (spender != src && spenderAllowance != uint96(-1)) { uint96 newAllowance = sub96( spenderAllowance, amount, "RadicleToken::transferFrom: transfer amount exceeds spender allowance" ); allowances[src][spender] = newAllowance; emit Approval(src, spender, newAllowance); } _transferTokens(src, dst, amount); return true; } /** * @notice Burn `rawAmount` tokens from `account` * @param account The address of the account to burn * @param rawAmount The number of tokens to burn */ function burnFrom(address account, uint256 rawAmount) public { require(account != address(0), "RadicleToken::burnFrom: cannot burn from the zero address"); uint96 amount = safe96(rawAmount, "RadicleToken::burnFrom: amount exceeds 96 bits"); address spender = msg.sender; uint96 spenderAllowance = allowances[account][spender]; if (spender != account && spenderAllowance != uint96(-1)) { uint96 newAllowance = sub96( spenderAllowance, amount, "RadicleToken::burnFrom: burn amount exceeds allowance" ); allowances[account][spender] = newAllowance; emit Approval(account, spender, newAllowance); } balances[account] = sub96( balances[account], amount, "RadicleToken::burnFrom: burn amount exceeds balance" ); emit Transfer(account, address(0), amount); _moveDelegates(delegates[account], address(0), amount); totalSupply -= rawAmount; } /** * @notice Delegate votes from `msg.sender` to `delegatee` * @param delegatee The address to delegate votes to */ function delegate(address delegatee) public { return _delegate(msg.sender, delegatee); } /** * @notice Delegates votes from signatory to `delegatee` * @param delegatee The address to delegate votes to * @param nonce The contract state required to match the signature * @param expiry The time at which to expire the signature * @param v The recovery byte of the signature * @param r Half of the ECDSA signature pair * @param s Half of the ECDSA signature pair */ function delegateBySig( address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s ) public { bytes32 structHash = keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry)); bytes32 digest = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR(), structHash)); address signatory = ecrecover(digest, v, r, s); require(signatory != address(0), "RadicleToken::delegateBySig: invalid signature"); require(nonce == nonces[signatory]++, "RadicleToken::delegateBySig: invalid nonce"); require(block.timestamp <= expiry, "RadicleToken::delegateBySig: signature expired"); _delegate(signatory, delegatee); } /** * @notice Approves spender to spend on behalf of owner. * @param owner The signer of the permit * @param spender The address to approve * @param deadline The time at which the signature expires * @param v The recovery byte of the signature * @param r Half of the ECDSA signature pair * @param s Half of the ECDSA signature pair */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public { bytes32 structHash = keccak256( abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline) ); bytes32 digest = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR(), structHash)); require(owner == ecrecover(digest, v, r, s), "RadicleToken::permit: invalid signature"); require(owner != address(0), "RadicleToken::permit: invalid signature"); require(block.timestamp <= deadline, "RadicleToken::permit: signature expired"); _approve(owner, spender, value); } /** * @notice Gets the current votes balance for `account` * @param account The address to get votes balance * @return The number of current votes for `account` */ function getCurrentVotes(address account) external view returns (uint96) { uint32 nCheckpoints = numCheckpoints[account]; return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0; } /** * @notice Determine the prior number of votes for an account as of a block number * @dev Block number must be a finalized block or else this function will revert to prevent misinformation. * @param account The address of the account to check * @param blockNumber The block number to get the vote balance at * @return The number of votes the account had as of the given block */ function getPriorVotes(address account, uint256 blockNumber) public view returns (uint96) { require(blockNumber < block.number, "RadicleToken::getPriorVotes: not yet determined"); uint32 nCheckpoints = numCheckpoints[account]; if (nCheckpoints == 0) { return 0; } // First check most recent balance if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) { return checkpoints[account][nCheckpoints - 1].votes; } // Next check implicit zero balance if (checkpoints[account][0].fromBlock > blockNumber) { return 0; } uint32 lower = 0; uint32 upper = nCheckpoints - 1; while (upper > lower) { uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow Checkpoint memory cp = checkpoints[account][center]; if (cp.fromBlock == blockNumber) { return cp.votes; } else if (cp.fromBlock < blockNumber) { lower = center; } else { upper = center - 1; } } return checkpoints[account][lower].votes; } function _delegate(address delegator, address delegatee) internal { address currentDelegate = delegates[delegator]; uint96 delegatorBalance = balances[delegator]; delegates[delegator] = delegatee; emit DelegateChanged(delegator, currentDelegate, delegatee); _moveDelegates(currentDelegate, delegatee, delegatorBalance); } function _transferTokens( address src, address dst, uint96 amount ) internal { require( src != address(0), "RadicleToken::_transferTokens: cannot transfer from the zero address" ); require( dst != address(0), "RadicleToken::_transferTokens: cannot transfer to the zero address" ); balances[src] = sub96( balances[src], amount, "RadicleToken::_transferTokens: transfer amount exceeds balance" ); balances[dst] = add96( balances[dst], amount, "RadicleToken::_transferTokens: transfer amount overflows" ); emit Transfer(src, dst, amount); _moveDelegates(delegates[src], delegates[dst], amount); } function _moveDelegates( address srcRep, address dstRep, uint96 amount ) internal { if (srcRep != dstRep && amount > 0) { if (srcRep != address(0)) { uint32 srcRepNum = numCheckpoints[srcRep]; uint96 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0; uint96 srcRepNew = sub96(srcRepOld, amount, "RadicleToken::_moveVotes: vote amount underflows"); _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew); } if (dstRep != address(0)) { uint32 dstRepNum = numCheckpoints[dstRep]; uint96 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0; uint96 dstRepNew = add96(dstRepOld, amount, "RadicleToken::_moveVotes: vote amount overflows"); _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew); } } } function _writeCheckpoint( address delegatee, uint32 nCheckpoints, uint96 oldVotes, uint96 newVotes ) internal { uint32 blockNumber = safe32(block.number, "RadicleToken::_writeCheckpoint: block number exceeds 32 bits"); if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) { checkpoints[delegatee][nCheckpoints - 1].votes = newVotes; } else { checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes); numCheckpoints[delegatee] = nCheckpoints + 1; } emit DelegateVotesChanged(delegatee, oldVotes, newVotes); } function safe32(uint256 n, string memory errorMessage) internal pure returns (uint32) { require(n < 2**32, errorMessage); return uint32(n); } function safe96(uint256 n, string memory errorMessage) internal pure returns (uint96) { require(n < 2**96, errorMessage); return uint96(n); } function add96( uint96 a, uint96 b, string memory errorMessage ) internal pure returns (uint96) { uint96 c = a + b; require(c >= a, errorMessage); return c; } function sub96( uint96 a, uint96 b, string memory errorMessage ) internal pure returns (uint96) { require(b <= a, errorMessage); return a - b; } function getChainId() internal pure returns (uint256) { uint256 chainId; // solhint-disable no-inline-assembly assembly { chainId := chainid() } return chainId; } }
File 4 of 12: BFactory
{"BColor.sol":{"content":"// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see \u003chttp://www.gnu.org/licenses/\u003e.\n\npragma solidity 0.5.12;\n\ncontract BColor {\n function getColor()\n external view\n returns (bytes32);\n}\n\ncontract BBronze is BColor {\n function getColor()\n external view\n returns (bytes32) {\n return bytes32(\"BRONZE\");\n }\n}\n"},"BConst.sol":{"content":"// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see \u003chttp://www.gnu.org/licenses/\u003e.\n\npragma solidity 0.5.12;\n\nimport \"./BColor.sol\";\n\ncontract BConst is BBronze {\n uint public constant BONE = 10**18;\n\n uint public constant MIN_BOUND_TOKENS = 2;\n uint public constant MAX_BOUND_TOKENS = 8;\n\n uint public constant MIN_FEE = BONE / 10**6;\n uint public constant MAX_FEE = BONE / 10;\n uint public constant EXIT_FEE = 0;\n\n uint public constant MIN_WEIGHT = BONE;\n uint public constant MAX_WEIGHT = BONE * 50;\n uint public constant MAX_TOTAL_WEIGHT = BONE * 50;\n uint public constant MIN_BALANCE = BONE / 10**12;\n\n uint public constant INIT_POOL_SUPPLY = BONE * 100;\n\n uint public constant MIN_BPOW_BASE = 1 wei;\n uint public constant MAX_BPOW_BASE = (2 * BONE) - 1 wei;\n uint public constant BPOW_PRECISION = BONE / 10**10;\n\n uint public constant MAX_IN_RATIO = BONE / 2;\n uint public constant MAX_OUT_RATIO = (BONE / 3) + 1 wei;\n}\n"},"BFactory.sol":{"content":"// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is disstributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see \u003chttp://www.gnu.org/licenses/\u003e.\n\npragma solidity 0.5.12;\n\n// Builds new BPools, logging their addresses and providing `isBPool(address) -\u003e (bool)`\n\nimport \"./BPool.sol\";\n\ncontract BFactory is BBronze {\n event LOG_NEW_POOL(\n address indexed caller,\n address indexed pool\n );\n\n event LOG_BLABS(\n address indexed caller,\n address indexed blabs\n );\n\n mapping(address=\u003ebool) private _isBPool;\n\n function isBPool(address b)\n external view returns (bool)\n {\n return _isBPool[b];\n }\n\n function newBPool()\n external\n returns (BPool)\n {\n BPool bpool = new BPool();\n _isBPool[address(bpool)] = true;\n emit LOG_NEW_POOL(msg.sender, address(bpool));\n bpool.setController(msg.sender);\n return bpool;\n }\n\n address private _blabs;\n\n constructor() public {\n _blabs = msg.sender;\n }\n\n function getBLabs()\n external view\n returns (address)\n {\n return _blabs;\n }\n\n function setBLabs(address b)\n external\n {\n require(msg.sender == _blabs, \"ERR_NOT_BLABS\");\n emit LOG_BLABS(msg.sender, b);\n _blabs = b;\n }\n\n function collect(BPool pool)\n external \n {\n require(msg.sender == _blabs, \"ERR_NOT_BLABS\");\n uint collected = IERC20(pool).balanceOf(address(this));\n bool xfer = pool.transfer(_blabs, collected);\n require(xfer, \"ERR_ERC20_FAILED\");\n }\n}\n"},"BMath.sol":{"content":"// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see \u003chttp://www.gnu.org/licenses/\u003e.\n\npragma solidity 0.5.12;\n\nimport \"./BNum.sol\";\n\ncontract BMath is BBronze, BConst, BNum {\n /**********************************************************************************************\n // calcSpotPrice //\n // sP = spotPrice //\n // bI = tokenBalanceIn ( bI / wI ) 1 //\n // bO = tokenBalanceOut sP = ----------- * ---------- //\n // wI = tokenWeightIn ( bO / wO ) ( 1 - sF ) //\n // wO = tokenWeightOut //\n // sF = swapFee //\n **********************************************************************************************/\n function calcSpotPrice(\n uint tokenBalanceIn,\n uint tokenWeightIn,\n uint tokenBalanceOut,\n uint tokenWeightOut,\n uint swapFee\n )\n public pure\n returns (uint spotPrice)\n {\n uint numer = bdiv(tokenBalanceIn, tokenWeightIn);\n uint denom = bdiv(tokenBalanceOut, tokenWeightOut);\n uint ratio = bdiv(numer, denom);\n uint scale = bdiv(BONE, bsub(BONE, swapFee));\n return (spotPrice = bmul(ratio, scale));\n }\n\n /**********************************************************************************************\n // calcOutGivenIn //\n // aO = tokenAmountOut //\n // bO = tokenBalanceOut //\n // bI = tokenBalanceIn / / bI \\ (wI / wO) \\ //\n // aI = tokenAmountIn aO = bO * | 1 - | -------------------------- | ^ | //\n // wI = tokenWeightIn \\ \\ ( bI + ( aI * ( 1 - sF )) / / //\n // wO = tokenWeightOut //\n // sF = swapFee //\n **********************************************************************************************/\n function calcOutGivenIn(\n uint tokenBalanceIn,\n uint tokenWeightIn,\n uint tokenBalanceOut,\n uint tokenWeightOut,\n uint tokenAmountIn,\n uint swapFee\n )\n public pure\n returns (uint tokenAmountOut)\n {\n uint weightRatio = bdiv(tokenWeightIn, tokenWeightOut);\n uint adjustedIn = bsub(BONE, swapFee);\n adjustedIn = bmul(tokenAmountIn, adjustedIn);\n uint y = bdiv(tokenBalanceIn, badd(tokenBalanceIn, adjustedIn));\n uint foo = bpow(y, weightRatio);\n uint bar = bsub(BONE, foo);\n tokenAmountOut = bmul(tokenBalanceOut, bar);\n return tokenAmountOut;\n }\n\n /**********************************************************************************************\n // calcInGivenOut //\n // aI = tokenAmountIn //\n // bO = tokenBalanceOut / / bO \\ (wO / wI) \\ //\n // bI = tokenBalanceIn bI * | | ------------ | ^ - 1 | //\n // aO = tokenAmountOut aI = \\ \\ ( bO - aO ) / / //\n // wI = tokenWeightIn -------------------------------------------- //\n // wO = tokenWeightOut ( 1 - sF ) //\n // sF = swapFee //\n **********************************************************************************************/\n function calcInGivenOut(\n uint tokenBalanceIn,\n uint tokenWeightIn,\n uint tokenBalanceOut,\n uint tokenWeightOut,\n uint tokenAmountOut,\n uint swapFee\n )\n public pure\n returns (uint tokenAmountIn)\n {\n uint weightRatio = bdiv(tokenWeightOut, tokenWeightIn);\n uint diff = bsub(tokenBalanceOut, tokenAmountOut);\n uint y = bdiv(tokenBalanceOut, diff);\n uint foo = bpow(y, weightRatio);\n foo = bsub(foo, BONE);\n tokenAmountIn = bsub(BONE, swapFee);\n tokenAmountIn = bdiv(bmul(tokenBalanceIn, foo), tokenAmountIn);\n return tokenAmountIn;\n }\n\n /**********************************************************************************************\n // calcPoolOutGivenSingleIn //\n // pAo = poolAmountOut / \\ //\n // tAi = tokenAmountIn /// / // wI \\ \\\\ \\ wI \\ //\n // wI = tokenWeightIn //| tAi *| 1 - || 1 - -- | * sF || + tBi \\ -- \\ //\n // tW = totalWeight pAo=|| \\ \\ \\\\ tW / // | ^ tW | * pS - pS //\n // tBi = tokenBalanceIn \\\\ ------------------------------------- / / //\n // pS = poolSupply \\\\ tBi / / //\n // sF = swapFee \\ / //\n **********************************************************************************************/\n function calcPoolOutGivenSingleIn(\n uint tokenBalanceIn,\n uint tokenWeightIn,\n uint poolSupply,\n uint totalWeight,\n uint tokenAmountIn,\n uint swapFee\n )\n public pure\n returns (uint poolAmountOut)\n {\n // Charge the trading fee for the proportion of tokenAi\n /// which is implicitly traded to the other pool tokens.\n // That proportion is (1- weightTokenIn)\n // tokenAiAfterFee = tAi * (1 - (1-weightTi) * poolFee);\n uint normalizedWeight = bdiv(tokenWeightIn, totalWeight);\n uint zaz = bmul(bsub(BONE, normalizedWeight), swapFee); \n uint tokenAmountInAfterFee = bmul(tokenAmountIn, bsub(BONE, zaz));\n\n uint newTokenBalanceIn = badd(tokenBalanceIn, tokenAmountInAfterFee);\n uint tokenInRatio = bdiv(newTokenBalanceIn, tokenBalanceIn);\n\n // uint newPoolSupply = (ratioTi ^ weightTi) * poolSupply;\n uint poolRatio = bpow(tokenInRatio, normalizedWeight);\n uint newPoolSupply = bmul(poolRatio, poolSupply);\n poolAmountOut = bsub(newPoolSupply, poolSupply);\n return poolAmountOut;\n }\n\n /**********************************************************************************************\n // calcSingleInGivenPoolOut //\n // tAi = tokenAmountIn //(pS + pAo)\\ / 1 \\\\ //\n // pS = poolSupply || --------- | ^ | --------- || * bI - bI //\n // pAo = poolAmountOut \\\\ pS / \\(wI / tW)// //\n // bI = balanceIn tAi = -------------------------------------------- //\n // wI = weightIn / wI \\ //\n // tW = totalWeight | 1 - ---- | * sF //\n // sF = swapFee \\ tW / //\n **********************************************************************************************/\n function calcSingleInGivenPoolOut(\n uint tokenBalanceIn,\n uint tokenWeightIn,\n uint poolSupply,\n uint totalWeight,\n uint poolAmountOut,\n uint swapFee\n )\n public pure\n returns (uint tokenAmountIn)\n {\n uint normalizedWeight = bdiv(tokenWeightIn, totalWeight);\n uint newPoolSupply = badd(poolSupply, poolAmountOut);\n uint poolRatio = bdiv(newPoolSupply, poolSupply);\n \n //uint newBalTi = poolRatio^(1/weightTi) * balTi;\n uint boo = bdiv(BONE, normalizedWeight); \n uint tokenInRatio = bpow(poolRatio, boo);\n uint newTokenBalanceIn = bmul(tokenInRatio, tokenBalanceIn);\n uint tokenAmountInAfterFee = bsub(newTokenBalanceIn, tokenBalanceIn);\n // Do reverse order of fees charged in joinswap_ExternAmountIn, this way \n // ``` pAo == joinswap_ExternAmountIn(Ti, joinswap_PoolAmountOut(pAo, Ti)) ```\n //uint tAi = tAiAfterFee / (1 - (1-weightTi) * swapFee) ;\n uint zar = bmul(bsub(BONE, normalizedWeight), swapFee);\n tokenAmountIn = bdiv(tokenAmountInAfterFee, bsub(BONE, zar));\n return tokenAmountIn;\n }\n\n /**********************************************************************************************\n // calcSingleOutGivenPoolIn //\n // tAo = tokenAmountOut / / \\\\ //\n // bO = tokenBalanceOut / // pS - (pAi * (1 - eF)) \\ / 1 \\ \\\\ //\n // pAi = poolAmountIn | bO - || ----------------------- | ^ | --------- | * b0 || //\n // ps = poolSupply \\ \\\\ pS / \\(wO / tW)/ // //\n // wI = tokenWeightIn tAo = \\ \\ // //\n // tW = totalWeight / / wO \\ \\ //\n // sF = swapFee * | 1 - | 1 - ---- | * sF | //\n // eF = exitFee \\ \\ tW / / //\n **********************************************************************************************/\n function calcSingleOutGivenPoolIn(\n uint tokenBalanceOut,\n uint tokenWeightOut,\n uint poolSupply,\n uint totalWeight,\n uint poolAmountIn,\n uint swapFee\n )\n public pure\n returns (uint tokenAmountOut)\n {\n uint normalizedWeight = bdiv(tokenWeightOut, totalWeight);\n // charge exit fee on the pool token side\n // pAiAfterExitFee = pAi*(1-exitFee)\n uint poolAmountInAfterExitFee = bmul(poolAmountIn, bsub(BONE, EXIT_FEE));\n uint newPoolSupply = bsub(poolSupply, poolAmountInAfterExitFee);\n uint poolRatio = bdiv(newPoolSupply, poolSupply);\n \n // newBalTo = poolRatio^(1/weightTo) * balTo;\n uint tokenOutRatio = bpow(poolRatio, bdiv(BONE, normalizedWeight));\n uint newTokenBalanceOut = bmul(tokenOutRatio, tokenBalanceOut);\n\n uint tokenAmountOutBeforeSwapFee = bsub(tokenBalanceOut, newTokenBalanceOut);\n\n // charge swap fee on the output token side \n //uint tAo = tAoBeforeSwapFee * (1 - (1-weightTo) * swapFee)\n uint zaz = bmul(bsub(BONE, normalizedWeight), swapFee); \n tokenAmountOut = bmul(tokenAmountOutBeforeSwapFee, bsub(BONE, zaz));\n return tokenAmountOut;\n }\n\n /**********************************************************************************************\n // calcPoolInGivenSingleOut //\n // pAi = poolAmountIn // / tAo \\\\ / wO \\ \\ //\n // bO = tokenBalanceOut // | bO - -------------------------- |\\ | ---- | \\ //\n // tAo = tokenAmountOut pS - || \\ 1 - ((1 - (tO / tW)) * sF)/ | ^ \\ tW / * pS | //\n // ps = poolSupply \\\\ -----------------------------------/ / //\n // wO = tokenWeightOut pAi = \\\\ bO / / //\n // tW = totalWeight ------------------------------------------------------------- //\n // sF = swapFee ( 1 - eF ) //\n // eF = exitFee //\n **********************************************************************************************/\n function calcPoolInGivenSingleOut(\n uint tokenBalanceOut,\n uint tokenWeightOut,\n uint poolSupply,\n uint totalWeight,\n uint tokenAmountOut,\n uint swapFee\n )\n public pure\n returns (uint poolAmountIn)\n {\n\n // charge swap fee on the output token side \n uint normalizedWeight = bdiv(tokenWeightOut, totalWeight);\n //uint tAoBeforeSwapFee = tAo / (1 - (1-weightTo) * swapFee) ;\n uint zoo = bsub(BONE, normalizedWeight);\n uint zar = bmul(zoo, swapFee); \n uint tokenAmountOutBeforeSwapFee = bdiv(tokenAmountOut, bsub(BONE, zar));\n\n uint newTokenBalanceOut = bsub(tokenBalanceOut, tokenAmountOutBeforeSwapFee);\n uint tokenOutRatio = bdiv(newTokenBalanceOut, tokenBalanceOut);\n\n //uint newPoolSupply = (ratioTo ^ weightTo) * poolSupply;\n uint poolRatio = bpow(tokenOutRatio, normalizedWeight);\n uint newPoolSupply = bmul(poolRatio, poolSupply);\n uint poolAmountInAfterExitFee = bsub(poolSupply, newPoolSupply);\n\n // charge exit fee on the pool token side\n // pAi = pAiAfterExitFee/(1-exitFee)\n poolAmountIn = bdiv(poolAmountInAfterExitFee, bsub(BONE, EXIT_FEE));\n return poolAmountIn;\n }\n\n\n}\n"},"BNum.sol":{"content":"// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see \u003chttp://www.gnu.org/licenses/\u003e.\n\npragma solidity 0.5.12;\n\nimport \"./BConst.sol\";\n\ncontract BNum is BConst {\n\n function btoi(uint a)\n internal pure \n returns (uint)\n {\n return a / BONE;\n }\n\n function bfloor(uint a)\n internal pure\n returns (uint)\n {\n return btoi(a) * BONE;\n }\n\n function badd(uint a, uint b)\n internal pure\n returns (uint)\n {\n uint c = a + b;\n require(c \u003e= a, \"ERR_ADD_OVERFLOW\");\n return c;\n }\n\n function bsub(uint a, uint b)\n internal pure\n returns (uint)\n {\n (uint c, bool flag) = bsubSign(a, b);\n require(!flag, \"ERR_SUB_UNDERFLOW\");\n return c;\n }\n\n function bsubSign(uint a, uint b)\n internal pure\n returns (uint, bool)\n {\n if (a \u003e= b) {\n return (a - b, false);\n } else {\n return (b - a, true);\n }\n }\n\n function bmul(uint a, uint b)\n internal pure\n returns (uint)\n {\n uint c0 = a * b;\n require(a == 0 || c0 / a == b, \"ERR_MUL_OVERFLOW\");\n uint c1 = c0 + (BONE / 2);\n require(c1 \u003e= c0, \"ERR_MUL_OVERFLOW\");\n uint c2 = c1 / BONE;\n return c2;\n }\n\n function bdiv(uint a, uint b)\n internal pure\n returns (uint)\n {\n require(b != 0, \"ERR_DIV_ZERO\");\n uint c0 = a * BONE;\n require(a == 0 || c0 / a == BONE, \"ERR_DIV_INTERNAL\"); // bmul overflow\n uint c1 = c0 + (b / 2);\n require(c1 \u003e= c0, \"ERR_DIV_INTERNAL\"); // badd require\n uint c2 = c1 / b;\n return c2;\n }\n\n // DSMath.wpow\n function bpowi(uint a, uint n)\n internal pure\n returns (uint)\n {\n uint z = n % 2 != 0 ? a : BONE;\n\n for (n /= 2; n != 0; n /= 2) {\n a = bmul(a, a);\n\n if (n % 2 != 0) {\n z = bmul(z, a);\n }\n }\n return z;\n }\n\n // Compute b^(e.w) by splitting it into (b^e)*(b^0.w).\n // Use `bpowi` for `b^e` and `bpowK` for k iterations\n // of approximation of b^0.w\n function bpow(uint base, uint exp)\n internal pure\n returns (uint)\n {\n require(base \u003e= MIN_BPOW_BASE, \"ERR_BPOW_BASE_TOO_LOW\");\n require(base \u003c= MAX_BPOW_BASE, \"ERR_BPOW_BASE_TOO_HIGH\");\n\n uint whole = bfloor(exp); \n uint remain = bsub(exp, whole);\n\n uint wholePow = bpowi(base, btoi(whole));\n\n if (remain == 0) {\n return wholePow;\n }\n\n uint partialResult = bpowApprox(base, remain, BPOW_PRECISION);\n return bmul(wholePow, partialResult);\n }\n\n function bpowApprox(uint base, uint exp, uint precision)\n internal pure\n returns (uint)\n {\n // term 0:\n uint a = exp;\n (uint x, bool xneg) = bsubSign(base, BONE);\n uint term = BONE;\n uint sum = term;\n bool negative = false;\n\n\n // term(k) = numer / denom \n // = (product(a - i - 1, i=1--\u003ek) * x^k) / (k!)\n // each iteration, multiply previous term by (a-(k-1)) * x / k\n // continue until term is less than precision\n for (uint i = 1; term \u003e= precision; i++) {\n uint bigK = i * BONE;\n (uint c, bool cneg) = bsubSign(a, bsub(bigK, BONE));\n term = bmul(term, bmul(c, x));\n term = bdiv(term, bigK);\n if (term == 0) break;\n\n if (xneg) negative = !negative;\n if (cneg) negative = !negative;\n if (negative) {\n sum = bsub(sum, term);\n } else {\n sum = badd(sum, term);\n }\n }\n\n return sum;\n }\n\n}\n"},"BPool.sol":{"content":"// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see \u003chttp://www.gnu.org/licenses/\u003e.\n\npragma solidity 0.5.12;\n\nimport \"./BToken.sol\";\nimport \"./BMath.sol\";\n\ncontract BPool is BBronze, BToken, BMath {\n\n struct Record {\n bool bound; // is token bound to pool\n uint index; // private\n uint denorm; // denormalized weight\n uint balance;\n }\n\n event LOG_SWAP(\n address indexed caller,\n address indexed tokenIn,\n address indexed tokenOut,\n uint256 tokenAmountIn,\n uint256 tokenAmountOut\n );\n\n event LOG_JOIN(\n address indexed caller,\n address indexed tokenIn,\n uint256 tokenAmountIn\n );\n\n event LOG_EXIT(\n address indexed caller,\n address indexed tokenOut,\n uint256 tokenAmountOut\n );\n\n event LOG_CALL(\n bytes4 indexed sig,\n address indexed caller,\n bytes data\n ) anonymous;\n\n modifier _logs_() {\n emit LOG_CALL(msg.sig, msg.sender, msg.data);\n _;\n }\n\n modifier _lock_() {\n require(!_mutex, \"ERR_REENTRY\");\n _mutex = true;\n _;\n _mutex = false;\n }\n\n modifier _viewlock_() {\n require(!_mutex, \"ERR_REENTRY\");\n _;\n }\n\n bool private _mutex;\n\n address private _factory; // BFactory address to push token exitFee to\n address private _controller; // has CONTROL role\n bool private _publicSwap; // true if PUBLIC can call SWAP functions\n\n // `setSwapFee` and `finalize` require CONTROL\n // `finalize` sets `PUBLIC can SWAP`, `PUBLIC can JOIN`\n uint private _swapFee;\n bool private _finalized;\n\n address[] private _tokens;\n mapping(address=\u003eRecord) private _records;\n uint private _totalWeight;\n\n constructor() public {\n _controller = msg.sender;\n _factory = msg.sender;\n _swapFee = MIN_FEE;\n _publicSwap = false;\n _finalized = false;\n }\n\n function isPublicSwap()\n external view\n returns (bool)\n {\n return _publicSwap;\n }\n\n function isFinalized()\n external view\n returns (bool)\n {\n return _finalized;\n }\n\n function isBound(address t)\n external view\n returns (bool)\n {\n return _records[t].bound;\n }\n\n function getNumTokens()\n external view\n returns (uint) \n {\n return _tokens.length;\n }\n\n function getCurrentTokens()\n external view _viewlock_\n returns (address[] memory tokens)\n {\n return _tokens;\n }\n\n function getFinalTokens()\n external view\n _viewlock_\n returns (address[] memory tokens)\n {\n require(_finalized, \"ERR_NOT_FINALIZED\");\n return _tokens;\n }\n\n function getDenormalizedWeight(address token)\n external view\n _viewlock_\n returns (uint)\n {\n\n require(_records[token].bound, \"ERR_NOT_BOUND\");\n return _records[token].denorm;\n }\n\n function getTotalDenormalizedWeight()\n external view\n _viewlock_\n returns (uint)\n {\n return _totalWeight;\n }\n\n function getNormalizedWeight(address token)\n external view\n _viewlock_\n returns (uint)\n {\n\n require(_records[token].bound, \"ERR_NOT_BOUND\");\n uint denorm = _records[token].denorm;\n return bdiv(denorm, _totalWeight);\n }\n\n function getBalance(address token)\n external view\n _viewlock_\n returns (uint)\n {\n\n require(_records[token].bound, \"ERR_NOT_BOUND\");\n return _records[token].balance;\n }\n\n function getSwapFee()\n external view\n _viewlock_\n returns (uint)\n {\n return _swapFee;\n }\n\n function getController()\n external view\n _viewlock_\n returns (address)\n {\n return _controller;\n }\n\n function setSwapFee(uint swapFee)\n external\n _logs_\n _lock_\n { \n require(!_finalized, \"ERR_IS_FINALIZED\");\n require(msg.sender == _controller, \"ERR_NOT_CONTROLLER\");\n require(swapFee \u003e= MIN_FEE, \"ERR_MIN_FEE\");\n require(swapFee \u003c= MAX_FEE, \"ERR_MAX_FEE\");\n _swapFee = swapFee;\n }\n\n function setController(address manager)\n external\n _logs_\n _lock_\n {\n require(msg.sender == _controller, \"ERR_NOT_CONTROLLER\");\n _controller = manager;\n }\n\n function setPublicSwap(bool public_)\n external\n _logs_\n _lock_\n {\n require(!_finalized, \"ERR_IS_FINALIZED\");\n require(msg.sender == _controller, \"ERR_NOT_CONTROLLER\");\n _publicSwap = public_;\n }\n\n function finalize()\n external\n _logs_\n _lock_\n {\n require(msg.sender == _controller, \"ERR_NOT_CONTROLLER\");\n require(!_finalized, \"ERR_IS_FINALIZED\");\n require(_tokens.length \u003e= MIN_BOUND_TOKENS, \"ERR_MIN_TOKENS\");\n\n _finalized = true;\n _publicSwap = true;\n\n _mintPoolShare(INIT_POOL_SUPPLY);\n _pushPoolShare(msg.sender, INIT_POOL_SUPPLY);\n }\n\n\n function bind(address token, uint balance, uint denorm)\n external\n _logs_\n // _lock_ Bind does not lock because it jumps to `rebind`, which does\n {\n require(msg.sender == _controller, \"ERR_NOT_CONTROLLER\");\n require(!_records[token].bound, \"ERR_IS_BOUND\");\n require(!_finalized, \"ERR_IS_FINALIZED\");\n\n require(_tokens.length \u003c MAX_BOUND_TOKENS, \"ERR_MAX_TOKENS\");\n\n _records[token] = Record({\n bound: true,\n index: _tokens.length,\n denorm: 0, // balance and denorm will be validated\n balance: 0 // and set by `rebind`\n });\n _tokens.push(token);\n rebind(token, balance, denorm);\n }\n\n function rebind(address token, uint balance, uint denorm)\n public\n _logs_\n _lock_\n {\n\n require(msg.sender == _controller, \"ERR_NOT_CONTROLLER\");\n require(_records[token].bound, \"ERR_NOT_BOUND\");\n require(!_finalized, \"ERR_IS_FINALIZED\");\n\n require(denorm \u003e= MIN_WEIGHT, \"ERR_MIN_WEIGHT\");\n require(denorm \u003c= MAX_WEIGHT, \"ERR_MAX_WEIGHT\");\n require(balance \u003e= MIN_BALANCE, \"ERR_MIN_BALANCE\");\n\n // Adjust the denorm and totalWeight\n uint oldWeight = _records[token].denorm;\n if (denorm \u003e oldWeight) {\n _totalWeight = badd(_totalWeight, bsub(denorm, oldWeight));\n require(_totalWeight \u003c= MAX_TOTAL_WEIGHT, \"ERR_MAX_TOTAL_WEIGHT\");\n } else if (denorm \u003c oldWeight) {\n _totalWeight = bsub(_totalWeight, bsub(oldWeight, denorm));\n } \n _records[token].denorm = denorm;\n\n // Adjust the balance record and actual token balance\n uint oldBalance = _records[token].balance;\n _records[token].balance = balance;\n if (balance \u003e oldBalance) {\n _pullUnderlying(token, msg.sender, bsub(balance, oldBalance));\n } else if (balance \u003c oldBalance) {\n // In this case liquidity is being withdrawn, so charge EXIT_FEE\n uint tokenBalanceWithdrawn = bsub(oldBalance, balance);\n uint tokenExitFee = bmul(tokenBalanceWithdrawn, EXIT_FEE);\n _pushUnderlying(token, msg.sender, bsub(tokenBalanceWithdrawn, tokenExitFee));\n _pushUnderlying(token, _factory, tokenExitFee);\n }\n }\n\n function unbind(address token)\n external\n _logs_\n _lock_\n {\n\n require(msg.sender == _controller, \"ERR_NOT_CONTROLLER\");\n require(_records[token].bound, \"ERR_NOT_BOUND\");\n require(!_finalized, \"ERR_IS_FINALIZED\");\n\n uint tokenBalance = _records[token].balance;\n uint tokenExitFee = bmul(tokenBalance, EXIT_FEE);\n\n _totalWeight = bsub(_totalWeight, _records[token].denorm);\n\n // Swap the token-to-unbind with the last token,\n // then delete the last token\n uint index = _records[token].index;\n uint last = _tokens.length - 1;\n _tokens[index] = _tokens[last];\n _records[_tokens[index]].index = index;\n _tokens.pop();\n _records[token] = Record({\n bound: false,\n index: 0,\n denorm: 0,\n balance: 0\n });\n\n _pushUnderlying(token, msg.sender, bsub(tokenBalance, tokenExitFee));\n _pushUnderlying(token, _factory, tokenExitFee);\n }\n\n // Absorb any tokens that have been sent to this contract into the pool\n function gulp(address token)\n external\n _logs_\n _lock_\n {\n require(_records[token].bound, \"ERR_NOT_BOUND\");\n _records[token].balance = IERC20(token).balanceOf(address(this));\n }\n\n function getSpotPrice(address tokenIn, address tokenOut)\n external view\n _viewlock_\n returns (uint spotPrice)\n {\n require(_records[tokenIn].bound, \"ERR_NOT_BOUND\");\n require(_records[tokenOut].bound, \"ERR_NOT_BOUND\");\n Record storage inRecord = _records[tokenIn];\n Record storage outRecord = _records[tokenOut];\n return calcSpotPrice(inRecord.balance, inRecord.denorm, outRecord.balance, outRecord.denorm, _swapFee);\n }\n\n function getSpotPriceSansFee(address tokenIn, address tokenOut)\n external view\n _viewlock_\n returns (uint spotPrice)\n {\n require(_records[tokenIn].bound, \"ERR_NOT_BOUND\");\n require(_records[tokenOut].bound, \"ERR_NOT_BOUND\");\n Record storage inRecord = _records[tokenIn];\n Record storage outRecord = _records[tokenOut];\n return calcSpotPrice(inRecord.balance, inRecord.denorm, outRecord.balance, outRecord.denorm, 0);\n }\n\n function joinPool(uint poolAmountOut, uint[] calldata maxAmountsIn)\n external\n _logs_\n _lock_\n {\n require(_finalized, \"ERR_NOT_FINALIZED\");\n\n uint poolTotal = totalSupply();\n uint ratio = bdiv(poolAmountOut, poolTotal);\n require(ratio != 0, \"ERR_MATH_APPROX\");\n\n for (uint i = 0; i \u003c _tokens.length; i++) {\n address t = _tokens[i];\n uint bal = _records[t].balance;\n uint tokenAmountIn = bmul(ratio, bal);\n require(tokenAmountIn != 0, \"ERR_MATH_APPROX\");\n require(tokenAmountIn \u003c= maxAmountsIn[i], \"ERR_LIMIT_IN\");\n _records[t].balance = badd(_records[t].balance, tokenAmountIn);\n emit LOG_JOIN(msg.sender, t, tokenAmountIn);\n _pullUnderlying(t, msg.sender, tokenAmountIn);\n }\n _mintPoolShare(poolAmountOut);\n _pushPoolShare(msg.sender, poolAmountOut);\n }\n\n function exitPool(uint poolAmountIn, uint[] calldata minAmountsOut)\n external\n _logs_\n _lock_\n {\n require(_finalized, \"ERR_NOT_FINALIZED\");\n\n uint poolTotal = totalSupply();\n uint exitFee = bmul(poolAmountIn, EXIT_FEE);\n uint pAiAfterExitFee = bsub(poolAmountIn, exitFee);\n uint ratio = bdiv(pAiAfterExitFee, poolTotal);\n require(ratio != 0, \"ERR_MATH_APPROX\");\n\n _pullPoolShare(msg.sender, poolAmountIn);\n _pushPoolShare(_factory, exitFee);\n _burnPoolShare(pAiAfterExitFee);\n\n for (uint i = 0; i \u003c _tokens.length; i++) {\n address t = _tokens[i];\n uint bal = _records[t].balance;\n uint tokenAmountOut = bmul(ratio, bal);\n require(tokenAmountOut != 0, \"ERR_MATH_APPROX\");\n require(tokenAmountOut \u003e= minAmountsOut[i], \"ERR_LIMIT_OUT\");\n _records[t].balance = bsub(_records[t].balance, tokenAmountOut);\n emit LOG_EXIT(msg.sender, t, tokenAmountOut);\n _pushUnderlying(t, msg.sender, tokenAmountOut);\n }\n\n }\n\n\n function swapExactAmountIn(\n address tokenIn,\n uint tokenAmountIn,\n address tokenOut,\n uint minAmountOut,\n uint maxPrice\n )\n external\n _logs_\n _lock_\n returns (uint tokenAmountOut, uint spotPriceAfter)\n {\n\n require(_records[tokenIn].bound, \"ERR_NOT_BOUND\");\n require(_records[tokenOut].bound, \"ERR_NOT_BOUND\");\n require(_publicSwap, \"ERR_SWAP_NOT_PUBLIC\");\n\n Record storage inRecord = _records[address(tokenIn)];\n Record storage outRecord = _records[address(tokenOut)];\n\n require(tokenAmountIn \u003c= bmul(inRecord.balance, MAX_IN_RATIO), \"ERR_MAX_IN_RATIO\");\n\n uint spotPriceBefore = calcSpotPrice(\n inRecord.balance,\n inRecord.denorm,\n outRecord.balance,\n outRecord.denorm,\n _swapFee\n );\n require(spotPriceBefore \u003c= maxPrice, \"ERR_BAD_LIMIT_PRICE\");\n\n tokenAmountOut = calcOutGivenIn(\n inRecord.balance,\n inRecord.denorm,\n outRecord.balance,\n outRecord.denorm,\n tokenAmountIn,\n _swapFee\n );\n require(tokenAmountOut \u003e= minAmountOut, \"ERR_LIMIT_OUT\");\n\n inRecord.balance = badd(inRecord.balance, tokenAmountIn);\n outRecord.balance = bsub(outRecord.balance, tokenAmountOut);\n\n spotPriceAfter = calcSpotPrice(\n inRecord.balance,\n inRecord.denorm,\n outRecord.balance,\n outRecord.denorm,\n _swapFee\n );\n require(spotPriceAfter \u003e= spotPriceBefore, \"ERR_MATH_APPROX\"); \n require(spotPriceAfter \u003c= maxPrice, \"ERR_LIMIT_PRICE\");\n require(spotPriceBefore \u003c= bdiv(tokenAmountIn, tokenAmountOut), \"ERR_MATH_APPROX\");\n\n emit LOG_SWAP(msg.sender, tokenIn, tokenOut, tokenAmountIn, tokenAmountOut);\n\n _pullUnderlying(tokenIn, msg.sender, tokenAmountIn);\n _pushUnderlying(tokenOut, msg.sender, tokenAmountOut);\n\n return (tokenAmountOut, spotPriceAfter);\n }\n\n function swapExactAmountOut(\n address tokenIn,\n uint maxAmountIn,\n address tokenOut,\n uint tokenAmountOut,\n uint maxPrice\n )\n external\n _logs_\n _lock_ \n returns (uint tokenAmountIn, uint spotPriceAfter)\n {\n require(_records[tokenIn].bound, \"ERR_NOT_BOUND\");\n require(_records[tokenOut].bound, \"ERR_NOT_BOUND\");\n require(_publicSwap, \"ERR_SWAP_NOT_PUBLIC\");\n\n Record storage inRecord = _records[address(tokenIn)];\n Record storage outRecord = _records[address(tokenOut)];\n\n require(tokenAmountOut \u003c= bmul(outRecord.balance, MAX_OUT_RATIO), \"ERR_MAX_OUT_RATIO\");\n\n uint spotPriceBefore = calcSpotPrice(\n inRecord.balance,\n inRecord.denorm,\n outRecord.balance,\n outRecord.denorm,\n _swapFee\n );\n require(spotPriceBefore \u003c= maxPrice, \"ERR_BAD_LIMIT_PRICE\");\n\n tokenAmountIn = calcInGivenOut(\n inRecord.balance,\n inRecord.denorm,\n outRecord.balance,\n outRecord.denorm,\n tokenAmountOut,\n _swapFee\n );\n require(tokenAmountIn \u003c= maxAmountIn, \"ERR_LIMIT_IN\");\n\n inRecord.balance = badd(inRecord.balance, tokenAmountIn);\n outRecord.balance = bsub(outRecord.balance, tokenAmountOut);\n\n spotPriceAfter = calcSpotPrice(\n inRecord.balance,\n inRecord.denorm,\n outRecord.balance,\n outRecord.denorm,\n _swapFee\n );\n require(spotPriceAfter \u003e= spotPriceBefore, \"ERR_MATH_APPROX\");\n require(spotPriceAfter \u003c= maxPrice, \"ERR_LIMIT_PRICE\");\n require(spotPriceBefore \u003c= bdiv(tokenAmountIn, tokenAmountOut), \"ERR_MATH_APPROX\");\n\n emit LOG_SWAP(msg.sender, tokenIn, tokenOut, tokenAmountIn, tokenAmountOut);\n\n _pullUnderlying(tokenIn, msg.sender, tokenAmountIn);\n _pushUnderlying(tokenOut, msg.sender, tokenAmountOut);\n\n return (tokenAmountIn, spotPriceAfter);\n }\n\n\n function joinswapExternAmountIn(address tokenIn, uint tokenAmountIn, uint minPoolAmountOut)\n external\n _logs_\n _lock_\n returns (uint poolAmountOut)\n\n { \n require(_finalized, \"ERR_NOT_FINALIZED\");\n require(_records[tokenIn].bound, \"ERR_NOT_BOUND\");\n require(tokenAmountIn \u003c= bmul(_records[tokenIn].balance, MAX_IN_RATIO), \"ERR_MAX_IN_RATIO\");\n\n Record storage inRecord = _records[tokenIn];\n\n poolAmountOut = calcPoolOutGivenSingleIn(\n inRecord.balance,\n inRecord.denorm,\n _totalSupply,\n _totalWeight,\n tokenAmountIn,\n _swapFee\n );\n\n require(poolAmountOut \u003e= minPoolAmountOut, \"ERR_LIMIT_OUT\");\n\n inRecord.balance = badd(inRecord.balance, tokenAmountIn);\n\n emit LOG_JOIN(msg.sender, tokenIn, tokenAmountIn);\n\n _mintPoolShare(poolAmountOut);\n _pushPoolShare(msg.sender, poolAmountOut);\n _pullUnderlying(tokenIn, msg.sender, tokenAmountIn);\n\n return poolAmountOut;\n }\n\n function joinswapPoolAmountOut(address tokenIn, uint poolAmountOut, uint maxAmountIn)\n external\n _logs_\n _lock_\n returns (uint tokenAmountIn)\n {\n require(_finalized, \"ERR_NOT_FINALIZED\");\n require(_records[tokenIn].bound, \"ERR_NOT_BOUND\");\n\n Record storage inRecord = _records[tokenIn];\n\n tokenAmountIn = calcSingleInGivenPoolOut(\n inRecord.balance,\n inRecord.denorm,\n _totalSupply,\n _totalWeight,\n poolAmountOut,\n _swapFee\n );\n\n require(tokenAmountIn != 0, \"ERR_MATH_APPROX\");\n require(tokenAmountIn \u003c= maxAmountIn, \"ERR_LIMIT_IN\");\n \n require(tokenAmountIn \u003c= bmul(_records[tokenIn].balance, MAX_IN_RATIO), \"ERR_MAX_IN_RATIO\");\n\n inRecord.balance = badd(inRecord.balance, tokenAmountIn);\n\n emit LOG_JOIN(msg.sender, tokenIn, tokenAmountIn);\n\n _mintPoolShare(poolAmountOut);\n _pushPoolShare(msg.sender, poolAmountOut);\n _pullUnderlying(tokenIn, msg.sender, tokenAmountIn);\n\n return tokenAmountIn;\n }\n\n function exitswapPoolAmountIn(address tokenOut, uint poolAmountIn, uint minAmountOut)\n external\n _logs_\n _lock_\n returns (uint tokenAmountOut)\n {\n require(_finalized, \"ERR_NOT_FINALIZED\");\n require(_records[tokenOut].bound, \"ERR_NOT_BOUND\");\n\n Record storage outRecord = _records[tokenOut];\n\n tokenAmountOut = calcSingleOutGivenPoolIn(\n outRecord.balance,\n outRecord.denorm,\n _totalSupply,\n _totalWeight,\n poolAmountIn,\n _swapFee\n );\n\n require(tokenAmountOut \u003e= minAmountOut, \"ERR_LIMIT_OUT\");\n \n require(tokenAmountOut \u003c= bmul(_records[tokenOut].balance, MAX_OUT_RATIO), \"ERR_MAX_OUT_RATIO\");\n\n outRecord.balance = bsub(outRecord.balance, tokenAmountOut);\n\n uint exitFee = bmul(poolAmountIn, EXIT_FEE);\n\n emit LOG_EXIT(msg.sender, tokenOut, tokenAmountOut);\n\n _pullPoolShare(msg.sender, poolAmountIn);\n _burnPoolShare(bsub(poolAmountIn, exitFee));\n _pushPoolShare(_factory, exitFee);\n _pushUnderlying(tokenOut, msg.sender, tokenAmountOut);\n\n return tokenAmountOut;\n }\n\n function exitswapExternAmountOut(address tokenOut, uint tokenAmountOut, uint maxPoolAmountIn)\n external\n _logs_\n _lock_\n returns (uint poolAmountIn)\n {\n require(_finalized, \"ERR_NOT_FINALIZED\");\n require(_records[tokenOut].bound, \"ERR_NOT_BOUND\");\n require(tokenAmountOut \u003c= bmul(_records[tokenOut].balance, MAX_OUT_RATIO), \"ERR_MAX_OUT_RATIO\");\n\n Record storage outRecord = _records[tokenOut];\n\n poolAmountIn = calcPoolInGivenSingleOut(\n outRecord.balance,\n outRecord.denorm,\n _totalSupply,\n _totalWeight,\n tokenAmountOut,\n _swapFee\n );\n\n require(poolAmountIn != 0, \"ERR_MATH_APPROX\");\n require(poolAmountIn \u003c= maxPoolAmountIn, \"ERR_LIMIT_IN\");\n\n outRecord.balance = bsub(outRecord.balance, tokenAmountOut);\n\n uint exitFee = bmul(poolAmountIn, EXIT_FEE);\n\n emit LOG_EXIT(msg.sender, tokenOut, tokenAmountOut);\n\n _pullPoolShare(msg.sender, poolAmountIn);\n _burnPoolShare(bsub(poolAmountIn, exitFee));\n _pushPoolShare(_factory, exitFee);\n _pushUnderlying(tokenOut, msg.sender, tokenAmountOut); \n\n return poolAmountIn;\n }\n\n\n // ==\n // \u0027Underlying\u0027 token-manipulation functions make external calls but are NOT locked\n // You must `_lock_` or otherwise ensure reentry-safety\n\n function _pullUnderlying(address erc20, address from, uint amount)\n internal\n {\n bool xfer = IERC20(erc20).transferFrom(from, address(this), amount);\n require(xfer, \"ERR_ERC20_FALSE\");\n }\n\n function _pushUnderlying(address erc20, address to, uint amount)\n internal\n {\n bool xfer = IERC20(erc20).transfer(to, amount);\n require(xfer, \"ERR_ERC20_FALSE\");\n }\n\n function _pullPoolShare(address from, uint amount)\n internal\n {\n _pull(from, amount);\n }\n\n function _pushPoolShare(address to, uint amount)\n internal\n {\n _push(to, amount);\n }\n\n function _mintPoolShare(uint amount)\n internal\n {\n _mint(amount);\n }\n\n function _burnPoolShare(uint amount)\n internal\n {\n _burn(amount);\n }\n\n}\n"},"BToken.sol":{"content":"// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see \u003chttp://www.gnu.org/licenses/\u003e.\n\npragma solidity 0.5.12;\n\nimport \"./BNum.sol\";\n\n// Highly opinionated token implementation\n\ninterface IERC20 {\n event Approval(address indexed src, address indexed dst, uint amt);\n event Transfer(address indexed src, address indexed dst, uint amt);\n\n function totalSupply() external view returns (uint);\n function balanceOf(address whom) external view returns (uint);\n function allowance(address src, address dst) external view returns (uint);\n\n function approve(address dst, uint amt) external returns (bool);\n function transfer(address dst, uint amt) external returns (bool);\n function transferFrom(\n address src, address dst, uint amt\n ) external returns (bool);\n}\n\ncontract BTokenBase is BNum {\n\n mapping(address =\u003e uint) internal _balance;\n mapping(address =\u003e mapping(address=\u003euint)) internal _allowance;\n uint internal _totalSupply;\n\n event Approval(address indexed src, address indexed dst, uint amt);\n event Transfer(address indexed src, address indexed dst, uint amt);\n\n function _mint(uint amt) internal {\n _balance[address(this)] = badd(_balance[address(this)], amt);\n _totalSupply = badd(_totalSupply, amt);\n emit Transfer(address(0), address(this), amt);\n }\n\n function _burn(uint amt) internal {\n require(_balance[address(this)] \u003e= amt, \"ERR_INSUFFICIENT_BAL\");\n _balance[address(this)] = bsub(_balance[address(this)], amt);\n _totalSupply = bsub(_totalSupply, amt);\n emit Transfer(address(this), address(0), amt);\n }\n\n function _move(address src, address dst, uint amt) internal {\n require(_balance[src] \u003e= amt, \"ERR_INSUFFICIENT_BAL\");\n _balance[src] = bsub(_balance[src], amt);\n _balance[dst] = badd(_balance[dst], amt);\n emit Transfer(src, dst, amt);\n }\n\n function _push(address to, uint amt) internal {\n _move(address(this), to, amt);\n }\n\n function _pull(address from, uint amt) internal {\n _move(from, address(this), amt);\n }\n}\n\ncontract BToken is BTokenBase, IERC20 {\n\n string private _name = \"Balancer Pool Token\";\n string private _symbol = \"BPT\";\n uint8 private _decimals = 18;\n\n function name() public view returns (string memory) {\n return _name;\n }\n\n function symbol() public view returns (string memory) {\n return _symbol;\n }\n\n function decimals() public view returns(uint8) {\n return _decimals;\n }\n\n function allowance(address src, address dst) external view returns (uint) {\n return _allowance[src][dst];\n }\n\n function balanceOf(address whom) external view returns (uint) {\n return _balance[whom];\n }\n\n function totalSupply() public view returns (uint) {\n return _totalSupply;\n }\n\n function approve(address dst, uint amt) external returns (bool) {\n _allowance[msg.sender][dst] = amt;\n emit Approval(msg.sender, dst, amt);\n return true;\n }\n\n function increaseApproval(address dst, uint amt) external returns (bool) {\n _allowance[msg.sender][dst] = badd(_allowance[msg.sender][dst], amt);\n emit Approval(msg.sender, dst, _allowance[msg.sender][dst]);\n return true;\n }\n\n function decreaseApproval(address dst, uint amt) external returns (bool) {\n uint oldValue = _allowance[msg.sender][dst];\n if (amt \u003e oldValue) {\n _allowance[msg.sender][dst] = 0;\n } else {\n _allowance[msg.sender][dst] = bsub(oldValue, amt);\n }\n emit Approval(msg.sender, dst, _allowance[msg.sender][dst]);\n return true;\n }\n\n function transfer(address dst, uint amt) external returns (bool) {\n _move(msg.sender, dst, amt);\n return true;\n }\n\n function transferFrom(address src, address dst, uint amt) external returns (bool) {\n require(msg.sender == src || amt \u003c= _allowance[src][msg.sender], \"ERR_BTOKEN_BAD_CALLER\");\n _move(src, dst, amt);\n if (msg.sender != src \u0026\u0026 _allowance[src][msg.sender] != uint256(-1)) {\n _allowance[src][msg.sender] = bsub(_allowance[src][msg.sender], amt);\n emit Approval(msg.sender, dst, _allowance[src][msg.sender]);\n }\n return true;\n }\n}\n"}}
File 5 of 12: Timelock
// SPDX-License-Identifier: GPL-3.0-only // Copyright 2020 Compound Labs, Inc. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // 3. Neither the name of the copyright holder nor the names of its // contributors may be used to endorse or promote products derived from this // software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. pragma solidity ^0.7.5; import "../libraries/SafeMath.sol"; contract Timelock { using SafeMath for uint256; event NewAdmin(address indexed newAdmin); event NewPendingAdmin(address indexed newPendingAdmin); event NewDelay(uint256 indexed newDelay); event CancelTransaction( bytes32 indexed txHash, address indexed target, uint256 value, string signature, bytes data, uint256 eta ); event ExecuteTransaction( bytes32 indexed txHash, address indexed target, uint256 value, string signature, bytes data, uint256 eta ); event QueueTransaction( bytes32 indexed txHash, address indexed target, uint256 value, string signature, bytes data, uint256 eta ); uint256 public constant GRACE_PERIOD = 14 days; uint256 public constant MINIMUM_DELAY = 2 days; uint256 public constant MAXIMUM_DELAY = 30 days; address public admin; address public pendingAdmin; uint256 public delay; mapping(bytes32 => bool) public queuedTransactions; constructor(address admin_, uint256 delay_) { require(delay_ >= MINIMUM_DELAY, "Timelock::constructor: Delay must exceed minimum delay."); require( delay_ <= MAXIMUM_DELAY, "Timelock::setDelay: Delay must not exceed maximum delay." ); admin = admin_; delay = delay_; } // solhint-disable no-empty-blocks receive() external payable {} function gracePeriod() public pure returns (uint256) { return GRACE_PERIOD; } function setDelay(uint256 delay_) public { require(msg.sender == address(this), "Timelock::setDelay: Call must come from Timelock."); require(delay_ >= MINIMUM_DELAY, "Timelock::setDelay: Delay must exceed minimum delay."); require( delay_ <= MAXIMUM_DELAY, "Timelock::setDelay: Delay must not exceed maximum delay." ); delay = delay_; emit NewDelay(delay); } function acceptAdmin() public { require( msg.sender == pendingAdmin, "Timelock::acceptAdmin: Call must come from pendingAdmin." ); admin = msg.sender; pendingAdmin = address(0); emit NewAdmin(admin); } function setPendingAdmin(address pendingAdmin_) public { require( msg.sender == address(this), "Timelock::setPendingAdmin: Call must come from Timelock." ); pendingAdmin = pendingAdmin_; emit NewPendingAdmin(pendingAdmin); } function queueTransaction( address target, uint256 value, string calldata signature, bytes calldata data, uint256 eta ) public returns (bytes32) { require(msg.sender == admin, "Timelock::queueTransaction: Call must come from admin."); require( eta >= getBlockTimestamp().add(delay), "Timelock::queueTransaction: Estimated execution block must satisfy delay." ); bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta)); queuedTransactions[txHash] = true; emit QueueTransaction(txHash, target, value, signature, data, eta); return txHash; } function cancelTransaction( address target, uint256 value, string calldata signature, bytes calldata data, uint256 eta ) public { require(msg.sender == admin, "Timelock::cancelTransaction: Call must come from admin."); bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta)); queuedTransactions[txHash] = false; emit CancelTransaction(txHash, target, value, signature, data, eta); } function executeTransaction( address target, uint256 value, string calldata signature, bytes calldata data, uint256 eta ) public payable returns (bytes memory) { require(msg.sender == admin, "Timelock::executeTransaction: Call must come from admin."); bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta)); require( queuedTransactions[txHash], "Timelock::executeTransaction: Transaction hasn't been queued." ); require( getBlockTimestamp() >= eta, "Timelock::executeTransaction: Transaction hasn't surpassed time lock." ); require( getBlockTimestamp() <= eta.add(GRACE_PERIOD), "Timelock::executeTransaction: Transaction is stale." ); queuedTransactions[txHash] = false; bytes memory callData; if (bytes(signature).length == 0) { callData = data; } else { callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data); } // solhint-disable avoid-low-level-calls (bool success, bytes memory returnData) = target.call{value: value}(callData); require(success, "Timelock::executeTransaction: Transaction execution reverted."); emit ExecuteTransaction(txHash, target, value, signature, data, eta); return returnData; } function getBlockTimestamp() internal view returns (uint256) { // solium-disable-next-line security/no-block-members return block.timestamp; } } // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.7.5; // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math) library SafeMath { function add(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x + y) >= x, "ds-math-add-overflow"); } function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x - y) <= x, "ds-math-sub-underflow"); } function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow"); } }
File 6 of 12: FiatTokenProxy
pragma solidity ^0.4.24; // File: zos-lib/contracts/upgradeability/Proxy.sol /** * @title Proxy * @dev Implements delegation of calls to other contracts, with proper * forwarding of return values and bubbling of failures. * It defines a fallback function that delegates all calls to the address * returned by the abstract _implementation() internal function. */ contract Proxy { /** * @dev Fallback function. * Implemented entirely in `_fallback`. */ function () payable external { _fallback(); } /** * @return The Address of the implementation. */ function _implementation() internal view returns (address); /** * @dev Delegates execution to an implementation contract. * This is a low level function that doesn't return to its internal call site. * It will return to the external caller whatever the implementation returns. * @param implementation Address to delegate. */ function _delegate(address implementation) internal { assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize) // Call the implementation. // out and outsize are 0 because we don't know the size yet. let result := delegatecall(gas, implementation, 0, calldatasize, 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize) } default { return(0, returndatasize) } } } /** * @dev Function that is run as the first thing in the fallback function. * Can be redefined in derived contracts to add functionality. * Redefinitions must call super._willFallback(). */ function _willFallback() internal { } /** * @dev fallback implementation. * Extracted to enable manual triggering. */ function _fallback() internal { _willFallback(); _delegate(_implementation()); } } // File: openzeppelin-solidity/contracts/AddressUtils.sol /** * Utility library of inline functions on addresses */ library AddressUtils { /** * Returns whether the target address is a contract * @dev This function will return false if invoked during the constructor of a contract, * as the code is not actually created until after the constructor finishes. * @param addr address to check * @return whether the target address is a contract */ function isContract(address addr) internal view returns (bool) { uint256 size; // XXX Currently there is no better way to check if there is a contract in an address // than to check the size of the code at that address. // See https://ethereum.stackexchange.com/a/14016/36603 // for more details about how this works. // TODO Check this again before the Serenity release, because all addresses will be // contracts then. // solium-disable-next-line security/no-inline-assembly assembly { size := extcodesize(addr) } return size > 0; } } // File: zos-lib/contracts/upgradeability/UpgradeabilityProxy.sol /** * @title UpgradeabilityProxy * @dev This contract implements a proxy that allows to change the * implementation address to which it will delegate. * Such a change is called an implementation upgrade. */ contract UpgradeabilityProxy is Proxy { /** * @dev Emitted when the implementation is upgraded. * @param implementation Address of the new implementation. */ event Upgraded(address implementation); /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "org.zeppelinos.proxy.implementation", and is * validated in the constructor. */ bytes32 private constant IMPLEMENTATION_SLOT = 0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3; /** * @dev Contract constructor. * @param _implementation Address of the initial implementation. */ constructor(address _implementation) public { assert(IMPLEMENTATION_SLOT == keccak256("org.zeppelinos.proxy.implementation")); _setImplementation(_implementation); } /** * @dev Returns the current implementation. * @return Address of the current implementation */ function _implementation() internal view returns (address impl) { bytes32 slot = IMPLEMENTATION_SLOT; assembly { impl := sload(slot) } } /** * @dev Upgrades the proxy to a new implementation. * @param newImplementation Address of the new implementation. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Sets the implementation address of the proxy. * @param newImplementation Address of the new implementation. */ function _setImplementation(address newImplementation) private { require(AddressUtils.isContract(newImplementation), "Cannot set a proxy implementation to a non-contract address"); bytes32 slot = IMPLEMENTATION_SLOT; assembly { sstore(slot, newImplementation) } } } // File: zos-lib/contracts/upgradeability/AdminUpgradeabilityProxy.sol /** * @title AdminUpgradeabilityProxy * @dev This contract combines an upgradeability proxy with an authorization * mechanism for administrative tasks. * All external functions in this contract must be guarded by the * `ifAdmin` modifier. See ethereum/solidity#3864 for a Solidity * feature proposal that would enable this to be done automatically. */ contract AdminUpgradeabilityProxy is UpgradeabilityProxy { /** * @dev Emitted when the administration has been transferred. * @param previousAdmin Address of the previous admin. * @param newAdmin Address of the new admin. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "org.zeppelinos.proxy.admin", and is * validated in the constructor. */ bytes32 private constant ADMIN_SLOT = 0x10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b; /** * @dev Modifier to check whether the `msg.sender` is the admin. * If it is, it will run the function. Otherwise, it will delegate the call * to the implementation. */ modifier ifAdmin() { if (msg.sender == _admin()) { _; } else { _fallback(); } } /** * Contract constructor. * It sets the `msg.sender` as the proxy administrator. * @param _implementation address of the initial implementation. */ constructor(address _implementation) UpgradeabilityProxy(_implementation) public { assert(ADMIN_SLOT == keccak256("org.zeppelinos.proxy.admin")); _setAdmin(msg.sender); } /** * @return The address of the proxy admin. */ function admin() external view ifAdmin returns (address) { return _admin(); } /** * @return The address of the implementation. */ function implementation() external view ifAdmin returns (address) { return _implementation(); } /** * @dev Changes the admin of the proxy. * Only the current admin can call this function. * @param newAdmin Address to transfer proxy administration to. */ function changeAdmin(address newAdmin) external ifAdmin { require(newAdmin != address(0), "Cannot change the admin of a proxy to the zero address"); emit AdminChanged(_admin(), newAdmin); _setAdmin(newAdmin); } /** * @dev Upgrade the backing implementation of the proxy. * Only the admin can call this function. * @param newImplementation Address of the new implementation. */ function upgradeTo(address newImplementation) external ifAdmin { _upgradeTo(newImplementation); } /** * @dev Upgrade the backing implementation of the proxy and call a function * on the new implementation. * This is useful to initialize the proxied contract. * @param newImplementation Address of the new implementation. * @param data Data to send as msg.data in the low level call. * It should include the signature and the parameters of the function to be * called, as described in * https://solidity.readthedocs.io/en/develop/abi-spec.html#function-selector-and-argument-encoding. */ function upgradeToAndCall(address newImplementation, bytes data) payable external ifAdmin { _upgradeTo(newImplementation); require(address(this).call.value(msg.value)(data)); } /** * @return The admin slot. */ function _admin() internal view returns (address adm) { bytes32 slot = ADMIN_SLOT; assembly { adm := sload(slot) } } /** * @dev Sets the address of the proxy admin. * @param newAdmin Address of the new proxy admin. */ function _setAdmin(address newAdmin) internal { bytes32 slot = ADMIN_SLOT; assembly { sstore(slot, newAdmin) } } /** * @dev Only fall back when the sender is not the admin. */ function _willFallback() internal { require(msg.sender != _admin(), "Cannot call fallback function from the proxy admin"); super._willFallback(); } } // File: contracts/FiatTokenProxy.sol /** * Copyright CENTRE SECZ 2018 * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is furnished to * do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ pragma solidity ^0.4.24; /** * @title FiatTokenProxy * @dev This contract proxies FiatToken calls and enables FiatToken upgrades */ contract FiatTokenProxy is AdminUpgradeabilityProxy { constructor(address _implementation) public AdminUpgradeabilityProxy(_implementation) { } }
File 7 of 12: AddLiquidity
// Verified using https://dapp.tools // hevm: flattened sources of src/AddLiquidity.sol pragma solidity >=0.7.4 <0.8.0; ////// src/AddLiquidity.sol // SPDX-License-Identifier: MIT /* pragma solidity ^0.7.4; */ interface ERC20_2 { function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); function approve(address, uint256) external; } interface UniswapV2Router02 { function addLiquidity(address, address, uint256, uint256, uint256, uint256, address, uint256) external; } contract AddLiquidity { address constant public UNISWAP_ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D; uint256 public radLiquidity = 0; uint256 public usdcLiquidity = 0; uint256 public minRadLiquidity = 0; uint256 public minUsdcLiquidity = 0; address immutable public admin; constructor(address _admin) { admin = _admin; } function setLiquidity( uint256 _radLiquidity, uint256 _usdcLiquidity, uint256 _minRadLiquidity, uint256 _minUsdcLiquidity ) public { require(msg.sender == admin, "Sender must be admin"); require(_radLiquidity <= 500_000e18, "RAD liquidity must not exceed maximum"); require(_usdcLiquidity <= 5_000_000e6, "USDC liquidity must not exceed maximum"); require(_minRadLiquidity <= _radLiquidity); require(_minUsdcLiquidity <= _usdcLiquidity); radLiquidity = _radLiquidity; usdcLiquidity = _usdcLiquidity; minRadLiquidity = _minRadLiquidity; minUsdcLiquidity = _minUsdcLiquidity; } function addLiquidity(address rad, address usdc) public { require( ERC20_2(rad).transferFrom(msg.sender, address(this), radLiquidity), "Transfer of RAD must succeed" ); require( ERC20_2(usdc).transferFrom(msg.sender, address(this), usdcLiquidity), "Transfer of USDC must succeed" ); ERC20_2(rad).approve(UNISWAP_ROUTER, radLiquidity); ERC20_2(usdc).approve(UNISWAP_ROUTER, usdcLiquidity); UniswapV2Router02(UNISWAP_ROUTER).addLiquidity( rad, usdc, radLiquidity, usdcLiquidity, minRadLiquidity, minUsdcLiquidity, msg.sender, block.timestamp + 1 days ); } }
File 8 of 12: UniswapV2Factory
pragma solidity =0.5.16; interface IUniswapV2Factory { event PairCreated(address indexed token0, address indexed token1, address pair, uint); function feeTo() external view returns (address); function feeToSetter() external view returns (address); function getPair(address tokenA, address tokenB) external view returns (address pair); function allPairs(uint) external view returns (address pair); function allPairsLength() external view returns (uint); function createPair(address tokenA, address tokenB) external returns (address pair); function setFeeTo(address) external; function setFeeToSetter(address) external; } interface IUniswapV2Pair { event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); function name() external pure returns (string memory); function symbol() external pure returns (string memory); function decimals() external pure returns (uint8); function totalSupply() external view returns (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); function transfer(address to, uint value) external returns (bool); function transferFrom(address from, address to, uint value) external returns (bool); function DOMAIN_SEPARATOR() external view returns (bytes32); function PERMIT_TYPEHASH() external pure returns (bytes32); function nonces(address owner) external view returns (uint); function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; event Mint(address indexed sender, uint amount0, uint amount1); event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); event Swap( address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to ); event Sync(uint112 reserve0, uint112 reserve1); function MINIMUM_LIQUIDITY() external pure returns (uint); function factory() external view returns (address); function token0() external view returns (address); function token1() external view returns (address); function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); function price0CumulativeLast() external view returns (uint); function price1CumulativeLast() external view returns (uint); function kLast() external view returns (uint); function mint(address to) external returns (uint liquidity); function burn(address to) external returns (uint amount0, uint amount1); function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; function skim(address to) external; function sync() external; function initialize(address, address) external; } interface IUniswapV2ERC20 { event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); function name() external pure returns (string memory); function symbol() external pure returns (string memory); function decimals() external pure returns (uint8); function totalSupply() external view returns (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); function transfer(address to, uint value) external returns (bool); function transferFrom(address from, address to, uint value) external returns (bool); function DOMAIN_SEPARATOR() external view returns (bytes32); function PERMIT_TYPEHASH() external pure returns (bytes32); function nonces(address owner) external view returns (uint); function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; } interface IERC20 { event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); 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 (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); function transfer(address to, uint value) external returns (bool); function transferFrom(address from, address to, uint value) external returns (bool); } interface IUniswapV2Callee { function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external; } contract UniswapV2ERC20 is IUniswapV2ERC20 { using SafeMath for uint; string public constant name = 'Uniswap V2'; string public constant symbol = 'UNI-V2'; uint8 public constant decimals = 18; uint public totalSupply; mapping(address => uint) public balanceOf; mapping(address => mapping(address => uint)) public allowance; bytes32 public DOMAIN_SEPARATOR; // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; mapping(address => uint) public nonces; event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); constructor() public { uint chainId; assembly { chainId := chainid } DOMAIN_SEPARATOR = keccak256( abi.encode( keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'), keccak256(bytes(name)), keccak256(bytes('1')), chainId, address(this) ) ); } function _mint(address to, uint value) internal { totalSupply = totalSupply.add(value); balanceOf[to] = balanceOf[to].add(value); emit Transfer(address(0), to, value); } function _burn(address from, uint value) internal { balanceOf[from] = balanceOf[from].sub(value); totalSupply = totalSupply.sub(value); emit Transfer(from, address(0), value); } function _approve(address owner, address spender, uint value) private { allowance[owner][spender] = value; emit Approval(owner, spender, value); } function _transfer(address from, address to, uint value) private { balanceOf[from] = balanceOf[from].sub(value); balanceOf[to] = balanceOf[to].add(value); emit Transfer(from, to, value); } function approve(address spender, uint value) external returns (bool) { _approve(msg.sender, spender, value); return true; } function transfer(address to, uint value) external returns (bool) { _transfer(msg.sender, to, value); return true; } function transferFrom(address from, address to, uint value) external returns (bool) { if (allowance[from][msg.sender] != uint(-1)) { allowance[from][msg.sender] = allowance[from][msg.sender].sub(value); } _transfer(from, to, value); return true; } function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external { require(deadline >= block.timestamp, 'UniswapV2: EXPIRED'); bytes32 digest = keccak256( abi.encodePacked( '\x19\x01', DOMAIN_SEPARATOR, keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline)) ) ); address recoveredAddress = ecrecover(digest, v, r, s); require(recoveredAddress != address(0) && recoveredAddress == owner, 'UniswapV2: INVALID_SIGNATURE'); _approve(owner, spender, value); } } contract UniswapV2Pair is IUniswapV2Pair, UniswapV2ERC20 { using SafeMath for uint; using UQ112x112 for uint224; uint public constant MINIMUM_LIQUIDITY = 10**3; bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)'))); address public factory; address public token0; address public token1; uint112 private reserve0; // uses single storage slot, accessible via getReserves uint112 private reserve1; // uses single storage slot, accessible via getReserves uint32 private blockTimestampLast; // uses single storage slot, accessible via getReserves uint public price0CumulativeLast; uint public price1CumulativeLast; uint public kLast; // reserve0 * reserve1, as of immediately after the most recent liquidity event uint private unlocked = 1; modifier lock() { require(unlocked == 1, 'UniswapV2: LOCKED'); unlocked = 0; _; unlocked = 1; } function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) { _reserve0 = reserve0; _reserve1 = reserve1; _blockTimestampLast = blockTimestampLast; } function _safeTransfer(address token, address to, uint value) private { (bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'UniswapV2: TRANSFER_FAILED'); } event Mint(address indexed sender, uint amount0, uint amount1); event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); event Swap( address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to ); event Sync(uint112 reserve0, uint112 reserve1); constructor() public { factory = msg.sender; } // called once by the factory at time of deployment function initialize(address _token0, address _token1) external { require(msg.sender == factory, 'UniswapV2: FORBIDDEN'); // sufficient check token0 = _token0; token1 = _token1; } // update reserves and, on the first call per block, price accumulators function _update(uint balance0, uint balance1, uint112 _reserve0, uint112 _reserve1) private { require(balance0 <= uint112(-1) && balance1 <= uint112(-1), 'UniswapV2: OVERFLOW'); uint32 blockTimestamp = uint32(block.timestamp % 2**32); uint32 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) { // * never overflows, and + overflow is desired price0CumulativeLast += uint(UQ112x112.encode(_reserve1).uqdiv(_reserve0)) * timeElapsed; price1CumulativeLast += uint(UQ112x112.encode(_reserve0).uqdiv(_reserve1)) * timeElapsed; } reserve0 = uint112(balance0); reserve1 = uint112(balance1); blockTimestampLast = blockTimestamp; emit Sync(reserve0, reserve1); } // if fee is on, mint liquidity equivalent to 1/6th of the growth in sqrt(k) function _mintFee(uint112 _reserve0, uint112 _reserve1) private returns (bool feeOn) { address feeTo = IUniswapV2Factory(factory).feeTo(); feeOn = feeTo != address(0); uint _kLast = kLast; // gas savings if (feeOn) { if (_kLast != 0) { uint rootK = Math.sqrt(uint(_reserve0).mul(_reserve1)); uint rootKLast = Math.sqrt(_kLast); if (rootK > rootKLast) { uint numerator = totalSupply.mul(rootK.sub(rootKLast)); uint denominator = rootK.mul(5).add(rootKLast); uint liquidity = numerator / denominator; if (liquidity > 0) _mint(feeTo, liquidity); } } } else if (_kLast != 0) { kLast = 0; } } // this low-level function should be called from a contract which performs important safety checks function mint(address to) external lock returns (uint liquidity) { (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings uint balance0 = IERC20(token0).balanceOf(address(this)); uint balance1 = IERC20(token1).balanceOf(address(this)); uint amount0 = balance0.sub(_reserve0); uint amount1 = balance1.sub(_reserve1); bool feeOn = _mintFee(_reserve0, _reserve1); uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee if (_totalSupply == 0) { liquidity = Math.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY); _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens } else { liquidity = Math.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply) / _reserve1); } require(liquidity > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY_MINTED'); _mint(to, liquidity); _update(balance0, balance1, _reserve0, _reserve1); if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date emit Mint(msg.sender, amount0, amount1); } // this low-level function should be called from a contract which performs important safety checks function burn(address to) external lock returns (uint amount0, uint amount1) { (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings address _token0 = token0; // gas savings address _token1 = token1; // gas savings uint balance0 = IERC20(_token0).balanceOf(address(this)); uint balance1 = IERC20(_token1).balanceOf(address(this)); uint liquidity = balanceOf[address(this)]; bool feeOn = _mintFee(_reserve0, _reserve1); uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee amount0 = liquidity.mul(balance0) / _totalSupply; // using balances ensures pro-rata distribution amount1 = liquidity.mul(balance1) / _totalSupply; // using balances ensures pro-rata distribution require(amount0 > 0 && amount1 > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY_BURNED'); _burn(address(this), liquidity); _safeTransfer(_token0, to, amount0); _safeTransfer(_token1, to, amount1); balance0 = IERC20(_token0).balanceOf(address(this)); balance1 = IERC20(_token1).balanceOf(address(this)); _update(balance0, balance1, _reserve0, _reserve1); if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date emit Burn(msg.sender, amount0, amount1, to); } // this low-level function should be called from a contract which performs important safety checks function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external lock { require(amount0Out > 0 || amount1Out > 0, 'UniswapV2: INSUFFICIENT_OUTPUT_AMOUNT'); (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings require(amount0Out < _reserve0 && amount1Out < _reserve1, 'UniswapV2: INSUFFICIENT_LIQUIDITY'); uint balance0; uint balance1; { // scope for _token{0,1}, avoids stack too deep errors address _token0 = token0; address _token1 = token1; require(to != _token0 && to != _token1, 'UniswapV2: INVALID_TO'); if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens if (data.length > 0) IUniswapV2Callee(to).uniswapV2Call(msg.sender, amount0Out, amount1Out, data); balance0 = IERC20(_token0).balanceOf(address(this)); balance1 = IERC20(_token1).balanceOf(address(this)); } uint amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0; uint amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0; require(amount0In > 0 || amount1In > 0, 'UniswapV2: INSUFFICIENT_INPUT_AMOUNT'); { // scope for reserve{0,1}Adjusted, avoids stack too deep errors uint balance0Adjusted = balance0.mul(1000).sub(amount0In.mul(3)); uint balance1Adjusted = balance1.mul(1000).sub(amount1In.mul(3)); require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(1000**2), 'UniswapV2: K'); } _update(balance0, balance1, _reserve0, _reserve1); emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to); } // force balances to match reserves function skim(address to) external lock { address _token0 = token0; // gas savings address _token1 = token1; // gas savings _safeTransfer(_token0, to, IERC20(_token0).balanceOf(address(this)).sub(reserve0)); _safeTransfer(_token1, to, IERC20(_token1).balanceOf(address(this)).sub(reserve1)); } // force reserves to match balances function sync() external lock { _update(IERC20(token0).balanceOf(address(this)), IERC20(token1).balanceOf(address(this)), reserve0, reserve1); } } contract UniswapV2Factory is IUniswapV2Factory { address public feeTo; address public feeToSetter; mapping(address => mapping(address => address)) public getPair; address[] public allPairs; event PairCreated(address indexed token0, address indexed token1, address pair, uint); constructor(address _feeToSetter) public { feeToSetter = _feeToSetter; } function allPairsLength() external view returns (uint) { return allPairs.length; } function createPair(address tokenA, address tokenB) external returns (address pair) { require(tokenA != tokenB, 'UniswapV2: IDENTICAL_ADDRESSES'); (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); require(token0 != address(0), 'UniswapV2: ZERO_ADDRESS'); require(getPair[token0][token1] == address(0), 'UniswapV2: PAIR_EXISTS'); // single check is sufficient bytes memory bytecode = type(UniswapV2Pair).creationCode; bytes32 salt = keccak256(abi.encodePacked(token0, token1)); assembly { pair := create2(0, add(bytecode, 32), mload(bytecode), salt) } IUniswapV2Pair(pair).initialize(token0, token1); getPair[token0][token1] = pair; getPair[token1][token0] = pair; // populate mapping in the reverse direction allPairs.push(pair); emit PairCreated(token0, token1, pair, allPairs.length); } function setFeeTo(address _feeTo) external { require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN'); feeTo = _feeTo; } function setFeeToSetter(address _feeToSetter) external { require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN'); feeToSetter = _feeToSetter; } } // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math) library SafeMath { function add(uint x, uint y) internal pure returns (uint z) { require((z = x + y) >= x, 'ds-math-add-overflow'); } function sub(uint x, uint y) internal pure returns (uint z) { require((z = x - y) <= x, 'ds-math-sub-underflow'); } function mul(uint x, uint y) internal pure returns (uint z) { require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow'); } } // a library for performing various math operations library Math { function min(uint x, uint y) internal pure returns (uint z) { z = x < y ? x : y; } // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method) function sqrt(uint y) internal pure returns (uint z) { if (y > 3) { z = y; uint x = y / 2 + 1; while (x < z) { z = x; x = (y / x + x) / 2; } } else if (y != 0) { z = 1; } } } // a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format)) // range: [0, 2**112 - 1] // resolution: 1 / 2**112 library UQ112x112 { uint224 constant Q112 = 2**112; // encode a uint112 as a UQ112x112 function encode(uint112 y) internal pure returns (uint224 z) { z = uint224(y) * Q112; // never overflows } // divide a UQ112x112 by a uint112, returning a UQ112x112 function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) { z = x / uint224(y); } }
File 9 of 12: UniswapV2Pair
// File: contracts/interfaces/IUniswapV2Pair.sol pragma solidity >=0.5.0; interface IUniswapV2Pair { event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); function name() external pure returns (string memory); function symbol() external pure returns (string memory); function decimals() external pure returns (uint8); function totalSupply() external view returns (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); function transfer(address to, uint value) external returns (bool); function transferFrom(address from, address to, uint value) external returns (bool); function DOMAIN_SEPARATOR() external view returns (bytes32); function PERMIT_TYPEHASH() external pure returns (bytes32); function nonces(address owner) external view returns (uint); function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; event Mint(address indexed sender, uint amount0, uint amount1); event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); event Swap( address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to ); event Sync(uint112 reserve0, uint112 reserve1); function MINIMUM_LIQUIDITY() external pure returns (uint); function factory() external view returns (address); function token0() external view returns (address); function token1() external view returns (address); function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); function price0CumulativeLast() external view returns (uint); function price1CumulativeLast() external view returns (uint); function kLast() external view returns (uint); function mint(address to) external returns (uint liquidity); function burn(address to) external returns (uint amount0, uint amount1); function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; function skim(address to) external; function sync() external; function initialize(address, address) external; } // File: contracts/interfaces/IUniswapV2ERC20.sol pragma solidity >=0.5.0; interface IUniswapV2ERC20 { event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); function name() external pure returns (string memory); function symbol() external pure returns (string memory); function decimals() external pure returns (uint8); function totalSupply() external view returns (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); function transfer(address to, uint value) external returns (bool); function transferFrom(address from, address to, uint value) external returns (bool); function DOMAIN_SEPARATOR() external view returns (bytes32); function PERMIT_TYPEHASH() external pure returns (bytes32); function nonces(address owner) external view returns (uint); function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; } // File: contracts/libraries/SafeMath.sol pragma solidity =0.5.16; // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math) library SafeMath { function add(uint x, uint y) internal pure returns (uint z) { require((z = x + y) >= x, 'ds-math-add-overflow'); } function sub(uint x, uint y) internal pure returns (uint z) { require((z = x - y) <= x, 'ds-math-sub-underflow'); } function mul(uint x, uint y) internal pure returns (uint z) { require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow'); } } // File: contracts/UniswapV2ERC20.sol pragma solidity =0.5.16; contract UniswapV2ERC20 is IUniswapV2ERC20 { using SafeMath for uint; string public constant name = 'Uniswap V2'; string public constant symbol = 'UNI-V2'; uint8 public constant decimals = 18; uint public totalSupply; mapping(address => uint) public balanceOf; mapping(address => mapping(address => uint)) public allowance; bytes32 public DOMAIN_SEPARATOR; // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; mapping(address => uint) public nonces; event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); constructor() public { uint chainId; assembly { chainId := chainid } DOMAIN_SEPARATOR = keccak256( abi.encode( keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'), keccak256(bytes(name)), keccak256(bytes('1')), chainId, address(this) ) ); } function _mint(address to, uint value) internal { totalSupply = totalSupply.add(value); balanceOf[to] = balanceOf[to].add(value); emit Transfer(address(0), to, value); } function _burn(address from, uint value) internal { balanceOf[from] = balanceOf[from].sub(value); totalSupply = totalSupply.sub(value); emit Transfer(from, address(0), value); } function _approve(address owner, address spender, uint value) private { allowance[owner][spender] = value; emit Approval(owner, spender, value); } function _transfer(address from, address to, uint value) private { balanceOf[from] = balanceOf[from].sub(value); balanceOf[to] = balanceOf[to].add(value); emit Transfer(from, to, value); } function approve(address spender, uint value) external returns (bool) { _approve(msg.sender, spender, value); return true; } function transfer(address to, uint value) external returns (bool) { _transfer(msg.sender, to, value); return true; } function transferFrom(address from, address to, uint value) external returns (bool) { if (allowance[from][msg.sender] != uint(-1)) { allowance[from][msg.sender] = allowance[from][msg.sender].sub(value); } _transfer(from, to, value); return true; } function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external { require(deadline >= block.timestamp, 'UniswapV2: EXPIRED'); bytes32 digest = keccak256( abi.encodePacked( '\x19\x01', DOMAIN_SEPARATOR, keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline)) ) ); address recoveredAddress = ecrecover(digest, v, r, s); require(recoveredAddress != address(0) && recoveredAddress == owner, 'UniswapV2: INVALID_SIGNATURE'); _approve(owner, spender, value); } } // File: contracts/libraries/Math.sol pragma solidity =0.5.16; // a library for performing various math operations library Math { function min(uint x, uint y) internal pure returns (uint z) { z = x < y ? x : y; } // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method) function sqrt(uint y) internal pure returns (uint z) { if (y > 3) { z = y; uint x = y / 2 + 1; while (x < z) { z = x; x = (y / x + x) / 2; } } else if (y != 0) { z = 1; } } } // File: contracts/libraries/UQ112x112.sol pragma solidity =0.5.16; // a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format)) // range: [0, 2**112 - 1] // resolution: 1 / 2**112 library UQ112x112 { uint224 constant Q112 = 2**112; // encode a uint112 as a UQ112x112 function encode(uint112 y) internal pure returns (uint224 z) { z = uint224(y) * Q112; // never overflows } // divide a UQ112x112 by a uint112, returning a UQ112x112 function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) { z = x / uint224(y); } } // File: contracts/interfaces/IERC20.sol pragma solidity >=0.5.0; interface IERC20 { event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); 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 (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); function transfer(address to, uint value) external returns (bool); function transferFrom(address from, address to, uint value) external returns (bool); } // File: contracts/interfaces/IUniswapV2Factory.sol pragma solidity >=0.5.0; interface IUniswapV2Factory { event PairCreated(address indexed token0, address indexed token1, address pair, uint); function feeTo() external view returns (address); function feeToSetter() external view returns (address); function getPair(address tokenA, address tokenB) external view returns (address pair); function allPairs(uint) external view returns (address pair); function allPairsLength() external view returns (uint); function createPair(address tokenA, address tokenB) external returns (address pair); function setFeeTo(address) external; function setFeeToSetter(address) external; } // File: contracts/interfaces/IUniswapV2Callee.sol pragma solidity >=0.5.0; interface IUniswapV2Callee { function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external; } // File: contracts/UniswapV2Pair.sol pragma solidity =0.5.16; contract UniswapV2Pair is IUniswapV2Pair, UniswapV2ERC20 { using SafeMath for uint; using UQ112x112 for uint224; uint public constant MINIMUM_LIQUIDITY = 10**3; bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)'))); address public factory; address public token0; address public token1; uint112 private reserve0; // uses single storage slot, accessible via getReserves uint112 private reserve1; // uses single storage slot, accessible via getReserves uint32 private blockTimestampLast; // uses single storage slot, accessible via getReserves uint public price0CumulativeLast; uint public price1CumulativeLast; uint public kLast; // reserve0 * reserve1, as of immediately after the most recent liquidity event uint private unlocked = 1; modifier lock() { require(unlocked == 1, 'UniswapV2: LOCKED'); unlocked = 0; _; unlocked = 1; } function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) { _reserve0 = reserve0; _reserve1 = reserve1; _blockTimestampLast = blockTimestampLast; } function _safeTransfer(address token, address to, uint value) private { (bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'UniswapV2: TRANSFER_FAILED'); } event Mint(address indexed sender, uint amount0, uint amount1); event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); event Swap( address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to ); event Sync(uint112 reserve0, uint112 reserve1); constructor() public { factory = msg.sender; } // called once by the factory at time of deployment function initialize(address _token0, address _token1) external { require(msg.sender == factory, 'UniswapV2: FORBIDDEN'); // sufficient check token0 = _token0; token1 = _token1; } // update reserves and, on the first call per block, price accumulators function _update(uint balance0, uint balance1, uint112 _reserve0, uint112 _reserve1) private { require(balance0 <= uint112(-1) && balance1 <= uint112(-1), 'UniswapV2: OVERFLOW'); uint32 blockTimestamp = uint32(block.timestamp % 2**32); uint32 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) { // * never overflows, and + overflow is desired price0CumulativeLast += uint(UQ112x112.encode(_reserve1).uqdiv(_reserve0)) * timeElapsed; price1CumulativeLast += uint(UQ112x112.encode(_reserve0).uqdiv(_reserve1)) * timeElapsed; } reserve0 = uint112(balance0); reserve1 = uint112(balance1); blockTimestampLast = blockTimestamp; emit Sync(reserve0, reserve1); } // if fee is on, mint liquidity equivalent to 1/6th of the growth in sqrt(k) function _mintFee(uint112 _reserve0, uint112 _reserve1) private returns (bool feeOn) { address feeTo = IUniswapV2Factory(factory).feeTo(); feeOn = feeTo != address(0); uint _kLast = kLast; // gas savings if (feeOn) { if (_kLast != 0) { uint rootK = Math.sqrt(uint(_reserve0).mul(_reserve1)); uint rootKLast = Math.sqrt(_kLast); if (rootK > rootKLast) { uint numerator = totalSupply.mul(rootK.sub(rootKLast)); uint denominator = rootK.mul(5).add(rootKLast); uint liquidity = numerator / denominator; if (liquidity > 0) _mint(feeTo, liquidity); } } } else if (_kLast != 0) { kLast = 0; } } // this low-level function should be called from a contract which performs important safety checks function mint(address to) external lock returns (uint liquidity) { (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings uint balance0 = IERC20(token0).balanceOf(address(this)); uint balance1 = IERC20(token1).balanceOf(address(this)); uint amount0 = balance0.sub(_reserve0); uint amount1 = balance1.sub(_reserve1); bool feeOn = _mintFee(_reserve0, _reserve1); uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee if (_totalSupply == 0) { liquidity = Math.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY); _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens } else { liquidity = Math.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply) / _reserve1); } require(liquidity > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY_MINTED'); _mint(to, liquidity); _update(balance0, balance1, _reserve0, _reserve1); if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date emit Mint(msg.sender, amount0, amount1); } // this low-level function should be called from a contract which performs important safety checks function burn(address to) external lock returns (uint amount0, uint amount1) { (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings address _token0 = token0; // gas savings address _token1 = token1; // gas savings uint balance0 = IERC20(_token0).balanceOf(address(this)); uint balance1 = IERC20(_token1).balanceOf(address(this)); uint liquidity = balanceOf[address(this)]; bool feeOn = _mintFee(_reserve0, _reserve1); uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee amount0 = liquidity.mul(balance0) / _totalSupply; // using balances ensures pro-rata distribution amount1 = liquidity.mul(balance1) / _totalSupply; // using balances ensures pro-rata distribution require(amount0 > 0 && amount1 > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY_BURNED'); _burn(address(this), liquidity); _safeTransfer(_token0, to, amount0); _safeTransfer(_token1, to, amount1); balance0 = IERC20(_token0).balanceOf(address(this)); balance1 = IERC20(_token1).balanceOf(address(this)); _update(balance0, balance1, _reserve0, _reserve1); if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date emit Burn(msg.sender, amount0, amount1, to); } // this low-level function should be called from a contract which performs important safety checks function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external lock { require(amount0Out > 0 || amount1Out > 0, 'UniswapV2: INSUFFICIENT_OUTPUT_AMOUNT'); (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings require(amount0Out < _reserve0 && amount1Out < _reserve1, 'UniswapV2: INSUFFICIENT_LIQUIDITY'); uint balance0; uint balance1; { // scope for _token{0,1}, avoids stack too deep errors address _token0 = token0; address _token1 = token1; require(to != _token0 && to != _token1, 'UniswapV2: INVALID_TO'); if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens if (data.length > 0) IUniswapV2Callee(to).uniswapV2Call(msg.sender, amount0Out, amount1Out, data); balance0 = IERC20(_token0).balanceOf(address(this)); balance1 = IERC20(_token1).balanceOf(address(this)); } uint amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0; uint amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0; require(amount0In > 0 || amount1In > 0, 'UniswapV2: INSUFFICIENT_INPUT_AMOUNT'); { // scope for reserve{0,1}Adjusted, avoids stack too deep errors uint balance0Adjusted = balance0.mul(1000).sub(amount0In.mul(3)); uint balance1Adjusted = balance1.mul(1000).sub(amount1In.mul(3)); require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(1000**2), 'UniswapV2: K'); } _update(balance0, balance1, _reserve0, _reserve1); emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to); } // force balances to match reserves function skim(address to) external lock { address _token0 = token0; // gas savings address _token1 = token1; // gas savings _safeTransfer(_token0, to, IERC20(_token0).balanceOf(address(this)).sub(reserve0)); _safeTransfer(_token1, to, IERC20(_token1).balanceOf(address(this)).sub(reserve1)); } // force reserves to match balances function sync() external lock { _update(IERC20(token0).balanceOf(address(this)), IERC20(token1).balanceOf(address(this)), reserve0, reserve1); } }
File 10 of 12: SmartPoolManager
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; // Needed to handle structures externally pragma experimental ABIEncoderV2; // Imports import "./IBFactory.sol"; import "./PCToken.sol"; import "./utils/BalancerReentrancyGuard.sol"; import "./utils/BalancerOwnable.sol"; // Interfaces // Libraries import { RightsManager } from "../libraries/RightsManager.sol"; import "../libraries/SmartPoolManager.sol"; import "../libraries/SafeApprove.sol"; // Contracts /** * @author Balancer Labs * @title Smart Pool with customizable features * @notice PCToken is the "Balancer Smart Pool" token (transferred upon finalization) * @dev Rights are defined as follows (index values into the array) * 0: canPauseSwapping - can setPublicSwap back to false after turning it on * by default, it is off on initialization and can only be turned on * 1: canChangeSwapFee - can setSwapFee after initialization (by default, it is fixed at create time) * 2: canChangeWeights - can bind new token weights (allowed by default in base pool) * 3: canAddRemoveTokens - can bind/unbind tokens (allowed by default in base pool) * 4: canWhitelistLPs - can restrict LPs to a whitelist * 5: canChangeCap - can change the BSP cap (max # of pool tokens) * * Note that functions called on bPool and bFactory may look like internal calls, * but since they are contracts accessed through an interface, they are really external. * To make this explicit, we could write "IBPool(address(bPool)).function()" everywhere, * instead of "bPool.function()". */ contract ConfigurableRightsPool is PCToken, BalancerOwnable, BalancerReentrancyGuard { using BalancerSafeMath for uint; using SafeApprove for IERC20; // Type declarations struct PoolParams { // Balancer Pool Token (representing shares of the pool) string poolTokenSymbol; string poolTokenName; // Tokens inside the Pool address[] constituentTokens; uint[] tokenBalances; uint[] tokenWeights; uint swapFee; } // State variables IBFactory public bFactory; IBPool public bPool; // Struct holding the rights configuration RightsManager.Rights public rights; // Hold the parameters used in updateWeightsGradually SmartPoolManager.GradualUpdateParams public gradualUpdate; // This is for adding a new (currently unbound) token to the pool // It's a two-step process: commitAddToken(), then applyAddToken() SmartPoolManager.NewTokenParams public newToken; // Fee is initialized on creation, and can be changed if permission is set // Only needed for temporary storage between construction and createPool // Thereafter, the swap fee should always be read from the underlying pool uint private _initialSwapFee; // Store the list of tokens in the pool, and balances // NOTE that the token list is *only* used to store the pool tokens between // construction and createPool - thereafter, use the underlying BPool's list // (avoids synchronization issues) address[] private _initialTokens; uint[] private _initialBalances; // Enforce a minimum time between the start and end blocks uint public minimumWeightChangeBlockPeriod; // Enforce a mandatory wait time between updates // This is also the wait time between committing and applying a new token uint public addTokenTimeLockInBlocks; // Whitelist of LPs (if configured) mapping(address => bool) private _liquidityProviderWhitelist; // Cap on the pool size (i.e., # of tokens minted when joining) // Limits the risk of experimental pools; failsafe/backup for fixed-size pools uint public bspCap; // Event declarations // Anonymous logger event - can only be filtered by contract address event LogCall( bytes4 indexed sig, address indexed caller, bytes data ) anonymous; event LogJoin( address indexed caller, address indexed tokenIn, uint tokenAmountIn ); event LogExit( address indexed caller, address indexed tokenOut, uint tokenAmountOut ); event CapChanged( address indexed caller, uint oldCap, uint newCap ); event NewTokenCommitted( address indexed token, address indexed pool, address indexed caller ); // Modifiers modifier logs() { emit LogCall(msg.sig, msg.sender, msg.data); _; } // Mark functions that require delegation to the underlying Pool modifier needsBPool() { require(address(bPool) != address(0), "ERR_NOT_CREATED"); _; } modifier lockUnderlyingPool() { // Turn off swapping on the underlying pool during joins // Otherwise tokens with callbacks would enable attacks involving simultaneous swaps and joins bool origSwapState = bPool.isPublicSwap(); bPool.setPublicSwap(false); _; bPool.setPublicSwap(origSwapState); } // Default values for these variables (used only in updateWeightsGradually), set in the constructor // Pools without permission to update weights cannot use them anyway, and should call // the default createPool() function. // To override these defaults, pass them into the overloaded createPool() // Period is in blocks; 500 blocks ~ 2 hours; 90,000 blocks ~ 2 weeks uint public constant DEFAULT_MIN_WEIGHT_CHANGE_BLOCK_PERIOD = 90000; uint public constant DEFAULT_ADD_TOKEN_TIME_LOCK_IN_BLOCKS = 500; // Function declarations /** * @notice Construct a new Configurable Rights Pool (wrapper around BPool) * @dev _initialTokens and _swapFee are only used for temporary storage between construction * and create pool, and should not be used thereafter! _initialTokens is destroyed in * createPool to prevent this, and _swapFee is kept in sync (defensively), but * should never be used except in this constructor and createPool() * @param factoryAddress - the BPoolFactory used to create the underlying pool * @param poolParams - struct containing pool parameters * @param rightsStruct - Set of permissions we are assigning to this smart pool */ constructor( address factoryAddress, PoolParams memory poolParams, RightsManager.Rights memory rightsStruct ) public PCToken(poolParams.poolTokenSymbol, poolParams.poolTokenName) { // We don't have a pool yet; check now or it will fail later (in order of likelihood to fail) // (and be unrecoverable if they don't have permission set to change it) // Most likely to fail, so check first require(poolParams.swapFee >= BalancerConstants.MIN_FEE, "ERR_INVALID_SWAP_FEE"); require(poolParams.swapFee <= BalancerConstants.MAX_FEE, "ERR_INVALID_SWAP_FEE"); // Arrays must be parallel require(poolParams.tokenBalances.length == poolParams.constituentTokens.length, "ERR_START_BALANCES_MISMATCH"); require(poolParams.tokenWeights.length == poolParams.constituentTokens.length, "ERR_START_WEIGHTS_MISMATCH"); // Cannot have too many or too few - technically redundant, since BPool.bind() would fail later // But if we don't check now, we could have a useless contract with no way to create a pool require(poolParams.constituentTokens.length >= BalancerConstants.MIN_ASSET_LIMIT, "ERR_TOO_FEW_TOKENS"); require(poolParams.constituentTokens.length <= BalancerConstants.MAX_ASSET_LIMIT, "ERR_TOO_MANY_TOKENS"); // There are further possible checks (e.g., if they use the same token twice), but // we can let bind() catch things like that (i.e., not things that might reasonably work) SmartPoolManager.verifyTokenCompliance(poolParams.constituentTokens); bFactory = IBFactory(factoryAddress); rights = rightsStruct; _initialTokens = poolParams.constituentTokens; _initialBalances = poolParams.tokenBalances; _initialSwapFee = poolParams.swapFee; // These default block time parameters can be overridden in createPool minimumWeightChangeBlockPeriod = DEFAULT_MIN_WEIGHT_CHANGE_BLOCK_PERIOD; addTokenTimeLockInBlocks = DEFAULT_ADD_TOKEN_TIME_LOCK_IN_BLOCKS; gradualUpdate.startWeights = poolParams.tokenWeights; // Initializing (unnecessarily) for documentation - 0 means no gradual weight change has been initiated gradualUpdate.startBlock = 0; // By default, there is no cap (unlimited pool token minting) bspCap = BalancerConstants.MAX_UINT; } // External functions /** * @notice Set the swap fee on the underlying pool * @dev Keep the local version and core in sync (see below) * bPool is a contract interface; function calls on it are external * @param swapFee in Wei */ function setSwapFee(uint swapFee) external logs lock onlyOwner needsBPool virtual { require(rights.canChangeSwapFee, "ERR_NOT_CONFIGURABLE_SWAP_FEE"); // Underlying pool will check against min/max fee bPool.setSwapFee(swapFee); } /** * @notice Getter for the publicSwap field on the underlying pool * @dev viewLock, because setPublicSwap is lock * bPool is a contract interface; function calls on it are external * @return Current value of isPublicSwap */ function isPublicSwap() external view viewlock needsBPool virtual returns (bool) { return bPool.isPublicSwap(); } /** * @notice Set the cap (max # of pool tokens) * @dev _bspCap defaults in the constructor to unlimited * Can set to 0 (or anywhere below the current supply), to halt new investment * Prevent setting it before creating a pool, since createPool sets to intialSupply * (it does this to avoid an unlimited cap window between construction and createPool) * Therefore setting it before then has no effect, so should not be allowed * @param newCap - new value of the cap */ function setCap(uint newCap) external logs lock needsBPool onlyOwner { require(rights.canChangeCap, "ERR_CANNOT_CHANGE_CAP"); emit CapChanged(msg.sender, bspCap, newCap); bspCap = newCap; } /** * @notice Set the public swap flag on the underlying pool * @dev If this smart pool has canPauseSwapping enabled, we can turn publicSwap off if it's already on * Note that if they turn swapping off - but then finalize the pool - finalizing will turn the * swapping back on. They're not supposed to finalize the underlying pool... would defeat the * smart pool functions. (Only the owner can finalize the pool - which is this contract - * so there is no risk from outside.) * * bPool is a contract interface; function calls on it are external * @param publicSwap new value of the swap */ function setPublicSwap(bool publicSwap) external logs lock onlyOwner needsBPool virtual { require(rights.canPauseSwapping, "ERR_NOT_PAUSABLE_SWAP"); bPool.setPublicSwap(publicSwap); } /** * @notice Create a new Smart Pool - and set the block period time parameters * @dev Initialize the swap fee to the value provided in the CRP constructor * Can be changed if the canChangeSwapFee permission is enabled * Time parameters will be fixed at these values * * If this contract doesn't have canChangeWeights permission - or you want to use the default * values, the block time arguments are not needed, and you can just call the single-argument * createPool() * @param initialSupply - Starting token balance * @param minimumWeightChangeBlockPeriodParam - Enforce a minimum time between the start and end blocks * @param addTokenTimeLockInBlocksParam - Enforce a mandatory wait time between updates * This is also the wait time between committing and applying a new token */ function createPool( uint initialSupply, uint minimumWeightChangeBlockPeriodParam, uint addTokenTimeLockInBlocksParam ) external onlyOwner logs lock virtual { require (minimumWeightChangeBlockPeriodParam >= addTokenTimeLockInBlocksParam, "ERR_INCONSISTENT_TOKEN_TIME_LOCK"); minimumWeightChangeBlockPeriod = minimumWeightChangeBlockPeriodParam; addTokenTimeLockInBlocks = addTokenTimeLockInBlocksParam; createPoolInternal(initialSupply); } /** * @notice Create a new Smart Pool * @dev Delegates to internal function * @param initialSupply starting token balance */ function createPool(uint initialSupply) external onlyOwner logs lock virtual { createPoolInternal(initialSupply); } /** * @notice Update the weight of an existing token * @dev Notice Balance is not an input (like with rebind on BPool) since we will require prices not to change * This is achieved by forcing balances to change proportionally to weights, so that prices don't change * If prices could be changed, this would allow the controller to drain the pool by arbing price changes * @param token - token to be reweighted * @param newWeight - new weight of the token */ function updateWeight(address token, uint newWeight) external logs lock onlyOwner needsBPool virtual { require(rights.canChangeWeights, "ERR_NOT_CONFIGURABLE_WEIGHTS"); // We don't want people to set weights manually if there's a block-based update in progress require(gradualUpdate.startBlock == 0, "ERR_NO_UPDATE_DURING_GRADUAL"); // Delegate to library to save space SmartPoolManager.updateWeight(IConfigurableRightsPool(address(this)), bPool, token, newWeight); } /** * @notice Update weights in a predetermined way, between startBlock and endBlock, * through external calls to pokeWeights * @dev Must call pokeWeights at least once past the end for it to do the final update * and enable calling this again. * It is possible to call updateWeightsGradually during an update in some use cases * For instance, setting newWeights to currentWeights to stop the update where it is * @param newWeights - final weights we want to get to. Note that the ORDER (and number) of * tokens can change if you have added or removed tokens from the pool * It ensures the counts are correct, but can't help you with the order! * You can get the underlying BPool (it's public), and call * getCurrentTokens() to see the current ordering, if you're not sure * @param startBlock - when weights should start to change * @param endBlock - when weights will be at their final values */ function updateWeightsGradually( uint[] calldata newWeights, uint startBlock, uint endBlock ) external logs lock onlyOwner needsBPool virtual { require(rights.canChangeWeights, "ERR_NOT_CONFIGURABLE_WEIGHTS"); // Don't start this when we're in the middle of adding a new token require(!newToken.isCommitted, "ERR_PENDING_TOKEN_ADD"); // Library computes the startBlock, computes startWeights as the current // denormalized weights of the core pool tokens. SmartPoolManager.updateWeightsGradually( bPool, gradualUpdate, newWeights, startBlock, endBlock, minimumWeightChangeBlockPeriod ); } /** * @notice External function called to make the contract update weights according to plan * @dev Still works if we poke after the end of the period; also works if the weights don't change * Resets if we are poking beyond the end, so that we can do it again */ function pokeWeights() external logs lock needsBPool virtual { require(rights.canChangeWeights, "ERR_NOT_CONFIGURABLE_WEIGHTS"); // Delegate to library to save space SmartPoolManager.pokeWeights(bPool, gradualUpdate); } /** * @notice Schedule (commit) a token to be added; must call applyAddToken after a fixed * number of blocks to actually add the token * * @dev The purpose of this two-stage commit is to give warning of a potentially dangerous * operation. A malicious pool operator could add a large amount of a low-value token, * then drain the pool through price manipulation. Of course, there are many * legitimate purposes, such as adding additional collateral tokens. * * @param token - the token to be added * @param balance - how much to be added * @param denormalizedWeight - the desired token weight */ function commitAddToken( address token, uint balance, uint denormalizedWeight ) external logs lock onlyOwner needsBPool virtual { require(rights.canAddRemoveTokens, "ERR_CANNOT_ADD_REMOVE_TOKENS"); // Can't do this while a progressive update is happening require(gradualUpdate.startBlock == 0, "ERR_NO_UPDATE_DURING_GRADUAL"); SmartPoolManager.verifyTokenCompliance(token); emit NewTokenCommitted(token, address(this), msg.sender); // Delegate to library to save space SmartPoolManager.commitAddToken( bPool, token, balance, denormalizedWeight, newToken ); } /** * @notice Add the token previously committed (in commitAddToken) to the pool */ function applyAddToken() external logs lock onlyOwner needsBPool virtual { require(rights.canAddRemoveTokens, "ERR_CANNOT_ADD_REMOVE_TOKENS"); // Delegate to library to save space SmartPoolManager.applyAddToken( IConfigurableRightsPool(address(this)), bPool, addTokenTimeLockInBlocks, newToken ); } /** * @notice Remove a token from the pool * @dev bPool is a contract interface; function calls on it are external * @param token - token to remove */ function removeToken(address token) external logs lock onlyOwner needsBPool { // It's possible to have remove rights without having add rights require(rights.canAddRemoveTokens,"ERR_CANNOT_ADD_REMOVE_TOKENS"); // After createPool, token list is maintained in the underlying BPool require(!newToken.isCommitted, "ERR_REMOVE_WITH_ADD_PENDING"); // Prevent removing during an update (or token lists can get out of sync) require(gradualUpdate.startBlock == 0, "ERR_NO_UPDATE_DURING_GRADUAL"); // Delegate to library to save space SmartPoolManager.removeToken(IConfigurableRightsPool(address(this)), bPool, token); } /** * @notice Join a pool * @dev Emits a LogJoin event (for each token) * bPool is a contract interface; function calls on it are external * @param poolAmountOut - number of pool tokens to receive * @param maxAmountsIn - Max amount of asset tokens to spend */ function joinPool(uint poolAmountOut, uint[] calldata maxAmountsIn) external logs lock needsBPool lockUnderlyingPool { require(!rights.canWhitelistLPs || _liquidityProviderWhitelist[msg.sender], "ERR_NOT_ON_WHITELIST"); // Delegate to library to save space // Library computes actualAmountsIn, and does many validations // Cannot call the push/pull/min from an external library for // any of these pool functions. Since msg.sender can be anybody, // they must be internal uint[] memory actualAmountsIn = SmartPoolManager.joinPool( IConfigurableRightsPool(address(this)), bPool, poolAmountOut, maxAmountsIn ); // After createPool, token list is maintained in the underlying BPool address[] memory poolTokens = bPool.getCurrentTokens(); for (uint i = 0; i < poolTokens.length; i++) { address t = poolTokens[i]; uint tokenAmountIn = actualAmountsIn[i]; emit LogJoin(msg.sender, t, tokenAmountIn); _pullUnderlying(t, msg.sender, tokenAmountIn); } _mintPoolShare(poolAmountOut); _pushPoolShare(msg.sender, poolAmountOut); } /** * @notice Exit a pool - redeem pool tokens for underlying assets * @dev Emits a LogExit event for each token * bPool is a contract interface; function calls on it are external * @param poolAmountIn - amount of pool tokens to redeem * @param minAmountsOut - minimum amount of asset tokens to receive */ function exitPool(uint poolAmountIn, uint[] calldata minAmountsOut) external logs lock needsBPool lockUnderlyingPool { // Delegate to library to save space // Library computes actualAmountsOut, and does many validations // Also computes the exitFee and pAiAfterExitFee (uint exitFee, uint pAiAfterExitFee, uint[] memory actualAmountsOut) = SmartPoolManager.exitPool( IConfigurableRightsPool(address(this)), bPool, poolAmountIn, minAmountsOut ); _pullPoolShare(msg.sender, poolAmountIn); _pushPoolShare(address(bFactory), exitFee); _burnPoolShare(pAiAfterExitFee); // After createPool, token list is maintained in the underlying BPool address[] memory poolTokens = bPool.getCurrentTokens(); for (uint i = 0; i < poolTokens.length; i++) { address t = poolTokens[i]; uint tokenAmountOut = actualAmountsOut[i]; emit LogExit(msg.sender, t, tokenAmountOut); _pushUnderlying(t, msg.sender, tokenAmountOut); } } /** * @notice Join by swapping a fixed amount of an external token in (must be present in the pool) * System calculates the pool token amount * @dev emits a LogJoin event * @param tokenIn - which token we're transferring in * @param tokenAmountIn - amount of deposit * @param minPoolAmountOut - minimum of pool tokens to receive * @return poolAmountOut - amount of pool tokens minted and transferred */ function joinswapExternAmountIn( address tokenIn, uint tokenAmountIn, uint minPoolAmountOut ) external logs lock needsBPool returns (uint poolAmountOut) { require(!rights.canWhitelistLPs || _liquidityProviderWhitelist[msg.sender], "ERR_NOT_ON_WHITELIST"); // Delegate to library to save space poolAmountOut = SmartPoolManager.joinswapExternAmountIn( IConfigurableRightsPool(address(this)), bPool, tokenIn, tokenAmountIn, minPoolAmountOut ); emit LogJoin(msg.sender, tokenIn, tokenAmountIn); _mintPoolShare(poolAmountOut); _pushPoolShare(msg.sender, poolAmountOut); _pullUnderlying(tokenIn, msg.sender, tokenAmountIn); return poolAmountOut; } /** * @notice Join by swapping an external token in (must be present in the pool) * To receive an exact amount of pool tokens out. System calculates the deposit amount * @dev emits a LogJoin event * @param tokenIn - which token we're transferring in (system calculates amount required) * @param poolAmountOut - amount of pool tokens to be received * @param maxAmountIn - Maximum asset tokens that can be pulled to pay for the pool tokens * @return tokenAmountIn - amount of asset tokens transferred in to purchase the pool tokens */ function joinswapPoolAmountOut( address tokenIn, uint poolAmountOut, uint maxAmountIn ) external logs lock needsBPool returns (uint tokenAmountIn) { require(!rights.canWhitelistLPs || _liquidityProviderWhitelist[msg.sender], "ERR_NOT_ON_WHITELIST"); // Delegate to library to save space tokenAmountIn = SmartPoolManager.joinswapPoolAmountOut( IConfigurableRightsPool(address(this)), bPool, tokenIn, poolAmountOut, maxAmountIn ); emit LogJoin(msg.sender, tokenIn, tokenAmountIn); _mintPoolShare(poolAmountOut); _pushPoolShare(msg.sender, poolAmountOut); _pullUnderlying(tokenIn, msg.sender, tokenAmountIn); return tokenAmountIn; } /** * @notice Exit a pool - redeem a specific number of pool tokens for an underlying asset * Asset must be present in the pool, and will incur an EXIT_FEE (if set to non-zero) * @dev Emits a LogExit event for the token * @param tokenOut - which token the caller wants to receive * @param poolAmountIn - amount of pool tokens to redeem * @param minAmountOut - minimum asset tokens to receive * @return tokenAmountOut - amount of asset tokens returned */ function exitswapPoolAmountIn( address tokenOut, uint poolAmountIn, uint minAmountOut ) external logs lock needsBPool returns (uint tokenAmountOut) { // Delegate to library to save space // Calculates final amountOut, and the fee and final amount in (uint exitFee, uint amountOut) = SmartPoolManager.exitswapPoolAmountIn( IConfigurableRightsPool(address(this)), bPool, tokenOut, poolAmountIn, minAmountOut ); tokenAmountOut = amountOut; uint pAiAfterExitFee = BalancerSafeMath.bsub(poolAmountIn, exitFee); emit LogExit(msg.sender, tokenOut, tokenAmountOut); _pullPoolShare(msg.sender, poolAmountIn); _burnPoolShare(pAiAfterExitFee); _pushPoolShare(address(bFactory), exitFee); _pushUnderlying(tokenOut, msg.sender, tokenAmountOut); return tokenAmountOut; } /** * @notice Exit a pool - redeem pool tokens for a specific amount of underlying assets * Asset must be present in the pool * @dev Emits a LogExit event for the token * @param tokenOut - which token the caller wants to receive * @param tokenAmountOut - amount of underlying asset tokens to receive * @param maxPoolAmountIn - maximum pool tokens to be redeemed * @return poolAmountIn - amount of pool tokens redeemed */ function exitswapExternAmountOut( address tokenOut, uint tokenAmountOut, uint maxPoolAmountIn ) external logs lock needsBPool returns (uint poolAmountIn) { // Delegate to library to save space // Calculates final amounts in, accounting for the exit fee (uint exitFee, uint amountIn) = SmartPoolManager.exitswapExternAmountOut( IConfigurableRightsPool(address(this)), bPool, tokenOut, tokenAmountOut, maxPoolAmountIn ); poolAmountIn = amountIn; uint pAiAfterExitFee = BalancerSafeMath.bsub(poolAmountIn, exitFee); emit LogExit(msg.sender, tokenOut, tokenAmountOut); _pullPoolShare(msg.sender, poolAmountIn); _burnPoolShare(pAiAfterExitFee); _pushPoolShare(address(bFactory), exitFee); _pushUnderlying(tokenOut, msg.sender, tokenAmountOut); return poolAmountIn; } /** * @notice Add to the whitelist of liquidity providers (if enabled) * @param provider - address of the liquidity provider */ function whitelistLiquidityProvider(address provider) external onlyOwner lock logs { require(rights.canWhitelistLPs, "ERR_CANNOT_WHITELIST_LPS"); require(provider != address(0), "ERR_INVALID_ADDRESS"); _liquidityProviderWhitelist[provider] = true; } /** * @notice Remove from the whitelist of liquidity providers (if enabled) * @param provider - address of the liquidity provider */ function removeWhitelistedLiquidityProvider(address provider) external onlyOwner lock logs { require(rights.canWhitelistLPs, "ERR_CANNOT_WHITELIST_LPS"); require(_liquidityProviderWhitelist[provider], "ERR_LP_NOT_WHITELISTED"); require(provider != address(0), "ERR_INVALID_ADDRESS"); _liquidityProviderWhitelist[provider] = false; } /** * @notice Check if an address is a liquidity provider * @dev If the whitelist feature is not enabled, anyone can provide liquidity (assuming finalized) * @return boolean value indicating whether the address can join a pool */ function canProvideLiquidity(address provider) external view returns(bool) { if (rights.canWhitelistLPs) { return _liquidityProviderWhitelist[provider]; } else { // Probably don't strictly need this (could just return true) // But the null address can't provide funds return provider != address(0); } } /** * @notice Getter for specific permissions * @dev value of the enum is just the 0-based index in the enumeration * For instance canPauseSwapping is 0; canChangeWeights is 2 * @return token boolean true if we have the given permission */ function hasPermission(RightsManager.Permissions permission) external view virtual returns(bool) { return RightsManager.hasPermission(rights, permission); } /** * @notice Get the denormalized weight of a token * @dev viewlock to prevent calling if it's being updated * @return token weight */ function getDenormalizedWeight(address token) external view viewlock needsBPool returns (uint) { return bPool.getDenormalizedWeight(token); } /** * @notice Getter for the RightsManager contract * @dev Convenience function to get the address of the RightsManager library (so clients can check version) * @return address of the RightsManager library */ function getRightsManagerVersion() external pure returns (address) { return address(RightsManager); } /** * @notice Getter for the BalancerSafeMath contract * @dev Convenience function to get the address of the BalancerSafeMath library (so clients can check version) * @return address of the BalancerSafeMath library */ function getBalancerSafeMathVersion() external pure returns (address) { return address(BalancerSafeMath); } /** * @notice Getter for the SmartPoolManager contract * @dev Convenience function to get the address of the SmartPoolManager library (so clients can check version) * @return address of the SmartPoolManager library */ function getSmartPoolManagerVersion() external pure returns (address) { return address(SmartPoolManager); } // Public functions // "Public" versions that can safely be called from SmartPoolManager // Allows only the contract itself to call them (not the controller or any external account) function mintPoolShareFromLib(uint amount) public { require (msg.sender == address(this), "ERR_NOT_CONTROLLER"); _mint(amount); } function pushPoolShareFromLib(address to, uint amount) public { require (msg.sender == address(this), "ERR_NOT_CONTROLLER"); _push(to, amount); } function pullPoolShareFromLib(address from, uint amount) public { require (msg.sender == address(this), "ERR_NOT_CONTROLLER"); _pull(from, amount); } function burnPoolShareFromLib(uint amount) public { require (msg.sender == address(this), "ERR_NOT_CONTROLLER"); _burn(amount); } // Internal functions // Lint wants the function to have a leading underscore too /* solhint-disable private-vars-leading-underscore */ /** * @notice Create a new Smart Pool * @dev Initialize the swap fee to the value provided in the CRP constructor * Can be changed if the canChangeSwapFee permission is enabled * @param initialSupply starting token balance */ function createPoolInternal(uint initialSupply) internal { require(address(bPool) == address(0), "ERR_IS_CREATED"); require(initialSupply >= BalancerConstants.MIN_POOL_SUPPLY, "ERR_INIT_SUPPLY_MIN"); require(initialSupply <= BalancerConstants.MAX_POOL_SUPPLY, "ERR_INIT_SUPPLY_MAX"); // If the controller can change the cap, initialize it to the initial supply // Defensive programming, so that there is no gap between creating the pool // (initialized to unlimited in the constructor), and setting the cap, // which they will presumably do if they have this right. if (rights.canChangeCap) { bspCap = initialSupply; } // There is technically reentrancy here, since we're making external calls and // then transferring tokens. However, the external calls are all to the underlying BPool // To the extent possible, modify state variables before calling functions _mintPoolShare(initialSupply); _pushPoolShare(msg.sender, initialSupply); // Deploy new BPool (bFactory and bPool are interfaces; all calls are external) bPool = bFactory.newBPool(); // EXIT_FEE must always be zero, or ConfigurableRightsPool._pushUnderlying will fail require(bPool.EXIT_FEE() == 0, "ERR_NONZERO_EXIT_FEE"); require(BalancerConstants.EXIT_FEE == 0, "ERR_NONZERO_EXIT_FEE"); for (uint i = 0; i < _initialTokens.length; i++) { address t = _initialTokens[i]; uint bal = _initialBalances[i]; uint denorm = gradualUpdate.startWeights[i]; bool returnValue = IERC20(t).transferFrom(msg.sender, address(this), bal); require(returnValue, "ERR_ERC20_FALSE"); returnValue = IERC20(t).safeApprove(address(bPool), BalancerConstants.MAX_UINT); require(returnValue, "ERR_ERC20_FALSE"); bPool.bind(t, bal, denorm); } while (_initialTokens.length > 0) { // Modifying state variable after external calls here, // but not essential, so not dangerous _initialTokens.pop(); } // Set fee to the initial value set in the constructor // Hereafter, read the swapFee from the underlying pool, not the local state variable bPool.setSwapFee(_initialSwapFee); bPool.setPublicSwap(true); // "destroy" the temporary swap fee (like _initialTokens above) in case a subclass tries to use it _initialSwapFee = 0; } /* solhint-enable private-vars-leading-underscore */ // Rebind BPool and pull tokens from address // bPool is a contract interface; function calls on it are external function _pullUnderlying(address erc20, address from, uint amount) internal needsBPool { // Gets current Balance of token i, Bi, and weight of token i, Wi, from BPool. uint tokenBalance = bPool.getBalance(erc20); uint tokenWeight = bPool.getDenormalizedWeight(erc20); bool xfer = IERC20(erc20).transferFrom(from, address(this), amount); require(xfer, "ERR_ERC20_FALSE"); bPool.rebind(erc20, BalancerSafeMath.badd(tokenBalance, amount), tokenWeight); } // Rebind BPool and push tokens to address // bPool is a contract interface; function calls on it are external function _pushUnderlying(address erc20, address to, uint amount) internal needsBPool { // Gets current Balance of token i, Bi, and weight of token i, Wi, from BPool. uint tokenBalance = bPool.getBalance(erc20); uint tokenWeight = bPool.getDenormalizedWeight(erc20); bPool.rebind(erc20, BalancerSafeMath.bsub(tokenBalance, amount), tokenWeight); bool xfer = IERC20(erc20).transfer(to, amount); require(xfer, "ERR_ERC20_FALSE"); } // Wrappers around corresponding core functions // function _mint(uint amount) internal override { super._mint(amount); require(varTotalSupply <= bspCap, "ERR_CAP_LIMIT_REACHED"); } function _mintPoolShare(uint amount) internal { _mint(amount); } function _pushPoolShare(address to, uint amount) internal { _push(to, amount); } function _pullPoolShare(address from, uint amount) internal { _pull(from, amount); } function _burnPoolShare(uint amount) internal { _burn(amount); } } // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; interface IBPool { function rebind(address token, uint balance, uint denorm) external; function setSwapFee(uint swapFee) external; function setPublicSwap(bool publicSwap) external; function bind(address token, uint balance, uint denorm) external; function unbind(address token) external; function gulp(address token) external; function isBound(address token) external view returns(bool); function getBalance(address token) external view returns (uint); function totalSupply() external view returns (uint); function getSwapFee() external view returns (uint); function isPublicSwap() external view returns (bool); function getDenormalizedWeight(address token) external view returns (uint); function getTotalDenormalizedWeight() external view returns (uint); // solhint-disable-next-line func-name-mixedcase function EXIT_FEE() external view returns (uint); function calcPoolOutGivenSingleIn( uint tokenBalanceIn, uint tokenWeightIn, uint poolSupply, uint totalWeight, uint tokenAmountIn, uint swapFee ) external pure returns (uint poolAmountOut); function calcSingleInGivenPoolOut( uint tokenBalanceIn, uint tokenWeightIn, uint poolSupply, uint totalWeight, uint poolAmountOut, uint swapFee ) external pure returns (uint tokenAmountIn); function calcSingleOutGivenPoolIn( uint tokenBalanceOut, uint tokenWeightOut, uint poolSupply, uint totalWeight, uint poolAmountIn, uint swapFee ) external pure returns (uint tokenAmountOut); function calcPoolInGivenSingleOut( uint tokenBalanceOut, uint tokenWeightOut, uint poolSupply, uint totalWeight, uint tokenAmountOut, uint swapFee ) external pure returns (uint poolAmountIn); function getCurrentTokens() external view returns (address[] memory tokens); } interface IBFactory { function newBPool() external returns (IBPool); function setBLabs(address b) external; function collect(IBPool pool) external; function isBPool(address b) external view returns (bool); function getBLabs() external view returns (address); } // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; // Imports import "../libraries/BalancerSafeMath.sol"; import "../interfaces/IERC20.sol"; // Contracts /* solhint-disable func-order */ /** * @author Balancer Labs * @title Highly opinionated token implementation */ contract PCToken is IERC20 { using BalancerSafeMath for uint; // State variables string public constant NAME = "Balancer Smart Pool"; uint8 public constant DECIMALS = 18; // No leading underscore per naming convention (non-private) // Cannot call totalSupply (name conflict) // solhint-disable-next-line private-vars-leading-underscore uint internal varTotalSupply; mapping(address => uint) private _balance; mapping(address => mapping(address => uint)) private _allowance; string private _symbol; string private _name; // Event declarations // See definitions above; must be redeclared to be emitted from this contract event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); // Function declarations /** * @notice Base token constructor * @param tokenSymbol - the token symbol */ constructor (string memory tokenSymbol, string memory tokenName) public { _symbol = tokenSymbol; _name = tokenName; } // External functions /** * @notice Getter for allowance: amount spender will be allowed to spend on behalf of owner * @param owner - owner of the tokens * @param spender - entity allowed to spend the tokens * @return uint - remaining amount spender is allowed to transfer */ function allowance(address owner, address spender) external view override returns (uint) { return _allowance[owner][spender]; } /** * @notice Getter for current account balance * @param account - address we're checking the balance of * @return uint - token balance in the account */ function balanceOf(address account) external view override returns (uint) { return _balance[account]; } /** * @notice Approve owner (sender) to spend a certain amount * @dev emits an Approval event * @param spender - entity the owner (sender) is approving to spend his tokens * @param amount - number of tokens being approved * @return bool - result of the approval (will always be true if it doesn't revert) */ function approve(address spender, uint amount) external override returns (bool) { /* In addition to the increase/decreaseApproval functions, could avoid the "approval race condition" by only allowing calls to approve when the current approval amount is 0 require(_allowance[msg.sender][spender] == 0, "ERR_RACE_CONDITION"); Some token contracts (e.g., KNC), already revert if you call approve on a non-zero allocation. To deal with these, we use the SafeApprove library and safeApprove function when adding tokens to the pool. */ _allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } /** * @notice Increase the amount the spender is allowed to spend on behalf of the owner (sender) * @dev emits an Approval event * @param spender - entity the owner (sender) is approving to spend his tokens * @param amount - number of tokens being approved * @return bool - result of the approval (will always be true if it doesn't revert) */ function increaseApproval(address spender, uint amount) external returns (bool) { _allowance[msg.sender][spender] = BalancerSafeMath.badd(_allowance[msg.sender][spender], amount); emit Approval(msg.sender, spender, _allowance[msg.sender][spender]); return true; } /** * @notice Decrease the amount the spender is allowed to spend on behalf of the owner (sender) * @dev emits an Approval event * @dev If you try to decrease it below the current limit, it's just set to zero (not an error) * @param spender - entity the owner (sender) is approving to spend his tokens * @param amount - number of tokens being approved * @return bool - result of the approval (will always be true if it doesn't revert) */ function decreaseApproval(address spender, uint amount) external returns (bool) { uint oldValue = _allowance[msg.sender][spender]; // Gas optimization - if amount == oldValue (or is larger), set to zero immediately if (amount >= oldValue) { _allowance[msg.sender][spender] = 0; } else { _allowance[msg.sender][spender] = BalancerSafeMath.bsub(oldValue, amount); } emit Approval(msg.sender, spender, _allowance[msg.sender][spender]); return true; } /** * @notice Transfer the given amount from sender (caller) to recipient * @dev _move emits a Transfer event if successful * @param recipient - entity receiving the tokens * @param amount - number of tokens being transferred * @return bool - result of the transfer (will always be true if it doesn't revert) */ function transfer(address recipient, uint amount) external override returns (bool) { require(recipient != address(0), "ERR_ZERO_ADDRESS"); _move(msg.sender, recipient, amount); return true; } /** * @notice Transfer the given amount from sender to recipient * @dev _move emits a Transfer event if successful; may also emit an Approval event * @param sender - entity sending the tokens (must be caller or allowed to spend on behalf of caller) * @param recipient - recipient of the tokens * @param amount - number of tokens being transferred * @return bool - result of the transfer (will always be true if it doesn't revert) */ function transferFrom(address sender, address recipient, uint amount) external override returns (bool) { require(recipient != address(0), "ERR_ZERO_ADDRESS"); require(msg.sender == sender || amount <= _allowance[sender][msg.sender], "ERR_PCTOKEN_BAD_CALLER"); _move(sender, recipient, amount); // memoize for gas optimization uint oldAllowance = _allowance[sender][msg.sender]; // If the sender is not the caller, adjust the allowance by the amount transferred if (msg.sender != sender && oldAllowance != uint(-1)) { _allowance[sender][msg.sender] = BalancerSafeMath.bsub(oldAllowance, amount); emit Approval(msg.sender, recipient, _allowance[sender][msg.sender]); } return true; } // public functions /** * @notice Getter for the total supply * @dev declared external for gas optimization * @return uint - total number of tokens in existence */ function totalSupply() external view override returns (uint) { return varTotalSupply; } // Public functions /** * @dev Returns the name of the token. * We allow the user to set this name (as well as the symbol). * Alternatives are 1) A fixed string (original design) * 2) A fixed string plus the user-defined symbol * return string(abi.encodePacked(NAME, "-", _symbol)); */ function name() external view returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() external view returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is * called. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() external pure returns (uint8) { return DECIMALS; } // internal functions // Mint an amount of new tokens, and add them to the balance (and total supply) // Emit a transfer amount from the null address to this contract function _mint(uint amount) internal virtual { _balance[address(this)] = BalancerSafeMath.badd(_balance[address(this)], amount); varTotalSupply = BalancerSafeMath.badd(varTotalSupply, amount); emit Transfer(address(0), address(this), amount); } // Burn an amount of new tokens, and subtract them from the balance (and total supply) // Emit a transfer amount from this contract to the null address function _burn(uint amount) internal virtual { // Can't burn more than we have // Remove require for gas optimization - bsub will revert on underflow // require(_balance[address(this)] >= amount, "ERR_INSUFFICIENT_BAL"); _balance[address(this)] = BalancerSafeMath.bsub(_balance[address(this)], amount); varTotalSupply = BalancerSafeMath.bsub(varTotalSupply, amount); emit Transfer(address(this), address(0), amount); } // Transfer tokens from sender to recipient // Adjust balances, and emit a Transfer event function _move(address sender, address recipient, uint amount) internal virtual { // Can't send more than sender has // Remove require for gas optimization - bsub will revert on underflow // require(_balance[sender] >= amount, "ERR_INSUFFICIENT_BAL"); _balance[sender] = BalancerSafeMath.bsub(_balance[sender], amount); _balance[recipient] = BalancerSafeMath.badd(_balance[recipient], amount); emit Transfer(sender, recipient, amount); } // Transfer from this contract to recipient // Emits a transfer event if successful function _push(address recipient, uint amount) internal { _move(address(this), recipient, amount); } // Transfer from recipient to this contract // Emits a transfer event if successful function _pull(address sender, uint amount) internal { _move(sender, address(this), amount); } } // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; // Imports import "./BalancerConstants.sol"; /** * @author Balancer Labs * @title SafeMath - wrap Solidity operators to prevent underflow/overflow * @dev badd and bsub are basically identical to OpenZeppelin SafeMath; mul/div have extra checks */ library BalancerSafeMath { /** * @notice Safe addition * @param a - first operand * @param b - second operand * @dev if we are adding b to a, the resulting sum must be greater than a * @return - sum of operands; throws if overflow */ function badd(uint a, uint b) internal pure returns (uint) { uint c = a + b; require(c >= a, "ERR_ADD_OVERFLOW"); return c; } /** * @notice Safe unsigned subtraction * @param a - first operand * @param b - second operand * @dev Do a signed subtraction, and check that it produces a positive value * (i.e., a - b is valid if b <= a) * @return - a - b; throws if underflow */ function bsub(uint a, uint b) internal pure returns (uint) { (uint c, bool negativeResult) = bsubSign(a, b); require(!negativeResult, "ERR_SUB_UNDERFLOW"); return c; } /** * @notice Safe signed subtraction * @param a - first operand * @param b - second operand * @dev Do a signed subtraction * @return - difference between a and b, and a flag indicating a negative result * (i.e., a - b if a is greater than or equal to b; otherwise b - a) */ function bsubSign(uint a, uint b) internal pure returns (uint, bool) { if (b <= a) { return (a - b, false); } else { return (b - a, true); } } /** * @notice Safe multiplication * @param a - first operand * @param b - second operand * @dev Multiply safely (and efficiently), rounding down * @return - product of operands; throws if overflow or rounding error */ function bmul(uint a, uint b) internal pure returns (uint) { // Gas optimization (see github.com/OpenZeppelin/openzeppelin-contracts/pull/522) if (a == 0) { return 0; } // Standard overflow check: a/a*b=b uint c0 = a * b; require(c0 / a == b, "ERR_MUL_OVERFLOW"); // Round to 0 if x*y < BONE/2? uint c1 = c0 + (BalancerConstants.BONE / 2); require(c1 >= c0, "ERR_MUL_OVERFLOW"); uint c2 = c1 / BalancerConstants.BONE; return c2; } /** * @notice Safe division * @param dividend - first operand * @param divisor - second operand * @dev Divide safely (and efficiently), rounding down * @return - quotient; throws if overflow or rounding error */ function bdiv(uint dividend, uint divisor) internal pure returns (uint) { require(divisor != 0, "ERR_DIV_ZERO"); // Gas optimization if (dividend == 0){ return 0; } uint c0 = dividend * BalancerConstants.BONE; require(c0 / dividend == BalancerConstants.BONE, "ERR_DIV_INTERNAL"); // bmul overflow uint c1 = c0 + (divisor / 2); require(c1 >= c0, "ERR_DIV_INTERNAL"); // badd require uint c2 = c1 / divisor; return c2; } /** * @notice Safe unsigned integer modulo * @dev Returns the remainder of dividing two unsigned integers. * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * @param dividend - first operand * @param divisor - second operand -- cannot be zero * @return - quotient; throws if overflow or rounding error */ function bmod(uint dividend, uint divisor) internal pure returns (uint) { require(divisor != 0, "ERR_MODULO_BY_ZERO"); return dividend % divisor; } /** * @notice Safe unsigned integer max * @dev Returns the greater of the two input values * * @param a - first operand * @param b - second operand * @return - the maximum of a and b */ function bmax(uint a, uint b) internal pure returns (uint) { return a >= b ? a : b; } /** * @notice Safe unsigned integer min * @dev returns b, if b < a; otherwise returns a * * @param a - first operand * @param b - second operand * @return - the lesser of the two input values */ function bmin(uint a, uint b) internal pure returns (uint) { return a < b ? a : b; } /** * @notice Safe unsigned integer average * @dev Guard against (a+b) overflow by dividing each operand separately * * @param a - first operand * @param b - second operand * @return - the average of the two values */ function baverage(uint a, uint b) internal pure returns (uint) { // (a + b) / 2 can overflow, so we distribute return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2); } /** * @notice Babylonian square root implementation * @dev (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method) * @param y - operand * @return z - the square root result */ function sqrt(uint y) internal pure returns (uint z) { if (y > 3) { z = y; uint x = y / 2 + 1; while (x < z) { z = x; x = (y / x + x) / 2; } } else if (y != 0) { z = 1; } } } // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; /** * @author Balancer Labs * @title Put all the constants in one place */ library BalancerConstants { // State variables (must be constant in a library) // B "ONE" - all math is in the "realm" of 10 ** 18; // where numeric 1 = 10 ** 18 uint public constant BONE = 10**18; uint public constant MIN_WEIGHT = BONE; uint public constant MAX_WEIGHT = BONE * 50; uint public constant MAX_TOTAL_WEIGHT = BONE * 50; uint public constant MIN_BALANCE = BONE / 10**6; uint public constant MAX_BALANCE = BONE * 10**12; uint public constant MIN_POOL_SUPPLY = BONE * 100; uint public constant MAX_POOL_SUPPLY = BONE * 10**9; uint public constant MIN_FEE = BONE / 10**6; uint public constant MAX_FEE = BONE / 10; // EXIT_FEE must always be zero, or ConfigurableRightsPool._pushUnderlying will fail uint public constant EXIT_FEE = 0; uint public constant MAX_IN_RATIO = BONE / 2; uint public constant MAX_OUT_RATIO = (BONE / 3) + 1 wei; // Must match BConst.MIN_BOUND_TOKENS and BConst.MAX_BOUND_TOKENS uint public constant MIN_ASSET_LIMIT = 2; uint public constant MAX_ASSET_LIMIT = 8; uint public constant MAX_UINT = uint(-1); } // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; // Interface declarations /* solhint-disable func-order */ interface IERC20 { // Emitted when the allowance of a spender for an owner is set by a call to approve. // Value is the new allowance event Approval(address indexed owner, address indexed spender, uint value); // Emitted when value tokens are moved from one account (from) to another (to). // Note that value may be zero event Transfer(address indexed from, address indexed to, uint value); // Returns the amount of tokens in existence function totalSupply() external view returns (uint); // Returns the amount of tokens owned by account function balanceOf(address account) external view returns (uint); // Returns the remaining number of tokens that spender will be allowed to spend on behalf of owner // through transferFrom. This is zero by default // This value changes when approve or transferFrom are called function allowance(address owner, address spender) external view returns (uint); // Sets amount as the allowance of spender over the caller’s tokens // Returns a boolean value indicating whether the operation succeeded // Emits an Approval event. function approve(address spender, uint amount) external returns (bool); // Moves amount tokens from the caller’s account to recipient // Returns a boolean value indicating whether the operation succeeded // Emits a Transfer event. function transfer(address recipient, uint amount) external returns (bool); // Moves amount tokens from sender to recipient using the allowance mechanism // Amount is then deducted from the caller’s allowance // Returns a boolean value indicating whether the operation succeeded // Emits a Transfer event function transferFrom(address sender, address recipient, uint amount) external returns (bool); } // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; /** * @author Balancer Labs (and OpenZeppelin) * @title Protect against reentrant calls (and also selectively protect view functions) * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {_lock_} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `_lock_` guard, functions marked as * `_lock_` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `_lock_` entry * points to them. * * Also adds a _lockview_ modifier, which doesn't create a lock, but fails * if another _lock_ call is in progress */ contract BalancerReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint private constant _NOT_ENTERED = 1; uint private constant _ENTERED = 2; uint private _status; constructor () internal { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `_lock_` function from another `_lock_` * function is not supported. It is possible to prevent this from happening * by making the `_lock_` function external, and make it call a * `private` function that does the actual work. */ modifier lock() { // On the first call to _lock_, _notEntered will be true require(_status != _ENTERED, "ERR_REENTRY"); // Any calls to _lock_ after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Also add a modifier that doesn't create a lock, but protects functions that * should not be called while a _lock_ function is running */ modifier viewlock() { require(_status != _ENTERED, "ERR_REENTRY_VIEW"); _; } } // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ contract BalancerOwnable { // State variables address private _owner; // Event declarations event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); // Modifiers /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(_owner == msg.sender, "ERR_NOT_CONTROLLER"); _; } // Function declarations /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor () internal { _owner = msg.sender; } /** * @notice Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner * @dev external for gas optimization * @param newOwner - address of new owner */ function setController(address newOwner) external onlyOwner { require(newOwner != address(0), "ERR_ZERO_ADDRESS"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } /** * @notice Returns the address of the current owner * @dev external for gas optimization * @return address - of the owner (AKA controller) */ function getController() external view returns (address) { return _owner; } } // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; // Needed to handle structures externally pragma experimental ABIEncoderV2; /** * @author Balancer Labs * @title Manage Configurable Rights for the smart pool * canPauseSwapping - can setPublicSwap back to false after turning it on * by default, it is off on initialization and can only be turned on * canChangeSwapFee - can setSwapFee after initialization (by default, it is fixed at create time) * canChangeWeights - can bind new token weights (allowed by default in base pool) * canAddRemoveTokens - can bind/unbind tokens (allowed by default in base pool) * canWhitelistLPs - can limit liquidity providers to a given set of addresses * canChangeCap - can change the BSP cap (max # of pool tokens) */ library RightsManager { // Type declarations enum Permissions { PAUSE_SWAPPING, CHANGE_SWAP_FEE, CHANGE_WEIGHTS, ADD_REMOVE_TOKENS, WHITELIST_LPS, CHANGE_CAP } struct Rights { bool canPauseSwapping; bool canChangeSwapFee; bool canChangeWeights; bool canAddRemoveTokens; bool canWhitelistLPs; bool canChangeCap; } // State variables (can only be constants in a library) bool public constant DEFAULT_CAN_PAUSE_SWAPPING = false; bool public constant DEFAULT_CAN_CHANGE_SWAP_FEE = true; bool public constant DEFAULT_CAN_CHANGE_WEIGHTS = true; bool public constant DEFAULT_CAN_ADD_REMOVE_TOKENS = false; bool public constant DEFAULT_CAN_WHITELIST_LPS = false; bool public constant DEFAULT_CAN_CHANGE_CAP = false; // Functions /** * @notice create a struct from an array (or return defaults) * @dev If you pass an empty array, it will construct it using the defaults * @param a - array input * @return Rights struct */ function constructRights(bool[] calldata a) external pure returns (Rights memory) { if (a.length == 0) { return Rights(DEFAULT_CAN_PAUSE_SWAPPING, DEFAULT_CAN_CHANGE_SWAP_FEE, DEFAULT_CAN_CHANGE_WEIGHTS, DEFAULT_CAN_ADD_REMOVE_TOKENS, DEFAULT_CAN_WHITELIST_LPS, DEFAULT_CAN_CHANGE_CAP); } else { return Rights(a[0], a[1], a[2], a[3], a[4], a[5]); } } /** * @notice Convert rights struct to an array (e.g., for events, GUI) * @dev avoids multiple calls to hasPermission * @param rights - the rights struct to convert * @return boolean array containing the rights settings */ function convertRights(Rights calldata rights) external pure returns (bool[] memory) { bool[] memory result = new bool[](6); result[0] = rights.canPauseSwapping; result[1] = rights.canChangeSwapFee; result[2] = rights.canChangeWeights; result[3] = rights.canAddRemoveTokens; result[4] = rights.canWhitelistLPs; result[5] = rights.canChangeCap; return result; } // Though it is actually simple, the number of branches triggers code-complexity /* solhint-disable code-complexity */ /** * @notice Externally check permissions using the Enum * @param self - Rights struct containing the permissions * @param permission - The permission to check * @return Boolean true if it has the permission */ function hasPermission(Rights calldata self, Permissions permission) external pure returns (bool) { if (Permissions.PAUSE_SWAPPING == permission) { return self.canPauseSwapping; } else if (Permissions.CHANGE_SWAP_FEE == permission) { return self.canChangeSwapFee; } else if (Permissions.CHANGE_WEIGHTS == permission) { return self.canChangeWeights; } else if (Permissions.ADD_REMOVE_TOKENS == permission) { return self.canAddRemoveTokens; } else if (Permissions.WHITELIST_LPS == permission) { return self.canWhitelistLPs; } else if (Permissions.CHANGE_CAP == permission) { return self.canChangeCap; } } /* solhint-enable code-complexity */ } // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; // Needed to pass in structs pragma experimental ABIEncoderV2; // Imports import "../interfaces/IERC20.sol"; import "../interfaces/IConfigurableRightsPool.sol"; import "../contracts/IBFactory.sol"; import "./BalancerSafeMath.sol"; import "./SafeApprove.sol"; /** * @author Balancer Labs * @title Factor out the weight updates */ library SmartPoolManager { // Type declarations struct NewTokenParams { address addr; bool isCommitted; uint commitBlock; uint denorm; uint balance; } // For blockwise, automated weight updates // Move weights linearly from startWeights to endWeights, // between startBlock and endBlock struct GradualUpdateParams { uint startBlock; uint endBlock; uint[] startWeights; uint[] endWeights; } // updateWeight and pokeWeights are unavoidably long /* solhint-disable function-max-lines */ /** * @notice Update the weight of an existing token * @dev Refactored to library to make CRPFactory deployable * @param self - ConfigurableRightsPool instance calling the library * @param bPool - Core BPool the CRP is wrapping * @param token - token to be reweighted * @param newWeight - new weight of the token */ function updateWeight( IConfigurableRightsPool self, IBPool bPool, address token, uint newWeight ) external { require(newWeight >= BalancerConstants.MIN_WEIGHT, "ERR_MIN_WEIGHT"); require(newWeight <= BalancerConstants.MAX_WEIGHT, "ERR_MAX_WEIGHT"); uint currentWeight = bPool.getDenormalizedWeight(token); // Save gas; return immediately on NOOP if (currentWeight == newWeight) { return; } uint currentBalance = bPool.getBalance(token); uint totalSupply = self.totalSupply(); uint totalWeight = bPool.getTotalDenormalizedWeight(); uint poolShares; uint deltaBalance; uint deltaWeight; uint newBalance; if (newWeight < currentWeight) { // This means the controller will withdraw tokens to keep price // So they need to redeem PCTokens deltaWeight = BalancerSafeMath.bsub(currentWeight, newWeight); // poolShares = totalSupply * (deltaWeight / totalWeight) poolShares = BalancerSafeMath.bmul(totalSupply, BalancerSafeMath.bdiv(deltaWeight, totalWeight)); // deltaBalance = currentBalance * (deltaWeight / currentWeight) deltaBalance = BalancerSafeMath.bmul(currentBalance, BalancerSafeMath.bdiv(deltaWeight, currentWeight)); // New balance cannot be lower than MIN_BALANCE newBalance = BalancerSafeMath.bsub(currentBalance, deltaBalance); require(newBalance >= BalancerConstants.MIN_BALANCE, "ERR_MIN_BALANCE"); // First get the tokens from this contract (Pool Controller) to msg.sender bPool.rebind(token, newBalance, newWeight); // Now with the tokens this contract can send them to msg.sender bool xfer = IERC20(token).transfer(msg.sender, deltaBalance); require(xfer, "ERR_ERC20_FALSE"); self.pullPoolShareFromLib(msg.sender, poolShares); self.burnPoolShareFromLib(poolShares); } else { // This means the controller will deposit tokens to keep the price. // They will be minted and given PCTokens deltaWeight = BalancerSafeMath.bsub(newWeight, currentWeight); require(BalancerSafeMath.badd(totalWeight, deltaWeight) <= BalancerConstants.MAX_TOTAL_WEIGHT, "ERR_MAX_TOTAL_WEIGHT"); // poolShares = totalSupply * (deltaWeight / totalWeight) poolShares = BalancerSafeMath.bmul(totalSupply, BalancerSafeMath.bdiv(deltaWeight, totalWeight)); // deltaBalance = currentBalance * (deltaWeight / currentWeight) deltaBalance = BalancerSafeMath.bmul(currentBalance, BalancerSafeMath.bdiv(deltaWeight, currentWeight)); // First gets the tokens from msg.sender to this contract (Pool Controller) bool xfer = IERC20(token).transferFrom(msg.sender, address(this), deltaBalance); require(xfer, "ERR_ERC20_FALSE"); // Now with the tokens this contract can bind them to the pool it controls bPool.rebind(token, BalancerSafeMath.badd(currentBalance, deltaBalance), newWeight); self.mintPoolShareFromLib(poolShares); self.pushPoolShareFromLib(msg.sender, poolShares); } } /** * @notice External function called to make the contract update weights according to plan * @param bPool - Core BPool the CRP is wrapping * @param gradualUpdate - gradual update parameters from the CRP */ function pokeWeights( IBPool bPool, GradualUpdateParams storage gradualUpdate ) external { // Do nothing if we call this when there is no update plan if (gradualUpdate.startBlock == 0) { return; } // Error to call it before the start of the plan require(block.number >= gradualUpdate.startBlock, "ERR_CANT_POKE_YET"); // Proposed error message improvement // require(block.number >= startBlock, "ERR_NO_HOKEY_POKEY"); // This allows for pokes after endBlock that get weights to endWeights // Get the current block (or the endBlock, if we're already past the end) uint currentBlock; if (block.number > gradualUpdate.endBlock) { currentBlock = gradualUpdate.endBlock; } else { currentBlock = block.number; } uint blockPeriod = BalancerSafeMath.bsub(gradualUpdate.endBlock, gradualUpdate.startBlock); uint blocksElapsed = BalancerSafeMath.bsub(currentBlock, gradualUpdate.startBlock); uint weightDelta; uint deltaPerBlock; uint newWeight; address[] memory tokens = bPool.getCurrentTokens(); // This loop contains external calls // External calls are to math libraries or the underlying pool, so low risk for (uint i = 0; i < tokens.length; i++) { // Make sure it does nothing if the new and old weights are the same (saves gas) // It's a degenerate case if they're *all* the same, but you certainly could have // a plan where you only change some of the weights in the set if (gradualUpdate.startWeights[i] != gradualUpdate.endWeights[i]) { if (gradualUpdate.endWeights[i] < gradualUpdate.startWeights[i]) { // We are decreasing the weight // First get the total weight delta weightDelta = BalancerSafeMath.bsub(gradualUpdate.startWeights[i], gradualUpdate.endWeights[i]); // And the amount it should change per block = total change/number of blocks in the period deltaPerBlock = BalancerSafeMath.bdiv(weightDelta, blockPeriod); //deltaPerBlock = bdivx(weightDelta, blockPeriod); // newWeight = startWeight - (blocksElapsed * deltaPerBlock) newWeight = BalancerSafeMath.bsub(gradualUpdate.startWeights[i], BalancerSafeMath.bmul(blocksElapsed, deltaPerBlock)); } else { // We are increasing the weight // First get the total weight delta weightDelta = BalancerSafeMath.bsub(gradualUpdate.endWeights[i], gradualUpdate.startWeights[i]); // And the amount it should change per block = total change/number of blocks in the period deltaPerBlock = BalancerSafeMath.bdiv(weightDelta, blockPeriod); //deltaPerBlock = bdivx(weightDelta, blockPeriod); // newWeight = startWeight + (blocksElapsed * deltaPerBlock) newWeight = BalancerSafeMath.badd(gradualUpdate.startWeights[i], BalancerSafeMath.bmul(blocksElapsed, deltaPerBlock)); } uint bal = bPool.getBalance(tokens[i]); bPool.rebind(tokens[i], bal, newWeight); } } // Reset to allow add/remove tokens, or manual weight updates if (block.number >= gradualUpdate.endBlock) { gradualUpdate.startBlock = 0; } } /* solhint-enable function-max-lines */ /** * @notice Schedule (commit) a token to be added; must call applyAddToken after a fixed * number of blocks to actually add the token * @param bPool - Core BPool the CRP is wrapping * @param token - the token to be added * @param balance - how much to be added * @param denormalizedWeight - the desired token weight * @param newToken - NewTokenParams struct used to hold the token data (in CRP storage) */ function commitAddToken( IBPool bPool, address token, uint balance, uint denormalizedWeight, NewTokenParams storage newToken ) external { require(!bPool.isBound(token), "ERR_IS_BOUND"); require(denormalizedWeight <= BalancerConstants.MAX_WEIGHT, "ERR_WEIGHT_ABOVE_MAX"); require(denormalizedWeight >= BalancerConstants.MIN_WEIGHT, "ERR_WEIGHT_BELOW_MIN"); require(BalancerSafeMath.badd(bPool.getTotalDenormalizedWeight(), denormalizedWeight) <= BalancerConstants.MAX_TOTAL_WEIGHT, "ERR_MAX_TOTAL_WEIGHT"); require(balance >= BalancerConstants.MIN_BALANCE, "ERR_BALANCE_BELOW_MIN"); newToken.addr = token; newToken.balance = balance; newToken.denorm = denormalizedWeight; newToken.commitBlock = block.number; newToken.isCommitted = true; } /** * @notice Add the token previously committed (in commitAddToken) to the pool * @param self - ConfigurableRightsPool instance calling the library * @param bPool - Core BPool the CRP is wrapping * @param addTokenTimeLockInBlocks - Wait time between committing and applying a new token * @param newToken - NewTokenParams struct used to hold the token data (in CRP storage) */ function applyAddToken( IConfigurableRightsPool self, IBPool bPool, uint addTokenTimeLockInBlocks, NewTokenParams storage newToken ) external { require(newToken.isCommitted, "ERR_NO_TOKEN_COMMIT"); require(BalancerSafeMath.bsub(block.number, newToken.commitBlock) >= addTokenTimeLockInBlocks, "ERR_TIMELOCK_STILL_COUNTING"); uint totalSupply = self.totalSupply(); // poolShares = totalSupply * newTokenWeight / totalWeight uint poolShares = BalancerSafeMath.bdiv(BalancerSafeMath.bmul(totalSupply, newToken.denorm), bPool.getTotalDenormalizedWeight()); // Clear this to allow adding more tokens newToken.isCommitted = false; // First gets the tokens from msg.sender to this contract (Pool Controller) bool returnValue = IERC20(newToken.addr).transferFrom(self.getController(), address(self), newToken.balance); require(returnValue, "ERR_ERC20_FALSE"); // Now with the tokens this contract can bind them to the pool it controls // Approves bPool to pull from this controller // Approve unlimited, same as when creating the pool, so they can join pools later returnValue = SafeApprove.safeApprove(IERC20(newToken.addr), address(bPool), BalancerConstants.MAX_UINT); require(returnValue, "ERR_ERC20_FALSE"); bPool.bind(newToken.addr, newToken.balance, newToken.denorm); self.mintPoolShareFromLib(poolShares); self.pushPoolShareFromLib(msg.sender, poolShares); } /** * @notice Remove a token from the pool * @dev Logic in the CRP controls when ths can be called. There are two related permissions: * AddRemoveTokens - which allows removing down to the underlying BPool limit of two * RemoveAllTokens - which allows completely draining the pool by removing all tokens * This can result in a non-viable pool with 0 or 1 tokens (by design), * meaning all swapping or binding operations would fail in this state * @param self - ConfigurableRightsPool instance calling the library * @param bPool - Core BPool the CRP is wrapping * @param token - token to remove */ function removeToken( IConfigurableRightsPool self, IBPool bPool, address token ) external { uint totalSupply = self.totalSupply(); // poolShares = totalSupply * tokenWeight / totalWeight uint poolShares = BalancerSafeMath.bdiv(BalancerSafeMath.bmul(totalSupply, bPool.getDenormalizedWeight(token)), bPool.getTotalDenormalizedWeight()); // this is what will be unbound from the pool // Have to get it before unbinding uint balance = bPool.getBalance(token); // Unbind and get the tokens out of balancer pool bPool.unbind(token); // Now with the tokens this contract can send them to msg.sender bool xfer = IERC20(token).transfer(self.getController(), balance); require(xfer, "ERR_ERC20_FALSE"); self.pullPoolShareFromLib(self.getController(), poolShares); self.burnPoolShareFromLib(poolShares); } /** * @notice Non ERC20-conforming tokens are problematic; don't allow them in pools * @dev Will revert if invalid * @param token - The prospective token to verify */ function verifyTokenCompliance(address token) external { verifyTokenComplianceInternal(token); } /** * @notice Non ERC20-conforming tokens are problematic; don't allow them in pools * @dev Will revert if invalid - overloaded to save space in the main contract * @param tokens - The prospective tokens to verify */ function verifyTokenCompliance(address[] calldata tokens) external { for (uint i = 0; i < tokens.length; i++) { verifyTokenComplianceInternal(tokens[i]); } } /** * @notice Update weights in a predetermined way, between startBlock and endBlock, * through external cals to pokeWeights * @param bPool - Core BPool the CRP is wrapping * @param newWeights - final weights we want to get to * @param startBlock - when weights should start to change * @param endBlock - when weights will be at their final values * @param minimumWeightChangeBlockPeriod - needed to validate the block period */ function updateWeightsGradually( IBPool bPool, GradualUpdateParams storage gradualUpdate, uint[] calldata newWeights, uint startBlock, uint endBlock, uint minimumWeightChangeBlockPeriod ) external { require(block.number < endBlock, "ERR_GRADUAL_UPDATE_TIME_TRAVEL"); if (block.number > startBlock) { // This means the weight update should start ASAP // Moving the start block up prevents a big jump/discontinuity in the weights gradualUpdate.startBlock = block.number; } else{ gradualUpdate.startBlock = startBlock; } // Enforce a minimum time over which to make the changes // The also prevents endBlock <= startBlock require(BalancerSafeMath.bsub(endBlock, gradualUpdate.startBlock) >= minimumWeightChangeBlockPeriod, "ERR_WEIGHT_CHANGE_TIME_BELOW_MIN"); address[] memory tokens = bPool.getCurrentTokens(); // Must specify weights for all tokens require(newWeights.length == tokens.length, "ERR_START_WEIGHTS_MISMATCH"); uint weightsSum = 0; gradualUpdate.startWeights = new uint[](tokens.length); // Check that endWeights are valid now to avoid reverting in a future pokeWeights call // // This loop contains external calls // External calls are to math libraries or the underlying pool, so low risk for (uint i = 0; i < tokens.length; i++) { require(newWeights[i] <= BalancerConstants.MAX_WEIGHT, "ERR_WEIGHT_ABOVE_MAX"); require(newWeights[i] >= BalancerConstants.MIN_WEIGHT, "ERR_WEIGHT_BELOW_MIN"); weightsSum = BalancerSafeMath.badd(weightsSum, newWeights[i]); gradualUpdate.startWeights[i] = bPool.getDenormalizedWeight(tokens[i]); } require(weightsSum <= BalancerConstants.MAX_TOTAL_WEIGHT, "ERR_MAX_TOTAL_WEIGHT"); gradualUpdate.endBlock = endBlock; gradualUpdate.endWeights = newWeights; } /** * @notice Join a pool * @param self - ConfigurableRightsPool instance calling the library * @param bPool - Core BPool the CRP is wrapping * @param poolAmountOut - number of pool tokens to receive * @param maxAmountsIn - Max amount of asset tokens to spend * @return actualAmountsIn - calculated values of the tokens to pull in */ function joinPool( IConfigurableRightsPool self, IBPool bPool, uint poolAmountOut, uint[] calldata maxAmountsIn ) external view returns (uint[] memory actualAmountsIn) { address[] memory tokens = bPool.getCurrentTokens(); require(maxAmountsIn.length == tokens.length, "ERR_AMOUNTS_MISMATCH"); uint poolTotal = self.totalSupply(); // Subtract 1 to ensure any rounding errors favor the pool uint ratio = BalancerSafeMath.bdiv(poolAmountOut, BalancerSafeMath.bsub(poolTotal, 1)); require(ratio != 0, "ERR_MATH_APPROX"); // We know the length of the array; initialize it, and fill it below // Cannot do "push" in memory actualAmountsIn = new uint[](tokens.length); // This loop contains external calls // External calls are to math libraries or the underlying pool, so low risk for (uint i = 0; i < tokens.length; i++) { address t = tokens[i]; uint bal = bPool.getBalance(t); // Add 1 to ensure any rounding errors favor the pool uint tokenAmountIn = BalancerSafeMath.bmul(ratio, BalancerSafeMath.badd(bal, 1)); require(tokenAmountIn != 0, "ERR_MATH_APPROX"); require(tokenAmountIn <= maxAmountsIn[i], "ERR_LIMIT_IN"); actualAmountsIn[i] = tokenAmountIn; } } /** * @notice Exit a pool - redeem pool tokens for underlying assets * @param self - ConfigurableRightsPool instance calling the library * @param bPool - Core BPool the CRP is wrapping * @param poolAmountIn - amount of pool tokens to redeem * @param minAmountsOut - minimum amount of asset tokens to receive * @return exitFee - calculated exit fee * @return pAiAfterExitFee - final amount in (after accounting for exit fee) * @return actualAmountsOut - calculated amounts of each token to pull */ function exitPool( IConfigurableRightsPool self, IBPool bPool, uint poolAmountIn, uint[] calldata minAmountsOut ) external view returns (uint exitFee, uint pAiAfterExitFee, uint[] memory actualAmountsOut) { address[] memory tokens = bPool.getCurrentTokens(); require(minAmountsOut.length == tokens.length, "ERR_AMOUNTS_MISMATCH"); uint poolTotal = self.totalSupply(); // Calculate exit fee and the final amount in exitFee = BalancerSafeMath.bmul(poolAmountIn, BalancerConstants.EXIT_FEE); pAiAfterExitFee = BalancerSafeMath.bsub(poolAmountIn, exitFee); uint ratio = BalancerSafeMath.bdiv(pAiAfterExitFee, BalancerSafeMath.badd(poolTotal, 1)); require(ratio != 0, "ERR_MATH_APPROX"); actualAmountsOut = new uint[](tokens.length); // This loop contains external calls // External calls are to math libraries or the underlying pool, so low risk for (uint i = 0; i < tokens.length; i++) { address t = tokens[i]; uint bal = bPool.getBalance(t); // Subtract 1 to ensure any rounding errors favor the pool uint tokenAmountOut = BalancerSafeMath.bmul(ratio, BalancerSafeMath.bsub(bal, 1)); require(tokenAmountOut != 0, "ERR_MATH_APPROX"); require(tokenAmountOut >= minAmountsOut[i], "ERR_LIMIT_OUT"); actualAmountsOut[i] = tokenAmountOut; } } /** * @notice Join by swapping a fixed amount of an external token in (must be present in the pool) * System calculates the pool token amount * @param self - ConfigurableRightsPool instance calling the library * @param bPool - Core BPool the CRP is wrapping * @param tokenIn - which token we're transferring in * @param tokenAmountIn - amount of deposit * @param minPoolAmountOut - minimum of pool tokens to receive * @return poolAmountOut - amount of pool tokens minted and transferred */ function joinswapExternAmountIn( IConfigurableRightsPool self, IBPool bPool, address tokenIn, uint tokenAmountIn, uint minPoolAmountOut ) external view returns (uint poolAmountOut) { require(bPool.isBound(tokenIn), "ERR_NOT_BOUND"); require(tokenAmountIn <= BalancerSafeMath.bmul(bPool.getBalance(tokenIn), BalancerConstants.MAX_IN_RATIO), "ERR_MAX_IN_RATIO"); poolAmountOut = bPool.calcPoolOutGivenSingleIn( bPool.getBalance(tokenIn), bPool.getDenormalizedWeight(tokenIn), self.totalSupply(), bPool.getTotalDenormalizedWeight(), tokenAmountIn, bPool.getSwapFee() ); require(poolAmountOut >= minPoolAmountOut, "ERR_LIMIT_OUT"); } /** * @notice Join by swapping an external token in (must be present in the pool) * To receive an exact amount of pool tokens out. System calculates the deposit amount * @param self - ConfigurableRightsPool instance calling the library * @param bPool - Core BPool the CRP is wrapping * @param tokenIn - which token we're transferring in (system calculates amount required) * @param poolAmountOut - amount of pool tokens to be received * @param maxAmountIn - Maximum asset tokens that can be pulled to pay for the pool tokens * @return tokenAmountIn - amount of asset tokens transferred in to purchase the pool tokens */ function joinswapPoolAmountOut( IConfigurableRightsPool self, IBPool bPool, address tokenIn, uint poolAmountOut, uint maxAmountIn ) external view returns (uint tokenAmountIn) { require(bPool.isBound(tokenIn), "ERR_NOT_BOUND"); tokenAmountIn = bPool.calcSingleInGivenPoolOut( bPool.getBalance(tokenIn), bPool.getDenormalizedWeight(tokenIn), self.totalSupply(), bPool.getTotalDenormalizedWeight(), poolAmountOut, bPool.getSwapFee() ); require(tokenAmountIn != 0, "ERR_MATH_APPROX"); require(tokenAmountIn <= maxAmountIn, "ERR_LIMIT_IN"); require(tokenAmountIn <= BalancerSafeMath.bmul(bPool.getBalance(tokenIn), BalancerConstants.MAX_IN_RATIO), "ERR_MAX_IN_RATIO"); } /** * @notice Exit a pool - redeem a specific number of pool tokens for an underlying asset * Asset must be present in the pool, and will incur an EXIT_FEE (if set to non-zero) * @param self - ConfigurableRightsPool instance calling the library * @param bPool - Core BPool the CRP is wrapping * @param tokenOut - which token the caller wants to receive * @param poolAmountIn - amount of pool tokens to redeem * @param minAmountOut - minimum asset tokens to receive * @return exitFee - calculated exit fee * @return tokenAmountOut - amount of asset tokens returned */ function exitswapPoolAmountIn( IConfigurableRightsPool self, IBPool bPool, address tokenOut, uint poolAmountIn, uint minAmountOut ) external view returns (uint exitFee, uint tokenAmountOut) { require(bPool.isBound(tokenOut), "ERR_NOT_BOUND"); tokenAmountOut = bPool.calcSingleOutGivenPoolIn( bPool.getBalance(tokenOut), bPool.getDenormalizedWeight(tokenOut), self.totalSupply(), bPool.getTotalDenormalizedWeight(), poolAmountIn, bPool.getSwapFee() ); require(tokenAmountOut >= minAmountOut, "ERR_LIMIT_OUT"); require(tokenAmountOut <= BalancerSafeMath.bmul(bPool.getBalance(tokenOut), BalancerConstants.MAX_OUT_RATIO), "ERR_MAX_OUT_RATIO"); exitFee = BalancerSafeMath.bmul(poolAmountIn, BalancerConstants.EXIT_FEE); } /** * @notice Exit a pool - redeem pool tokens for a specific amount of underlying assets * Asset must be present in the pool * @param self - ConfigurableRightsPool instance calling the library * @param bPool - Core BPool the CRP is wrapping * @param tokenOut - which token the caller wants to receive * @param tokenAmountOut - amount of underlying asset tokens to receive * @param maxPoolAmountIn - maximum pool tokens to be redeemed * @return exitFee - calculated exit fee * @return poolAmountIn - amount of pool tokens redeemed */ function exitswapExternAmountOut( IConfigurableRightsPool self, IBPool bPool, address tokenOut, uint tokenAmountOut, uint maxPoolAmountIn ) external view returns (uint exitFee, uint poolAmountIn) { require(bPool.isBound(tokenOut), "ERR_NOT_BOUND"); require(tokenAmountOut <= BalancerSafeMath.bmul(bPool.getBalance(tokenOut), BalancerConstants.MAX_OUT_RATIO), "ERR_MAX_OUT_RATIO"); poolAmountIn = bPool.calcPoolInGivenSingleOut( bPool.getBalance(tokenOut), bPool.getDenormalizedWeight(tokenOut), self.totalSupply(), bPool.getTotalDenormalizedWeight(), tokenAmountOut, bPool.getSwapFee() ); require(poolAmountIn != 0, "ERR_MATH_APPROX"); require(poolAmountIn <= maxPoolAmountIn, "ERR_LIMIT_IN"); exitFee = BalancerSafeMath.bmul(poolAmountIn, BalancerConstants.EXIT_FEE); } // Internal functions // Check for zero transfer, and make sure it returns true to returnValue function verifyTokenComplianceInternal(address token) internal { bool returnValue = IERC20(token).transfer(msg.sender, 0); require(returnValue, "ERR_NONCONFORMING_TOKEN"); } } // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; // Interface declarations // Introduce to avoid circularity (otherwise, the CRP and SmartPoolManager include each other) // Removing circularity allows flattener tools to work, which enables Etherscan verification interface IConfigurableRightsPool { function mintPoolShareFromLib(uint amount) external; function pushPoolShareFromLib(address to, uint amount) external; function pullPoolShareFromLib(address from, uint amount) external; function burnPoolShareFromLib(uint amount) external; function totalSupply() external view returns (uint); function getController() external view returns (address); } // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; // Imports import "../interfaces/IERC20.sol"; // Libraries /** * @author PieDAO (ported to Balancer Labs) * @title SafeApprove - set approval for tokens that require 0 prior approval * @dev Perhaps to address the known ERC20 race condition issue * See https://github.com/crytic/not-so-smart-contracts/tree/master/race_condition * Some tokens - notably KNC - only allow approvals to be increased from 0 */ library SafeApprove { /** * @notice handle approvals of tokens that require approving from a base of 0 * @param token - the token we're approving * @param spender - entity the owner (sender) is approving to spend his tokens * @param amount - number of tokens being approved */ function safeApprove(IERC20 token, address spender, uint amount) internal returns (bool) { uint currentAllowance = token.allowance(address(this), spender); // Do nothing if allowance is already set to this value if(currentAllowance == amount) { return true; } // If approval is not zero reset it to zero first if(currentAllowance != 0) { return token.approve(spender, 0); } // do the actual approval return token.approve(spender, amount); } } // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; // Needed to handle structures externally pragma experimental ABIEncoderV2; // Imports import "./ConfigurableRightsPool.sol"; // Contracts /** * @author Balancer Labs * @title Configurable Rights Pool Factory - create parameterized smart pools * @dev Rights are held in a corresponding struct in ConfigurableRightsPool * Index values are as follows: * 0: canPauseSwapping - can setPublicSwap back to false after turning it on * by default, it is off on initialization and can only be turned on * 1: canChangeSwapFee - can setSwapFee after initialization (by default, it is fixed at create time) * 2: canChangeWeights - can bind new token weights (allowed by default in base pool) * 3: canAddRemoveTokens - can bind/unbind tokens (allowed by default in base pool) * 4: canWhitelistLPs - if set, only whitelisted addresses can join pools * (enables private pools with more than one LP) * 5: canChangeCap - can change the BSP cap (max # of pool tokens) */ contract CRPFactory { // State variables // Keep a list of all Configurable Rights Pools mapping(address=>bool) private _isCrp; // Event declarations // Log the address of each new smart pool, and its creator event LogNewCrp( address indexed caller, address indexed pool ); // Function declarations /** * @notice Create a new CRP * @dev emits a LogNewCRP event * @param factoryAddress - the BFactory instance used to create the underlying pool * @param poolParams - struct containing the names, tokens, weights, balances, and swap fee * @param rights - struct of permissions, configuring this CRP instance (see above for definitions) */ function newCrp( address factoryAddress, ConfigurableRightsPool.PoolParams calldata poolParams, RightsManager.Rights calldata rights ) external returns (ConfigurableRightsPool) { require(poolParams.constituentTokens.length >= BalancerConstants.MIN_ASSET_LIMIT, "ERR_TOO_FEW_TOKENS"); // Arrays must be parallel require(poolParams.tokenBalances.length == poolParams.constituentTokens.length, "ERR_START_BALANCES_MISMATCH"); require(poolParams.tokenWeights.length == poolParams.constituentTokens.length, "ERR_START_WEIGHTS_MISMATCH"); ConfigurableRightsPool crp = new ConfigurableRightsPool( factoryAddress, poolParams, rights ); emit LogNewCrp(msg.sender, address(crp)); _isCrp[address(crp)] = true; // The caller is the controller of the CRP // The CRP will be the controller of the underlying Core BPool crp.setController(msg.sender); return crp; } /** * @notice Check to see if a given address is a CRP * @param addr - address to check * @return boolean indicating whether it is a CRP */ function isCrp(address addr) external view returns (bool) { return _isCrp[addr]; } } // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; contract Migrations { address public owner; uint public lastCompletedMigration; constructor() public { owner = msg.sender; } modifier restricted() { if (msg.sender == owner) _; } /** * @notice set lastCompletedMigration variable * @param completed - id of the desired migration level */ function setCompleted(uint completed) external restricted { lastCompletedMigration = completed; } } // SPDX-License-Identifier: MIT pragma solidity 0.6.12; // Imports import "../../libraries/BalancerSafeMath.sol"; // Contracts /* * @author Balancer Labs * @title Wrap BalancerSafeMath for testing */ contract BalancerSafeMathMock { function bmul(uint a, uint b) external pure returns (uint) { return BalancerSafeMath.bmul(a, b); } function bdiv(uint a, uint b) external pure returns (uint) { return BalancerSafeMath.bdiv(a, b); } function bsub(uint a, uint b) external pure returns (uint) { return BalancerSafeMath.bsub(a, b); } function badd(uint a, uint b) external pure returns (uint) { return BalancerSafeMath.badd(a, b); } function bmod(uint a, uint b) external pure returns (uint) { return BalancerSafeMath.bmod(a, b); } function bmax(uint a, uint b) external pure returns (uint) { return BalancerSafeMath.bmax(a, b); } function bmin(uint a, uint b) external pure returns (uint) { return BalancerSafeMath.bmin(a, b); } function baverage(uint a, uint b) external pure returns (uint) { return BalancerSafeMath.baverage(a, b); } }// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; // Needed to handle structures externally pragma experimental ABIEncoderV2; // Imports import "../IBFactory.sol"; import "../PCToken.sol"; import "../utils/BalancerReentrancyGuard.sol"; import "../utils/BalancerOwnable.sol"; import "../ConfigurableRightsPool.sol"; // Interfaces // Libraries import { RightsManager } from "../../libraries/RightsManager.sol"; // Contracts /** * @author Ampleforth engineering team & Balancer Labs * * Reference: * https://github.com/balancer-labs/configurable-rights-pool/blob/master/contracts/templates/ElasticSupplyPool.sol * * @title Ampl Elastic Configurable Rights Pool. * * @dev Extension of Balancer labs' configurable rights pool (smart-pool). * Amples are a dynamic supply tokens, supply and individual balances change daily by a Rebase operation. * In constant-function markets, Ampleforth's supply adjustments result in Impermanent Loss (IL) * to liquidity providers. The AmplElasticCRP is an extension of Balancer Lab's * ConfigurableRightsPool which mitigates IL induced by supply adjustments. * * It accomplishes this by doing the following mechanism: * The `resyncWeight` method will be invoked atomically after rebase through Ampleforth's orchestrator. * * When rebase changes supply, ampl weight is updated to the geometric mean of * the current ampl weight and the target. Every other token's weight is updated * proportionally such that relative ratios are same. * * Weights: {w_ampl, w_t1 ... w_tn} * * Rebase_change: x% (Ample's supply changes by x%, can be positive or negative) * * Ample target weight: w_ampl_target = (100+x)/100 * w_ampl * * w_ampl_new = sqrt(w_ampl * w_ampl_target) // geometric mean * for i in tn: * w_ti_new = (w_ampl_new * w_ti) / w_ampl_target * */ contract ElasticSupplyPool is ConfigurableRightsPool { using BalancerSafeMath for uint; // Event declarations // Have to redeclare in the subclass, to be emitted from this contract event LogCall( bytes4 indexed sig, address indexed caller, bytes data ) anonymous; event LogJoin( address indexed caller, address indexed tokenIn, uint tokenAmountIn ); event LogExit( address indexed caller, address indexed tokenOut, uint tokenAmountOut ); // Modifiers // Function declarations /** * @notice Construct a new Configurable Rights Pool (wrapper around BPool) * @param factoryAddress - the BPoolFactory used to create the underlying pool * @param poolParams - CRP pool parameters * @param rightsParams - Set of permissions we are assigning to this smart pool */ constructor( address factoryAddress, ConfigurableRightsPool.PoolParams memory poolParams, RightsManager.Rights memory rightsParams ) // solhint-disable-next-line visibility-modifier-order public ConfigurableRightsPool(factoryAddress, poolParams, rightsParams) { require(rightsParams.canChangeWeights, "ERR_NOT_CONFIGURABLE_WEIGHTS"); } // External functions /** * @notice ElasticSupply pools don't have updateWeightsGradually, so cannot call this * param initialSupply starting token balance * param minimumWeightChangeBlockPeriod - Enforce a minimum time between the start and end blocks * param addTokenTimeLockInBlocks - Enforce a mandatory wait time between updates * This is also the wait time between committing and applying a new token */ function createPool( uint, // initialSupply uint, // minimumWeightChangeBlockPeriod uint // addTokenTimeLockInBlocks ) external override { revert("ERR_UNSUPPORTED_OPERATION"); } /** * @notice Update the weight of an existing token - cannot do this in ElasticSupplyPools * param token - token to be reweighted * param newWeight - new weight of the token */ function updateWeight( address, // token uint // newWeight ) external logs onlyOwner needsBPool override { revert("ERR_UNSUPPORTED_OPERATION"); } /** * @notice Update weights in a predetermined way, between startBlock and endBlock, * through external calls to pokeWeights -- cannot do this in ElasticSupplyPools * @dev Makes sure we aren't already in a weight update scheme * Must call pokeWeights at least once past the end for it to do the final update * and enable calling this again. (Could make this check for that case, but unwarranted complexity.) * param newWeights - final weights we want to get to * param startBlock - when weights should start to change * param endBlock - when weights will be at their final values */ function updateWeightsGradually( uint[] calldata, // newWeights uint, // startBlock uint // endBlock ) external logs onlyOwner needsBPool override { revert("ERR_UNSUPPORTED_OPERATION"); } /** * @notice External function called to make the contract update weights according to plan * Unsupported in ElasticSupplyPools */ function pokeWeights() external logs needsBPool override { revert("ERR_UNSUPPORTED_OPERATION"); } /** * @notice Update the weight of a token without changing the price (or transferring tokens) * @param token The address of the token in the underlying BPool to be weight adjusted. * @dev Checks if the token's current pool balance has deviated from cached balance, * if so it adjusts the token's weights proportional to the deviation. * The underlying BPool enforces bounds on MIN_WEIGHTS=1e18, MAX_WEIGHT=50e18 and TOTAL_WEIGHT=50e18. * NOTE: The BPool.rebind function CAN REVERT if the updated weights go beyond the enforced bounds. */ function resyncWeight(address token) external logs lock needsBPool virtual { require(gradualUpdate.startBlock == 0, "ERR_NO_UPDATE_DURING_GRADUAL"); require(IBPool(address(bPool)).isBound(token), "ERR_NOT_BOUND"); // get cached balance uint tokenBalanceBefore = IBPool(address(bPool)).getBalance(token); // sync balance IBPool(address(bPool)).gulp(token); // get new balance uint tokenBalanceAfter = IBPool(address(bPool)).getBalance(token); // No-Op if(tokenBalanceBefore == tokenBalanceAfter) { return; } // current token weight uint tokenWeightBefore = IBPool(address(bPool)).getDenormalizedWeight(token); // target token weight = RebaseRatio * previous token weight uint tokenWeightTarget = BalancerSafeMath.bdiv( BalancerSafeMath.bmul(tokenWeightBefore, tokenBalanceAfter), tokenBalanceBefore ); // new token weight = sqrt(current token weight * target token weight) uint tokenWeightAfter = BalancerSafeMath.sqrt( BalancerSafeMath.bdiv( BalancerSafeMath.bmul(tokenWeightBefore, tokenWeightTarget), 1 ) ); address[] memory tokens = IBPool(address(bPool)).getCurrentTokens(); for(uint i=0; i<tokens.length; i++){ if(tokens[i] == token) { // adjust weight IBPool(address(bPool)).rebind(token, tokenBalanceAfter, tokenWeightAfter); } else { uint otherWeightBefore = IBPool(address(bPool)).getDenormalizedWeight(tokens[i]); uint otherBalance = bPool.getBalance(tokens[i]); // other token weight = (new token weight * other token weight before) / target token weight uint otherWeightAfter = BalancerSafeMath.bdiv( BalancerSafeMath.bmul(tokenWeightAfter, otherWeightBefore), tokenWeightTarget ); // adjust weight IBPool(address(bPool)).rebind(tokens[i], otherBalance, otherWeightAfter); } } } } // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; // Needed to handle structures externally pragma experimental ABIEncoderV2; // Imports import "./ElasticSupplyPool.sol"; // Contracts /** * @author Balancer Labs * @title Configurable Rights Pool Factory - create parameterized smart pools * @dev Rights are held in a corresponding struct in ConfigurableRightsPool * Index values are as follows: * 0: canPauseSwapping - can setPublicSwap back to false after turning it on * by default, it is off on initialization and can only be turned on * 1: canChangeSwapFee - can setSwapFee after initialization (by default, it is fixed at create time) * 2: canChangeWeights - can bind new token weights (allowed by default in base pool) * 3: canAddRemoveTokens - can bind/unbind tokens (allowed by default in base pool) * 4: canWhitelistLPs - if set, only whitelisted addresses can join pools * (enables private pools with more than one LP) */ contract ESPFactory { // State variables // Keep a list of all Elastic Supply Pools mapping(address => bool) private _isEsp; // Event declarations // Log the address of each new smart pool, and its creator event LogNewEsp( address indexed caller, address indexed pool ); // Function declarations /** * @notice Create a new ESP * @dev emits a LogNewESP event * @param factoryAddress - the BFactory instance used to create the underlying pool * @param poolParams - CRP pool parameters * @param rights - struct of permissions, configuring this CRP instance (see above for definitions) */ function newEsp( address factoryAddress, ConfigurableRightsPool.PoolParams calldata poolParams, RightsManager.Rights calldata rights ) external returns (ElasticSupplyPool) { require(poolParams.constituentTokens.length >= BalancerConstants.MIN_ASSET_LIMIT, "ERR_TOO_FEW_TOKENS"); // Arrays must be parallel require(poolParams.tokenBalances.length == poolParams.constituentTokens.length, "ERR_START_BALANCES_MISMATCH"); require(poolParams.tokenWeights.length == poolParams.constituentTokens.length, "ERR_START_WEIGHTS_MISMATCH"); ElasticSupplyPool esp = new ElasticSupplyPool( factoryAddress, poolParams, rights ); emit LogNewEsp(msg.sender, address(esp)); _isEsp[address(esp)] = true; esp.setController(msg.sender); return esp; } /** * @notice Check to see if a given address is an ESP * @param addr - address to check * @return boolean indicating whether it is an ESP */ function isEsp(address addr) external view returns (bool) { return _isEsp[addr]; } } // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.6.6; contract BadToken { string internal _name; string internal _symbol; uint8 internal _decimals; address internal _owner; uint internal _totalSupply; mapping(address => uint) internal _balance; mapping(address => mapping(address=>uint)) internal _allowance; modifier _onlyOwner_() { require(msg.sender == _owner, "ERR_NOT_OWNER"); _; } event Approval(address indexed src, address indexed dst, uint amt); event Transfer(address indexed src, address indexed dst, uint amt); /* solhint-disable private-vars-leading-underscore */ // Math function add(uint a, uint b) internal pure returns (uint c) { require((c = a + b) >= a, "ERR_ADD"); } function sub(uint a, uint b) internal pure returns (uint c) { require((c = a - b) <= a, "ERR_SUB"); } /* solhint-disable func-order */ constructor( string memory name, string memory symbol, uint8 decimals ) public { _name = name; _symbol = symbol; _decimals = decimals; _owner = msg.sender; } function name() public view returns (string memory) { return _name; } function symbol() public view returns (string memory) { return _symbol; } function decimals() public view returns(uint8) { return _decimals; } function _move(address src, address dst, uint amt) internal virtual { // Fail if trying to transfer 0 //require(amt > 0, "ERR_NO_ZERO_XFER"); require(_balance[src] >= amt, "ERR_INSUFFICIENT_BAL"); _balance[src] = sub(_balance[src], amt); _balance[dst] = add(_balance[dst], amt); emit Transfer(src, dst, amt); } function _push(address to, uint amt) internal { _move(address(this), to, amt); } function _pull(address from, uint amt) internal { _move(from, address(this), amt); } function _mint(address dst, uint amt) internal { _balance[dst] = add(_balance[dst], amt); _totalSupply = add(_totalSupply, amt); emit Transfer(address(0), dst, amt); } function allowance(address src, address dst) external view returns (uint) { return _allowance[src][dst]; } function balanceOf(address whom) external view returns (uint) { return _balance[whom]; } function totalSupply() public view returns (uint) { return _totalSupply; } function approve(address dst, uint amt) external virtual returns (bool) { // Fail if prior approval is not zero //require(_allowance[msg.sender][dst] == 0, "ERR_PRIOR_ZERO_APPROVE"); _allowance[msg.sender][dst] = amt; emit Approval(msg.sender, dst, amt); return true; } function mint(address dst, uint256 amt) public _onlyOwner_ returns (bool) { _mint(dst, amt); return true; } function burn(uint amt) public returns (bool) { require(_balance[address(this)] >= amt, "ERR_INSUFFICIENT_BAL"); _balance[address(this)] = sub(_balance[address(this)], amt); _totalSupply = sub(_totalSupply, amt); emit Transfer(address(this), address(0), amt); return true; } function transfer(address dst, uint amt) external virtual returns (bool) { _move(msg.sender, dst, amt); return true; } function transferFrom(address src, address dst, uint amt) external virtual 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] = sub(_allowance[src][msg.sender], amt); emit Approval(msg.sender, dst, _allowance[src][msg.sender]); } return true; } } /* solhint-disable no-empty-blocks */ contract NoZeroXferToken is BadToken { constructor( string memory name, string memory symbol, uint8 decimals ) public BadToken(name, symbol, decimals) { } function _move(address src, address dst, uint amt) internal override { // Fail if trying to transfer 0 require(amt > 0, "ERR_NO_ZERO_XFER"); require(_balance[src] >= amt, "ERR_INSUFFICIENT_BAL"); _balance[src] = sub(_balance[src], amt); _balance[dst] = add(_balance[dst], amt); emit Transfer(src, dst, amt); } } contract NoPriorApprovalToken is BadToken { constructor( string memory name, string memory symbol, uint8 decimals ) public BadToken(name, symbol, decimals) { } function approve(address dst, uint amt) external override returns (bool) { // Fail if prior approval is not zero require(_allowance[msg.sender][dst] == 0, "ERR_PRIOR_ZERO_APPROVE"); _allowance[msg.sender][dst] = amt; emit Approval(msg.sender, dst, amt); return true; } } contract FalseReturningToken is BadToken { constructor( string memory name, string memory symbol, uint8 decimals ) public BadToken(name, symbol, decimals) { } function transfer(address dst, uint amt) external override returns (bool) { _move(msg.sender, dst, amt); // Don't return anything (or return false; same result) } function transferFrom(address src, address dst, uint amt) external override 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] = sub(_allowance[src][msg.sender], amt); emit Approval(msg.sender, dst, _allowance[src][msg.sender]); } return false; } } contract TaxingToken is BadToken { constructor( string memory name, string memory symbol, uint8 decimals ) public BadToken(name, symbol, decimals) { } function transfer(address dst, uint amt) external override returns (bool) { _move(msg.sender, dst, amt - 1); return true; } function transferFrom(address src, address dst, uint amt) external override returns (bool) { require(msg.sender == src || amt <= _allowance[src][msg.sender], "ERR_BTOKEN_BAD_CALLER"); _move(src, dst, amt - 1); if (msg.sender != src && _allowance[src][msg.sender] != uint256(-1)) { _allowance[src][msg.sender] = sub(_allowance[src][msg.sender], amt - 1); emit Approval(msg.sender, dst, _allowance[src][msg.sender]); } return true; } }// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.6.6; // abstract contract BColor { // function getColor() // external view virtual // returns (bytes32); // } contract BBronze { function getColor() external view returns (bytes32) { return bytes32("BRONZE"); } } // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.6.6; import "./BColor.sol"; contract BConst is BBronze { uint public constant BONE = 10**18; uint public constant MIN_BOUND_TOKENS = 2; uint public constant MAX_BOUND_TOKENS = 8; uint public constant MIN_FEE = BONE / 10**6; uint public constant MAX_FEE = BONE / 10; uint public constant EXIT_FEE = 0; uint public constant MIN_WEIGHT = BONE; uint public constant MAX_WEIGHT = BONE * 50; uint public constant MAX_TOTAL_WEIGHT = BONE * 50; uint public constant MIN_BALANCE = BONE / 10**12; uint public constant INIT_POOL_SUPPLY = BONE * 100; uint public constant MIN_BPOW_BASE = 1 wei; uint public constant MAX_BPOW_BASE = (2 * BONE) - 1 wei; uint public constant BPOW_PRECISION = BONE / 10**10; uint public constant MAX_IN_RATIO = BONE / 2; uint public constant MAX_OUT_RATIO = (BONE / 3) + 1 wei; } // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.6.6; // Builds new BPools, logging their addresses and providing `isBPool(address) -> (bool)` import "./BPool.sol"; // Core contract; can't be changed. So disable solhint (reminder for v2) /* solhint-disable func-order */ /* solhint-disable event-name-camelcase */ contract BFactory is BBronze { event LOG_NEW_POOL( address indexed caller, address indexed pool ); event LOG_BLABS( address indexed caller, address indexed blabs ); mapping(address=>bool) private _isBPool; function isBPool(address b) external view returns (bool) { return _isBPool[b]; } function newBPool() external returns (BPool) { BPool bpool = new BPool(); _isBPool[address(bpool)] = true; emit LOG_NEW_POOL(msg.sender, address(bpool)); bpool.setController(msg.sender); return bpool; } address private _blabs; constructor() public { _blabs = msg.sender; } function getBLabs() external view returns (address) { return _blabs; } function setBLabs(address b) external { require(msg.sender == _blabs, "ERR_NOT_BLABS"); emit LOG_BLABS(msg.sender, b); _blabs = b; } function collect(BPool pool) external { require(msg.sender == _blabs, "ERR_NOT_BLABS"); uint collected = IERC20(pool).balanceOf(address(this)); bool xfer = pool.transfer(_blabs, collected); require(xfer, "ERR_ERC20_FAILED"); } } // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.6.6; import "./BToken.sol"; import "./BMath.sol"; // Core contract; can't be changed. So disable solhint (reminder for v2) /* solhint-disable func-order */ /* solhint-disable event-name-camelcase */ contract BPool is BBronze, BToken, BMath { struct Record { bool bound; // is token bound to pool uint index; // private uint denorm; // denormalized weight uint balance; } event LOG_SWAP( address indexed caller, address indexed tokenIn, address indexed tokenOut, uint256 tokenAmountIn, uint256 tokenAmountOut ); event LOG_JOIN( address indexed caller, address indexed tokenIn, uint256 tokenAmountIn ); event LOG_EXIT( address indexed caller, address indexed tokenOut, uint256 tokenAmountOut ); 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 private _factory; // BFactory address to push token exitFee to address private _controller; // has CONTROL role bool private _publicSwap; // true if PUBLIC can call SWAP functions // `setSwapFee` and `finalize` require CONTROL // `finalize` sets `PUBLIC can SWAP`, `PUBLIC can JOIN` uint private _swapFee; bool private _finalized; address[] private _tokens; mapping(address=>Record) private _records; uint private _totalWeight; constructor() public { _controller = msg.sender; _factory = msg.sender; _swapFee = MIN_FEE; _publicSwap = false; _finalized = false; } function isPublicSwap() external view returns (bool) { return _publicSwap; } function isFinalized() external view returns (bool) { return _finalized; } function isBound(address t) external view returns (bool) { return _records[t].bound; } function getNumTokens() external view returns (uint) { return _tokens.length; } function getCurrentTokens() external view _viewlock_ returns (address[] memory tokens) { return _tokens; } function getFinalTokens() external view _viewlock_ returns (address[] memory tokens) { require(_finalized, "ERR_NOT_FINALIZED"); return _tokens; } function getDenormalizedWeight(address token) external view _viewlock_ returns (uint) { require(_records[token].bound, "ERR_NOT_BOUND"); return _records[token].denorm; } function getTotalDenormalizedWeight() external view _viewlock_ returns (uint) { return _totalWeight; } function getNormalizedWeight(address token) external view _viewlock_ returns (uint) { require(_records[token].bound, "ERR_NOT_BOUND"); uint denorm = _records[token].denorm; return bdiv(denorm, _totalWeight); } function getBalance(address token) external view _viewlock_ returns (uint) { require(_records[token].bound, "ERR_NOT_BOUND"); return _records[token].balance; } function getSwapFee() external view _viewlock_ returns (uint) { return _swapFee; } function getController() external view _viewlock_ returns (address) { return _controller; } function setSwapFee(uint swapFee) external _logs_ _lock_ { require(!_finalized, "ERR_IS_FINALIZED"); require(msg.sender == _controller, "ERR_NOT_CONTROLLER"); require(swapFee >= MIN_FEE, "ERR_MIN_FEE"); require(swapFee <= MAX_FEE, "ERR_MAX_FEE"); _swapFee = swapFee; } function setController(address manager) external _logs_ _lock_ { require(msg.sender == _controller, "ERR_NOT_CONTROLLER"); _controller = manager; } function setPublicSwap(bool public_) external _logs_ _lock_ { require(!_finalized, "ERR_IS_FINALIZED"); require(msg.sender == _controller, "ERR_NOT_CONTROLLER"); _publicSwap = public_; } function finalize() external _logs_ _lock_ { require(msg.sender == _controller, "ERR_NOT_CONTROLLER"); require(!_finalized, "ERR_IS_FINALIZED"); require(_tokens.length >= MIN_BOUND_TOKENS, "ERR_MIN_TOKENS"); _finalized = true; _publicSwap = true; _mintPoolShare(INIT_POOL_SUPPLY); _pushPoolShare(msg.sender, INIT_POOL_SUPPLY); } function bind(address token, uint balance, uint denorm) external _logs_ // _lock_ Bind does not lock because it jumps to `rebind`, which does { 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"); _records[token] = Record({ bound: true, index: _tokens.length, denorm: 0, // balance and denorm will be validated balance: 0 // and set by `rebind` }); _tokens.push(token); rebind(token, balance, denorm); } function rebind(address token, uint balance, uint denorm) public _logs_ _lock_ { require(msg.sender == _controller, "ERR_NOT_CONTROLLER"); require(_records[token].bound, "ERR_NOT_BOUND"); require(!_finalized, "ERR_IS_FINALIZED"); require(denorm >= MIN_WEIGHT, "ERR_MIN_WEIGHT"); require(denorm <= MAX_WEIGHT, "ERR_MAX_WEIGHT"); require(balance >= MIN_BALANCE, "ERR_MIN_BALANCE"); // Adjust the denorm and totalWeight uint oldWeight = _records[token].denorm; if (denorm > oldWeight) { _totalWeight = badd(_totalWeight, bsub(denorm, oldWeight)); require(_totalWeight <= MAX_TOTAL_WEIGHT, "ERR_MAX_TOTAL_WEIGHT"); } else if (denorm < oldWeight) { _totalWeight = bsub(_totalWeight, bsub(oldWeight, denorm)); } _records[token].denorm = denorm; // Adjust the balance record and actual token balance uint oldBalance = _records[token].balance; _records[token].balance = balance; if (balance > oldBalance) { _pullUnderlying(token, msg.sender, bsub(balance, oldBalance)); } else if (balance < oldBalance) { // In this case liquidity is being withdrawn, so charge EXIT_FEE uint tokenBalanceWithdrawn = bsub(oldBalance, balance); uint tokenExitFee = bmul(tokenBalanceWithdrawn, EXIT_FEE); _pushUnderlying(token, msg.sender, bsub(tokenBalanceWithdrawn, tokenExitFee)); _pushUnderlying(token, _factory, tokenExitFee); } } function unbind(address token) external _logs_ _lock_ { require(msg.sender == _controller, "ERR_NOT_CONTROLLER"); require(_records[token].bound, "ERR_NOT_BOUND"); require(!_finalized, "ERR_IS_FINALIZED"); uint tokenBalance = _records[token].balance; uint tokenExitFee = bmul(tokenBalance, EXIT_FEE); _totalWeight = bsub(_totalWeight, _records[token].denorm); // Swap the token-to-unbind with the last token, // then delete the last token uint index = _records[token].index; uint last = _tokens.length - 1; _tokens[index] = _tokens[last]; _records[_tokens[index]].index = index; _tokens.pop(); _records[token] = Record({ bound: false, index: 0, denorm: 0, balance: 0 }); _pushUnderlying(token, msg.sender, bsub(tokenBalance, tokenExitFee)); _pushUnderlying(token, _factory, tokenExitFee); } // 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 (uint 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 calcSpotPrice(inRecord.balance, inRecord.denorm, outRecord.balance, outRecord.denorm, _swapFee); } function getSpotPriceSansFee(address tokenIn, address tokenOut) external view _viewlock_ returns (uint 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 calcSpotPrice(inRecord.balance, inRecord.denorm, outRecord.balance, outRecord.denorm, 0); } function joinPool(uint poolAmountOut, uint[] calldata maxAmountsIn) external _logs_ _lock_ { require(_finalized, "ERR_NOT_FINALIZED"); uint poolTotal = totalSupply(); uint ratio = bdiv(poolAmountOut, poolTotal); require(ratio != 0, "ERR_MATH_APPROX"); for (uint i = 0; i < _tokens.length; i++) { address t = _tokens[i]; uint bal = _records[t].balance; uint tokenAmountIn = bmul(ratio, bal); require(tokenAmountIn != 0, "ERR_MATH_APPROX"); require(tokenAmountIn <= maxAmountsIn[i], "ERR_LIMIT_IN"); _records[t].balance = badd(_records[t].balance, tokenAmountIn); emit LOG_JOIN(msg.sender, t, tokenAmountIn); _pullUnderlying(t, msg.sender, tokenAmountIn); } _mintPoolShare(poolAmountOut); _pushPoolShare(msg.sender, poolAmountOut); } function exitPool(uint poolAmountIn, uint[] calldata minAmountsOut) external _logs_ _lock_ { require(_finalized, "ERR_NOT_FINALIZED"); uint poolTotal = totalSupply(); uint exitFee = bmul(poolAmountIn, EXIT_FEE); uint pAiAfterExitFee = bsub(poolAmountIn, exitFee); uint ratio = bdiv(pAiAfterExitFee, poolTotal); require(ratio != 0, "ERR_MATH_APPROX"); _pullPoolShare(msg.sender, poolAmountIn); _pushPoolShare(_factory, exitFee); _burnPoolShare(pAiAfterExitFee); for (uint i = 0; i < _tokens.length; i++) { address t = _tokens[i]; uint bal = _records[t].balance; uint tokenAmountOut = bmul(ratio, bal); require(tokenAmountOut != 0, "ERR_MATH_APPROX"); require(tokenAmountOut >= minAmountsOut[i], "ERR_LIMIT_OUT"); _records[t].balance = bsub(_records[t].balance, tokenAmountOut); emit LOG_EXIT(msg.sender, t, tokenAmountOut); _pushUnderlying(t, msg.sender, tokenAmountOut); } } function swapExactAmountIn( address tokenIn, uint tokenAmountIn, address tokenOut, uint minAmountOut, uint maxPrice ) external _logs_ _lock_ returns (uint tokenAmountOut, uint spotPriceAfter) { require(_records[tokenIn].bound, "ERR_NOT_BOUND"); require(_records[tokenOut].bound, "ERR_NOT_BOUND"); require(_publicSwap, "ERR_SWAP_NOT_PUBLIC"); Record storage inRecord = _records[address(tokenIn)]; Record storage outRecord = _records[address(tokenOut)]; require(tokenAmountIn <= bmul(inRecord.balance, MAX_IN_RATIO), "ERR_MAX_IN_RATIO"); uint spotPriceBefore = 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"); inRecord.balance = badd(inRecord.balance, tokenAmountIn); outRecord.balance = bsub(outRecord.balance, tokenAmountOut); spotPriceAfter = calcSpotPrice( inRecord.balance, inRecord.denorm, outRecord.balance, outRecord.denorm, _swapFee ); require(spotPriceAfter >= spotPriceBefore, "ERR_MATH_APPROX"); require(spotPriceAfter <= maxPrice, "ERR_LIMIT_PRICE"); require(spotPriceBefore <= bdiv(tokenAmountIn, tokenAmountOut), "ERR_MATH_APPROX"); emit LOG_SWAP(msg.sender, tokenIn, tokenOut, tokenAmountIn, tokenAmountOut); _pullUnderlying(tokenIn, msg.sender, tokenAmountIn); _pushUnderlying(tokenOut, msg.sender, tokenAmountOut); return (tokenAmountOut, spotPriceAfter); } function swapExactAmountOut( address tokenIn, uint maxAmountIn, address tokenOut, uint tokenAmountOut, uint maxPrice ) external _logs_ _lock_ returns (uint tokenAmountIn, uint spotPriceAfter) { require(_records[tokenIn].bound, "ERR_NOT_BOUND"); require(_records[tokenOut].bound, "ERR_NOT_BOUND"); require(_publicSwap, "ERR_SWAP_NOT_PUBLIC"); Record storage inRecord = _records[address(tokenIn)]; Record storage outRecord = _records[address(tokenOut)]; require(tokenAmountOut <= bmul(outRecord.balance, MAX_OUT_RATIO), "ERR_MAX_OUT_RATIO"); uint spotPriceBefore = 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"); inRecord.balance = badd(inRecord.balance, tokenAmountIn); outRecord.balance = bsub(outRecord.balance, tokenAmountOut); spotPriceAfter = calcSpotPrice( inRecord.balance, inRecord.denorm, outRecord.balance, outRecord.denorm, _swapFee ); require(spotPriceAfter >= spotPriceBefore, "ERR_MATH_APPROX"); require(spotPriceAfter <= maxPrice, "ERR_LIMIT_PRICE"); require(spotPriceBefore <= bdiv(tokenAmountIn, tokenAmountOut), "ERR_MATH_APPROX"); emit LOG_SWAP(msg.sender, tokenIn, tokenOut, tokenAmountIn, tokenAmountOut); _pullUnderlying(tokenIn, msg.sender, tokenAmountIn); _pushUnderlying(tokenOut, msg.sender, tokenAmountOut); return (tokenAmountIn, spotPriceAfter); } function joinswapExternAmountIn(address tokenIn, uint tokenAmountIn, uint minPoolAmountOut) external _logs_ _lock_ returns (uint poolAmountOut) { require(_finalized, "ERR_NOT_FINALIZED"); require(_records[tokenIn].bound, "ERR_NOT_BOUND"); require(tokenAmountIn <= bmul(_records[tokenIn].balance, MAX_IN_RATIO), "ERR_MAX_IN_RATIO"); Record storage inRecord = _records[tokenIn]; poolAmountOut = calcPoolOutGivenSingleIn( inRecord.balance, inRecord.denorm, _totalSupply, _totalWeight, tokenAmountIn, _swapFee ); require(poolAmountOut >= minPoolAmountOut, "ERR_LIMIT_OUT"); inRecord.balance = badd(inRecord.balance, tokenAmountIn); emit LOG_JOIN(msg.sender, tokenIn, tokenAmountIn); _mintPoolShare(poolAmountOut); _pushPoolShare(msg.sender, poolAmountOut); _pullUnderlying(tokenIn, msg.sender, tokenAmountIn); return poolAmountOut; } function joinswapPoolAmountOut(address tokenIn, uint poolAmountOut, uint maxAmountIn) external _logs_ _lock_ returns (uint tokenAmountIn) { require(_finalized, "ERR_NOT_FINALIZED"); require(_records[tokenIn].bound, "ERR_NOT_BOUND"); Record storage inRecord = _records[tokenIn]; tokenAmountIn = calcSingleInGivenPoolOut( inRecord.balance, inRecord.denorm, _totalSupply, _totalWeight, poolAmountOut, _swapFee ); require(tokenAmountIn != 0, "ERR_MATH_APPROX"); require(tokenAmountIn <= maxAmountIn, "ERR_LIMIT_IN"); require(tokenAmountIn <= bmul(_records[tokenIn].balance, MAX_IN_RATIO), "ERR_MAX_IN_RATIO"); inRecord.balance = badd(inRecord.balance, tokenAmountIn); emit LOG_JOIN(msg.sender, tokenIn, tokenAmountIn); _mintPoolShare(poolAmountOut); _pushPoolShare(msg.sender, poolAmountOut); _pullUnderlying(tokenIn, msg.sender, tokenAmountIn); return tokenAmountIn; } function exitswapPoolAmountIn(address tokenOut, uint poolAmountIn, uint minAmountOut) external _logs_ _lock_ returns (uint tokenAmountOut) { require(_finalized, "ERR_NOT_FINALIZED"); require(_records[tokenOut].bound, "ERR_NOT_BOUND"); Record storage outRecord = _records[tokenOut]; tokenAmountOut = calcSingleOutGivenPoolIn( outRecord.balance, outRecord.denorm, _totalSupply, _totalWeight, poolAmountIn, _swapFee ); require(tokenAmountOut >= minAmountOut, "ERR_LIMIT_OUT"); require(tokenAmountOut <= bmul(_records[tokenOut].balance, MAX_OUT_RATIO), "ERR_MAX_OUT_RATIO"); outRecord.balance = bsub(outRecord.balance, tokenAmountOut); uint exitFee = bmul(poolAmountIn, EXIT_FEE); emit LOG_EXIT(msg.sender, tokenOut, tokenAmountOut); _pullPoolShare(msg.sender, poolAmountIn); _burnPoolShare(bsub(poolAmountIn, exitFee)); _pushPoolShare(_factory, exitFee); _pushUnderlying(tokenOut, msg.sender, tokenAmountOut); return tokenAmountOut; } function exitswapExternAmountOut(address tokenOut, uint tokenAmountOut, uint maxPoolAmountIn) external _logs_ _lock_ returns (uint poolAmountIn) { require(_finalized, "ERR_NOT_FINALIZED"); require(_records[tokenOut].bound, "ERR_NOT_BOUND"); require(tokenAmountOut <= bmul(_records[tokenOut].balance, MAX_OUT_RATIO), "ERR_MAX_OUT_RATIO"); Record storage outRecord = _records[tokenOut]; poolAmountIn = calcPoolInGivenSingleOut( outRecord.balance, outRecord.denorm, _totalSupply, _totalWeight, tokenAmountOut, _swapFee ); require(poolAmountIn != 0, "ERR_MATH_APPROX"); require(poolAmountIn <= maxPoolAmountIn, "ERR_LIMIT_IN"); outRecord.balance = bsub(outRecord.balance, tokenAmountOut); uint exitFee = bmul(poolAmountIn, EXIT_FEE); emit LOG_EXIT(msg.sender, tokenOut, tokenAmountOut); _pullPoolShare(msg.sender, poolAmountIn); _burnPoolShare(bsub(poolAmountIn, exitFee)); _pushPoolShare(_factory, exitFee); _pushUnderlying(tokenOut, msg.sender, tokenAmountOut); return poolAmountIn; } // == // 'Underlying' token-manipulation functions make external calls but are NOT locked // You must `_lock_` or otherwise ensure reentry-safety function _pullUnderlying(address erc20, address from, uint amount) internal { bool xfer = IERC20(erc20).transferFrom(from, address(this), amount); require(xfer, "ERR_ERC20_FALSE"); } function _pushUnderlying(address erc20, address to, uint amount) internal { bool xfer = IERC20(erc20).transfer(to, amount); require(xfer, "ERR_ERC20_FALSE"); } function _pullPoolShare(address from, uint amount) internal { _pull(from, amount); } function _pushPoolShare(address to, uint amount) internal { _push(to, amount); } function _mintPoolShare(uint amount) internal { _mint(amount); } function _burnPoolShare(uint amount) internal { _burn(amount); } } // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.6.6; import "./BNum.sol"; import "../PCToken.sol"; // Highly opinionated token implementation /* interface IERC20 { event Approval(address indexed src, address indexed dst, uint amt); event Transfer(address indexed src, address indexed dst, uint amt); function totalSupply() external view returns (uint); function balanceOf(address whom) external view returns (uint); function allowance(address src, address dst) external view returns (uint); function approve(address dst, uint amt) external returns (bool); function transfer(address dst, uint amt) external returns (bool); function transferFrom( address src, address dst, uint amt ) external returns (bool); } */ // Core contract; can't be changed. So disable solhint (reminder for v2) /* solhint-disable func-order */ contract BTokenBase is BNum { mapping(address => uint) internal _balance; mapping(address => mapping(address=>uint)) internal _allowance; uint internal _totalSupply; event Approval(address indexed src, address indexed dst, uint amt); event Transfer(address indexed src, address indexed dst, uint amt); function _mint(uint amt) internal { _balance[address(this)] = badd(_balance[address(this)], amt); _totalSupply = badd(_totalSupply, amt); emit Transfer(address(0), address(this), amt); } function _burn(uint amt) internal { require(_balance[address(this)] >= amt, "ERR_INSUFFICIENT_BAL"); _balance[address(this)] = bsub(_balance[address(this)], amt); _totalSupply = bsub(_totalSupply, amt); emit Transfer(address(this), address(0), amt); } function _move(address src, address dst, uint amt) internal { require(_balance[src] >= amt, "ERR_INSUFFICIENT_BAL"); _balance[src] = bsub(_balance[src], amt); _balance[dst] = badd(_balance[dst], amt); emit Transfer(src, dst, amt); } function _push(address to, uint amt) internal { _move(address(this), to, amt); } function _pull(address from, uint amt) internal { _move(from, address(this), amt); } } contract BToken is BTokenBase, IERC20 { string private _name = "Balancer Pool Token"; string private _symbol = "BPT"; uint8 private _decimals = 18; function name() public view returns (string memory) { return _name; } function symbol() public view returns (string memory) { return _symbol; } function decimals() public view returns(uint8) { return _decimals; } function allowance(address src, address dst) external view override returns (uint) { return _allowance[src][dst]; } function balanceOf(address whom) external view override returns (uint) { return _balance[whom]; } function totalSupply() public view override returns (uint) { return _totalSupply; } function approve(address dst, uint amt) external override returns (bool) { _allowance[msg.sender][dst] = amt; emit Approval(msg.sender, dst, amt); return true; } function increaseApproval(address dst, uint amt) external returns (bool) { _allowance[msg.sender][dst] = badd(_allowance[msg.sender][dst], amt); emit Approval(msg.sender, dst, _allowance[msg.sender][dst]); return true; } function decreaseApproval(address dst, uint amt) external returns (bool) { uint oldValue = _allowance[msg.sender][dst]; if (amt > oldValue) { _allowance[msg.sender][dst] = 0; } else { _allowance[msg.sender][dst] = bsub(oldValue, amt); } emit Approval(msg.sender, dst, _allowance[msg.sender][dst]); return true; } function transfer(address dst, uint amt) external override returns (bool) { _move(msg.sender, dst, amt); return true; } function transferFrom(address src, address dst, uint amt) external override 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] = bsub(_allowance[src][msg.sender], amt); emit Approval(msg.sender, dst, _allowance[src][msg.sender]); } return true; } } // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.6.6; import "./BConst.sol"; // Core contract; can't be changed. So disable solhint (reminder for v2) /* solhint-disable private-vars-leading-underscore */ contract BNum is BConst { function btoi(uint a) internal pure returns (uint) { return a / BONE; } function bfloor(uint a) internal pure returns (uint) { return btoi(a) * BONE; } function badd(uint a, uint b) internal pure returns (uint) { uint c = a + b; require(c >= a, "ERR_ADD_OVERFLOW"); return c; } function bsub(uint a, uint b) internal pure returns (uint) { (uint c, bool flag) = bsubSign(a, b); require(!flag, "ERR_SUB_UNDERFLOW"); return c; } function bsubSign(uint a, uint b) internal pure returns (uint, bool) { if (a >= b) { return (a - b, false); } else { return (b - a, true); } } function bmul(uint a, uint b) internal pure returns (uint) { uint c0 = a * b; require(a == 0 || c0 / a == b, "ERR_MUL_OVERFLOW"); uint c1 = c0 + (BONE / 2); require(c1 >= c0, "ERR_MUL_OVERFLOW"); uint c2 = c1 / BONE; return c2; } function bdiv(uint a, uint b) internal pure returns (uint) { require(b != 0, "ERR_DIV_ZERO"); uint c0 = a * BONE; require(a == 0 || c0 / a == BONE, "ERR_DIV_INTERNAL"); // bmul overflow uint c1 = c0 + (b / 2); require(c1 >= c0, "ERR_DIV_INTERNAL"); // badd require uint c2 = c1 / b; return c2; } // DSMath.wpow function bpowi(uint a, uint n) internal pure returns (uint) { uint 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(uint base, uint exp) internal pure returns (uint) { require(base >= MIN_BPOW_BASE, "ERR_BPOW_BASE_TOO_LOW"); require(base <= MAX_BPOW_BASE, "ERR_BPOW_BASE_TOO_HIGH"); uint whole = bfloor(exp); uint remain = bsub(exp, whole); uint wholePow = bpowi(base, btoi(whole)); if (remain == 0) { return wholePow; } uint partialResult = bpowApprox(base, remain, BPOW_PRECISION); return bmul(wholePow, partialResult); } function bpowApprox(uint base, uint exp, uint precision) internal pure returns (uint) { // term 0: uint a = exp; (uint x, bool xneg) = bsubSign(base, BONE); uint term = BONE; uint 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 (uint i = 1; term >= precision; i++) { uint bigK = i * BONE; (uint 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; } } // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.6.6; import "./BNum.sol"; contract BMath is BBronze, BConst, BNum { /********************************************************************************************** // calcSpotPrice // // sP = spotPrice // // bI = tokenBalanceIn ( bI / wI ) 1 // // bO = tokenBalanceOut sP = ----------- * ---------- // // wI = tokenWeightIn ( bO / wO ) ( 1 - sF ) // // wO = tokenWeightOut // // sF = swapFee // **********************************************************************************************/ function calcSpotPrice( uint tokenBalanceIn, uint tokenWeightIn, uint tokenBalanceOut, uint tokenWeightOut, uint swapFee ) public pure returns (uint spotPrice) { uint numer = bdiv(tokenBalanceIn, tokenWeightIn); uint denom = bdiv(tokenBalanceOut, tokenWeightOut); uint ratio = bdiv(numer, denom); uint scale = bdiv(BONE, bsub(BONE, swapFee)); return (spotPrice = bmul(ratio, 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( uint tokenBalanceIn, uint tokenWeightIn, uint tokenBalanceOut, uint tokenWeightOut, uint tokenAmountIn, uint swapFee ) public pure returns (uint tokenAmountOut) { uint weightRatio = bdiv(tokenWeightIn, tokenWeightOut); uint adjustedIn = bsub(BONE, swapFee); adjustedIn = bmul(tokenAmountIn, adjustedIn); uint y = bdiv(tokenBalanceIn, badd(tokenBalanceIn, adjustedIn)); uint foo = bpow(y, weightRatio); uint bar = bsub(BONE, foo); tokenAmountOut = bmul(tokenBalanceOut, 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( uint tokenBalanceIn, uint tokenWeightIn, uint tokenBalanceOut, uint tokenWeightOut, uint tokenAmountOut, uint swapFee ) public pure returns (uint tokenAmountIn) { uint weightRatio = bdiv(tokenWeightOut, tokenWeightIn); uint diff = bsub(tokenBalanceOut, tokenAmountOut); uint y = bdiv(tokenBalanceOut, diff); uint foo = bpow(y, weightRatio); foo = bsub(foo, BONE); tokenAmountIn = bsub(BONE, swapFee); tokenAmountIn = bdiv(bmul(tokenBalanceIn, foo), 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( uint tokenBalanceIn, uint tokenWeightIn, uint poolSupply, uint totalWeight, uint tokenAmountIn, uint swapFee ) public pure returns (uint 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); uint normalizedWeight = bdiv(tokenWeightIn, totalWeight); uint zaz = bmul(bsub(BONE, normalizedWeight), swapFee); uint tokenAmountInAfterFee = bmul(tokenAmountIn, bsub(BONE, zaz)); uint newTokenBalanceIn = badd(tokenBalanceIn, tokenAmountInAfterFee); uint tokenInRatio = bdiv(newTokenBalanceIn, tokenBalanceIn); // uint newPoolSupply = (ratioTi ^ weightTi) * poolSupply; uint poolRatio = bpow(tokenInRatio, normalizedWeight); uint newPoolSupply = bmul(poolRatio, poolSupply); poolAmountOut = bsub(newPoolSupply, poolSupply); return poolAmountOut; } /********************************************************************************************** // calcSingleInGivenPoolOut // // tAi = tokenAmountIn //(pS + pAo)\\ / 1 \\\\ // // pS = poolSupply || --------- | ^ | --------- || * bI - bI // // pAo = poolAmountOut \\\\ pS / \\(wI / tW)// // // bI = balanceIn tAi = -------------------------------------------- // // wI = weightIn / wI \\ // // tW = totalWeight | 1 - ---- | * sF // // sF = swapFee \\ tW / // **********************************************************************************************/ function calcSingleInGivenPoolOut( uint tokenBalanceIn, uint tokenWeightIn, uint poolSupply, uint totalWeight, uint poolAmountOut, uint swapFee ) public pure returns (uint tokenAmountIn) { uint normalizedWeight = bdiv(tokenWeightIn, totalWeight); uint newPoolSupply = badd(poolSupply, poolAmountOut); uint poolRatio = bdiv(newPoolSupply, poolSupply); //uint newBalTi = poolRatio^(1/weightTi) * balTi; uint boo = bdiv(BONE, normalizedWeight); uint tokenInRatio = bpow(poolRatio, boo); uint newTokenBalanceIn = bmul(tokenInRatio, tokenBalanceIn); uint tokenAmountInAfterFee = bsub(newTokenBalanceIn, tokenBalanceIn); // Do reverse order of fees charged in joinswap_ExternAmountIn, this way // ``` pAo == joinswap_ExternAmountIn(Ti, joinswap_PoolAmountOut(pAo, Ti)) ``` //uint tAi = tAiAfterFee / (1 - (1-weightTi) * swapFee) ; uint zar = bmul(bsub(BONE, normalizedWeight), swapFee); tokenAmountIn = bdiv(tokenAmountInAfterFee, bsub(BONE, zar)); return tokenAmountIn; } /********************************************************************************************** // 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( uint tokenBalanceOut, uint tokenWeightOut, uint poolSupply, uint totalWeight, uint poolAmountIn, uint swapFee ) public pure returns (uint tokenAmountOut) { uint normalizedWeight = bdiv(tokenWeightOut, totalWeight); // charge exit fee on the pool token side // pAiAfterExitFee = pAi*(1-exitFee) uint poolAmountInAfterExitFee = bmul(poolAmountIn, bsub(BONE, EXIT_FEE)); uint newPoolSupply = bsub(poolSupply, poolAmountInAfterExitFee); uint poolRatio = bdiv(newPoolSupply, poolSupply); // newBalTo = poolRatio^(1/weightTo) * balTo; uint tokenOutRatio = bpow(poolRatio, bdiv(BONE, normalizedWeight)); uint newTokenBalanceOut = bmul(tokenOutRatio, tokenBalanceOut); uint tokenAmountOutBeforeSwapFee = bsub(tokenBalanceOut, newTokenBalanceOut); // charge swap fee on the output token side //uint tAo = tAoBeforeSwapFee * (1 - (1-weightTo) * swapFee) uint zaz = bmul(bsub(BONE, normalizedWeight), swapFee); tokenAmountOut = bmul(tokenAmountOutBeforeSwapFee, bsub(BONE, zaz)); return tokenAmountOut; } /********************************************************************************************** // calcPoolInGivenSingleOut // // pAi = poolAmountIn // / tAo \\\\ / wO \\ \\ // // bO = tokenBalanceOut // | bO - -------------------------- |\\ | ---- | \\ // // tAo = tokenAmountOut pS - || \\ 1 - ((1 - (tO / tW)) * sF)/ | ^ \\ tW / * pS | // // ps = poolSupply \\\\ -----------------------------------/ / // // wO = tokenWeightOut pAi = \\\\ bO / / // // tW = totalWeight ------------------------------------------------------------- // // sF = swapFee ( 1 - eF ) // // eF = exitFee // **********************************************************************************************/ function calcPoolInGivenSingleOut( uint tokenBalanceOut, uint tokenWeightOut, uint poolSupply, uint totalWeight, uint tokenAmountOut, uint swapFee ) public pure returns (uint poolAmountIn) { // charge swap fee on the output token side uint normalizedWeight = bdiv(tokenWeightOut, totalWeight); //uint tAoBeforeSwapFee = tAo / (1 - (1-weightTo) * swapFee) ; uint zoo = bsub(BONE, normalizedWeight); uint zar = bmul(zoo, swapFee); uint tokenAmountOutBeforeSwapFee = bdiv(tokenAmountOut, bsub(BONE, zar)); uint newTokenBalanceOut = bsub(tokenBalanceOut, tokenAmountOutBeforeSwapFee); uint tokenOutRatio = bdiv(newTokenBalanceOut, tokenBalanceOut); //uint newPoolSupply = (ratioTo ^ weightTo) * poolSupply; uint poolRatio = bpow(tokenOutRatio, normalizedWeight); uint newPoolSupply = bmul(poolRatio, poolSupply); uint poolAmountInAfterExitFee = bsub(poolSupply, newPoolSupply); // charge exit fee on the pool token side // pAi = pAiAfterExitFee/(1-exitFee) poolAmountIn = bdiv(poolAmountInAfterExitFee, bsub(BONE, EXIT_FEE)); return poolAmountIn; } } // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.6.6; // Core contract; can't be changed. So disable solhint (reminder for v2) /* solhint-disable private-vars-leading-underscore */ /* solhint-disable reason-string */ /* solhint-disable func-order */ // Test Token contract TToken { string private _name; string private _symbol; uint8 private _decimals; address private _owner; uint internal _totalSupply; mapping(address => uint) private _balance; mapping(address => mapping(address=>uint)) private _allowance; modifier _onlyOwner_() { require(msg.sender == _owner, "ERR_NOT_OWNER"); _; } event Approval(address indexed src, address indexed dst, uint amt); event Transfer(address indexed src, address indexed dst, uint amt); // Math function add(uint a, uint b) internal pure returns (uint c) { require((c = a + b) >= a); } function sub(uint a, uint b) internal pure returns (uint c) { require((c = a - b) <= a); } constructor( string memory name, string memory symbol, uint8 decimals ) public { _name = name; _symbol = symbol; _decimals = decimals; _owner = msg.sender; } function name() public view returns (string memory) { return _name; } function symbol() public view returns (string memory) { return _symbol; } function decimals() public view returns(uint8) { return _decimals; } function _move(address src, address dst, uint amt) internal { require(_balance[src] >= amt, "ERR_INSUFFICIENT_BAL"); _balance[src] = sub(_balance[src], amt); _balance[dst] = add(_balance[dst], amt); emit Transfer(src, dst, amt); } function _push(address to, uint amt) internal { _move(address(this), to, amt); } function _pull(address from, uint amt) internal { _move(from, address(this), amt); } function _mint(address dst, uint amt) internal { _balance[dst] = add(_balance[dst], amt); _totalSupply = add(_totalSupply, amt); emit Transfer(address(0), dst, amt); } function allowance(address src, address dst) external view returns (uint) { return _allowance[src][dst]; } function balanceOf(address whom) external view returns (uint) { return _balance[whom]; } function totalSupply() public view returns (uint) { return _totalSupply; } function approve(address dst, uint amt) external returns (bool) { _allowance[msg.sender][dst] = amt; emit Approval(msg.sender, dst, amt); return true; } function mint(address dst, uint256 amt) public _onlyOwner_ returns (bool) { _mint(dst, amt); return true; } function burn(uint amt) public returns (bool) { require(_balance[address(this)] >= amt, "ERR_INSUFFICIENT_BAL"); _balance[address(this)] = sub(_balance[address(this)], amt); _totalSupply = sub(_totalSupply, amt); emit Transfer(address(this), address(0), amt); return true; } function transfer(address dst, uint amt) external returns (bool) { _move(msg.sender, dst, amt); return true; } function transferFrom(address src, address dst, uint 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] = sub(_allowance[src][msg.sender], amt); emit Approval(msg.sender, dst, _allowance[src][msg.sender]); } return true; } }
File 11 of 12: FiatTokenV2
// File: @openzeppelin/contracts/math/SafeMath.sol // License: MIT pragma solidity ^0.6.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } // File: @openzeppelin/contracts/token/ERC20/IERC20.sol // License: MIT pragma solidity ^0.6.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval( address indexed owner, address indexed spender, uint256 value ); } // File: contracts/v1/AbstractFiatTokenV1.sol /** * License: MIT * * Copyright (c) 2018-2020 CENTRE SECZ * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ pragma solidity 0.6.12; abstract contract AbstractFiatTokenV1 is IERC20 { function _approve( address owner, address spender, uint256 value ) internal virtual; function _transfer( address from, address to, uint256 value ) internal virtual; } // File: contracts/v1/Ownable.sol /** * License: MIT * * Copyright (c) 2018 zOS Global Limited. * Copyright (c) 2018-2020 CENTRE SECZ * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ pragma solidity 0.6.12; /** * @notice The Ownable contract has an owner address, and provides basic * authorization control functions * @dev Forked from https://github.com/OpenZeppelin/openzeppelin-labs/blob/3887ab77b8adafba4a26ace002f3a684c1a3388b/upgradeability_ownership/contracts/ownership/Ownable.sol * Modifications: * 1. Consolidate OwnableStorage into this contract (7/13/18) * 2. Reformat, conform to Solidity 0.6 syntax, and add error messages (5/13/20) * 3. Make public functions external (5/27/20) */ contract Ownable { // Owner of the contract address private _owner; /** * @dev Event to show ownership has been transferred * @param previousOwner representing the address of the previous owner * @param newOwner representing the address of the new owner */ event OwnershipTransferred(address previousOwner, address newOwner); /** * @dev The constructor sets the original owner of the contract to the sender account. */ constructor() public { setOwner(msg.sender); } /** * @dev Tells the address of the owner * @return the address of the owner */ function owner() external view returns (address) { return _owner; } /** * @dev Sets a new owner address */ function setOwner(address newOwner) internal { _owner = newOwner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(msg.sender == _owner, "Ownable: caller is not the owner"); _; } /** * @dev Allows the current owner to transfer control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function transferOwnership(address newOwner) external onlyOwner { require( newOwner != address(0), "Ownable: new owner is the zero address" ); emit OwnershipTransferred(_owner, newOwner); setOwner(newOwner); } } // File: contracts/v1/Pausable.sol /** * License: MIT * * Copyright (c) 2016 Smart Contract Solutions, Inc. * Copyright (c) 2018-2020 CENTRE SECZ0 * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ pragma solidity 0.6.12; /** * @notice Base contract which allows children to implement an emergency stop * mechanism * @dev Forked from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/feb665136c0dae9912e08397c1a21c4af3651ef3/contracts/lifecycle/Pausable.sol * Modifications: * 1. Added pauser role, switched pause/unpause to be onlyPauser (6/14/2018) * 2. Removed whenNotPause/whenPaused from pause/unpause (6/14/2018) * 3. Removed whenPaused (6/14/2018) * 4. Switches ownable library to use ZeppelinOS (7/12/18) * 5. Remove constructor (7/13/18) * 6. Reformat, conform to Solidity 0.6 syntax and add error messages (5/13/20) * 7. Make public functions external (5/27/20) */ contract Pausable is Ownable { event Pause(); event Unpause(); event PauserChanged(address indexed newAddress); address public pauser; bool public paused = false; /** * @dev Modifier to make a function callable only when the contract is not paused. */ modifier whenNotPaused() { require(!paused, "Pausable: paused"); _; } /** * @dev throws if called by any account other than the pauser */ modifier onlyPauser() { require(msg.sender == pauser, "Pausable: caller is not the pauser"); _; } /** * @dev called by the owner to pause, triggers stopped state */ function pause() external onlyPauser { paused = true; emit Pause(); } /** * @dev called by the owner to unpause, returns to normal state */ function unpause() external onlyPauser { paused = false; emit Unpause(); } /** * @dev update the pauser role */ function updatePauser(address _newPauser) external onlyOwner { require( _newPauser != address(0), "Pausable: new pauser is the zero address" ); pauser = _newPauser; emit PauserChanged(pauser); } } // File: contracts/v1/Blacklistable.sol /** * License: MIT * * Copyright (c) 2018-2020 CENTRE SECZ * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ pragma solidity 0.6.12; /** * @title Blacklistable Token * @dev Allows accounts to be blacklisted by a "blacklister" role */ contract Blacklistable is Ownable { address public blacklister; mapping(address => bool) internal blacklisted; event Blacklisted(address indexed _account); event UnBlacklisted(address indexed _account); event BlacklisterChanged(address indexed newBlacklister); /** * @dev Throws if called by any account other than the blacklister */ modifier onlyBlacklister() { require( msg.sender == blacklister, "Blacklistable: caller is not the blacklister" ); _; } /** * @dev Throws if argument account is blacklisted * @param _account The address to check */ modifier notBlacklisted(address _account) { require( !blacklisted[_account], "Blacklistable: account is blacklisted" ); _; } /** * @dev Checks if account is blacklisted * @param _account The address to check */ function isBlacklisted(address _account) external view returns (bool) { return blacklisted[_account]; } /** * @dev Adds account to blacklist * @param _account The address to blacklist */ function blacklist(address _account) external onlyBlacklister { blacklisted[_account] = true; emit Blacklisted(_account); } /** * @dev Removes account from blacklist * @param _account The address to remove from the blacklist */ function unBlacklist(address _account) external onlyBlacklister { blacklisted[_account] = false; emit UnBlacklisted(_account); } function updateBlacklister(address _newBlacklister) external onlyOwner { require( _newBlacklister != address(0), "Blacklistable: new blacklister is the zero address" ); blacklister = _newBlacklister; emit BlacklisterChanged(blacklister); } } // File: contracts/v1/FiatTokenV1.sol /** * License: MIT * * Copyright (c) 2018-2020 CENTRE SECZ * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ pragma solidity 0.6.12; /** * @title FiatToken * @dev ERC20 Token backed by fiat reserves */ contract FiatTokenV1 is AbstractFiatTokenV1, Ownable, Pausable, Blacklistable { using SafeMath for uint256; string public name; string public symbol; uint8 public decimals; string public currency; address public masterMinter; bool internal initialized; mapping(address => uint256) internal balances; mapping(address => mapping(address => uint256)) internal allowed; uint256 internal totalSupply_ = 0; mapping(address => bool) internal minters; mapping(address => uint256) internal minterAllowed; event Mint(address indexed minter, address indexed to, uint256 amount); event Burn(address indexed burner, uint256 amount); event MinterConfigured(address indexed minter, uint256 minterAllowedAmount); event MinterRemoved(address indexed oldMinter); event MasterMinterChanged(address indexed newMasterMinter); function initialize( string memory tokenName, string memory tokenSymbol, string memory tokenCurrency, uint8 tokenDecimals, address newMasterMinter, address newPauser, address newBlacklister, address newOwner ) public { require(!initialized, "FiatToken: contract is already initialized"); require( newMasterMinter != address(0), "FiatToken: new masterMinter is the zero address" ); require( newPauser != address(0), "FiatToken: new pauser is the zero address" ); require( newBlacklister != address(0), "FiatToken: new blacklister is the zero address" ); require( newOwner != address(0), "FiatToken: new owner is the zero address" ); name = tokenName; symbol = tokenSymbol; currency = tokenCurrency; decimals = tokenDecimals; masterMinter = newMasterMinter; pauser = newPauser; blacklister = newBlacklister; setOwner(newOwner); initialized = true; } /** * @dev Throws if called by any account other than a minter */ modifier onlyMinters() { require(minters[msg.sender], "FiatToken: caller is not a minter"); _; } /** * @dev Function to mint tokens * @param _to The address that will receive the minted tokens. * @param _amount The amount of tokens to mint. Must be less than or equal * to the minterAllowance of the caller. * @return A boolean that indicates if the operation was successful. */ function mint(address _to, uint256 _amount) external whenNotPaused onlyMinters notBlacklisted(msg.sender) notBlacklisted(_to) returns (bool) { require(_to != address(0), "FiatToken: mint to the zero address"); require(_amount > 0, "FiatToken: mint amount not greater than 0"); uint256 mintingAllowedAmount = minterAllowed[msg.sender]; require( _amount <= mintingAllowedAmount, "FiatToken: mint amount exceeds minterAllowance" ); totalSupply_ = totalSupply_.add(_amount); balances[_to] = balances[_to].add(_amount); minterAllowed[msg.sender] = mintingAllowedAmount.sub(_amount); emit Mint(msg.sender, _to, _amount); emit Transfer(address(0), _to, _amount); return true; } /** * @dev Throws if called by any account other than the masterMinter */ modifier onlyMasterMinter() { require( msg.sender == masterMinter, "FiatToken: caller is not the masterMinter" ); _; } /** * @dev Get minter allowance for an account * @param minter The address of the minter */ function minterAllowance(address minter) external view returns (uint256) { return minterAllowed[minter]; } /** * @dev Checks if account is a minter * @param account The address to check */ function isMinter(address account) external view returns (bool) { return minters[account]; } /** * @notice Amount of remaining tokens spender is allowed to transfer on * behalf of the token owner * @param owner Token owner's address * @param spender Spender's address * @return Allowance amount */ function allowance(address owner, address spender) external override view returns (uint256) { return allowed[owner][spender]; } /** * @dev Get totalSupply of token */ function totalSupply() external override view returns (uint256) { return totalSupply_; } /** * @dev Get token balance of an account * @param account address The account */ function balanceOf(address account) external override view returns (uint256) { return balances[account]; } /** * @notice Set spender's allowance over the caller's tokens to be a given * value. * @param spender Spender's address * @param value Allowance amount * @return True if successful */ function approve(address spender, uint256 value) external override whenNotPaused notBlacklisted(msg.sender) notBlacklisted(spender) returns (bool) { _approve(msg.sender, spender, value); return true; } /** * @dev Internal function to set allowance * @param owner Token owner's address * @param spender Spender's address * @param value Allowance amount */ function _approve( address owner, address spender, uint256 value ) internal override { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); allowed[owner][spender] = value; emit Approval(owner, spender, value); } /** * @notice Transfer tokens by spending allowance * @param from Payer's address * @param to Payee's address * @param value Transfer amount * @return True if successful */ function transferFrom( address from, address to, uint256 value ) external override whenNotPaused notBlacklisted(msg.sender) notBlacklisted(from) notBlacklisted(to) returns (bool) { require( value <= allowed[from][msg.sender], "ERC20: transfer amount exceeds allowance" ); _transfer(from, to, value); allowed[from][msg.sender] = allowed[from][msg.sender].sub(value); return true; } /** * @notice Transfer tokens from the caller * @param to Payee's address * @param value Transfer amount * @return True if successful */ function transfer(address to, uint256 value) external override whenNotPaused notBlacklisted(msg.sender) notBlacklisted(to) returns (bool) { _transfer(msg.sender, to, value); return true; } /** * @notice Internal function to process transfers * @param from Payer's address * @param to Payee's address * @param value Transfer amount */ function _transfer( address from, address to, uint256 value ) internal override { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); require( value <= balances[from], "ERC20: transfer amount exceeds balance" ); balances[from] = balances[from].sub(value); balances[to] = balances[to].add(value); emit Transfer(from, to, value); } /** * @dev Function to add/update a new minter * @param minter The address of the minter * @param minterAllowedAmount The minting amount allowed for the minter * @return True if the operation was successful. */ function configureMinter(address minter, uint256 minterAllowedAmount) external whenNotPaused onlyMasterMinter returns (bool) { minters[minter] = true; minterAllowed[minter] = minterAllowedAmount; emit MinterConfigured(minter, minterAllowedAmount); return true; } /** * @dev Function to remove a minter * @param minter The address of the minter to remove * @return True if the operation was successful. */ function removeMinter(address minter) external onlyMasterMinter returns (bool) { minters[minter] = false; minterAllowed[minter] = 0; emit MinterRemoved(minter); return true; } /** * @dev allows a minter to burn some of its own tokens * Validates that caller is a minter and that sender is not blacklisted * amount is less than or equal to the minter's account balance * @param _amount uint256 the amount of tokens to be burned */ function burn(uint256 _amount) external whenNotPaused onlyMinters notBlacklisted(msg.sender) { uint256 balance = balances[msg.sender]; require(_amount > 0, "FiatToken: burn amount not greater than 0"); require(balance >= _amount, "FiatToken: burn amount exceeds balance"); totalSupply_ = totalSupply_.sub(_amount); balances[msg.sender] = balance.sub(_amount); emit Burn(msg.sender, _amount); emit Transfer(msg.sender, address(0), _amount); } function updateMasterMinter(address _newMasterMinter) external onlyOwner { require( _newMasterMinter != address(0), "FiatToken: new masterMinter is the zero address" ); masterMinter = _newMasterMinter; emit MasterMinterChanged(masterMinter); } } // File: @openzeppelin/contracts/utils/Address.sol // License: MIT pragma solidity ^0.6.2; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // According to EIP-1052, 0x0 is the value returned for not-yet created accounts // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned // for accounts without code, i.e. `keccak256('')` bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // solhint-disable-next-line no-inline-assembly assembly { codehash := extcodehash(account) } return (codehash != accountHash && codehash != 0x0); } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require( address(this).balance >= amount, "Address: insufficient balance" ); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require( success, "Address: unable to send value, recipient may have reverted" ); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return _functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue( target, data, value, "Address: low-level call with value failed" ); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require( address(this).balance >= value, "Address: insufficient balance for call" ); return _functionCallWithValue(target, data, value, errorMessage); } function _functionCallWithValue( address target, bytes memory data, uint256 weiValue, string memory errorMessage ) private returns (bytes memory) { require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: weiValue }(data); if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } // File: @openzeppelin/contracts/token/ERC20/SafeERC20.sol // License: MIT pragma solidity ^0.6.0; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn( token, abi.encodeWithSelector(token.transfer.selector, to, value) ); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn( token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value) ); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn( token, abi.encodeWithSelector(token.approve.selector, spender, value) ); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender).add( value ); _callOptionalReturn( token, abi.encodeWithSelector( token.approve.selector, spender, newAllowance ) ); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender).sub( value, "SafeERC20: decreased allowance below zero" ); _callOptionalReturn( token, abi.encodeWithSelector( token.approve.selector, spender, newAllowance ) ); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall( data, "SafeERC20: low-level call failed" ); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require( abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed" ); } } } // File: contracts/v1.1/Rescuable.sol /** * License: MIT * * Copyright (c) 2018-2020 CENTRE SECZ * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ pragma solidity 0.6.12; contract Rescuable is Ownable { using SafeERC20 for IERC20; address private _rescuer; event RescuerChanged(address indexed newRescuer); /** * @notice Returns current rescuer * @return Rescuer's address */ function rescuer() external view returns (address) { return _rescuer; } /** * @notice Revert if called by any account other than the rescuer. */ modifier onlyRescuer() { require(msg.sender == _rescuer, "Rescuable: caller is not the rescuer"); _; } /** * @notice Rescue ERC20 tokens locked up in this contract. * @param tokenContract ERC20 token contract address * @param to Recipient address * @param amount Amount to withdraw */ function rescueERC20( IERC20 tokenContract, address to, uint256 amount ) external onlyRescuer { tokenContract.safeTransfer(to, amount); } /** * @notice Assign the rescuer role to a given address. * @param newRescuer New rescuer's address */ function updateRescuer(address newRescuer) external onlyOwner { require( newRescuer != address(0), "Rescuable: new rescuer is the zero address" ); _rescuer = newRescuer; emit RescuerChanged(newRescuer); } } // File: contracts/v1.1/FiatTokenV1_1.sol /** * License: MIT * * Copyright (c) 2018-2020 CENTRE SECZ * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ pragma solidity 0.6.12; /** * @title FiatTokenV1_1 * @dev ERC20 Token backed by fiat reserves */ contract FiatTokenV1_1 is FiatTokenV1, Rescuable { } // File: contracts/v2/AbstractFiatTokenV2.sol /** * License: MIT * * Copyright (c) 2018-2020 CENTRE SECZ * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ pragma solidity 0.6.12; abstract contract AbstractFiatTokenV2 is AbstractFiatTokenV1 { function _increaseAllowance( address owner, address spender, uint256 increment ) internal virtual; function _decreaseAllowance( address owner, address spender, uint256 decrement ) internal virtual; } // File: contracts/util/ECRecover.sol /** * License: MIT * * Copyright (c) 2016-2019 zOS Global Limited * Copyright (c) 2018-2020 CENTRE SECZ * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ pragma solidity 0.6.12; /** * @title ECRecover * @notice A library that provides a safe ECDSA recovery function */ library ECRecover { /** * @notice Recover signer's address from a signed message * @dev Adapted from: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/65e4ffde586ec89af3b7e9140bdc9235d1254853/contracts/cryptography/ECDSA.sol * Modifications: Accept v, r, and s as separate arguments * @param digest Keccak-256 hash digest of the signed message * @param v v of the signature * @param r r of the signature * @param s s of the signature * @return Signer address */ function recover( bytes32 digest, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if ( uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0 ) { revert("ECRecover: invalid signature 's' value"); } if (v != 27 && v != 28) { revert("ECRecover: invalid signature 'v' value"); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(digest, v, r, s); require(signer != address(0), "ECRecover: invalid signature"); return signer; } } // File: contracts/util/EIP712.sol /** * License: MIT * * Copyright (c) 2018-2020 CENTRE SECZ * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ pragma solidity 0.6.12; /** * @title EIP712 * @notice A library that provides EIP712 helper functions */ library EIP712 { /** * @notice Make EIP712 domain separator * @param name Contract name * @param version Contract version * @return Domain separator */ function makeDomainSeparator(string memory name, string memory version) internal view returns (bytes32) { uint256 chainId; assembly { chainId := chainid() } return keccak256( abi.encode( 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f, // = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)") keccak256(bytes(name)), keccak256(bytes(version)), chainId, address(this) ) ); } /** * @notice Recover signer's address from a EIP712 signature * @param domainSeparator Domain separator * @param v v of the signature * @param r r of the signature * @param s s of the signature * @param typeHashAndData Type hash concatenated with data * @return Signer's address */ function recover( bytes32 domainSeparator, uint8 v, bytes32 r, bytes32 s, bytes memory typeHashAndData ) internal pure returns (address) { bytes32 digest = keccak256( abi.encodePacked( "\x19\x01", domainSeparator, keccak256(typeHashAndData) ) ); return ECRecover.recover(digest, v, r, s); } } // File: contracts/v2/EIP712Domain.sol /** * License: MIT * * Copyright (c) 2018-2020 CENTRE SECZ * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ pragma solidity 0.6.12; /** * @title EIP712 Domain */ contract EIP712Domain { /** * @dev EIP712 Domain Separator */ bytes32 public DOMAIN_SEPARATOR; } // File: contracts/v2/GasAbstraction.sol /** * License: MIT * * Copyright (c) 2018-2020 CENTRE SECZ * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ pragma solidity 0.6.12; /** * @title Gas Abstraction * @notice Provide internal implementation for gas-abstracted transfers and * approvals * @dev Contracts that inherit from this must wrap these with publicly * accessible functions, optionally adding modifiers where necessary */ abstract contract GasAbstraction is AbstractFiatTokenV2, EIP712Domain { bytes32 public constant TRANSFER_WITH_AUTHORIZATION_TYPEHASH = 0x7c7c6cdb67a18743f49ec6fa9b35f50d52ed05cbed4cc592e13b44501c1a2267; // = keccak256("TransferWithAuthorization(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)") bytes32 public constant APPROVE_WITH_AUTHORIZATION_TYPEHASH = 0x808c10407a796f3ef2c7ea38c0638ea9d2b8a1c63e3ca9e1f56ce84ae59df73c; // = keccak256("ApproveWithAuthorization(address owner,address spender,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)") bytes32 public constant INCREASE_ALLOWANCE_WITH_AUTHORIZATION_TYPEHASH = 0x424222bb050a1f7f14017232a5671f2680a2d3420f504bd565cf03035c53198a; // = keccak256("IncreaseAllowanceWithAuthorization(address owner,address spender,uint256 increment,uint256 validAfter,uint256 validBefore,bytes32 nonce)") bytes32 public constant DECREASE_ALLOWANCE_WITH_AUTHORIZATION_TYPEHASH = 0xb70559e94cbda91958ebec07f9b65b3b490097c8d25c8dacd71105df1015b6d8; // = keccak256("DecreaseAllowanceWithAuthorization(address owner,address spender,uint256 decrement,uint256 validAfter,uint256 validBefore,bytes32 nonce)") bytes32 public constant CANCEL_AUTHORIZATION_TYPEHASH = 0x158b0a9edf7a828aad02f63cd515c68ef2f50ba807396f6d12842833a1597429; // = keccak256("CancelAuthorization(address authorizer,bytes32 nonce)") enum AuthorizationState { Unused, Used, Canceled } /** * @dev authorizer address => nonce => authorization state */ mapping(address => mapping(bytes32 => AuthorizationState)) private _authorizationStates; event AuthorizationUsed(address indexed authorizer, bytes32 indexed nonce); event AuthorizationCanceled( address indexed authorizer, bytes32 indexed nonce ); /** * @notice Returns the state of an authorization * @param authorizer Authorizer's address * @param nonce Nonce of the authorization * @return Authorization state */ function authorizationState(address authorizer, bytes32 nonce) external view returns (AuthorizationState) { return _authorizationStates[authorizer][nonce]; } /** * @notice Verify a signed transfer authorization and execute if valid * @param from Payer's address (Authorizer) * @param to Payee's address * @param value Amount to be transferred * @param validAfter The time after which this is valid (unix time) * @param validBefore The time before which this is valid (unix time) * @param nonce Unique nonce * @param v v of the signature * @param r r of the signature * @param s s of the signature */ function _transferWithAuthorization( address from, address to, uint256 value, uint256 validAfter, uint256 validBefore, bytes32 nonce, uint8 v, bytes32 r, bytes32 s ) internal { _requireValidAuthorization(from, nonce, validAfter, validBefore); bytes memory data = abi.encode( TRANSFER_WITH_AUTHORIZATION_TYPEHASH, from, to, value, validAfter, validBefore, nonce ); require( EIP712.recover(DOMAIN_SEPARATOR, v, r, s, data) == from, "FiatTokenV2: invalid signature" ); _markAuthorizationAsUsed(from, nonce); _transfer(from, to, value); } /** * @notice Verify a signed authorization for an increase in the allowance * granted to the spender and execute if valid * @param owner Token owner's address (Authorizer) * @param spender Spender's address * @param increment Amount of increase in allowance * @param validAfter The time after which this is valid (unix time) * @param validBefore The time before which this is valid (unix time) * @param nonce Unique nonce * @param v v of the signature * @param r r of the signature * @param s s of the signature */ function _increaseAllowanceWithAuthorization( address owner, address spender, uint256 increment, uint256 validAfter, uint256 validBefore, bytes32 nonce, uint8 v, bytes32 r, bytes32 s ) internal { _requireValidAuthorization(owner, nonce, validAfter, validBefore); bytes memory data = abi.encode( INCREASE_ALLOWANCE_WITH_AUTHORIZATION_TYPEHASH, owner, spender, increment, validAfter, validBefore, nonce ); require( EIP712.recover(DOMAIN_SEPARATOR, v, r, s, data) == owner, "FiatTokenV2: invalid signature" ); _markAuthorizationAsUsed(owner, nonce); _increaseAllowance(owner, spender, increment); } /** * @notice Verify a signed authorization for a decrease in the allowance * granted to the spender and execute if valid * @param owner Token owner's address (Authorizer) * @param spender Spender's address * @param decrement Amount of decrease in allowance * @param validAfter The time after which this is valid (unix time) * @param validBefore The time before which this is valid (unix time) * @param nonce Unique nonce * @param v v of the signature * @param r r of the signature * @param s s of the signature */ function _decreaseAllowanceWithAuthorization( address owner, address spender, uint256 decrement, uint256 validAfter, uint256 validBefore, bytes32 nonce, uint8 v, bytes32 r, bytes32 s ) internal { _requireValidAuthorization(owner, nonce, validAfter, validBefore); bytes memory data = abi.encode( DECREASE_ALLOWANCE_WITH_AUTHORIZATION_TYPEHASH, owner, spender, decrement, validAfter, validBefore, nonce ); require( EIP712.recover(DOMAIN_SEPARATOR, v, r, s, data) == owner, "FiatTokenV2: invalid signature" ); _markAuthorizationAsUsed(owner, nonce); _decreaseAllowance(owner, spender, decrement); } /** * @notice Verify a signed approval authorization and execute if valid * @param owner Token owner's address (Authorizer) * @param spender Spender's address * @param value Amount of allowance * @param validAfter The time after which this is valid (unix time) * @param validBefore The time before which this is valid (unix time) * @param nonce Unique nonce * @param v v of the signature * @param r r of the signature * @param s s of the signature */ function _approveWithAuthorization( address owner, address spender, uint256 value, uint256 validAfter, uint256 validBefore, bytes32 nonce, uint8 v, bytes32 r, bytes32 s ) internal { _requireValidAuthorization(owner, nonce, validAfter, validBefore); bytes memory data = abi.encode( APPROVE_WITH_AUTHORIZATION_TYPEHASH, owner, spender, value, validAfter, validBefore, nonce ); require( EIP712.recover(DOMAIN_SEPARATOR, v, r, s, data) == owner, "FiatTokenV2: invalid signature" ); _markAuthorizationAsUsed(owner, nonce); _approve(owner, spender, value); } /** * @notice Attempt to cancel an authorization * @param authorizer Authorizer's address * @param nonce Nonce of the authorization * @param v v of the signature * @param r r of the signature * @param s s of the signature */ function _cancelAuthorization( address authorizer, bytes32 nonce, uint8 v, bytes32 r, bytes32 s ) internal { _requireUnusedAuthorization(authorizer, nonce); bytes memory data = abi.encode( CANCEL_AUTHORIZATION_TYPEHASH, authorizer, nonce ); require( EIP712.recover(DOMAIN_SEPARATOR, v, r, s, data) == authorizer, "FiatTokenV2: invalid signature" ); _authorizationStates[authorizer][nonce] = AuthorizationState.Canceled; emit AuthorizationCanceled(authorizer, nonce); } /** * @notice Check that an authorization is unused * @param authorizer Authorizer's address * @param nonce Nonce of the authorization */ function _requireUnusedAuthorization(address authorizer, bytes32 nonce) private view { require( _authorizationStates[authorizer][nonce] == AuthorizationState.Unused, "FiatTokenV2: authorization is used or canceled" ); } /** * @notice Check that authorization is valid * @param authorizer Authorizer's address * @param nonce Nonce of the authorization * @param validAfter The time after which this is valid (unix time) * @param validBefore The time before which this is valid (unix time) */ function _requireValidAuthorization( address authorizer, bytes32 nonce, uint256 validAfter, uint256 validBefore ) private view { require( now > validAfter, "FiatTokenV2: authorization is not yet valid" ); require(now < validBefore, "FiatTokenV2: authorization is expired"); _requireUnusedAuthorization(authorizer, nonce); } /** * @notice Mark an authorization as used * @param authorizer Authorizer's address * @param nonce Nonce of the authorization */ function _markAuthorizationAsUsed(address authorizer, bytes32 nonce) private { _authorizationStates[authorizer][nonce] = AuthorizationState.Used; emit AuthorizationUsed(authorizer, nonce); } } // File: contracts/v2/Permit.sol /** * License: MIT * * Copyright (c) 2018-2020 CENTRE SECZ * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ pragma solidity 0.6.12; /** * @title Permit * @notice An alternative to approveWithAuthorization, provided for * compatibility with the draft EIP2612 proposed by Uniswap. * @dev Differences: * - Uses sequential nonce, which restricts transaction submission to one at a * time, or else it will revert * - Has deadline (= validBefore - 1) but does not have validAfter * - Doesn't have a way to change allowance atomically to prevent ERC20 multiple * withdrawal attacks */ abstract contract Permit is AbstractFiatTokenV2, EIP712Domain { bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; // = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)") mapping(address => uint256) private _permitNonces; /** * @notice Nonces for permit * @param owner Token owner's address (Authorizer) * @return Next nonce */ function nonces(address owner) external view returns (uint256) { return _permitNonces[owner]; } /** * @notice Verify a signed approval permit and execute if valid * @param owner Token owner's address (Authorizer) * @param spender Spender's address * @param value Amount of allowance * @param deadline The time at which this expires (unix time) * @param v v of the signature * @param r r of the signature * @param s s of the signature */ function _permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { require(deadline >= now, "FiatTokenV2: permit is expired"); bytes memory data = abi.encode( PERMIT_TYPEHASH, owner, spender, value, _permitNonces[owner]++, deadline ); require( EIP712.recover(DOMAIN_SEPARATOR, v, r, s, data) == owner, "FiatTokenV2: invalid signature" ); _approve(owner, spender, value); } } // File: contracts/v2/FiatTokenV2.sol /** * License: MIT * * Copyright (c) 2018-2020 CENTRE SECZ * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ pragma solidity 0.6.12; /** * @title FiatToken V2 * @notice ERC20 Token backed by fiat reserves, version 2 */ contract FiatTokenV2 is FiatTokenV1_1, GasAbstraction, Permit { bool internal _initializedV2; /** * @notice Initialize V2 contract * @dev When upgrading to V2, this function must also be invoked by using * upgradeToAndCall instead of upgradeTo, or by calling both from a contract * in a single transaction. * @param newName New token name */ function initializeV2(string calldata newName) external { require( !_initializedV2, "FiatTokenV2: contract is already initialized" ); name = newName; DOMAIN_SEPARATOR = EIP712.makeDomainSeparator(newName, "2"); _initializedV2 = true; } /** * @notice Increase the allowance by a given increment * @param spender Spender's address * @param increment Amount of increase in allowance * @return True if successful */ function increaseAllowance(address spender, uint256 increment) external whenNotPaused notBlacklisted(msg.sender) notBlacklisted(spender) returns (bool) { _increaseAllowance(msg.sender, spender, increment); return true; } /** * @notice Decrease the allowance by a given decrement * @param spender Spender's address * @param decrement Amount of decrease in allowance * @return True if successful */ function decreaseAllowance(address spender, uint256 decrement) external whenNotPaused notBlacklisted(msg.sender) notBlacklisted(spender) returns (bool) { _decreaseAllowance(msg.sender, spender, decrement); return true; } /** * @notice Execute a transfer with a signed authorization * @param from Payer's address (Authorizer) * @param to Payee's address * @param value Amount to be transferred * @param validAfter The time after which this is valid (unix time) * @param validBefore The time before which this is valid (unix time) * @param nonce Unique nonce * @param v v of the signature * @param r r of the signature * @param s s of the signature */ function transferWithAuthorization( address from, address to, uint256 value, uint256 validAfter, uint256 validBefore, bytes32 nonce, uint8 v, bytes32 r, bytes32 s ) external whenNotPaused notBlacklisted(from) notBlacklisted(to) { _transferWithAuthorization( from, to, value, validAfter, validBefore, nonce, v, r, s ); } /** * @notice Update allowance with a signed authorization * @param owner Token owner's address (Authorizer) * @param spender Spender's address * @param value Amount of allowance * @param validAfter The time after which this is valid (unix time) * @param validBefore The time before which this is valid (unix time) * @param nonce Unique nonce * @param v v of the signature * @param r r of the signature * @param s s of the signature */ function approveWithAuthorization( address owner, address spender, uint256 value, uint256 validAfter, uint256 validBefore, bytes32 nonce, uint8 v, bytes32 r, bytes32 s ) external whenNotPaused notBlacklisted(owner) notBlacklisted(spender) { _approveWithAuthorization( owner, spender, value, validAfter, validBefore, nonce, v, r, s ); } /** * @notice Increase allowance with a signed authorization * @param owner Token owner's address (Authorizer) * @param spender Spender's address * @param increment Amount of increase in allowance * @param validAfter The time after which this is valid (unix time) * @param validBefore The time before which this is valid (unix time) * @param nonce Unique nonce * @param v v of the signature * @param r r of the signature * @param s s of the signature */ function increaseAllowanceWithAuthorization( address owner, address spender, uint256 increment, uint256 validAfter, uint256 validBefore, bytes32 nonce, uint8 v, bytes32 r, bytes32 s ) external whenNotPaused notBlacklisted(owner) notBlacklisted(spender) { _increaseAllowanceWithAuthorization( owner, spender, increment, validAfter, validBefore, nonce, v, r, s ); } /** * @notice Decrease allowance with a signed authorization * @param owner Token owner's address (Authorizer) * @param spender Spender's address * @param decrement Amount of decrease in allowance * @param validAfter The time after which this is valid (unix time) * @param validBefore The time before which this is valid (unix time) * @param nonce Unique nonce * @param v v of the signature * @param r r of the signature * @param s s of the signature */ function decreaseAllowanceWithAuthorization( address owner, address spender, uint256 decrement, uint256 validAfter, uint256 validBefore, bytes32 nonce, uint8 v, bytes32 r, bytes32 s ) external whenNotPaused notBlacklisted(owner) notBlacklisted(spender) { _decreaseAllowanceWithAuthorization( owner, spender, decrement, validAfter, validBefore, nonce, v, r, s ); } /** * @notice Attempt to cancel an authorization * @dev Works only if the authorization is not yet used. * @param authorizer Authorizer's address * @param nonce Nonce of the authorization * @param v v of the signature * @param r r of the signature * @param s s of the signature */ function cancelAuthorization( address authorizer, bytes32 nonce, uint8 v, bytes32 r, bytes32 s ) external whenNotPaused { _cancelAuthorization(authorizer, nonce, v, r, s); } /** * @notice Update allowance with a signed permit * @param owner Token owner's address (Authorizer) * @param spender Spender's address * @param value Amount of allowance * @param deadline Expiration time, seconds since the epoch * @param v v of the signature * @param r r of the signature * @param s s of the signature */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external whenNotPaused notBlacklisted(owner) notBlacklisted(spender) { _permit(owner, spender, value, deadline, v, r, s); } /** * @notice Internal function to increase the allowance by a given increment * @param owner Token owner's address * @param spender Spender's address * @param increment Amount of increase */ function _increaseAllowance( address owner, address spender, uint256 increment ) internal override { _approve(owner, spender, allowed[owner][spender].add(increment)); } /** * @notice Internal function to decrease the allowance by a given decrement * @param owner Token owner's address * @param spender Spender's address * @param decrement Amount of decrease */ function _decreaseAllowance( address owner, address spender, uint256 decrement ) internal override { _approve( owner, spender, allowed[owner][spender].sub( decrement, "ERC20: decreased allowance below zero" ) ); } }
File 12 of 12: UniswapV2Router02
pragma solidity =0.6.6; interface IUniswapV2Factory { event PairCreated(address indexed token0, address indexed token1, address pair, uint); function feeTo() external view returns (address); function feeToSetter() external view returns (address); function getPair(address tokenA, address tokenB) external view returns (address pair); function allPairs(uint) external view returns (address pair); function allPairsLength() external view returns (uint); function createPair(address tokenA, address tokenB) external returns (address pair); function setFeeTo(address) external; function setFeeToSetter(address) external; } interface IUniswapV2Pair { event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); function name() external pure returns (string memory); function symbol() external pure returns (string memory); function decimals() external pure returns (uint8); function totalSupply() external view returns (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); function transfer(address to, uint value) external returns (bool); function transferFrom(address from, address to, uint value) external returns (bool); function DOMAIN_SEPARATOR() external view returns (bytes32); function PERMIT_TYPEHASH() external pure returns (bytes32); function nonces(address owner) external view returns (uint); function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; event Mint(address indexed sender, uint amount0, uint amount1); event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); event Swap( address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to ); event Sync(uint112 reserve0, uint112 reserve1); function MINIMUM_LIQUIDITY() external pure returns (uint); function factory() external view returns (address); function token0() external view returns (address); function token1() external view returns (address); function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); function price0CumulativeLast() external view returns (uint); function price1CumulativeLast() external view returns (uint); function kLast() external view returns (uint); function mint(address to) external returns (uint liquidity); function burn(address to) external returns (uint amount0, uint amount1); function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; function skim(address to) external; function sync() external; function initialize(address, address) external; } interface IUniswapV2Router01 { function factory() external pure returns (address); function WETH() external pure returns (address); function addLiquidity( address tokenA, address tokenB, uint amountADesired, uint amountBDesired, uint amountAMin, uint amountBMin, address to, uint deadline ) external returns (uint amountA, uint amountB, uint liquidity); function addLiquidityETH( address token, uint amountTokenDesired, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external payable returns (uint amountToken, uint amountETH, uint liquidity); function removeLiquidity( address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline ) external returns (uint amountA, uint amountB); function removeLiquidityETH( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external returns (uint amountToken, uint amountETH); function removeLiquidityWithPermit( address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint amountA, uint amountB); function removeLiquidityETHWithPermit( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint amountToken, uint amountETH); function swapExactTokensForTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external returns (uint[] memory amounts); function swapTokensForExactTokens( uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline ) external returns (uint[] memory amounts); function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts); function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts); function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts); function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts); function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB); function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut); function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn); function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts); } interface IUniswapV2Router02 is IUniswapV2Router01 { function removeLiquidityETHSupportingFeeOnTransferTokens( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external returns (uint amountETH); function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint amountETH); function swapExactTokensForTokensSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external; function swapExactETHForTokensSupportingFeeOnTransferTokens( uint amountOutMin, address[] calldata path, address to, uint deadline ) external payable; function swapExactTokensForETHSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external; } interface IERC20 { event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); 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 (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); function transfer(address to, uint value) external returns (bool); function transferFrom(address from, address to, uint value) external returns (bool); } interface IWETH { function deposit() external payable; function transfer(address to, uint value) external returns (bool); function withdraw(uint) external; } contract UniswapV2Router02 is IUniswapV2Router02 { using SafeMath for uint; address public immutable override factory; address public immutable override WETH; modifier ensure(uint deadline) { require(deadline >= block.timestamp, 'UniswapV2Router: EXPIRED'); _; } constructor(address _factory, address _WETH) public { factory = _factory; WETH = _WETH; } receive() external payable { assert(msg.sender == WETH); // only accept ETH via fallback from the WETH contract } // **** ADD LIQUIDITY **** function _addLiquidity( address tokenA, address tokenB, uint amountADesired, uint amountBDesired, uint amountAMin, uint amountBMin ) internal virtual returns (uint amountA, uint amountB) { // create the pair if it doesn't exist yet if (IUniswapV2Factory(factory).getPair(tokenA, tokenB) == address(0)) { IUniswapV2Factory(factory).createPair(tokenA, tokenB); } (uint reserveA, uint reserveB) = UniswapV2Library.getReserves(factory, tokenA, tokenB); if (reserveA == 0 && reserveB == 0) { (amountA, amountB) = (amountADesired, amountBDesired); } else { uint amountBOptimal = UniswapV2Library.quote(amountADesired, reserveA, reserveB); if (amountBOptimal <= amountBDesired) { require(amountBOptimal >= amountBMin, 'UniswapV2Router: INSUFFICIENT_B_AMOUNT'); (amountA, amountB) = (amountADesired, amountBOptimal); } else { uint amountAOptimal = UniswapV2Library.quote(amountBDesired, reserveB, reserveA); assert(amountAOptimal <= amountADesired); require(amountAOptimal >= amountAMin, 'UniswapV2Router: INSUFFICIENT_A_AMOUNT'); (amountA, amountB) = (amountAOptimal, amountBDesired); } } } function addLiquidity( address tokenA, address tokenB, uint amountADesired, uint amountBDesired, uint amountAMin, uint amountBMin, address to, uint deadline ) external virtual override ensure(deadline) returns (uint amountA, uint amountB, uint liquidity) { (amountA, amountB) = _addLiquidity(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin); address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB); TransferHelper.safeTransferFrom(tokenA, msg.sender, pair, amountA); TransferHelper.safeTransferFrom(tokenB, msg.sender, pair, amountB); liquidity = IUniswapV2Pair(pair).mint(to); } function addLiquidityETH( address token, uint amountTokenDesired, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external virtual override payable ensure(deadline) returns (uint amountToken, uint amountETH, uint liquidity) { (amountToken, amountETH) = _addLiquidity( token, WETH, amountTokenDesired, msg.value, amountTokenMin, amountETHMin ); address pair = UniswapV2Library.pairFor(factory, token, WETH); TransferHelper.safeTransferFrom(token, msg.sender, pair, amountToken); IWETH(WETH).deposit{value: amountETH}(); assert(IWETH(WETH).transfer(pair, amountETH)); liquidity = IUniswapV2Pair(pair).mint(to); // refund dust eth, if any if (msg.value > amountETH) TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH); } // **** REMOVE LIQUIDITY **** function removeLiquidity( address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline ) public virtual override ensure(deadline) returns (uint amountA, uint amountB) { address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB); IUniswapV2Pair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair (uint amount0, uint amount1) = IUniswapV2Pair(pair).burn(to); (address token0,) = UniswapV2Library.sortTokens(tokenA, tokenB); (amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0); require(amountA >= amountAMin, 'UniswapV2Router: INSUFFICIENT_A_AMOUNT'); require(amountB >= amountBMin, 'UniswapV2Router: INSUFFICIENT_B_AMOUNT'); } function removeLiquidityETH( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) public virtual override ensure(deadline) returns (uint amountToken, uint amountETH) { (amountToken, amountETH) = removeLiquidity( token, WETH, liquidity, amountTokenMin, amountETHMin, address(this), deadline ); TransferHelper.safeTransfer(token, to, amountToken); IWETH(WETH).withdraw(amountETH); TransferHelper.safeTransferETH(to, amountETH); } function removeLiquidityWithPermit( address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external virtual override returns (uint amountA, uint amountB) { address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB); uint value = approveMax ? uint(-1) : liquidity; IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s); (amountA, amountB) = removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline); } function removeLiquidityETHWithPermit( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external virtual override returns (uint amountToken, uint amountETH) { address pair = UniswapV2Library.pairFor(factory, token, WETH); uint value = approveMax ? uint(-1) : liquidity; IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s); (amountToken, amountETH) = removeLiquidityETH(token, liquidity, amountTokenMin, amountETHMin, to, deadline); } // **** REMOVE LIQUIDITY (supporting fee-on-transfer tokens) **** function removeLiquidityETHSupportingFeeOnTransferTokens( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) public virtual override ensure(deadline) returns (uint amountETH) { (, amountETH) = removeLiquidity( token, WETH, liquidity, amountTokenMin, amountETHMin, address(this), deadline ); TransferHelper.safeTransfer(token, to, IERC20(token).balanceOf(address(this))); IWETH(WETH).withdraw(amountETH); TransferHelper.safeTransferETH(to, amountETH); } function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external virtual override returns (uint amountETH) { address pair = UniswapV2Library.pairFor(factory, token, WETH); uint value = approveMax ? uint(-1) : liquidity; IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s); amountETH = removeLiquidityETHSupportingFeeOnTransferTokens( token, liquidity, amountTokenMin, amountETHMin, to, deadline ); } // **** SWAP **** // requires the initial amount to have already been sent to the first pair function _swap(uint[] memory amounts, address[] memory path, address _to) internal virtual { for (uint i; i < path.length - 1; i++) { (address input, address output) = (path[i], path[i + 1]); (address token0,) = UniswapV2Library.sortTokens(input, output); uint amountOut = amounts[i + 1]; (uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOut) : (amountOut, uint(0)); address to = i < path.length - 2 ? UniswapV2Library.pairFor(factory, output, path[i + 2]) : _to; IUniswapV2Pair(UniswapV2Library.pairFor(factory, input, output)).swap( amount0Out, amount1Out, to, new bytes(0) ); } } function swapExactTokensForTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external virtual override ensure(deadline) returns (uint[] memory amounts) { amounts = UniswapV2Library.getAmountsOut(factory, amountIn, path); require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT'); TransferHelper.safeTransferFrom( path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0] ); _swap(amounts, path, to); } function swapTokensForExactTokens( uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline ) external virtual override ensure(deadline) returns (uint[] memory amounts) { amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path); require(amounts[0] <= amountInMax, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT'); TransferHelper.safeTransferFrom( path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0] ); _swap(amounts, path, to); } function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external virtual override payable ensure(deadline) returns (uint[] memory amounts) { require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH'); amounts = UniswapV2Library.getAmountsOut(factory, msg.value, path); require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT'); IWETH(WETH).deposit{value: amounts[0]}(); assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0])); _swap(amounts, path, to); } function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) external virtual override ensure(deadline) returns (uint[] memory amounts) { require(path[path.length - 1] == WETH, 'UniswapV2Router: INVALID_PATH'); amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path); require(amounts[0] <= amountInMax, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT'); TransferHelper.safeTransferFrom( path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0] ); _swap(amounts, path, address(this)); IWETH(WETH).withdraw(amounts[amounts.length - 1]); TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]); } function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external virtual override ensure(deadline) returns (uint[] memory amounts) { require(path[path.length - 1] == WETH, 'UniswapV2Router: INVALID_PATH'); amounts = UniswapV2Library.getAmountsOut(factory, amountIn, path); require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT'); TransferHelper.safeTransferFrom( path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0] ); _swap(amounts, path, address(this)); IWETH(WETH).withdraw(amounts[amounts.length - 1]); TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]); } function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) external virtual override payable ensure(deadline) returns (uint[] memory amounts) { require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH'); amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path); require(amounts[0] <= msg.value, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT'); IWETH(WETH).deposit{value: amounts[0]}(); assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0])); _swap(amounts, path, to); // refund dust eth, if any if (msg.value > amounts[0]) TransferHelper.safeTransferETH(msg.sender, msg.value - amounts[0]); } // **** SWAP (supporting fee-on-transfer tokens) **** // requires the initial amount to have already been sent to the first pair function _swapSupportingFeeOnTransferTokens(address[] memory path, address _to) internal virtual { for (uint i; i < path.length - 1; i++) { (address input, address output) = (path[i], path[i + 1]); (address token0,) = UniswapV2Library.sortTokens(input, output); IUniswapV2Pair pair = IUniswapV2Pair(UniswapV2Library.pairFor(factory, input, output)); uint amountInput; uint amountOutput; { // scope to avoid stack too deep errors (uint reserve0, uint reserve1,) = pair.getReserves(); (uint reserveInput, uint reserveOutput) = input == token0 ? (reserve0, reserve1) : (reserve1, reserve0); amountInput = IERC20(input).balanceOf(address(pair)).sub(reserveInput); amountOutput = UniswapV2Library.getAmountOut(amountInput, reserveInput, reserveOutput); } (uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOutput) : (amountOutput, uint(0)); address to = i < path.length - 2 ? UniswapV2Library.pairFor(factory, output, path[i + 2]) : _to; pair.swap(amount0Out, amount1Out, to, new bytes(0)); } } function swapExactTokensForTokensSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external virtual override ensure(deadline) { TransferHelper.safeTransferFrom( path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amountIn ); uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to); _swapSupportingFeeOnTransferTokens(path, to); require( IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT' ); } function swapExactETHForTokensSupportingFeeOnTransferTokens( uint amountOutMin, address[] calldata path, address to, uint deadline ) external virtual override payable ensure(deadline) { require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH'); uint amountIn = msg.value; IWETH(WETH).deposit{value: amountIn}(); assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amountIn)); uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to); _swapSupportingFeeOnTransferTokens(path, to); require( IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT' ); } function swapExactTokensForETHSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external virtual override ensure(deadline) { require(path[path.length - 1] == WETH, 'UniswapV2Router: INVALID_PATH'); TransferHelper.safeTransferFrom( path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amountIn ); _swapSupportingFeeOnTransferTokens(path, address(this)); uint amountOut = IERC20(WETH).balanceOf(address(this)); require(amountOut >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT'); IWETH(WETH).withdraw(amountOut); TransferHelper.safeTransferETH(to, amountOut); } // **** LIBRARY FUNCTIONS **** function quote(uint amountA, uint reserveA, uint reserveB) public pure virtual override returns (uint amountB) { return UniswapV2Library.quote(amountA, reserveA, reserveB); } function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) public pure virtual override returns (uint amountOut) { return UniswapV2Library.getAmountOut(amountIn, reserveIn, reserveOut); } function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) public pure virtual override returns (uint amountIn) { return UniswapV2Library.getAmountIn(amountOut, reserveIn, reserveOut); } function getAmountsOut(uint amountIn, address[] memory path) public view virtual override returns (uint[] memory amounts) { return UniswapV2Library.getAmountsOut(factory, amountIn, path); } function getAmountsIn(uint amountOut, address[] memory path) public view virtual override returns (uint[] memory amounts) { return UniswapV2Library.getAmountsIn(factory, amountOut, path); } } // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math) library SafeMath { function add(uint x, uint y) internal pure returns (uint z) { require((z = x + y) >= x, 'ds-math-add-overflow'); } function sub(uint x, uint y) internal pure returns (uint z) { require((z = x - y) <= x, 'ds-math-sub-underflow'); } function mul(uint x, uint y) internal pure returns (uint z) { require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow'); } } library UniswapV2Library { using SafeMath for uint; // returns sorted token addresses, used to handle return values from pairs sorted in this order function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) { require(tokenA != tokenB, 'UniswapV2Library: IDENTICAL_ADDRESSES'); (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); require(token0 != address(0), 'UniswapV2Library: ZERO_ADDRESS'); } // calculates the CREATE2 address for a pair without making any external calls function pairFor(address factory, address tokenA, address tokenB) internal pure returns (address pair) { (address token0, address token1) = sortTokens(tokenA, tokenB); pair = address(uint(keccak256(abi.encodePacked( hex'ff', factory, keccak256(abi.encodePacked(token0, token1)), hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f' // init code hash )))); } // fetches and sorts the reserves for a pair function getReserves(address factory, address tokenA, address tokenB) internal view returns (uint reserveA, uint reserveB) { (address token0,) = sortTokens(tokenA, tokenB); (uint reserve0, uint reserve1,) = IUniswapV2Pair(pairFor(factory, tokenA, tokenB)).getReserves(); (reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0); } // given some amount of an asset and pair reserves, returns an equivalent amount of the other asset function quote(uint amountA, uint reserveA, uint reserveB) internal pure returns (uint amountB) { require(amountA > 0, 'UniswapV2Library: INSUFFICIENT_AMOUNT'); require(reserveA > 0 && reserveB > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY'); amountB = amountA.mul(reserveB) / reserveA; } // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) { require(amountIn > 0, 'UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT'); require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY'); uint amountInWithFee = amountIn.mul(997); uint numerator = amountInWithFee.mul(reserveOut); uint denominator = reserveIn.mul(1000).add(amountInWithFee); amountOut = numerator / denominator; } // given an output amount of an asset and pair reserves, returns a required input amount of the other asset function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) internal pure returns (uint amountIn) { require(amountOut > 0, 'UniswapV2Library: INSUFFICIENT_OUTPUT_AMOUNT'); require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY'); uint numerator = reserveIn.mul(amountOut).mul(1000); uint denominator = reserveOut.sub(amountOut).mul(997); amountIn = (numerator / denominator).add(1); } // performs chained getAmountOut calculations on any number of pairs function getAmountsOut(address factory, uint amountIn, address[] memory path) internal view returns (uint[] memory amounts) { require(path.length >= 2, 'UniswapV2Library: INVALID_PATH'); amounts = new uint[](path.length); amounts[0] = amountIn; for (uint i; i < path.length - 1; i++) { (uint reserveIn, uint reserveOut) = getReserves(factory, path[i], path[i + 1]); amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut); } } // performs chained getAmountIn calculations on any number of pairs function getAmountsIn(address factory, uint amountOut, address[] memory path) internal view returns (uint[] memory amounts) { require(path.length >= 2, 'UniswapV2Library: INVALID_PATH'); amounts = new uint[](path.length); amounts[amounts.length - 1] = amountOut; for (uint i = path.length - 1; i > 0; i--) { (uint reserveIn, uint reserveOut) = getReserves(factory, path[i - 1], path[i]); amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut); } } } // helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false library TransferHelper { function safeApprove(address token, address to, uint value) internal { // bytes4(keccak256(bytes('approve(address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED'); } function safeTransfer(address token, address to, uint value) internal { // bytes4(keccak256(bytes('transfer(address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED'); } function safeTransferFrom(address token, address from, address to, uint value) internal { // bytes4(keccak256(bytes('transferFrom(address,address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED'); } function safeTransferETH(address to, uint value) internal { (bool success,) = to.call{value:value}(new bytes(0)); require(success, 'TransferHelper: ETH_TRANSFER_FAILED'); } }