diff --git a/.circleci/config.yml b/.circleci/config.yml index fc76c79..4391cfd 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -7,7 +7,7 @@ jobs: build: working_directory: ~/repo docker: - - image: circleci/node:10.18.1 + - image: circleci/node:erbium steps: - checkout - run: @@ -49,7 +49,7 @@ jobs: test: working_directory: ~/repo docker: - - image: circleci/node:10.18.1 + - image: circleci/node:erbium steps: - restore_cache: keys: diff --git a/packages/contract-artifacts/contracts/NoteStream.ts b/packages/contract-artifacts/contracts/NoteStream.ts index bfe7aab..1b901da 100644 --- a/packages/contract-artifacts/contracts/NoteStream.ts +++ b/packages/contract-artifacts/contracts/NoteStream.ts @@ -242,9 +242,14 @@ export default { type: 'address', }, { - internalType: 'bytes32', - name: 'noteHash', - type: 'bytes32', + internalType: 'bytes', + name: 'proof', + type: 'bytes', + }, + { + internalType: 'bytes', + name: 'proofSignature', + type: 'bytes', }, { internalType: 'address', @@ -435,9 +440,9 @@ export default { }, ], bytecode: - '0x60806040523480156200001157600080fd5b506040516200290b3803806200290b833981810160405260208110156200003757600080fd5b50516200005f620000506001600160e01b03620000fb16565b6001600160e01b03620000ff16565b6001805461ffff19166101001790556001600160a01b038116620000ca576040805162461bcd60e51b815260206004820181905260248201527f41434520636f6e747261637420697320746865207a65726f2061646472657373604482015290519081900360640190fd5b600180546001600160a01b03909216620100000262010000600160b01b031990921691909117815560025562000247565b3390565b6200011a8160006200015160201b620021401790919060201c565b6040516001600160a01b038216907f6719d08c1888103bea251a4ed56406bd0c3e69723c8a1686e017e7bbe159b6f890600090a250565b6200016682826001600160e01b03620001de16565b15620001b9576040805162461bcd60e51b815260206004820152601f60248201527f526f6c65733a206163636f756e7420616c72656164792068617320726f6c6500604482015290519081900360640190fd5b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b60006001600160a01b038216620002275760405162461bcd60e51b8152600401808060200182810382526022815260200180620028e96022913960400191505060405180910390fd5b506001600160a01b03166000908152602091909152604090205460ff1690565b61269280620002576000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c80635c975abb116100715780635c975abb146103035780636ef8d66d1461030b57806382dc1ec4146103135780638456cb5914610339578063894e9a0d14610341578063911ab96c146103a8576100a9565b80631468a5d4146100ae5780631e99d569146101e25780633bc9e403146101fc5780633f4ba83a146102d557806346fbf68e146102dd575b600080fd5b6101e0600480360360808110156100c457600080fd5b81359190810190604081016020820135600160201b8111156100e557600080fd5b8201836020820111156100f757600080fd5b803590602001918460018302840111600160201b8311171561011857600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b81111561016a57600080fd5b82018360208201111561017c57600080fd5b803590602001918460018302840111600160201b8311171561019d57600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955050913592506103e8915050565b005b6101ea6106f0565b60408051918252519081900360200190f35b6102c16004803603608081101561021257600080fd5b81359190810190604081016020820135600160201b81111561023357600080fd5b82018360208201111561024557600080fd5b803590602001918460018302840111600160201b8311171561026657600080fd5b919390929091602081019035600160201b81111561028357600080fd5b82018360208201111561029557600080fd5b803590602001918460018302840111600160201b831117156102b657600080fd5b9193509150356106f6565b604080519115158252519081900360200190f35b6101e0610a90565b6102c1600480360360208110156102f357600080fd5b50356001600160a01b0316610b79565b6102c1610b91565b6101e0610b9a565b6101e06004803603602081101561032957600080fd5b50356001600160a01b0316610bac565b6101e0610bfe565b61035e6004803603602081101561035757600080fd5b5035610cc4565b604080516001600160a01b039889168152968816602088015286810195909552929095166060850152608084015260a083019390935260c082019290925290519081900360e00190f35b6101ea600480360360a08110156103be57600080fd5b506001600160a01b0381358116916020810135916040820135169060608101359060800135610d88565b600154610100900460ff16610444576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6001805461ff0019811690915560ff1615610499576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6000848152600360205260409020600601548490600160a01b900460ff16610500576040805162461bcd60e51b81526020600482015260156024820152741cdd1c99585b48191bd95cc81b9bdd08195e1a5cdd605a1b604482015290519081900360640190fd5b60008581526003602052604090206004015485906001600160a01b0316331461055a5760405162461bcd60e51b81526004018080602001828103825260298152602001806126136029913960400191505060405180910390fd5b6000868152600360205260409020836105b2576040805162461bcd60e51b81526020600482015260156024820152741e995c9bc81d985b1d59481dda5d1a191c985dd85b605a1b604482015290519081900360640190fd5b600281015442906105c9908663ffffffff6110b216565b1061061b576040805162461bcd60e51b815260206004820181905260248201527f77697468647261772069732067726561746572207468616e20616c6c6f776564604482015290519081900360640190fd5b60015460609061063c906201000090046001600160a01b0316888785611113565b9150506000610662600160029054906101000a90046001600160a01b03168884866113e1565b808455600284015490915061067d908763ffffffff6110b216565b60028401556004830154600584015460408051848152602081018a905281516001600160a01b0394851694909316928d927fc40560fdf83328f954941bff2b9141084d3c22e88c89a758557961e1966a57a9928290030190a450506001805461ff00191661010017905550505050505050565b60025481565b600154600090610100900460ff16610755576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6001805461ff00191690556000878152600360205260409020600601548790600160a01b900460ff166107c7576040805162461bcd60e51b81526020600482015260156024820152741cdd1c99585b48191bd95cc81b9bdd08195e1a5cdd605a1b604482015290519081900360640190fd5b60008881526003602052604090206005015488906001600160a01b031633148061080a57506000818152600360205260409020600401546001600160a01b031633145b6108455760405162461bcd60e51b815260040180806020018281038252603781526020018061256b6037913960400191505060405180910390fd5b60008981526003602081905260409091209081015460028201541415610878576108708a60006116cb565b935050610a75565b600085116108b75760405162461bcd60e51b815260040180806020018281038252602581526020018061248a6025913960400191505060405180910390fd5b60058101546001600160a01b031633141561094657600281015442906108e3908763ffffffff6110b216565b1180610906575060038101546002820154610904908763ffffffff6110b216565b145b6109415760405162461bcd60e51b815260040180806020018281038252602a8152602001806123ab602a913960400191505060405180910390fd5b6109ae565b60048101546001600160a01b03163314156109ae5760028101544290610972908763ffffffff6110b216565b106109ae5760405162461bcd60e51b815260040180806020018281038252602d81526020018061237e602d913960400191505060405180910390fd5b6060610a09600160029054906101000a90046001600160a01b03168b8b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508b92508791506111139050565b915050610a65600160029054906101000a90046001600160a01b031689898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525086925087915061178c9050565b50610a708b876116cb565b945050505b50506001805461ff0019166101001790559695505050505050565b610aa0610a9b611a0d565b610b79565b610adb5760405162461bcd60e51b81526004018080602001828103825260308152602001806123026030913960400191505060405180910390fd5b60015460ff16610b29576040805162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015290519081900360640190fd5b6001805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa610b5c611a0d565b604080516001600160a01b039092168252519081900360200190a1565b6000610b8b818363ffffffff611a1116565b92915050565b60015460ff1690565b610baa610ba5611a0d565b611a78565b565b610bb7610a9b611a0d565b610bf25760405162461bcd60e51b81526004018080602001828103825260308152602001806123026030913960400191505060405180910390fd5b610bfb81611ac0565b50565b610c09610a9b611a0d565b610c445760405162461bcd60e51b81526004018080602001828103825260308152602001806123026030913960400191505060405180910390fd5b60015460ff1615610c8f576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6001805460ff1916811790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258610b5c611a0d565b6000818152600360205260408120600601548190819081908190819081908890600160a01b900460ff16610d37576040805162461bcd60e51b81526020600482015260156024820152741cdd1c99585b48191bd95cc81b9bdd08195e1a5cdd605a1b604482015290519081900360640190fd5b5050506000958652505060036020819052604090942060058101546004820154825460068401546001850154600286015495909901546001600160a01b039485169a93851699929850931695509350565b60015460009060ff1615610dd6576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6001600160a01b038616610e31576040805162461bcd60e51b815260206004820152601a60248201527f73747265616d20746f20746865207a65726f2061646472657373000000000000604482015290519081900360640190fd5b6001600160a01b038616301415610e8f576040805162461bcd60e51b815260206004820152601d60248201527f73747265616d20746f2074686520636f6e747261637420697473656c66000000604482015290519081900360640190fd5b6001600160a01b038616331415610ee4576040805162461bcd60e51b815260206004820152601460248201527339ba3932b0b6903a37903a34329031b0b63632b960611b604482015290519081900360640190fd5b42831015610f235760405162461bcd60e51b815260040180806020018281038252602181526020018061235d6021913960400191505060405180910390fd5b828211610f615760405162461bcd60e51b81526004018080602001828103825260258152602001806124656025913960400191505060405180910390fd5b6002805460408051610100810182528881526020808201888152828401898152606084018981526001600160a01b03808f16608087019081523360a088019081528e831660c08901908152600160e08a0181815260008d815260039a8b90529b909b2099518a559651898801559451888c015592519587019590955593516004860180549186166001600160a01b0319928316179055905160058601805491861691831691909117905590516006909401805495511515600160a01b0260ff60a01b1995909416959091169490941792909216179091559154909161104c919063ffffffff6110b216565b600255604080516001600160a01b0387811682526020820189905281830187905260608201869052915191891691339184917fede16fa759a9d06c1022b933b4d4ed9b2cdcaafe19510813fdd430456f951b9a9181900360800190a49695505050505050565b60008282018381101561110c576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b606080600061113384600201548560030154611b0890919063ffffffff16565b90506111598561114d83633b9aca0063ffffffff611b4a16565b9063ffffffff611ba316565b61116287611be5565b146111aa576040805162461bcd60e51b81526020600482015260136024820152720e4c2e8d2dee640c8de40dcdee840dac2e8c6d606b1b604482015290519081900360640190fd5b60405163a2866ea360e01b8152620104016004820181815230602484018190526060604485018181528b5160648701528b5191956001600160a01b038e169563a2866ea3959094938e93919260840190602085019080838360005b8381101561121d578181015183820152602001611205565b50505050905090810190601f16801561124a5780820380516001836020036101000a031916815260200191505b50945050505050600060405180830381600087803b15801561126b57600080fd5b505af115801561127f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156112a857600080fd5b8101908080516040519392919084600160201b8211156112c757600080fd5b9083019060208201858111156112dc57600080fd5b8251600160201b8111828201881017156112f557600080fd5b82525081516020918201929091019080838360005b8381101561132257818101518382015260200161130a565b50505050905090810190601f16801561134f5780820380516001836020036101000a031916815260200191505b50604052505050905061137461136f600083611c1390919063ffffffff16565b611c6a565b50508654919550935061139661139186600063ffffffff611c1316565b611c94565b60200151146113d65760405162461bcd60e51b81526004018080602001828103825260228152602001806125a26022913960400191505060405180910390fd5b505094509492505050565b6000606061140786866113fd611391888763ffffffff611c1316565b6020015186611cd7565b905060608061141583611c6a565b5050915091506114236122e2565b61143761139183600163ffffffff611c1316565b80519091506001600160a01b031630146114825760405162461bcd60e51b81526004018080602001828103825260308152602001806124af6030913960400191505060405180910390fd5b600586015460408201516001600160a01b03909116906114a390600061208a565b6001600160a01b0316146114e85760405162461bcd60e51b81526004018080602001828103825260288152602001806125c46028913960400191505060405180910390fd5b600486015460408201516001600160a01b039091169061150990600161208a565b6001600160a01b03161461154e5760405162461bcd60e51b815260040180806020018281038252602b815260200180612332602b913960400191505060405180910390fd5b60068601546001600160a01b0316631f2ac16a61157561139186600063ffffffff611c1316565b60200151604080516001600160e01b031960e085901b16815260048101929092523060248301526001604483015260806064830152600060848301819052905160c48084019382900301818387803b1580156115d057600080fd5b505af11580156115e4573d6000803e3d6000fd5b505050506006860154604080516366ff548760e11b81526201010160048201818152602483019384528851604484015288516001600160a01b039095169463cdfea90e9492938a9391606490910190602085019080838360005b8381101561165657818101518382015260200161163e565b50505050905090810190601f1680156116835780820380516001836020036101000a031916815260200191505b509350505050600060405180830381600087803b1580156116a357600080fd5b505af11580156116b7573d6000803e3d6000fd5b505050506020015198975050505050505050565b6000828152600360209081526040808320600481015460058201548351878152935192946001600160a01b0392831694919092169288927f78771645abf470107bd6a847c532dba992a0e2c0995d479ebe8153dea930543c928290030190a450505060009081526003602081905260408220828155600180820184905560028201849055918101929092556004820180546001600160a01b03199081169091556005830180549091169055600690910180546001600160a81b031916905590565b600060606117a886866113fd611391888763ffffffff611c1316565b90506060806117b683611c6a565b509193509150600090506117d3611391848363ffffffff611c1316565b6020015160048701549091506001600160a01b03166117fc61139184600063ffffffff611c1316565b516001600160a01b0316146118425760405162461bcd60e51b815260040180806020018281038252602e8152602001806124df602e913960400191505060405180910390fd5b60058601546001600160a01b031661186461139184600163ffffffff611c1316565b516001600160a01b0316146118aa5760405162461bcd60e51b815260040180806020018281038252602c815260200180612439602c913960400191505060405180910390fd5b600686015460408051630f9560b560e11b815260048101849052306024820152600160448201526080606482015260006084820181905291516001600160a01b0390931692631f2ac16a9260c48084019391929182900301818387803b15801561191357600080fd5b505af1158015611927573d6000803e3d6000fd5b505050506006860154604080516366ff548760e11b81526201010160048201818152602483019384528851604484015288516001600160a01b039095169463cdfea90e9492938a9391606490910190602085019080838360005b83811015611999578181015183820152602001611981565b50505050905090810190601f1680156119c65780820380516001836020036101000a031916815260200191505b509350505050600060405180830381600087803b1580156119e657600080fd5b505af11580156119fa573d6000803e3d6000fd5b5060019c9b505050505050505050505050565b3390565b60006001600160a01b038216611a585760405162461bcd60e51b81526004018080602001828103825260228152602001806124176022913960400191505060405180910390fd5b506001600160a01b03166000908152602091909152604090205460ff1690565b611a8960008263ffffffff6120d916565b6040516001600160a01b038216907fcd265ebaf09df2871cc7bd4133404a235ba12eff2041bb89d9c714a2621c7c7e90600090a250565b611ad160008263ffffffff61214016565b6040516001600160a01b038216907f6719d08c1888103bea251a4ed56406bd0c3e69723c8a1686e017e7bbe159b6f890600090a250565b600061110c83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506121c1565b600082611b5957506000610b8b565b82820282848281611b6657fe5b041461110c5760405162461bcd60e51b81526004018080602001828103825260218152602001806123f66021913960400191505060405180910390fd5b600061110c83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612258565b6040810151606082015160009190611c0b8161114d84633b9aca0063ffffffff611b4a16565b949350505050565b602082810151908202830160400151830190821080611c635760405162461bcd60e51b815260040180806020018281038252602281526020018061263c6022913960400191505060405180910390fd5b5092915050565b60208101516040820151606083015160808401519284019491909301926001600160a01b03169190565b611c9c6122e2565b6000806060611caa856122bd565b604080516060810182526001600160a01b0390941684526020840192909252908201529350505050919050565b60405163a2866ea360e01b8152620101016004820181815230602484018190526060604485018181528851606487015288519195611e98956000956001600160a01b038d169563a2866ea395929490938d9360849091019060208501908083838d5b83811015611d51578181015183820152602001611d39565b50505050905090810190601f168015611d7e5780820380516001836020036101000a031916815260200191505b50945050505050600060405180830381600087803b158015611d9f57600080fd5b505af1158015611db3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015611ddc57600080fd5b8101908080516040519392919084600160201b821115611dfb57600080fd5b908301906020820185811115611e1057600080fd5b8251600160201b811182820188101715611e2957600080fd5b82525081516020918201929091019080838360005b83811015611e56578181015183820152602001611e3e565b50505050905090810190601f168015611e835780820380516001836020036101000a031916815260200191505b50604052505050611c1390919063ffffffff16565b90506060806000611ea884611c6a565b9350509250925080600014611f04576040805162461bcd60e51b815260206004820152601d60248201527f6e6f6e7a65726f207075626c69632076616c7565207472616e73666572000000604482015290519081900360640190fd5b611f0d836122db565b600114611f61576040805162461bcd60e51b815260206004820152601f60248201527f496e636f7272656374206e756d626572206f6620696e707574206e6f74657300604482015290519081900360640190fd5b611f6a826122db565b600214611fbe576040805162461bcd60e51b815260206004820181905260248201527f496e636f7272656374206e756d626572206f66206f7574707574206e6f746573604482015290519081900360640190fd5b85611fd361139184600063ffffffff611c1316565b60200151146120135760405162461bcd60e51b81526004018080602001828103825260278152602001806125ec6027913960400191505060405180910390fd5b845461202961139185600063ffffffff611c1316565b602001511461207f576040805162461bcd60e51b815260206004820152601f60248201527f73747265616d206e6f746520696e2032206973206e6f7420636f727265637400604482015290519081900360640190fd5b505050949350505050565b6020828101519082028301610101015190808310611c635760405162461bcd60e51b815260040180806020018281038252605e81526020018061250d605e913960600191505060405180910390fd5b6120e38282611a11565b61211e5760405162461bcd60e51b81526004018080602001828103825260218152602001806123d56021913960400191505060405180910390fd5b6001600160a01b0316600090815260209190915260409020805460ff19169055565b61214a8282611a11565b1561219c576040805162461bcd60e51b815260206004820152601f60248201527f526f6c65733a206163636f756e7420616c72656164792068617320726f6c6500604482015290519081900360640190fd5b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b600081848411156122505760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156122155781810151838201526020016121fd565b50505050905090810190601f1680156122425780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600081836122a75760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156122155781810151838201526020016121fd565b5060008385816122b357fe5b0495945050505050565b604081015160608201516001600160a01b0390911692909160800190565b6020015190565b604080516060808201835260008083526020830152918101919091529056fe506175736572526f6c653a2063616c6c657220646f6573206e6f742068617665207468652050617573657220726f6c6573747265616d20726563697069656e742063616e27742076696577206e65772073747265616d206e6f746573746172742074696d65206265666f726520626c6f636b2e74696d657374616d70726563697069656e7420726563656976657320746f6f206d7563682066726f6d2063616e63656c6c6174696f6e73656e64657220726563656976657320746f6f206d7563682066726f6d2063616e63656c6c6174696f6e526f6c65733a206163636f756e7420646f6573206e6f74206861766520726f6c65536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77526f6c65733a206163636f756e7420697320746865207a65726f206164647265737353747265616d2073656e64657220646f65736e2774206f776e207365636f6e64206f7574707574206e6f746553747265616d206475726174696f6e206e6f742067726561746572207468616e207a65726f63616e63656c6c6174696f6e2077697468207a65726f20756e636c61696d65642074696d656368616e6765206e6f746520696e2032206973206e6f74206f776e65642062792073747265616d20636f6e747261637453747265616d20726563697069656e7420646f65736e2774206f776e206669727374206f7574707574206e6f746561646472657373506f73206f7574206f6620626f756e6473202d2061646472657373506f73206d757374206265206c657373207468616e20746865206e756d626572206f662061646472657373657320746f20626520617070726f76656463616c6c6572206973206e6f74207468652073656e646572206f722074686520726563697069656e74206f66207468652073747265616d696e636f7272656374206e6f74696f6e616c206e6f746520696e2070726f6f66203173747265616d2073656e6465722063616e27742076696577206e65772073747265616d206e6f74657769746864726177206e6f746520696e2032206973206e6f74207468652073616d65206173203163616c6c6572206973206e6f742074686520726563697069656e74206f66207468652073747265616d415a54454320617272617920696e646578206973206f7574206f6620626f756e6473a265627a7a723158204b885b0fbc3e77ad991ce1dd489201ae8a4576ce93a7ba422ecf6cb1e2ceeb3464736f6c634300050f0032526f6c65733a206163636f756e7420697320746865207a65726f2061646472657373', + '0x60806040523480156200001157600080fd5b50604051620031af380380620031af833981810160405260208110156200003757600080fd5b50516200005f620000506001600160e01b03620000fb16565b6001600160e01b03620000ff16565b6001805461ffff19166101001790556001600160a01b038116620000ca576040805162461bcd60e51b815260206004820181905260248201527f41434520636f6e747261637420697320746865207a65726f2061646472657373604482015290519081900360640190fd5b600180546001600160a01b03909216620100000262010000600160b01b031990921691909117815560025562000247565b3390565b6200011a8160006200015160201b620029261790919060201c565b6040516001600160a01b038216907f6719d08c1888103bea251a4ed56406bd0c3e69723c8a1686e017e7bbe159b6f890600090a250565b6200016682826001600160e01b03620001de16565b15620001b9576040805162461bcd60e51b815260206004820152601f60248201527f526f6c65733a206163636f756e7420616c72656164792068617320726f6c6500604482015290519081900360640190fd5b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b60006001600160a01b038216620002275760405162461bcd60e51b81526004018080602001828103825260228152602001806200318d6022913960400191505060405180910390fd5b506001600160a01b03166000908152602091909152604090205460ff1690565b612f3680620002576000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c80635989dcde116100715780635989dcde146103035780635c975abb146104505780636ef8d66d1461045857806382dc1ec4146104605780638456cb5914610486578063894e9a0d1461048e576100a9565b80631468a5d4146100ae5780631e99d569146101e25780633bc9e403146101fc5780633f4ba83a146102d557806346fbf68e146102dd575b600080fd5b6101e0600480360360808110156100c457600080fd5b81359190810190604081016020820135600160201b8111156100e557600080fd5b8201836020820111156100f757600080fd5b803590602001918460018302840111600160201b8311171561011857600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b81111561016a57600080fd5b82018360208201111561017c57600080fd5b803590602001918460018302840111600160201b8311171561019d57600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955050913592506104f5915050565b005b6101ea6107b2565b60408051918252519081900360200190f35b6102c16004803603608081101561021257600080fd5b81359190810190604081016020820135600160201b81111561023357600080fd5b82018360208201111561024557600080fd5b803590602001918460018302840111600160201b8311171561026657600080fd5b919390929091602081019035600160201b81111561028357600080fd5b82018360208201111561029557600080fd5b803590602001918460018302840111600160201b831117156102b657600080fd5b9193509150356107b8565b604080519115158252519081900360200190f35b6101e0610b51565b6102c1600480360360208110156102f357600080fd5b50356001600160a01b0316610c3a565b6101ea600480360360c081101561031957600080fd5b6001600160a01b038235169190810190604081016020820135600160201b81111561034357600080fd5b82018360208201111561035557600080fd5b803590602001918460018302840111600160201b8311171561037657600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b8111156103c857600080fd5b8201836020820111156103da57600080fd5b803590602001918460018302840111600160201b831117156103fb57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550506001600160a01b038335169350505060208101359060400135610c52565b6102c1611014565b6101e061101d565b6101e06004803603602081101561047657600080fd5b50356001600160a01b031661102f565b6101e0611081565b6104ab600480360360208110156104a457600080fd5b5035611147565b604080516001600160a01b039889168152968816602088015286810195909552929095166060850152608084015260a083019390935260c082019290925290519081900360e00190f35b600154610100900460ff16610551576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6001805461ff00191690556000848152600360205260409020600601548490600160a01b900460ff166105c3576040805162461bcd60e51b81526020600482015260156024820152741cdd1c99585b48191bd95cc81b9bdd08195e1a5cdd605a1b604482015290519081900360640190fd5b60008581526003602052604090206004015485906001600160a01b0316331461061d5760405162461bcd60e51b8152600401808060200182810382526029815260200180612eb76029913960400191505060405180910390fd5b600086815260036020526040902083610675576040805162461bcd60e51b81526020600482015260156024820152741e995c9bc81d985b1d59481dda5d1a191c985dd85b605a1b604482015290519081900360640190fd5b6002810154429061068c908663ffffffff61120b16565b106106de576040805162461bcd60e51b815260206004820181905260248201527f77697468647261772069732067726561746572207468616e20616c6c6f776564604482015290519081900360640190fd5b6001546000906106ff906201000090046001600160a01b031688878561126c565b90506000610724600160029054906101000a90046001600160a01b0316888486611555565b808455600284015490915061073f908763ffffffff61120b16565b60028401556004830154600584015460408051848152602081018a905281516001600160a01b0394851694909316928d927fc40560fdf83328f954941bff2b9141084d3c22e88c89a758557961e1966a57a9928290030190a450506001805461ff00191661010017905550505050505050565b60025481565b600154600090610100900460ff16610817576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6001805461ff00191690556000878152600360205260409020600601548790600160a01b900460ff16610889576040805162461bcd60e51b81526020600482015260156024820152741cdd1c99585b48191bd95cc81b9bdd08195e1a5cdd605a1b604482015290519081900360640190fd5b60008881526003602052604090206005015488906001600160a01b03163314806108cc57506000818152600360205260409020600401546001600160a01b031633145b6109075760405162461bcd60e51b8152600401808060200182810382526037815260200180612de86037913960400191505060405180910390fd5b6000898152600360208190526040909120908101546002820154141561093a576109328a6000611829565b935050610b36565b600085116109795760405162461bcd60e51b8152600401808060200182810382526025815260200180612cb86025913960400191505060405180910390fd5b60058101546001600160a01b0316331415610a0857600281015442906109a5908763ffffffff61120b16565b11806109c85750600381015460028201546109c6908763ffffffff61120b16565b145b610a035760405162461bcd60e51b815260040180806020018281038252602a815260200180612bd9602a913960400191505060405180910390fd5b610a70565b60048101546001600160a01b0316331415610a705760028101544290610a34908763ffffffff61120b16565b10610a705760405162461bcd60e51b815260040180806020018281038252602d815260200180612b81602d913960400191505060405180910390fd5b6000610acb600160029054906101000a90046001600160a01b03168b8b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508b925087915061126c9050565b9050610b26600160029054906101000a90046001600160a01b031689898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508692508791506118ea9050565b50610b318b87611829565b945050505b50506001805461ff0019166101001790559695505050505050565b610b61610b5c611c39565b610c3a565b610b9c5760405162461bcd60e51b8152600401808060200182810382526030815260200180612ae16030913960400191505060405180910390fd5b60015460ff16610bea576040805162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015290519081900360640190fd5b6001805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa610c1d611c39565b604080516001600160a01b039092168252519081900360200190a1565b6000610c4c818363ffffffff611c3d16565b92915050565b60015460009060ff1615610ca0576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6001600160a01b038716610cfb576040805162461bcd60e51b815260206004820152601a60248201527f73747265616d20746f20746865207a65726f2061646472657373000000000000604482015290519081900360640190fd5b6001600160a01b038716301415610d59576040805162461bcd60e51b815260206004820152601d60248201527f73747265616d20746f2074686520636f6e747261637420697473656c66000000604482015290519081900360640190fd5b6001600160a01b038716331415610dae576040805162461bcd60e51b815260206004820152601460248201527339ba3932b0b6903a37903a34329031b0b63632b960611b604482015290519081900360640190fd5b42831015610ded5760405162461bcd60e51b8152600401808060200182810382526021815260200180612b606021913960400191505060405180910390fd5b828211610e2b5760405162461bcd60e51b8152600401808060200182810382526025815260200180612c936025913960400191505060405180910390fd5b6000610e508787600160029054906101000a90046001600160a01b0316338c8a611ca4565b9050600060025490506040518061010001604052808381526020018681526020018681526020018581526020018a6001600160a01b03168152602001336001600160a01b03168152602001876001600160a01b0316815260200160011515815250600360008381526020019081526020016000206000820151816000015560208201518160010155604082015181600201556060820151816003015560808201518160040160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060a08201518160050160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060c08201518160060160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060e08201518160060160146101000a81548160ff021916908315150217905550905050610fac600160025461120b90919063ffffffff16565b600255604080516001600160a01b03888116825260208201859052818301889052606082018790529151918b1691339184917fede16fa759a9d06c1022b933b4d4ed9b2cdcaafe19510813fdd430456f951b9a9181900360800190a498975050505050505050565b60015460ff1690565b61102d611028611c39565b612257565b565b61103a610b5c611c39565b6110755760405162461bcd60e51b8152600401808060200182810382526030815260200180612ae16030913960400191505060405180910390fd5b61107e8161229f565b50565b61108c610b5c611c39565b6110c75760405162461bcd60e51b8152600401808060200182810382526030815260200180612ae16030913960400191505060405180910390fd5b60015460ff1615611112576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6001805460ff1916811790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258610c1d611c39565b6000818152600360205260408120600601548190819081908190819081908890600160a01b900460ff166111ba576040805162461bcd60e51b81526020600482015260156024820152741cdd1c99585b48191bd95cc81b9bdd08195e1a5cdd605a1b604482015290519081900360640190fd5b5050506000958652505060036020819052604090942060058101546004820154825460068401546001850154600286015495909901546001600160a01b039485169a93851699929850931695509350565b600082820183811015611265576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b60008061128a836002015484600301546122e790919063ffffffff16565b90506112b0846112a483633b9aca0063ffffffff61232916565b9063ffffffff61238216565b6112b9866123c4565b14611301576040805162461bcd60e51b81526020600482015260136024820152720e4c2e8d2dee640c8de40dcdee840dac2e8c6d606b1b604482015290519081900360640190fd5b60405163a2866ea360e01b8152620104016004820181815230602484018190526060604485018181528a5160648701528a5191956001600160a01b038d169563a2866ea3959094938d93919260840190602085019080838360005b8381101561137457818101518382015260200161135c565b50505050905090810190601f1680156113a15780820380516001836020036101000a031916815260200191505b50945050505050600060405180830381600087803b1580156113c257600080fd5b505af11580156113d6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156113ff57600080fd5b8101908080516040519392919084600160201b82111561141e57600080fd5b90830190602082018581111561143357600080fd5b8251600160201b81118282018810171561144c57600080fd5b82525081516020918201929091019080838360005b83811015611479578181015183820152602001611461565b50505050905090810190601f1680156114a65780820380516001836020036101000a031916815260200191505b5060405250505090506060806114ce6114c96000856123f290919063ffffffff16565b612449565b5050875491935091506114f06114eb84600063ffffffff6123f216565b612473565b60200151146115305760405162461bcd60e51b8152600401808060200182810382526022815260200180612e1f6022913960400191505060405180910390fd5b6115446114eb82600063ffffffff6123f216565b602001519998505050505050505050565b60006060611565868686866124b6565b905060608061157383612449565b505091509150611581612ac1565b6115956114eb83600163ffffffff6123f216565b80519091506001600160a01b031630146115e05760405162461bcd60e51b8152600401808060200182810382526030815260200180612cdd6030913960400191505060405180910390fd5b600586015460408201516001600160a01b0390911690611601906000612869565b6001600160a01b0316146116465760405162461bcd60e51b8152600401808060200182810382526028815260200180612e686028913960400191505060405180910390fd5b600486015460408201516001600160a01b0390911690611667906001612869565b6001600160a01b0316146116ac5760405162461bcd60e51b815260040180806020018281038252602b815260200180612b11602b913960400191505060405180910390fd5b60068601546001600160a01b0316631f2ac16a6116d36114eb86600063ffffffff6123f216565b60200151604080516001600160e01b031960e085901b16815260048101929092523060248301526001604483015260806064830152600060848301819052905160c48084019382900301818387803b15801561172e57600080fd5b505af1158015611742573d6000803e3d6000fd5b505050506006860154604080516366ff548760e11b81526201010160048201818152602483019384528851604484015288516001600160a01b039095169463cdfea90e9492938a9391606490910190602085019080838360005b838110156117b457818101518382015260200161179c565b50505050905090810190601f1680156117e15780820380516001836020036101000a031916815260200191505b509350505050600060405180830381600087803b15801561180157600080fd5b505af1158015611815573d6000803e3d6000fd5b505050506020015198975050505050505050565b6000828152600360209081526040808320600481015460058201548351878152935192946001600160a01b0392831694919092169288927f78771645abf470107bd6a847c532dba992a0e2c0995d479ebe8153dea930543c928290030190a450505060009081526003602081905260408220828155600180820184905560028201849055918101929092556004820180546001600160a01b03199081169091556005830180549091169055600690910180546001600160a81b031916905590565b600060606118fa868686866124b6565b905060608061190883612449565b509193509150600090506119256114eb848363ffffffff6123f216565b602001519050611933612ac1565b6119476114eb84600063ffffffff6123f216565b9050611951612ac1565b6119656114eb85600163ffffffff6123f216565b600489015483519192506001600160a01b039182169116146119b85760405162461bcd60e51b815260040180806020018281038252602e815260200180612d5c602e913960400191505060405180910390fd5b600588015481516001600160a01b03908116911614611a085760405162461bcd60e51b815260040180806020018281038252602c815260200180612c67602c913960400191505060405180910390fd5b600488015460408301516001600160a01b0390911690611a29906000612869565b6001600160a01b031614611a6e5760405162461bcd60e51b815260040180806020018281038252602b815260200180612d31602b913960400191505060405180910390fd5b600588015460408201516001600160a01b0390911690611a8f906000612869565b6001600160a01b031614611ad45760405162461bcd60e51b8152600401808060200182810382526024815260200180612d0d6024913960400191505060405180910390fd5b600688015460408051630f9560b560e11b815260048101869052306024820152600160448201526080606482015260006084820181905291516001600160a01b0390931692631f2ac16a9260c48084019391929182900301818387803b158015611b3d57600080fd5b505af1158015611b51573d6000803e3d6000fd5b505050506006880154604080516366ff548760e11b81526201010160048201818152602483019384528a5160448401528a516001600160a01b039095169463cdfea90e9492938c9391606490910190602085019080838360005b83811015611bc3578181015183820152602001611bab565b50505050905090810190601f168015611bf05780820380516001836020036101000a031916815260200191505b509350505050600060405180830381600087803b158015611c1057600080fd5b505af1158015611c24573d6000803e3d6000fd5b5060019e9d5050505050505050505050505050565b3390565b60006001600160a01b038216611c845760405162461bcd60e51b8152600401808060200182810382526022815260200180612c456022913960400191505060405180910390fd5b506001600160a01b03166000908152602091909152604090205460ff1690565b60006060856001600160a01b031663a2866ea362010101338b6040518463ffffffff1660e01b8152600401808462ffffff1662ffffff168152602001836001600160a01b03166001600160a01b0316815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611d31578181015183820152602001611d19565b50505050905090810190601f168015611d5e5780820380516001836020036101000a031916815260200191505b50945050505050600060405180830381600087803b158015611d7f57600080fd5b505af1158015611d93573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015611dbc57600080fd5b8101908080516040519392919084600160201b821115611ddb57600080fd5b908301906020820185811115611df057600080fd5b8251600160201b811182820188101715611e0957600080fd5b82525081516020918201929091019080838360005b83811015611e36578181015183820152602001611e1e565b50505050905090810190601f168015611e635780820380516001836020036101000a031916815260200191505b5060405250505090506060611e826000836123f290919063ffffffff16565b90506060611e8f82612449565b5050915050611e9d816128b8565b600114611ef1576040805162461bcd60e51b815260206004820181905260248201527f496e636f7272656374206e756d626572206f66206f7574707574206e6f746573604482015290519081900360640190fd5b611ef9612ac1565b611f0d6114eb83600063ffffffff6123f216565b80519091506001600160a01b03163014611f585760405162461bcd60e51b815260040180806020018281038252602b815260200180612bae602b913960400191505060405180910390fd5b876001600160a01b0316611f7182604001516000612869565b6001600160a01b031614611fb65760405162461bcd60e51b8152600401808060200182810382526024815260200180612b3c6024913960400191505060405180910390fd5b866001600160a01b0316611fcf82604001516001612869565b6001600160a01b0316146120145760405162461bcd60e51b8152600401808060200182810382526027815260200180612e416027913960400191505060405180910390fd5b856001600160a01b0316630a60305a62010101863060018f6040518663ffffffff1660e01b8152600401808662ffffff1662ffffff16815260200180602001856001600160a01b03166001600160a01b031681526020018415151515815260200180602001838103835287818151815260200191508051906020019080838360005b838110156120ae578181015183820152602001612096565b50505050905090810190601f1680156120db5780820380516001836020036101000a031916815260200191505b50838103825284518152845160209182019186019080838360005b8381101561210e5781810151838201526020016120f6565b50505050905090810190601f16801561213b5780820380516001836020036101000a031916815260200191505b50975050505050505050600060405180830381600087803b15801561215f57600080fd5b505af1158015612173573d6000803e3d6000fd5b5050604080516366ff548760e11b81526201010160048201818152602483019384528851604484015288516001600160a01b038d16965063cdfea90e9550919389939192909160640190602085019080838360005b838110156121e05781810151838201526020016121c8565b50505050905090810190601f16801561220d5780820380516001836020036101000a031916815260200191505b509350505050600060405180830381600087803b15801561222d57600080fd5b505af1158015612241573d6000803e3d6000fd5b50505050602001519a9950505050505050505050565b61226860008263ffffffff6128bf16565b6040516001600160a01b038216907fcd265ebaf09df2871cc7bd4133404a235ba12eff2041bb89d9c714a2621c7c7e90600090a250565b6122b060008263ffffffff61292616565b6040516001600160a01b038216907f6719d08c1888103bea251a4ed56406bd0c3e69723c8a1686e017e7bbe159b6f890600090a250565b600061126583836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506129a7565b60008261233857506000610c4c565b8282028284828161234557fe5b04146112655760405162461bcd60e51b8152600401808060200182810382526021815260200180612c246021913960400191505060405180910390fd5b600061126583836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612a3e565b60408101516060820151600091906123ea816112a484633b9aca0063ffffffff61232916565b949350505050565b6020828101519082028301604001518301908210806124425760405162461bcd60e51b8152600401808060200182810382526022815260200180612ee06022913960400191505060405180910390fd5b5092915050565b60208101516040820151606083015160808401519284019491909301926001600160a01b03169190565b61247b612ac1565b600080606061248985612aa3565b604080516060810182526001600160a01b0390941684526020840192909252908201529350505050919050565b60405163a2866ea360e01b8152620101016004820181815230602484018190526060604485018181528851606487015288519195612677956000956001600160a01b038d169563a2866ea395929490938d9360849091019060208501908083838d5b83811015612530578181015183820152602001612518565b50505050905090810190601f16801561255d5780820380516001836020036101000a031916815260200191505b50945050505050600060405180830381600087803b15801561257e57600080fd5b505af1158015612592573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156125bb57600080fd5b8101908080516040519392919084600160201b8211156125da57600080fd5b9083019060208201858111156125ef57600080fd5b8251600160201b81118282018810171561260857600080fd5b82525081516020918201929091019080838360005b8381101561263557818101518382015260200161261d565b50505050905090810190601f1680156126625780820380516001836020036101000a031916815260200191505b506040525050506123f290919063ffffffff16565b9050606080600061268784612449565b93505092509250806000146126e3576040805162461bcd60e51b815260206004820152601d60248201527f6e6f6e7a65726f207075626c69632076616c7565207472616e73666572000000604482015290519081900360640190fd5b6126ec836128b8565b600114612740576040805162461bcd60e51b815260206004820152601f60248201527f496e636f7272656374206e756d626572206f6620696e707574206e6f74657300604482015290519081900360640190fd5b612749826128b8565b60021461279d576040805162461bcd60e51b815260206004820181905260248201527f496e636f7272656374206e756d626572206f66206f7574707574206e6f746573604482015290519081900360640190fd5b856127b26114eb84600063ffffffff6123f216565b60200151146127f25760405162461bcd60e51b8152600401808060200182810382526027815260200180612e906027913960400191505060405180910390fd5b84546128086114eb85600063ffffffff6123f216565b602001511461285e576040805162461bcd60e51b815260206004820152601f60248201527f73747265616d206e6f746520696e2032206973206e6f7420636f727265637400604482015290519081900360640190fd5b505050949350505050565b60208281015190820283016101010151908083106124425760405162461bcd60e51b815260040180806020018281038252605e815260200180612d8a605e913960600191505060405180910390fd5b6020015190565b6128c98282611c3d565b6129045760405162461bcd60e51b8152600401808060200182810382526021815260200180612c036021913960400191505060405180910390fd5b6001600160a01b0316600090815260209190915260409020805460ff19169055565b6129308282611c3d565b15612982576040805162461bcd60e51b815260206004820152601f60248201527f526f6c65733a206163636f756e7420616c72656164792068617320726f6c6500604482015290519081900360640190fd5b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b60008184841115612a365760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156129fb5781810151838201526020016129e3565b50505050905090810190601f168015612a285780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b60008183612a8d5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156129fb5781810151838201526020016129e3565b506000838581612a9957fe5b0495945050505050565b604081015160608201516001600160a01b0390911692909160800190565b604080516060808201835260008083526020830152918101919091529056fe506175736572526f6c653a2063616c6c657220646f6573206e6f742068617665207468652050617573657220726f6c6573747265616d20726563697069656e742063616e27742076696577206e65772073747265616d206e6f746573747265616d2073656e6465722063616e277420766965772073747265616d206e6f746573746172742074696d65206265666f726520626c6f636b2e74696d657374616d70726563697069656e7420726563656976657320746f6f206d7563682066726f6d2063616e63656c6c6174696f6e73747265616d206e6f7465206973206e6f74206f776e65642062792073747265616d20636f6e747261637473656e64657220726563656976657320746f6f206d7563682066726f6d2063616e63656c6c6174696f6e526f6c65733a206163636f756e7420646f6573206e6f74206861766520726f6c65536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77526f6c65733a206163636f756e7420697320746865207a65726f206164647265737353747265616d2073656e64657220646f65736e2774206f776e207365636f6e64206f7574707574206e6f746553747265616d206475726174696f6e206e6f742067726561746572207468616e207a65726f63616e63656c6c6174696f6e2077697468207a65726f20756e636c61696d65642074696d656368616e6765206e6f746520696e2032206973206e6f74206f776e65642062792073747265616d20636f6e747261637473747265616d2073656e6465722063616e2774207669657720726566756e64206e6f746573747265616d20726563697069656e742063616e27742076696577207769746864726177616c206e6f746553747265616d20726563697069656e7420646f65736e2774206f776e206669727374206f7574707574206e6f746561646472657373506f73206f7574206f6620626f756e6473202d2061646472657373506f73206d757374206265206c657373207468616e20746865206e756d626572206f662061646472657373657320746f20626520617070726f76656463616c6c6572206973206e6f74207468652073656e646572206f722074686520726563697069656e74206f66207468652073747265616d696e636f7272656374206e6f74696f6e616c206e6f746520696e2070726f6f66203173747265616d20726563697069656e742063616e277420766965772073747265616d206e6f746573747265616d2073656e6465722063616e27742076696577206e65772073747265616d206e6f74657769746864726177206e6f746520696e2032206973206e6f74207468652073616d65206173203163616c6c6572206973206e6f742074686520726563697069656e74206f66207468652073747265616d415a54454320617272617920696e646578206973206f7574206f6620626f756e6473a265627a7a7231582082989ecb6430bf512f28d08363cc0a6bf2a065c4959092b9b848a6c99678da7964736f6c634300050f0032526f6c65733a206163636f756e7420697320746865207a65726f2061646472657373', deployedBytecode: - '0x608060405234801561001057600080fd5b50600436106100a95760003560e01c80635c975abb116100715780635c975abb146103035780636ef8d66d1461030b57806382dc1ec4146103135780638456cb5914610339578063894e9a0d14610341578063911ab96c146103a8576100a9565b80631468a5d4146100ae5780631e99d569146101e25780633bc9e403146101fc5780633f4ba83a146102d557806346fbf68e146102dd575b600080fd5b6101e0600480360360808110156100c457600080fd5b81359190810190604081016020820135600160201b8111156100e557600080fd5b8201836020820111156100f757600080fd5b803590602001918460018302840111600160201b8311171561011857600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b81111561016a57600080fd5b82018360208201111561017c57600080fd5b803590602001918460018302840111600160201b8311171561019d57600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955050913592506103e8915050565b005b6101ea6106f0565b60408051918252519081900360200190f35b6102c16004803603608081101561021257600080fd5b81359190810190604081016020820135600160201b81111561023357600080fd5b82018360208201111561024557600080fd5b803590602001918460018302840111600160201b8311171561026657600080fd5b919390929091602081019035600160201b81111561028357600080fd5b82018360208201111561029557600080fd5b803590602001918460018302840111600160201b831117156102b657600080fd5b9193509150356106f6565b604080519115158252519081900360200190f35b6101e0610a90565b6102c1600480360360208110156102f357600080fd5b50356001600160a01b0316610b79565b6102c1610b91565b6101e0610b9a565b6101e06004803603602081101561032957600080fd5b50356001600160a01b0316610bac565b6101e0610bfe565b61035e6004803603602081101561035757600080fd5b5035610cc4565b604080516001600160a01b039889168152968816602088015286810195909552929095166060850152608084015260a083019390935260c082019290925290519081900360e00190f35b6101ea600480360360a08110156103be57600080fd5b506001600160a01b0381358116916020810135916040820135169060608101359060800135610d88565b600154610100900460ff16610444576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6001805461ff0019811690915560ff1615610499576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6000848152600360205260409020600601548490600160a01b900460ff16610500576040805162461bcd60e51b81526020600482015260156024820152741cdd1c99585b48191bd95cc81b9bdd08195e1a5cdd605a1b604482015290519081900360640190fd5b60008581526003602052604090206004015485906001600160a01b0316331461055a5760405162461bcd60e51b81526004018080602001828103825260298152602001806126136029913960400191505060405180910390fd5b6000868152600360205260409020836105b2576040805162461bcd60e51b81526020600482015260156024820152741e995c9bc81d985b1d59481dda5d1a191c985dd85b605a1b604482015290519081900360640190fd5b600281015442906105c9908663ffffffff6110b216565b1061061b576040805162461bcd60e51b815260206004820181905260248201527f77697468647261772069732067726561746572207468616e20616c6c6f776564604482015290519081900360640190fd5b60015460609061063c906201000090046001600160a01b0316888785611113565b9150506000610662600160029054906101000a90046001600160a01b03168884866113e1565b808455600284015490915061067d908763ffffffff6110b216565b60028401556004830154600584015460408051848152602081018a905281516001600160a01b0394851694909316928d927fc40560fdf83328f954941bff2b9141084d3c22e88c89a758557961e1966a57a9928290030190a450506001805461ff00191661010017905550505050505050565b60025481565b600154600090610100900460ff16610755576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6001805461ff00191690556000878152600360205260409020600601548790600160a01b900460ff166107c7576040805162461bcd60e51b81526020600482015260156024820152741cdd1c99585b48191bd95cc81b9bdd08195e1a5cdd605a1b604482015290519081900360640190fd5b60008881526003602052604090206005015488906001600160a01b031633148061080a57506000818152600360205260409020600401546001600160a01b031633145b6108455760405162461bcd60e51b815260040180806020018281038252603781526020018061256b6037913960400191505060405180910390fd5b60008981526003602081905260409091209081015460028201541415610878576108708a60006116cb565b935050610a75565b600085116108b75760405162461bcd60e51b815260040180806020018281038252602581526020018061248a6025913960400191505060405180910390fd5b60058101546001600160a01b031633141561094657600281015442906108e3908763ffffffff6110b216565b1180610906575060038101546002820154610904908763ffffffff6110b216565b145b6109415760405162461bcd60e51b815260040180806020018281038252602a8152602001806123ab602a913960400191505060405180910390fd5b6109ae565b60048101546001600160a01b03163314156109ae5760028101544290610972908763ffffffff6110b216565b106109ae5760405162461bcd60e51b815260040180806020018281038252602d81526020018061237e602d913960400191505060405180910390fd5b6060610a09600160029054906101000a90046001600160a01b03168b8b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508b92508791506111139050565b915050610a65600160029054906101000a90046001600160a01b031689898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525086925087915061178c9050565b50610a708b876116cb565b945050505b50506001805461ff0019166101001790559695505050505050565b610aa0610a9b611a0d565b610b79565b610adb5760405162461bcd60e51b81526004018080602001828103825260308152602001806123026030913960400191505060405180910390fd5b60015460ff16610b29576040805162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015290519081900360640190fd5b6001805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa610b5c611a0d565b604080516001600160a01b039092168252519081900360200190a1565b6000610b8b818363ffffffff611a1116565b92915050565b60015460ff1690565b610baa610ba5611a0d565b611a78565b565b610bb7610a9b611a0d565b610bf25760405162461bcd60e51b81526004018080602001828103825260308152602001806123026030913960400191505060405180910390fd5b610bfb81611ac0565b50565b610c09610a9b611a0d565b610c445760405162461bcd60e51b81526004018080602001828103825260308152602001806123026030913960400191505060405180910390fd5b60015460ff1615610c8f576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6001805460ff1916811790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258610b5c611a0d565b6000818152600360205260408120600601548190819081908190819081908890600160a01b900460ff16610d37576040805162461bcd60e51b81526020600482015260156024820152741cdd1c99585b48191bd95cc81b9bdd08195e1a5cdd605a1b604482015290519081900360640190fd5b5050506000958652505060036020819052604090942060058101546004820154825460068401546001850154600286015495909901546001600160a01b039485169a93851699929850931695509350565b60015460009060ff1615610dd6576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6001600160a01b038616610e31576040805162461bcd60e51b815260206004820152601a60248201527f73747265616d20746f20746865207a65726f2061646472657373000000000000604482015290519081900360640190fd5b6001600160a01b038616301415610e8f576040805162461bcd60e51b815260206004820152601d60248201527f73747265616d20746f2074686520636f6e747261637420697473656c66000000604482015290519081900360640190fd5b6001600160a01b038616331415610ee4576040805162461bcd60e51b815260206004820152601460248201527339ba3932b0b6903a37903a34329031b0b63632b960611b604482015290519081900360640190fd5b42831015610f235760405162461bcd60e51b815260040180806020018281038252602181526020018061235d6021913960400191505060405180910390fd5b828211610f615760405162461bcd60e51b81526004018080602001828103825260258152602001806124656025913960400191505060405180910390fd5b6002805460408051610100810182528881526020808201888152828401898152606084018981526001600160a01b03808f16608087019081523360a088019081528e831660c08901908152600160e08a0181815260008d815260039a8b90529b909b2099518a559651898801559451888c015592519587019590955593516004860180549186166001600160a01b0319928316179055905160058601805491861691831691909117905590516006909401805495511515600160a01b0260ff60a01b1995909416959091169490941792909216179091559154909161104c919063ffffffff6110b216565b600255604080516001600160a01b0387811682526020820189905281830187905260608201869052915191891691339184917fede16fa759a9d06c1022b933b4d4ed9b2cdcaafe19510813fdd430456f951b9a9181900360800190a49695505050505050565b60008282018381101561110c576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b606080600061113384600201548560030154611b0890919063ffffffff16565b90506111598561114d83633b9aca0063ffffffff611b4a16565b9063ffffffff611ba316565b61116287611be5565b146111aa576040805162461bcd60e51b81526020600482015260136024820152720e4c2e8d2dee640c8de40dcdee840dac2e8c6d606b1b604482015290519081900360640190fd5b60405163a2866ea360e01b8152620104016004820181815230602484018190526060604485018181528b5160648701528b5191956001600160a01b038e169563a2866ea3959094938e93919260840190602085019080838360005b8381101561121d578181015183820152602001611205565b50505050905090810190601f16801561124a5780820380516001836020036101000a031916815260200191505b50945050505050600060405180830381600087803b15801561126b57600080fd5b505af115801561127f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156112a857600080fd5b8101908080516040519392919084600160201b8211156112c757600080fd5b9083019060208201858111156112dc57600080fd5b8251600160201b8111828201881017156112f557600080fd5b82525081516020918201929091019080838360005b8381101561132257818101518382015260200161130a565b50505050905090810190601f16801561134f5780820380516001836020036101000a031916815260200191505b50604052505050905061137461136f600083611c1390919063ffffffff16565b611c6a565b50508654919550935061139661139186600063ffffffff611c1316565b611c94565b60200151146113d65760405162461bcd60e51b81526004018080602001828103825260228152602001806125a26022913960400191505060405180910390fd5b505094509492505050565b6000606061140786866113fd611391888763ffffffff611c1316565b6020015186611cd7565b905060608061141583611c6a565b5050915091506114236122e2565b61143761139183600163ffffffff611c1316565b80519091506001600160a01b031630146114825760405162461bcd60e51b81526004018080602001828103825260308152602001806124af6030913960400191505060405180910390fd5b600586015460408201516001600160a01b03909116906114a390600061208a565b6001600160a01b0316146114e85760405162461bcd60e51b81526004018080602001828103825260288152602001806125c46028913960400191505060405180910390fd5b600486015460408201516001600160a01b039091169061150990600161208a565b6001600160a01b03161461154e5760405162461bcd60e51b815260040180806020018281038252602b815260200180612332602b913960400191505060405180910390fd5b60068601546001600160a01b0316631f2ac16a61157561139186600063ffffffff611c1316565b60200151604080516001600160e01b031960e085901b16815260048101929092523060248301526001604483015260806064830152600060848301819052905160c48084019382900301818387803b1580156115d057600080fd5b505af11580156115e4573d6000803e3d6000fd5b505050506006860154604080516366ff548760e11b81526201010160048201818152602483019384528851604484015288516001600160a01b039095169463cdfea90e9492938a9391606490910190602085019080838360005b8381101561165657818101518382015260200161163e565b50505050905090810190601f1680156116835780820380516001836020036101000a031916815260200191505b509350505050600060405180830381600087803b1580156116a357600080fd5b505af11580156116b7573d6000803e3d6000fd5b505050506020015198975050505050505050565b6000828152600360209081526040808320600481015460058201548351878152935192946001600160a01b0392831694919092169288927f78771645abf470107bd6a847c532dba992a0e2c0995d479ebe8153dea930543c928290030190a450505060009081526003602081905260408220828155600180820184905560028201849055918101929092556004820180546001600160a01b03199081169091556005830180549091169055600690910180546001600160a81b031916905590565b600060606117a886866113fd611391888763ffffffff611c1316565b90506060806117b683611c6a565b509193509150600090506117d3611391848363ffffffff611c1316565b6020015160048701549091506001600160a01b03166117fc61139184600063ffffffff611c1316565b516001600160a01b0316146118425760405162461bcd60e51b815260040180806020018281038252602e8152602001806124df602e913960400191505060405180910390fd5b60058601546001600160a01b031661186461139184600163ffffffff611c1316565b516001600160a01b0316146118aa5760405162461bcd60e51b815260040180806020018281038252602c815260200180612439602c913960400191505060405180910390fd5b600686015460408051630f9560b560e11b815260048101849052306024820152600160448201526080606482015260006084820181905291516001600160a01b0390931692631f2ac16a9260c48084019391929182900301818387803b15801561191357600080fd5b505af1158015611927573d6000803e3d6000fd5b505050506006860154604080516366ff548760e11b81526201010160048201818152602483019384528851604484015288516001600160a01b039095169463cdfea90e9492938a9391606490910190602085019080838360005b83811015611999578181015183820152602001611981565b50505050905090810190601f1680156119c65780820380516001836020036101000a031916815260200191505b509350505050600060405180830381600087803b1580156119e657600080fd5b505af11580156119fa573d6000803e3d6000fd5b5060019c9b505050505050505050505050565b3390565b60006001600160a01b038216611a585760405162461bcd60e51b81526004018080602001828103825260228152602001806124176022913960400191505060405180910390fd5b506001600160a01b03166000908152602091909152604090205460ff1690565b611a8960008263ffffffff6120d916565b6040516001600160a01b038216907fcd265ebaf09df2871cc7bd4133404a235ba12eff2041bb89d9c714a2621c7c7e90600090a250565b611ad160008263ffffffff61214016565b6040516001600160a01b038216907f6719d08c1888103bea251a4ed56406bd0c3e69723c8a1686e017e7bbe159b6f890600090a250565b600061110c83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506121c1565b600082611b5957506000610b8b565b82820282848281611b6657fe5b041461110c5760405162461bcd60e51b81526004018080602001828103825260218152602001806123f66021913960400191505060405180910390fd5b600061110c83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612258565b6040810151606082015160009190611c0b8161114d84633b9aca0063ffffffff611b4a16565b949350505050565b602082810151908202830160400151830190821080611c635760405162461bcd60e51b815260040180806020018281038252602281526020018061263c6022913960400191505060405180910390fd5b5092915050565b60208101516040820151606083015160808401519284019491909301926001600160a01b03169190565b611c9c6122e2565b6000806060611caa856122bd565b604080516060810182526001600160a01b0390941684526020840192909252908201529350505050919050565b60405163a2866ea360e01b8152620101016004820181815230602484018190526060604485018181528851606487015288519195611e98956000956001600160a01b038d169563a2866ea395929490938d9360849091019060208501908083838d5b83811015611d51578181015183820152602001611d39565b50505050905090810190601f168015611d7e5780820380516001836020036101000a031916815260200191505b50945050505050600060405180830381600087803b158015611d9f57600080fd5b505af1158015611db3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015611ddc57600080fd5b8101908080516040519392919084600160201b821115611dfb57600080fd5b908301906020820185811115611e1057600080fd5b8251600160201b811182820188101715611e2957600080fd5b82525081516020918201929091019080838360005b83811015611e56578181015183820152602001611e3e565b50505050905090810190601f168015611e835780820380516001836020036101000a031916815260200191505b50604052505050611c1390919063ffffffff16565b90506060806000611ea884611c6a565b9350509250925080600014611f04576040805162461bcd60e51b815260206004820152601d60248201527f6e6f6e7a65726f207075626c69632076616c7565207472616e73666572000000604482015290519081900360640190fd5b611f0d836122db565b600114611f61576040805162461bcd60e51b815260206004820152601f60248201527f496e636f7272656374206e756d626572206f6620696e707574206e6f74657300604482015290519081900360640190fd5b611f6a826122db565b600214611fbe576040805162461bcd60e51b815260206004820181905260248201527f496e636f7272656374206e756d626572206f66206f7574707574206e6f746573604482015290519081900360640190fd5b85611fd361139184600063ffffffff611c1316565b60200151146120135760405162461bcd60e51b81526004018080602001828103825260278152602001806125ec6027913960400191505060405180910390fd5b845461202961139185600063ffffffff611c1316565b602001511461207f576040805162461bcd60e51b815260206004820152601f60248201527f73747265616d206e6f746520696e2032206973206e6f7420636f727265637400604482015290519081900360640190fd5b505050949350505050565b6020828101519082028301610101015190808310611c635760405162461bcd60e51b815260040180806020018281038252605e81526020018061250d605e913960600191505060405180910390fd5b6120e38282611a11565b61211e5760405162461bcd60e51b81526004018080602001828103825260218152602001806123d56021913960400191505060405180910390fd5b6001600160a01b0316600090815260209190915260409020805460ff19169055565b61214a8282611a11565b1561219c576040805162461bcd60e51b815260206004820152601f60248201527f526f6c65733a206163636f756e7420616c72656164792068617320726f6c6500604482015290519081900360640190fd5b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b600081848411156122505760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156122155781810151838201526020016121fd565b50505050905090810190601f1680156122425780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600081836122a75760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156122155781810151838201526020016121fd565b5060008385816122b357fe5b0495945050505050565b604081015160608201516001600160a01b0390911692909160800190565b6020015190565b604080516060808201835260008083526020830152918101919091529056fe506175736572526f6c653a2063616c6c657220646f6573206e6f742068617665207468652050617573657220726f6c6573747265616d20726563697069656e742063616e27742076696577206e65772073747265616d206e6f746573746172742074696d65206265666f726520626c6f636b2e74696d657374616d70726563697069656e7420726563656976657320746f6f206d7563682066726f6d2063616e63656c6c6174696f6e73656e64657220726563656976657320746f6f206d7563682066726f6d2063616e63656c6c6174696f6e526f6c65733a206163636f756e7420646f6573206e6f74206861766520726f6c65536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77526f6c65733a206163636f756e7420697320746865207a65726f206164647265737353747265616d2073656e64657220646f65736e2774206f776e207365636f6e64206f7574707574206e6f746553747265616d206475726174696f6e206e6f742067726561746572207468616e207a65726f63616e63656c6c6174696f6e2077697468207a65726f20756e636c61696d65642074696d656368616e6765206e6f746520696e2032206973206e6f74206f776e65642062792073747265616d20636f6e747261637453747265616d20726563697069656e7420646f65736e2774206f776e206669727374206f7574707574206e6f746561646472657373506f73206f7574206f6620626f756e6473202d2061646472657373506f73206d757374206265206c657373207468616e20746865206e756d626572206f662061646472657373657320746f20626520617070726f76656463616c6c6572206973206e6f74207468652073656e646572206f722074686520726563697069656e74206f66207468652073747265616d696e636f7272656374206e6f74696f6e616c206e6f746520696e2070726f6f66203173747265616d2073656e6465722063616e27742076696577206e65772073747265616d206e6f74657769746864726177206e6f746520696e2032206973206e6f74207468652073616d65206173203163616c6c6572206973206e6f742074686520726563697069656e74206f66207468652073747265616d415a54454320617272617920696e646578206973206f7574206f6620626f756e6473a265627a7a723158204b885b0fbc3e77ad991ce1dd489201ae8a4576ce93a7ba422ecf6cb1e2ceeb3464736f6c634300050f0032', + '0x608060405234801561001057600080fd5b50600436106100a95760003560e01c80635989dcde116100715780635989dcde146103035780635c975abb146104505780636ef8d66d1461045857806382dc1ec4146104605780638456cb5914610486578063894e9a0d1461048e576100a9565b80631468a5d4146100ae5780631e99d569146101e25780633bc9e403146101fc5780633f4ba83a146102d557806346fbf68e146102dd575b600080fd5b6101e0600480360360808110156100c457600080fd5b81359190810190604081016020820135600160201b8111156100e557600080fd5b8201836020820111156100f757600080fd5b803590602001918460018302840111600160201b8311171561011857600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b81111561016a57600080fd5b82018360208201111561017c57600080fd5b803590602001918460018302840111600160201b8311171561019d57600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955050913592506104f5915050565b005b6101ea6107b2565b60408051918252519081900360200190f35b6102c16004803603608081101561021257600080fd5b81359190810190604081016020820135600160201b81111561023357600080fd5b82018360208201111561024557600080fd5b803590602001918460018302840111600160201b8311171561026657600080fd5b919390929091602081019035600160201b81111561028357600080fd5b82018360208201111561029557600080fd5b803590602001918460018302840111600160201b831117156102b657600080fd5b9193509150356107b8565b604080519115158252519081900360200190f35b6101e0610b51565b6102c1600480360360208110156102f357600080fd5b50356001600160a01b0316610c3a565b6101ea600480360360c081101561031957600080fd5b6001600160a01b038235169190810190604081016020820135600160201b81111561034357600080fd5b82018360208201111561035557600080fd5b803590602001918460018302840111600160201b8311171561037657600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b8111156103c857600080fd5b8201836020820111156103da57600080fd5b803590602001918460018302840111600160201b831117156103fb57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550506001600160a01b038335169350505060208101359060400135610c52565b6102c1611014565b6101e061101d565b6101e06004803603602081101561047657600080fd5b50356001600160a01b031661102f565b6101e0611081565b6104ab600480360360208110156104a457600080fd5b5035611147565b604080516001600160a01b039889168152968816602088015286810195909552929095166060850152608084015260a083019390935260c082019290925290519081900360e00190f35b600154610100900460ff16610551576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6001805461ff00191690556000848152600360205260409020600601548490600160a01b900460ff166105c3576040805162461bcd60e51b81526020600482015260156024820152741cdd1c99585b48191bd95cc81b9bdd08195e1a5cdd605a1b604482015290519081900360640190fd5b60008581526003602052604090206004015485906001600160a01b0316331461061d5760405162461bcd60e51b8152600401808060200182810382526029815260200180612eb76029913960400191505060405180910390fd5b600086815260036020526040902083610675576040805162461bcd60e51b81526020600482015260156024820152741e995c9bc81d985b1d59481dda5d1a191c985dd85b605a1b604482015290519081900360640190fd5b6002810154429061068c908663ffffffff61120b16565b106106de576040805162461bcd60e51b815260206004820181905260248201527f77697468647261772069732067726561746572207468616e20616c6c6f776564604482015290519081900360640190fd5b6001546000906106ff906201000090046001600160a01b031688878561126c565b90506000610724600160029054906101000a90046001600160a01b0316888486611555565b808455600284015490915061073f908763ffffffff61120b16565b60028401556004830154600584015460408051848152602081018a905281516001600160a01b0394851694909316928d927fc40560fdf83328f954941bff2b9141084d3c22e88c89a758557961e1966a57a9928290030190a450506001805461ff00191661010017905550505050505050565b60025481565b600154600090610100900460ff16610817576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6001805461ff00191690556000878152600360205260409020600601548790600160a01b900460ff16610889576040805162461bcd60e51b81526020600482015260156024820152741cdd1c99585b48191bd95cc81b9bdd08195e1a5cdd605a1b604482015290519081900360640190fd5b60008881526003602052604090206005015488906001600160a01b03163314806108cc57506000818152600360205260409020600401546001600160a01b031633145b6109075760405162461bcd60e51b8152600401808060200182810382526037815260200180612de86037913960400191505060405180910390fd5b6000898152600360208190526040909120908101546002820154141561093a576109328a6000611829565b935050610b36565b600085116109795760405162461bcd60e51b8152600401808060200182810382526025815260200180612cb86025913960400191505060405180910390fd5b60058101546001600160a01b0316331415610a0857600281015442906109a5908763ffffffff61120b16565b11806109c85750600381015460028201546109c6908763ffffffff61120b16565b145b610a035760405162461bcd60e51b815260040180806020018281038252602a815260200180612bd9602a913960400191505060405180910390fd5b610a70565b60048101546001600160a01b0316331415610a705760028101544290610a34908763ffffffff61120b16565b10610a705760405162461bcd60e51b815260040180806020018281038252602d815260200180612b81602d913960400191505060405180910390fd5b6000610acb600160029054906101000a90046001600160a01b03168b8b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508b925087915061126c9050565b9050610b26600160029054906101000a90046001600160a01b031689898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508692508791506118ea9050565b50610b318b87611829565b945050505b50506001805461ff0019166101001790559695505050505050565b610b61610b5c611c39565b610c3a565b610b9c5760405162461bcd60e51b8152600401808060200182810382526030815260200180612ae16030913960400191505060405180910390fd5b60015460ff16610bea576040805162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015290519081900360640190fd5b6001805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa610c1d611c39565b604080516001600160a01b039092168252519081900360200190a1565b6000610c4c818363ffffffff611c3d16565b92915050565b60015460009060ff1615610ca0576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6001600160a01b038716610cfb576040805162461bcd60e51b815260206004820152601a60248201527f73747265616d20746f20746865207a65726f2061646472657373000000000000604482015290519081900360640190fd5b6001600160a01b038716301415610d59576040805162461bcd60e51b815260206004820152601d60248201527f73747265616d20746f2074686520636f6e747261637420697473656c66000000604482015290519081900360640190fd5b6001600160a01b038716331415610dae576040805162461bcd60e51b815260206004820152601460248201527339ba3932b0b6903a37903a34329031b0b63632b960611b604482015290519081900360640190fd5b42831015610ded5760405162461bcd60e51b8152600401808060200182810382526021815260200180612b606021913960400191505060405180910390fd5b828211610e2b5760405162461bcd60e51b8152600401808060200182810382526025815260200180612c936025913960400191505060405180910390fd5b6000610e508787600160029054906101000a90046001600160a01b0316338c8a611ca4565b9050600060025490506040518061010001604052808381526020018681526020018681526020018581526020018a6001600160a01b03168152602001336001600160a01b03168152602001876001600160a01b0316815260200160011515815250600360008381526020019081526020016000206000820151816000015560208201518160010155604082015181600201556060820151816003015560808201518160040160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060a08201518160050160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060c08201518160060160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060e08201518160060160146101000a81548160ff021916908315150217905550905050610fac600160025461120b90919063ffffffff16565b600255604080516001600160a01b03888116825260208201859052818301889052606082018790529151918b1691339184917fede16fa759a9d06c1022b933b4d4ed9b2cdcaafe19510813fdd430456f951b9a9181900360800190a498975050505050505050565b60015460ff1690565b61102d611028611c39565b612257565b565b61103a610b5c611c39565b6110755760405162461bcd60e51b8152600401808060200182810382526030815260200180612ae16030913960400191505060405180910390fd5b61107e8161229f565b50565b61108c610b5c611c39565b6110c75760405162461bcd60e51b8152600401808060200182810382526030815260200180612ae16030913960400191505060405180910390fd5b60015460ff1615611112576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6001805460ff1916811790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258610c1d611c39565b6000818152600360205260408120600601548190819081908190819081908890600160a01b900460ff166111ba576040805162461bcd60e51b81526020600482015260156024820152741cdd1c99585b48191bd95cc81b9bdd08195e1a5cdd605a1b604482015290519081900360640190fd5b5050506000958652505060036020819052604090942060058101546004820154825460068401546001850154600286015495909901546001600160a01b039485169a93851699929850931695509350565b600082820183811015611265576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b60008061128a836002015484600301546122e790919063ffffffff16565b90506112b0846112a483633b9aca0063ffffffff61232916565b9063ffffffff61238216565b6112b9866123c4565b14611301576040805162461bcd60e51b81526020600482015260136024820152720e4c2e8d2dee640c8de40dcdee840dac2e8c6d606b1b604482015290519081900360640190fd5b60405163a2866ea360e01b8152620104016004820181815230602484018190526060604485018181528a5160648701528a5191956001600160a01b038d169563a2866ea3959094938d93919260840190602085019080838360005b8381101561137457818101518382015260200161135c565b50505050905090810190601f1680156113a15780820380516001836020036101000a031916815260200191505b50945050505050600060405180830381600087803b1580156113c257600080fd5b505af11580156113d6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156113ff57600080fd5b8101908080516040519392919084600160201b82111561141e57600080fd5b90830190602082018581111561143357600080fd5b8251600160201b81118282018810171561144c57600080fd5b82525081516020918201929091019080838360005b83811015611479578181015183820152602001611461565b50505050905090810190601f1680156114a65780820380516001836020036101000a031916815260200191505b5060405250505090506060806114ce6114c96000856123f290919063ffffffff16565b612449565b5050875491935091506114f06114eb84600063ffffffff6123f216565b612473565b60200151146115305760405162461bcd60e51b8152600401808060200182810382526022815260200180612e1f6022913960400191505060405180910390fd5b6115446114eb82600063ffffffff6123f216565b602001519998505050505050505050565b60006060611565868686866124b6565b905060608061157383612449565b505091509150611581612ac1565b6115956114eb83600163ffffffff6123f216565b80519091506001600160a01b031630146115e05760405162461bcd60e51b8152600401808060200182810382526030815260200180612cdd6030913960400191505060405180910390fd5b600586015460408201516001600160a01b0390911690611601906000612869565b6001600160a01b0316146116465760405162461bcd60e51b8152600401808060200182810382526028815260200180612e686028913960400191505060405180910390fd5b600486015460408201516001600160a01b0390911690611667906001612869565b6001600160a01b0316146116ac5760405162461bcd60e51b815260040180806020018281038252602b815260200180612b11602b913960400191505060405180910390fd5b60068601546001600160a01b0316631f2ac16a6116d36114eb86600063ffffffff6123f216565b60200151604080516001600160e01b031960e085901b16815260048101929092523060248301526001604483015260806064830152600060848301819052905160c48084019382900301818387803b15801561172e57600080fd5b505af1158015611742573d6000803e3d6000fd5b505050506006860154604080516366ff548760e11b81526201010160048201818152602483019384528851604484015288516001600160a01b039095169463cdfea90e9492938a9391606490910190602085019080838360005b838110156117b457818101518382015260200161179c565b50505050905090810190601f1680156117e15780820380516001836020036101000a031916815260200191505b509350505050600060405180830381600087803b15801561180157600080fd5b505af1158015611815573d6000803e3d6000fd5b505050506020015198975050505050505050565b6000828152600360209081526040808320600481015460058201548351878152935192946001600160a01b0392831694919092169288927f78771645abf470107bd6a847c532dba992a0e2c0995d479ebe8153dea930543c928290030190a450505060009081526003602081905260408220828155600180820184905560028201849055918101929092556004820180546001600160a01b03199081169091556005830180549091169055600690910180546001600160a81b031916905590565b600060606118fa868686866124b6565b905060608061190883612449565b509193509150600090506119256114eb848363ffffffff6123f216565b602001519050611933612ac1565b6119476114eb84600063ffffffff6123f216565b9050611951612ac1565b6119656114eb85600163ffffffff6123f216565b600489015483519192506001600160a01b039182169116146119b85760405162461bcd60e51b815260040180806020018281038252602e815260200180612d5c602e913960400191505060405180910390fd5b600588015481516001600160a01b03908116911614611a085760405162461bcd60e51b815260040180806020018281038252602c815260200180612c67602c913960400191505060405180910390fd5b600488015460408301516001600160a01b0390911690611a29906000612869565b6001600160a01b031614611a6e5760405162461bcd60e51b815260040180806020018281038252602b815260200180612d31602b913960400191505060405180910390fd5b600588015460408201516001600160a01b0390911690611a8f906000612869565b6001600160a01b031614611ad45760405162461bcd60e51b8152600401808060200182810382526024815260200180612d0d6024913960400191505060405180910390fd5b600688015460408051630f9560b560e11b815260048101869052306024820152600160448201526080606482015260006084820181905291516001600160a01b0390931692631f2ac16a9260c48084019391929182900301818387803b158015611b3d57600080fd5b505af1158015611b51573d6000803e3d6000fd5b505050506006880154604080516366ff548760e11b81526201010160048201818152602483019384528a5160448401528a516001600160a01b039095169463cdfea90e9492938c9391606490910190602085019080838360005b83811015611bc3578181015183820152602001611bab565b50505050905090810190601f168015611bf05780820380516001836020036101000a031916815260200191505b509350505050600060405180830381600087803b158015611c1057600080fd5b505af1158015611c24573d6000803e3d6000fd5b5060019e9d5050505050505050505050505050565b3390565b60006001600160a01b038216611c845760405162461bcd60e51b8152600401808060200182810382526022815260200180612c456022913960400191505060405180910390fd5b506001600160a01b03166000908152602091909152604090205460ff1690565b60006060856001600160a01b031663a2866ea362010101338b6040518463ffffffff1660e01b8152600401808462ffffff1662ffffff168152602001836001600160a01b03166001600160a01b0316815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611d31578181015183820152602001611d19565b50505050905090810190601f168015611d5e5780820380516001836020036101000a031916815260200191505b50945050505050600060405180830381600087803b158015611d7f57600080fd5b505af1158015611d93573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015611dbc57600080fd5b8101908080516040519392919084600160201b821115611ddb57600080fd5b908301906020820185811115611df057600080fd5b8251600160201b811182820188101715611e0957600080fd5b82525081516020918201929091019080838360005b83811015611e36578181015183820152602001611e1e565b50505050905090810190601f168015611e635780820380516001836020036101000a031916815260200191505b5060405250505090506060611e826000836123f290919063ffffffff16565b90506060611e8f82612449565b5050915050611e9d816128b8565b600114611ef1576040805162461bcd60e51b815260206004820181905260248201527f496e636f7272656374206e756d626572206f66206f7574707574206e6f746573604482015290519081900360640190fd5b611ef9612ac1565b611f0d6114eb83600063ffffffff6123f216565b80519091506001600160a01b03163014611f585760405162461bcd60e51b815260040180806020018281038252602b815260200180612bae602b913960400191505060405180910390fd5b876001600160a01b0316611f7182604001516000612869565b6001600160a01b031614611fb65760405162461bcd60e51b8152600401808060200182810382526024815260200180612b3c6024913960400191505060405180910390fd5b866001600160a01b0316611fcf82604001516001612869565b6001600160a01b0316146120145760405162461bcd60e51b8152600401808060200182810382526027815260200180612e416027913960400191505060405180910390fd5b856001600160a01b0316630a60305a62010101863060018f6040518663ffffffff1660e01b8152600401808662ffffff1662ffffff16815260200180602001856001600160a01b03166001600160a01b031681526020018415151515815260200180602001838103835287818151815260200191508051906020019080838360005b838110156120ae578181015183820152602001612096565b50505050905090810190601f1680156120db5780820380516001836020036101000a031916815260200191505b50838103825284518152845160209182019186019080838360005b8381101561210e5781810151838201526020016120f6565b50505050905090810190601f16801561213b5780820380516001836020036101000a031916815260200191505b50975050505050505050600060405180830381600087803b15801561215f57600080fd5b505af1158015612173573d6000803e3d6000fd5b5050604080516366ff548760e11b81526201010160048201818152602483019384528851604484015288516001600160a01b038d16965063cdfea90e9550919389939192909160640190602085019080838360005b838110156121e05781810151838201526020016121c8565b50505050905090810190601f16801561220d5780820380516001836020036101000a031916815260200191505b509350505050600060405180830381600087803b15801561222d57600080fd5b505af1158015612241573d6000803e3d6000fd5b50505050602001519a9950505050505050505050565b61226860008263ffffffff6128bf16565b6040516001600160a01b038216907fcd265ebaf09df2871cc7bd4133404a235ba12eff2041bb89d9c714a2621c7c7e90600090a250565b6122b060008263ffffffff61292616565b6040516001600160a01b038216907f6719d08c1888103bea251a4ed56406bd0c3e69723c8a1686e017e7bbe159b6f890600090a250565b600061126583836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506129a7565b60008261233857506000610c4c565b8282028284828161234557fe5b04146112655760405162461bcd60e51b8152600401808060200182810382526021815260200180612c246021913960400191505060405180910390fd5b600061126583836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612a3e565b60408101516060820151600091906123ea816112a484633b9aca0063ffffffff61232916565b949350505050565b6020828101519082028301604001518301908210806124425760405162461bcd60e51b8152600401808060200182810382526022815260200180612ee06022913960400191505060405180910390fd5b5092915050565b60208101516040820151606083015160808401519284019491909301926001600160a01b03169190565b61247b612ac1565b600080606061248985612aa3565b604080516060810182526001600160a01b0390941684526020840192909252908201529350505050919050565b60405163a2866ea360e01b8152620101016004820181815230602484018190526060604485018181528851606487015288519195612677956000956001600160a01b038d169563a2866ea395929490938d9360849091019060208501908083838d5b83811015612530578181015183820152602001612518565b50505050905090810190601f16801561255d5780820380516001836020036101000a031916815260200191505b50945050505050600060405180830381600087803b15801561257e57600080fd5b505af1158015612592573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156125bb57600080fd5b8101908080516040519392919084600160201b8211156125da57600080fd5b9083019060208201858111156125ef57600080fd5b8251600160201b81118282018810171561260857600080fd5b82525081516020918201929091019080838360005b8381101561263557818101518382015260200161261d565b50505050905090810190601f1680156126625780820380516001836020036101000a031916815260200191505b506040525050506123f290919063ffffffff16565b9050606080600061268784612449565b93505092509250806000146126e3576040805162461bcd60e51b815260206004820152601d60248201527f6e6f6e7a65726f207075626c69632076616c7565207472616e73666572000000604482015290519081900360640190fd5b6126ec836128b8565b600114612740576040805162461bcd60e51b815260206004820152601f60248201527f496e636f7272656374206e756d626572206f6620696e707574206e6f74657300604482015290519081900360640190fd5b612749826128b8565b60021461279d576040805162461bcd60e51b815260206004820181905260248201527f496e636f7272656374206e756d626572206f66206f7574707574206e6f746573604482015290519081900360640190fd5b856127b26114eb84600063ffffffff6123f216565b60200151146127f25760405162461bcd60e51b8152600401808060200182810382526027815260200180612e906027913960400191505060405180910390fd5b84546128086114eb85600063ffffffff6123f216565b602001511461285e576040805162461bcd60e51b815260206004820152601f60248201527f73747265616d206e6f746520696e2032206973206e6f7420636f727265637400604482015290519081900360640190fd5b505050949350505050565b60208281015190820283016101010151908083106124425760405162461bcd60e51b815260040180806020018281038252605e815260200180612d8a605e913960600191505060405180910390fd5b6020015190565b6128c98282611c3d565b6129045760405162461bcd60e51b8152600401808060200182810382526021815260200180612c036021913960400191505060405180910390fd5b6001600160a01b0316600090815260209190915260409020805460ff19169055565b6129308282611c3d565b15612982576040805162461bcd60e51b815260206004820152601f60248201527f526f6c65733a206163636f756e7420616c72656164792068617320726f6c6500604482015290519081900360640190fd5b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b60008184841115612a365760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156129fb5781810151838201526020016129e3565b50505050905090810190601f168015612a285780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b60008183612a8d5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156129fb5781810151838201526020016129e3565b506000838581612a9957fe5b0495945050505050565b604081015160608201516001600160a01b0390911692909160800190565b604080516060808201835260008083526020830152918101919091529056fe506175736572526f6c653a2063616c6c657220646f6573206e6f742068617665207468652050617573657220726f6c6573747265616d20726563697069656e742063616e27742076696577206e65772073747265616d206e6f746573747265616d2073656e6465722063616e277420766965772073747265616d206e6f746573746172742074696d65206265666f726520626c6f636b2e74696d657374616d70726563697069656e7420726563656976657320746f6f206d7563682066726f6d2063616e63656c6c6174696f6e73747265616d206e6f7465206973206e6f74206f776e65642062792073747265616d20636f6e747261637473656e64657220726563656976657320746f6f206d7563682066726f6d2063616e63656c6c6174696f6e526f6c65733a206163636f756e7420646f6573206e6f74206861766520726f6c65536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77526f6c65733a206163636f756e7420697320746865207a65726f206164647265737353747265616d2073656e64657220646f65736e2774206f776e207365636f6e64206f7574707574206e6f746553747265616d206475726174696f6e206e6f742067726561746572207468616e207a65726f63616e63656c6c6174696f6e2077697468207a65726f20756e636c61696d65642074696d656368616e6765206e6f746520696e2032206973206e6f74206f776e65642062792073747265616d20636f6e747261637473747265616d2073656e6465722063616e2774207669657720726566756e64206e6f746573747265616d20726563697069656e742063616e27742076696577207769746864726177616c206e6f746553747265616d20726563697069656e7420646f65736e2774206f776e206669727374206f7574707574206e6f746561646472657373506f73206f7574206f6620626f756e6473202d2061646472657373506f73206d757374206265206c657373207468616e20746865206e756d626572206f662061646472657373657320746f20626520617070726f76656463616c6c6572206973206e6f74207468652073656e646572206f722074686520726563697069656e74206f66207468652073747265616d696e636f7272656374206e6f74696f6e616c206e6f746520696e2070726f6f66203173747265616d20726563697069656e742063616e277420766965772073747265616d206e6f746573747265616d2073656e6465722063616e27742076696577206e65772073747265616d206e6f74657769746864726177206e6f746520696e2032206973206e6f74207468652073616d65206173203163616c6c6572206973206e6f742074686520726563697069656e74206f66207468652073747265616d415a54454320617272617920696e646578206973206f7574206f6620626f756e6473a265627a7a7231582082989ecb6430bf512f28d08363cc0a6bf2a065c4959092b9b848a6c99678da7964736f6c634300050f0032', linkReferences: {}, deployedLinkReferences: {}, }; diff --git a/packages/contract-artifacts/contracts/StreamUtilities.ts b/packages/contract-artifacts/contracts/StreamUtilities.ts index 88a396f..e71d258 100644 --- a/packages/contract-artifacts/contracts/StreamUtilities.ts +++ b/packages/contract-artifacts/contracts/StreamUtilities.ts @@ -2,9 +2,9 @@ export default { contractName: 'StreamUtilities', abi: [], bytecode: - '0x60556023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea265627a7a72315820b0c8047152ae625605cc7c7239b8e424dfb7a37caeb5490776c10883d23299b664736f6c634300050f0032', + '0x60556023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea265627a7a72315820c8f9a590281f6d9170e715b7aeb1810d2783e72d630d1643d60a3320a9751d7664736f6c634300050f0032', deployedBytecode: - '0x73000000000000000000000000000000000000000030146080604052600080fdfea265627a7a72315820b0c8047152ae625605cc7c7239b8e424dfb7a37caeb5490776c10883d23299b664736f6c634300050f0032', + '0x73000000000000000000000000000000000000000030146080604052600080fdfea265627a7a72315820c8f9a590281f6d9170e715b7aeb1810d2783e72d630d1643d60a3320a9751d7664736f6c634300050f0032', linkReferences: {}, deployedLinkReferences: {}, }; diff --git a/packages/contract-artifacts/package.json b/packages/contract-artifacts/package.json index 781bb24..b51fae5 100644 --- a/packages/contract-artifacts/package.json +++ b/packages/contract-artifacts/package.json @@ -13,13 +13,14 @@ "@babel/preset-env": "^7.9.0", "@babel/preset-typescript": "^7.9.0", "@typescript-eslint/eslint-plugin-tslint": "^2.27.0", - "eslint": "^5.15.3", - "eslint-config-airbnb-base": "^13.1.0", - "eslint-config-prettier": "^6.0.0", - "eslint-plugin-import": "^2.20.2", - "lint-staged": "^10.2.2", + "eslint": "^7.5.0", + "eslint-config-airbnb-base": "^14.2.0", + "eslint-config-prettier": "^6.11.0", + "eslint-plugin-import": "^2.22.0", + "eslint-plugin-prettier": "^3.1.4", + "lint-staged": "^10.2.11", "shx": "^0.3.2", - "typescript": "^3.8.3" + "typescript": "^3.9.7" }, "engines": { "node": ">=8.3" @@ -53,7 +54,7 @@ "build:types": "tsc --emitDeclarationOnly", "clean": "shx rm -rf ./lib", "has:changed": "bash ../monorepo-scripts/ci/hasChanged.sh contract-artifacts", - "lint": "eslint --config .eslintrc.js --ext .js,.ts . ", + "lint": "eslint --config .eslintrc.js --ext .ts . ", "watch": "yarn build --watch" }, "config": { diff --git a/packages/contracts/contracts/AZTEC/Imports.sol b/packages/contracts/contracts/AZTEC/Imports.sol deleted file mode 100644 index 24da250..0000000 --- a/packages/contracts/contracts/AZTEC/Imports.sol +++ /dev/null @@ -1,24 +0,0 @@ -pragma solidity ^0.5.11; - -import "@aztec/protocol/contracts/ACE/ACE.sol"; -import "@aztec/protocol/contracts/ACE/noteRegistry/epochs/201912/base/FactoryBase201912.sol"; -import "@aztec/protocol/contracts/ACE/validators/joinSplit/JoinSplit.sol"; -import "@aztec/protocol/contracts/ACE/validators/dividend/Dividend.sol"; -import "@aztec/protocol/contracts/ERC1724/ZkAsset.sol"; - - -// You might think this file is a bit odd, but let me explain. -// We only use some contracts in our tests, which means Truffle -// will not compile it for us, because it is from an external -// dependency. -// -// We are now left with three options: -// - Copy/paste these contracts -// - Run the tests with `truffle compile --all` on -// - Or trick Truffle by claiming we use it in a Solidity test -// -// You know which one I went for. - -contract Imports { - constructor() public {} -} diff --git a/packages/contracts/contracts/NoteStream.sol b/packages/contracts/contracts/NoteStream.sol index e3047fa..80e5842 100644 --- a/packages/contracts/contracts/NoteStream.sol +++ b/packages/contracts/contracts/NoteStream.sol @@ -1,11 +1,11 @@ pragma solidity ^0.5.11; -import "@openzeppelin/contracts/lifecycle/Pausable.sol"; -import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; +import '@openzeppelin/contracts/lifecycle/Pausable.sol'; +import '@openzeppelin/contracts/utils/ReentrancyGuard.sol'; -import "./StreamUtilities.sol"; +import './StreamUtilities.sol'; -import "./Types.sol"; +import './Types.sol'; /** @@ -65,7 +65,7 @@ contract NoteStream is Pausable, ReentrancyGuard { require( msg.sender == streams[streamId].sender || msg.sender == streams[streamId].recipient, - "caller is not the sender or the recipient of the stream" + 'caller is not the sender or the recipient of the stream' ); _; } @@ -76,7 +76,7 @@ contract NoteStream is Pausable, ReentrancyGuard { modifier onlyRecipient(uint256 streamId) { require( msg.sender == streams[streamId].recipient, - "caller is not the recipient of the stream" + 'caller is not the recipient of the stream' ); _; } @@ -85,7 +85,7 @@ contract NoteStream is Pausable, ReentrancyGuard { * @dev Throws if the provided id does not point to a valid stream. */ modifier streamExists(uint256 streamId) { - require(streams[streamId].isEntity, "stream does not exist"); + require(streams[streamId].isEntity, 'stream does not exist'); _; } @@ -94,7 +94,7 @@ contract NoteStream is Pausable, ReentrancyGuard { constructor(address _aceContractAddress) public { require( _aceContractAddress != address(0x00), - "ACE contract is the zero address" + 'ACE contract is the zero address' ); aceContractAddress = _aceContractAddress; nextStreamId = 1; @@ -144,7 +144,7 @@ contract NoteStream is Pausable, ReentrancyGuard { * Throws if the contract is not allowed to transfer enough tokens. * Throws if there is a token transfer failure. * @param recipient The address towards which the money is streamed. - * @param noteHash The note of a zkAsset to be streamed. + * @param proof The JoinSplit proof transfering a zkAsset to be streamed. * @param tokenAddress The zkAsset to use as streaming currency. * @param startTime The unix timestamp for when the stream starts. * @param stopTime The unix timestamp for when the stream stops. @@ -152,24 +152,35 @@ contract NoteStream is Pausable, ReentrancyGuard { */ function createStream( address recipient, - bytes32 noteHash, + bytes memory proof, + bytes memory proofSignature, address tokenAddress, uint256 startTime, uint256 stopTime ) public whenNotPaused returns (uint256) { - require(recipient != address(0x00), "stream to the zero address"); - require(recipient != address(this), "stream to the contract itself"); - require(recipient != msg.sender, "stream to the caller"); + require(recipient != address(0x00), 'stream to the zero address'); + require(recipient != address(this), 'stream to the contract itself'); + require(recipient != msg.sender, 'stream to the caller'); require( startTime >= block.timestamp, // solium-disable-line security/no-block-members - "start time before block.timestamp" + 'start time before block.timestamp' + ); + require(stopTime > startTime, 'Stream duration not greater than zero'); + + // Transfer the ZkAsset to the streaming contract + bytes32 streamNoteHash = StreamUtilities._processDeposit( + proof, + proofSignature, + aceContractAddress, + msg.sender, + recipient, + tokenAddress ); - require(stopTime > startTime, "Stream duration not greater than zero"); /* Create and store the stream object. */ uint256 streamId = nextStreamId; streams[streamId] = Types.AztecStream({ - noteHash: noteHash, + noteHash: streamNoteHash, sender: msg.sender, recipient: recipient, startTime: startTime, @@ -187,7 +198,7 @@ contract NoteStream is Pausable, ReentrancyGuard { msg.sender, recipient, tokenAddress, - noteHash, + streamNoteHash, startTime, stopTime ); @@ -200,27 +211,21 @@ contract NoteStream is Pausable, ReentrancyGuard { bytes memory _proof1, // Dividend Proof bytes memory _proof2, // Join-Split Proof uint256 _streamDurationToWithdraw - ) - public - nonReentrant - streamExists(streamId) - onlyRecipient(streamId) - { + ) public nonReentrant streamExists(streamId) onlyRecipient(streamId) { Types.AztecStream storage stream = streams[streamId]; // First check that this isn't a zero value withdrawal - require(_streamDurationToWithdraw > 0, "zero value withdrawal"); + require(_streamDurationToWithdraw > 0, 'zero value withdrawal'); // Check that fraction to withdraw isn't greater than fraction of time passed require( stream.lastWithdrawTime.add(_streamDurationToWithdraw) < block.timestamp, // solium-disable-line security/no-block-members - "withdraw is greater than allowed" + 'withdraw is greater than allowed' ); // Check that value of withdrawal matches the fraction given by the above timestamp - (, bytes memory _proof1OutputNotes) = StreamUtilities - ._validateRatioProof( + bytes32 withdrawalNoteHash = StreamUtilities._validateRatioProof( aceContractAddress, _proof1, _streamDurationToWithdraw, @@ -232,7 +237,7 @@ contract NoteStream is Pausable, ReentrancyGuard { bytes32 newNoteHash = StreamUtilities._processWithdrawal( aceContractAddress, _proof2, - _proof1OutputNotes, + withdrawalNoteHash, stream ); @@ -283,7 +288,7 @@ contract NoteStream is Pausable, ReentrancyGuard { } // We require the denominator of ratio proof to be nonzero - require(_unclaimedTime > 0, "cancellation with zero unclaimed time"); + require(_unclaimedTime > 0, 'cancellation with zero unclaimed time'); // Otherwise check that cancelling party isn't trying to scam the other // Each party can only cancel from a timestamp favourable to the other party. @@ -296,20 +301,19 @@ contract NoteStream is Pausable, ReentrancyGuard { stream.lastWithdrawTime.add(_unclaimedTime) > block.timestamp || stream.lastWithdrawTime.add(_unclaimedTime) == stream.stopTime, - "sender receives too much from cancellation" + 'sender receives too much from cancellation' ); } else if (msg.sender == stream.recipient) { // Recipient can only cancel from a timestamp which has already passed require( // solium-disable-next-line security/no-block-members stream.lastWithdrawTime.add(_unclaimedTime) < block.timestamp, - "recipient receives too much from cancellation" + 'recipient receives too much from cancellation' ); } // Check that value of withdrawal matches the fraction given by the above timestamp - (, bytes memory _proof1OutputNotes) = StreamUtilities - ._validateRatioProof( + bytes32 withdrawalNoteHash = StreamUtilities._validateRatioProof( aceContractAddress, _proof1, _unclaimedTime, @@ -318,10 +322,10 @@ contract NoteStream is Pausable, ReentrancyGuard { // Check that cancellation transaction is valid and perform transfer // i.e. Each party receives a note of correct value - StreamUtilities._processCancelation( + StreamUtilities._processCancellation( aceContractAddress, _proof2, - _proof1OutputNotes, + withdrawalNoteHash, stream ); diff --git a/packages/contracts/contracts/StreamUtilities.sol b/packages/contracts/contracts/StreamUtilities.sol index b1ba4ff..2ff44a6 100644 --- a/packages/contracts/contracts/StreamUtilities.sol +++ b/packages/contracts/contracts/StreamUtilities.sol @@ -1,13 +1,13 @@ pragma solidity ^0.5.11; -import "@openzeppelin/contracts/math/SafeMath.sol"; +import '@openzeppelin/contracts/math/SafeMath.sol'; -import "@aztec/protocol/contracts/interfaces/IACE.sol"; -import "@aztec/protocol/contracts/interfaces/IZkAsset.sol"; -import "@aztec/protocol/contracts/libs/NoteUtils.sol"; -import "@aztec/protocol/contracts/libs/MetaDataUtils.sol"; +import '@aztec/protocol/contracts/interfaces/IACE.sol'; +import '@aztec/protocol/contracts/interfaces/IZkAsset.sol'; +import '@aztec/protocol/contracts/libs/NoteUtils.sol'; +import '@aztec/protocol/contracts/libs/MetaDataUtils.sol'; -import "./Types.sol"; +import './Types.sol'; library StreamUtilities { @@ -51,24 +51,82 @@ library StreamUtilities { return za.mul(scalingFactor).div(zb); } + function _processDeposit( + bytes memory _proof, + bytes memory _proofSignature, + address _aceContractAddress, + address _sender, + address _recipient, + address _tokenAddress + ) internal returns (bytes32 streamNoteHash) { + // Validate Join-Split proof + bytes memory proofOutputs = IACE(_aceContractAddress).validateProof( + JOIN_SPLIT_PROOF, + msg.sender, + _proof + ); + + bytes memory proofOutput = proofOutputs.get(0); + + // Extract notes used in proof + (, bytes memory _proofOutputNotes, , ) = proofOutput + .extractProofOutput(); + + // Ensure that there is only a single output note to avoid loss of funds + require( + _proofOutputNotes.getLength() == 1, + 'Incorrect number of output notes' + ); + + Note memory streamNote = _noteCoderToStruct(_proofOutputNotes.get(0)); + + // Require that stream note is owned by contract + require( + streamNote.owner == address(this), + 'stream note is not owned by stream contract' + ); + + // Require that sender and receiver have view access to stream note + require( + MetaDataUtils.extractAddress(streamNote.metaData, 0) == _sender, + "stream sender can't view stream note" + ); + require( + MetaDataUtils.extractAddress(streamNote.metaData, 1) == _recipient, + "stream recipient can't view stream note" + ); + + // Approve contract to place user's zkAssets into the stream note + IZkAsset(_tokenAddress).approveProof( + JOIN_SPLIT_PROOF, + proofOutputs, + address(this), + true, + _proofSignature + ); + + // Send transfer + IZkAsset(_tokenAddress).confidentialTransferFrom( + JOIN_SPLIT_PROOF, + proofOutput + ); + + // Return stream note hash + streamNoteHash = streamNote.noteHash; + } + function _validateRatioProof( address _aceContractAddress, bytes memory _proof1, uint256 _withdrawDuration, Types.AztecStream storage _stream - ) - internal - returns ( - bytes memory _proof1InputNotes, - bytes memory _proof1OutputNotes - ) - { + ) internal returns (bytes32 withdrawalNoteHash) { // Check that ratio of notes match that given by fraction of remaining time to withdraw uint256 totalTime = _stream.stopTime.sub(_stream.lastWithdrawTime); require( getRatio(_proof1) == totalTime.mul(scalingFactor).div(_withdrawDuration), - "ratios do not match" + 'ratios do not match' ); // Validate ratio proof @@ -77,17 +135,23 @@ library StreamUtilities { address(this), _proof1 ); - (_proof1InputNotes, _proof1OutputNotes, , ) = _proof1Outputs - .get(0) - .extractProofOutput(); + ( + bytes memory _proof1InputNotes, + bytes memory _proof1OutputNotes, + , + + ) = _proof1Outputs.get(0).extractProofOutput(); // Make sure that recipient has provided the note on the contract as input // This prevents recipient using a larger note for this proof to allow a larger withdrawal require( _noteCoderToStruct(_proof1InputNotes.get(0)).noteHash == _stream.noteHash, - "incorrect notional note in proof 1" + 'incorrect notional note in proof 1' ); + + withdrawalNoteHash = _noteCoderToStruct(_proof1OutputNotes.get(0)) + .noteHash; } function _validateJoinSplitProof( @@ -109,45 +173,45 @@ library StreamUtilities { int256 publicValue ) = proof2Outputs.extractProofOutput(); - require(publicValue == 0, "nonzero public value transfer"); + require(publicValue == 0, 'nonzero public value transfer'); // Ensure stream note is the only input note require( _proof2InputNotes.getLength() == 1, - "Incorrect number of input notes" + 'Incorrect number of input notes' ); // Ensure that there isn't a third output note used to avoid the below checks require( _proof2OutputNotes.getLength() == 2, - "Incorrect number of output notes" + 'Incorrect number of output notes' ); // Requires that output note respects dividend proof require( _noteCoderToStruct(_proof2OutputNotes.get(0)).noteHash == _withdrawalNoteHash, - "withdraw note in 2 is not the same as 1" + 'withdraw note in 2 is not the same as 1' ); // Require that input note is stream note require( _noteCoderToStruct(_proof2InputNotes.get(0)).noteHash == _stream.noteHash, - "stream note in 2 is not correct" + 'stream note in 2 is not correct' ); } function _processWithdrawal( address _aceContractAddress, bytes memory _proof2, - bytes memory _proof1OutputNotes, + bytes32 _withdrawalNoteHash, Types.AztecStream storage _stream ) internal returns (bytes32) { bytes memory proof2Outputs = _validateJoinSplitProof( _aceContractAddress, _proof2, - _noteCoderToStruct(_proof1OutputNotes.get(0)).noteHash, // withdrawal note hash + _withdrawalNoteHash, _stream ); @@ -165,7 +229,7 @@ library StreamUtilities { // Require that change note is owned by contract require( newStreamNote.owner == address(this), - "change note in 2 is not owned by stream contract" + 'change note in 2 is not owned by stream contract' ); // Require that sender and receiver have view access to change note @@ -185,7 +249,7 @@ library StreamUtilities { _noteCoderToStruct(_proof2InputNotes.get(0)).noteHash, address(this), true, - "" + '' ); // Send transfer @@ -198,16 +262,16 @@ library StreamUtilities { return newStreamNote.noteHash; } - function _processCancelation( + function _processCancellation( address _aceContractAddress, bytes memory _proof2, - bytes memory _proof1OutputNotes, + bytes32 _withdrawalNoteHash, Types.AztecStream storage _stream ) internal returns (bool) { bytes memory proof2Outputs = _validateJoinSplitProof( _aceContractAddress, _proof2, - _noteCoderToStruct(_proof1OutputNotes.get(0)).noteHash, // withdrawal note hash + _withdrawalNoteHash, _stream ); // Extract notes used in proof @@ -221,24 +285,39 @@ library StreamUtilities { bytes32 inputNoteHash = _noteCoderToStruct(_proof2InputNotes.get(0)) .noteHash; + Note memory withdrawalNote = _noteCoderToStruct( + _proof2OutputNotes.get(0) + ); + Note memory refundNote = _noteCoderToStruct(_proof2OutputNotes.get(1)); + // Require that each participant owns an output note require( - _noteCoderToStruct(_proof2OutputNotes.get(0)).owner == - _stream.recipient, + withdrawalNote.owner == _stream.recipient, "Stream recipient doesn't own first output note" ); require( - _noteCoderToStruct(_proof2OutputNotes.get(1)).owner == - _stream.sender, + refundNote.owner == _stream.sender, "Stream sender doesn't own second output note" ); + // Require that sender and receiver have view access to their notes + require( + MetaDataUtils.extractAddress(withdrawalNote.metaData, 0) == + _stream.recipient, + "stream recipient can't view withdrawal note" + ); + require( + MetaDataUtils.extractAddress(refundNote.metaData, 0) == + _stream.sender, + "stream sender can't view refund note" + ); + // Approve contract to spend with stream note IZkAsset(_stream.tokenAddress).confidentialApprove( inputNoteHash, address(this), true, - "" + '' ); // Send transfer diff --git a/packages/contracts/contracts/mocks/StreamUtilitiesMock.sol b/packages/contracts/contracts/mocks/StreamUtilitiesMock.sol index 26ada8f..c48aa0d 100644 --- a/packages/contracts/contracts/mocks/StreamUtilitiesMock.sol +++ b/packages/contracts/contracts/mocks/StreamUtilitiesMock.sol @@ -1,20 +1,24 @@ pragma solidity ^0.5.11; pragma experimental ABIEncoderV2; -import "../StreamUtilities.sol"; +import '../StreamUtilities.sol'; contract StreamUtilitiesMock { - // The provided struct object is stored here as StreamUtilities expects a storage variable. Types.AztecStream public stream; + event ValidateRatioProof(bytes32 withdrawalNoteHash); + event ValidateJoinSplitProof(bytes32 withdrawalNoteHash); + event ProcessDeposit(bytes32 streamNoteHash); + event ProcessWithdrawal(bytes32 newStreamNoteHash); + event ProcessCancellation(bool cancellationSuccess); function getRatio(bytes memory _proofData) public pure returns (uint256 ratio) { - return StreamUtilities.getRatio(_proofData); + return StreamUtilities.getRatio(_proofData); } function validateRatioProof( @@ -22,12 +26,15 @@ contract StreamUtilitiesMock { bytes memory _proof1, uint256 _withdrawDuration, Types.AztecStream memory _stream - ) - public - returns (bytes memory, bytes memory) - { + ) public returns (bytes32) { stream = _stream; - return StreamUtilities._validateRatioProof(_aceContractAddress, _proof1, _withdrawDuration, stream); + bytes32 withdrawalNoteHash = StreamUtilities._validateRatioProof( + _aceContractAddress, + _proof1, + _withdrawDuration, + stream + ); + emit ValidateRatioProof(withdrawalNoteHash); } function validateJoinSplitProof( @@ -35,28 +42,66 @@ contract StreamUtilitiesMock { bytes memory _proof2, bytes32 _withdrawalNoteHash, Types.AztecStream memory _stream - ) public returns (bytes memory proof2Outputs) { + ) public returns (bytes memory) { stream = _stream; - return StreamUtilities._validateJoinSplitProof(_aceContractAddress, _proof2, _withdrawalNoteHash, stream); + bytes memory proofOutputs = + StreamUtilities._validateJoinSplitProof( + _aceContractAddress, + _proof2, + _withdrawalNoteHash, + stream + ); + } + + function processDeposit( + bytes memory _proof, + bytes memory _proofSignature, + address _aceContractAddress, + address _sender, + address _recipient, + address _tokenAddress + ) public returns (bytes32) { + bytes32 newStreamNoteHash = StreamUtilities._processDeposit( + _proof, + _proofSignature, + _aceContractAddress, + _sender, + _recipient, + _tokenAddress + ); + emit ProcessDeposit(newStreamNoteHash); } function processWithdrawal( address _aceContractAddress, bytes memory _proof2, - bytes memory _proof1OutputNotes, + bytes32 _withdrawalNoteHash, Types.AztecStream memory _stream ) public returns (bytes32) { stream = _stream; - return StreamUtilities._processWithdrawal(_aceContractAddress, _proof2, _proof1OutputNotes, stream); + bytes32 newStreamNoteHash = StreamUtilities._processWithdrawal( + _aceContractAddress, + _proof2, + _withdrawalNoteHash, + stream + ); + emit ProcessWithdrawal(newStreamNoteHash); } - function processCancelation( + function processCancellation( address _aceContractAddress, bytes memory _proof2, - bytes memory _proof1OutputNotes, + bytes32 _proof1OutputNotes, Types.AztecStream memory _stream ) public returns (bool) { stream = _stream; - return StreamUtilities._processCancelation(_aceContractAddress, _proof2, _proof1OutputNotes, stream); + bool cancellationSuccess = + StreamUtilities._processCancellation( + _aceContractAddress, + _proof2, + _proof1OutputNotes, + stream + ); + emit ProcessCancellation(cancellationSuccess); } } diff --git a/packages/contracts/contracts/test/Imports.sol b/packages/contracts/contracts/test/Imports.sol deleted file mode 100644 index 34f5978..0000000 --- a/packages/contracts/contracts/test/Imports.sol +++ /dev/null @@ -1,22 +0,0 @@ -pragma solidity ^0.5.11; - -import "@aztec/protocol/contracts/ACE/noteRegistry/epochs/201912/base/FactoryBase201912.sol"; -import "@aztec/protocol/contracts/ACE/ACE.sol"; -import "@aztec/protocol/contracts/ACE/validators/joinSplit/JoinSplit.sol"; -import "@aztec/protocol/contracts/ACE/validators/dividend/Dividend.sol"; - -// You might think this file is a bit odd, but let me explain. -// We only use some contracts in our tests, which means Truffle -// will not compile it for us, because it is from an external -// dependency. -// -// We are now left with three options: -// - Copy/paste these contracts -// - Run the tests with `truffle compile --all` on -// - Or trick Truffle by claiming we use it in a Solidity test -// -// You know which one I went for. - -contract Imports { - constructor() public {} -} diff --git a/packages/contracts/package.json b/packages/contracts/package.json index 2bea997..93088e8 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -33,6 +33,7 @@ "@aztec/contract-artifacts": "^1.22.0", "@aztec/dev-utils": "^2.3.1", "@aztec/protocol": "^1.7.0", + "@aztec/secp256k1": "^1.2.0", "@nomiclabs/buidler": "^1.3.3", "@nomiclabs/buidler-ethers": "^1.3.3", "@nomiclabs/buidler-etherscan": "^1.3.3", @@ -40,6 +41,7 @@ "@notestream/dev-utils": "^0.1.0", "@openzeppelin/contracts": "^2.5.0", "@openzeppelin/upgrades": "^2.8.0", + "aztec.js": "^0.18.0", "chai": "^4.2.0", "chalk": "^4.0.0", "crypto": "^1.0.1", diff --git a/packages/contracts/test/NoteStream/cancelStream.js b/packages/contracts/test/NoteStream/cancelStream.js index c49d70e..43c705e 100644 --- a/packages/contracts/test/NoteStream/cancelStream.js +++ b/packages/contracts/test/NoteStream/cancelStream.js @@ -9,6 +9,9 @@ const crypto = require('crypto'); const NoteStream = require('../../build/NoteStream.json'); const { noteStreamFixture } = require('../fixtures'); +const { mintZkAsset } = require('../helpers/mint/mintZkAssets'); +const { signProof } = require('../helpers/signProof'); +const { createStreamDepositProof } = require('../helpers/deposit/streamNote'); const { contextForStreamDidEnd, @@ -63,7 +66,6 @@ function testValidCancellation() { // ).to.be.revertedWith('stream does not exist'); // } ); - it('returns true'); } function runTests() { @@ -132,29 +134,56 @@ function runTests() { } describe('NoteStream - cancelStream', function () { + let ace; + let token; let noteStream; let zkAsset; beforeEach(async function () { - ({ noteStream, zkAsset } = await loadFixture(noteStreamFixture)); + ({ ace, token, noteStream, zkAsset } = await loadFixture( + noteStreamFixture + )); }); - const now = bigNumberify(moment().format('X')); - describe('when the stream exists', function () { let streamId; + const streamDeposit = 100000; beforeEach(async function () { - const startTime = now.add( - STANDARD_TIME_OFFSET.multipliedBy(2).toString() + const depositOutputNote = await mintZkAsset( + sender.address, + streamDeposit, + token, + zkAsset, + ace ); + + const { depositProof } = await createStreamDepositProof( + [depositOutputNote], + noteStream.address, + sender.address, + recipient.address, + 0 + ); + + const { data, signature } = signProof( + zkAsset, + depositProof, + noteStream.address, + sender.signingKey.privateKey + ); + + const now = bigNumberify(moment().format('X')); + const startTime = now.add(STANDARD_TIME_OFFSET.toString()); const stopTime = startTime.add(STANDARD_TIME_DELTA.toString()); - const notehash = crypto.randomBytes(32); + const tx = await noteStream.createStream( recipient.address, - notehash, + data, + signature, zkAsset.address, startTime, stopTime ); + const receipt = await tx.wait(); streamId = NoteStreamInterface.parseLog( receipt.logs[receipt.logs.length - 1] diff --git a/packages/contracts/test/NoteStream/createStream.js b/packages/contracts/test/NoteStream/createStream.js index ff5a11d..19885a1 100644 --- a/packages/contracts/test/NoteStream/createStream.js +++ b/packages/contracts/test/NoteStream/createStream.js @@ -3,10 +3,8 @@ const { waffle } = require('@nomiclabs/buidler'); const { use, expect } = require('chai'); const { solidity, createFixtureLoader } = require('ethereum-waffle'); const { bigNumberify, Interface } = require('ethers/utils'); - const { devConstants } = require('@notestream/dev-utils'); const moment = require('moment'); -const crypto = require('crypto'); const { // STANDARD_SALARY, @@ -17,6 +15,9 @@ const { const NoteStream = require('../../build/NoteStream.json'); const { noteStreamFixture } = require('../fixtures'); +const { mintZkAsset } = require('../helpers/mint/mintZkAssets'); +const { signProof } = require('../helpers/signProof'); +const { createStreamDepositProof } = require('../helpers/deposit/streamNote'); use(solidity); @@ -27,23 +28,56 @@ describe('NoteStream - createStream', function () { const NoteStreamInterface = new Interface(NoteStream.abi); + let ace; + let token; let noteStream; let zkAsset; + let streamNote; + let data; + let signature; + const streamDeposit = 100000; beforeEach(async function () { - ({ noteStream, zkAsset } = await loadFixture(noteStreamFixture)); + ({ ace, token, noteStream, zkAsset } = await loadFixture( + noteStreamFixture + )); + + const depositOutputNote = await mintZkAsset( + sender.address, + streamDeposit, + token, + zkAsset, + ace + ); + + const { depositProof } = await createStreamDepositProof( + [depositOutputNote], + noteStream.address, + sender.address, + recipient.address, + 0 + ); + + [streamNote] = depositProof.outputNotes; + + ({ data, signature } = signProof( + zkAsset, + depositProof, + noteStream.address, + sender.signingKey.privateKey + )); }); const now = bigNumberify(moment().format('X')); const startTime = now.add(STANDARD_TIME_OFFSET.toString()); const stopTime = startTime.add(STANDARD_TIME_DELTA.toString()); - const notehash = crypto.randomBytes(32); describe('when not paused', function () { describe('when the recipient is valid', function () { it('creates the stream', async function () { const tx = await noteStream.createStream( recipient.address, - notehash, + data, + signature, zkAsset.address, startTime, stopTime @@ -56,9 +90,7 @@ describe('NoteStream - createStream', function () { const streamObject = await noteStream.getStream(streamId); expect(streamObject.sender).to.equal(sender.address); expect(streamObject.recipient).to.equal(recipient.address); - expect(streamObject.noteHash).to.equal( - `0x${notehash.toString('hex')}` - ); + expect(streamObject.noteHash).to.equal(streamNote.noteHash); expect(streamObject.tokenAddress).to.equal(zkAsset.address); expect(streamObject.startTime).to.equal(startTime); @@ -70,7 +102,8 @@ describe('NoteStream - createStream', function () { const currentStreamId = await noteStream.nextStreamId(); await noteStream.createStream( recipient.address, - notehash, + data, + signature, zkAsset.address, startTime, stopTime @@ -84,7 +117,8 @@ describe('NoteStream - createStream', function () { await expect( noteStream.createStream( recipient.address, - notehash, + data, + signature, zkAsset.address, startTime, stopTime @@ -99,7 +133,8 @@ describe('NoteStream - createStream', function () { await expect( noteStream.createStream( recipient.address, - notehash, + data, + signature, zkAsset.address, invalidStartTime, stopTime @@ -111,7 +146,8 @@ describe('NoteStream - createStream', function () { await expect( noteStream.createStream( recipient.address, - notehash, + data, + signature, zkAsset.address, startTime, startTime @@ -126,7 +162,8 @@ describe('NoteStream - createStream', function () { await expect( noteStream.createStream( recipient.address, - notehash, + data, + signature, zkAsset.address, startTime, invalidStopTime @@ -139,7 +176,8 @@ describe('NoteStream - createStream', function () { await expect( noteStream.createStream( sender.address, - notehash, + data, + signature, zkAsset.address, startTime, stopTime @@ -151,7 +189,8 @@ describe('NoteStream - createStream', function () { await expect( noteStream.createStream( noteStream.address, - notehash, + data, + signature, zkAsset.address, startTime, stopTime @@ -163,7 +202,8 @@ describe('NoteStream - createStream', function () { await expect( noteStream.createStream( ZERO_ADDRESS, - notehash, + data, + signature, zkAsset.address, startTime, stopTime @@ -179,7 +219,8 @@ describe('NoteStream - createStream', function () { await expect( noteStream.createStream( recipient.address, - notehash, + data, + signature, zkAsset.address, startTime, stopTime diff --git a/packages/contracts/test/NoteStream/withdrawFromStream.js b/packages/contracts/test/NoteStream/withdrawFromStream.js index 797d7dd..a34c1c1 100644 --- a/packages/contracts/test/NoteStream/withdrawFromStream.js +++ b/packages/contracts/test/NoteStream/withdrawFromStream.js @@ -1,10 +1,6 @@ const { waffle } = require('@nomiclabs/buidler'); const { use, expect } = require('chai'); -const { - solidity, - MockProvider, - createFixtureLoader, -} = require('ethereum-waffle'); +const { solidity, createFixtureLoader } = require('ethereum-waffle'); const { bigNumberify, Interface } = require('ethers/utils'); const { devConstants, mochaContexts } = require('@notestream/dev-utils'); @@ -13,6 +9,9 @@ const crypto = require('crypto'); const NoteStream = require('../../build/NoteStream.json'); const { noteStreamFixture } = require('../fixtures'); +const { mintZkAsset } = require('../helpers/mint/mintZkAssets'); +const { signProof } = require('../helpers/signProof'); +const { createStreamDepositProof } = require('../helpers/deposit/streamNote'); const { contextForStreamDidEnd, @@ -29,144 +28,63 @@ const { use(solidity); -function runTests() { - const { provider } = waffle; - const [sender, recipient] = provider.getWallets(); - const loadFixture = createFixtureLoader(provider, [sender, recipient]); - - const NoteStreamInterface = new Interface(NoteStream.abi); - - let noteStream; - let zkAsset; - let streamId; - beforeEach(async function () { - ({ noteStream, zkAsset } = await loadFixture(noteStreamFixture)); - const now = bigNumberify(moment().format('X')); - const startTime = now.add(STANDARD_TIME_OFFSET.toString()); - const stopTime = startTime.add(STANDARD_TIME_DELTA.toString()); - - const notehash = crypto.randomBytes(32); - const tx = await noteStream.createStream( - recipient.address, - notehash, - zkAsset.address, - startTime, - stopTime - ); - const receipt = await tx.wait(); - streamId = NoteStreamInterface.parseLog( - receipt.logs[receipt.logs.length - 1] - ).values.streamId; - noteStream = noteStream.connect(recipient); - }); - - describe('when the withdrawal amount is higher than 0', function () { - it('reverts if the stream did not start', async function () { - const dividendProof = crypto.randomBytes(1); - const joinSplitProof = crypto.randomBytes(1); - const withrawDuration = FIVE_UNITS.toString(10); - await expect( - noteStream.withdrawFromStream( - streamId, - dividendProof, - joinSplitProof, - withrawDuration - ) - ).to.be.revertedWith('withdraw is greater than allowed'); - }); - - contextForStreamDidStartButNotEnd(provider, function () { - it('reverts if the withdrawal amount exceeds the available balance', async function () { - const withdrawDuration = STANDARD_TIME_OFFSET.multipliedBy( - 2 - ).toString(10); - const dividendProof = crypto.randomBytes(1); - const joinSplitProof = crypto.randomBytes(1); - await expect( - noteStream.withdrawFromStream( - streamId, - dividendProof, - joinSplitProof, - withdrawDuration - ) - ).to.be.revertedWith('withdraw is greater than allowed'); - }); - it('updates the streams lastWithdrawTime parameter'); - it('emits a WithdrawFromStream event'); - }); - - contextForStreamDidEnd(provider, function () { - it('reverts if the withdrawal amount exceeds the available balance', async function () { - const withdrawDuration = bigNumberify( - STANDARD_TIME_DELTA.toString() - ) - .mul(2) - .toString(); - const dividendProof = crypto.randomBytes(1); - const joinSplitProof = crypto.randomBytes(1); - await expect( - noteStream.withdrawFromStream( - streamId, - dividendProof, - joinSplitProof, - withdrawDuration - ) - ).to.be.revertedWith('withdraw is greater than allowed'); - }); - describe('when the balance is not withdrawn in full', function () { - it('updates the streams lastWithdrawTime parameter'); - it('emits a WithdrawFromStream event'); - }); - describe('when the balance is withdrawn in full', function () { - it('updates the streams lastWithdrawTime parameter'); - it('emits a WithdrawFromStream event'); - }); - }); - }); - - it('reverts when the withdrawal amount is zero', async function () { - const dividendProof = crypto.randomBytes(1); - const joinSplitProof = crypto.randomBytes(1); - const withdrawalDuration = '0'; - await expect( - noteStream.withdrawFromStream( - streamId, - dividendProof, - joinSplitProof, - withdrawalDuration - ) - ).to.be.revertedWith('zero value withdrawal'); - }); -} - describe('NoteStream - withdrawFromStream', function () { - const provider = new MockProvider(); - const [sender, recipient] = provider.getWallets(); + const { provider } = waffle; + const [sender, recipient, attacker] = provider.getWallets(); const loadFixture = createFixtureLoader(provider, [sender, recipient]); const NoteStreamInterface = new Interface(NoteStream.abi); + let ace; + let token; let noteStream; let zkAsset; beforeEach(async function () { - ({ noteStream, zkAsset } = await loadFixture(noteStreamFixture)); + ({ ace, token, noteStream, zkAsset } = await loadFixture( + noteStreamFixture + )); }); describe('when the stream exists', function () { let streamId; + const streamDeposit = 100000; beforeEach(async function () { + const depositOutputNote = await mintZkAsset( + sender.address, + streamDeposit, + token, + zkAsset, + ace + ); + + const { depositProof } = await createStreamDepositProof( + [depositOutputNote], + noteStream.address, + sender.address, + recipient.address, + 0 + ); + + const { data, signature } = signProof( + zkAsset, + depositProof, + noteStream.address, + sender.signingKey.privateKey + ); + const now = bigNumberify(moment().format('X')); const startTime = now.add(STANDARD_TIME_OFFSET.toString()); const stopTime = startTime.add(STANDARD_TIME_DELTA.toString()); - const notehash = crypto.randomBytes(32); const tx = await noteStream.createStream( recipient.address, - notehash, + data, + signature, zkAsset.address, startTime, stopTime ); + const receipt = await tx.wait(); streamId = NoteStreamInterface.parseLog( receipt.logs[receipt.logs.length - 1] @@ -178,17 +96,105 @@ describe('NoteStream - withdrawFromStream', function () { const joinSplitProof = crypto.randomBytes(1); const withdrawDuration = 1; await expect( - noteStream.withdrawFromStream( - streamId, - dividendProof, - joinSplitProof, - withdrawDuration - ) + noteStream + .connect(sender) + .withdrawFromStream( + streamId, + dividendProof, + joinSplitProof, + withdrawDuration + ) ).to.be.revertedWith('caller is not the recipient of the stream'); }); describe('when the caller is the recipient of the stream', function () { - runTests(); + beforeEach(function () { + noteStream = noteStream.connect(recipient); + }); + + describe('when the withdrawal amount is higher than 0', function () { + it('reverts if the stream did not start', async function () { + const dividendProof = crypto.randomBytes(1); + const joinSplitProof = crypto.randomBytes(1); + const withrawDuration = FIVE_UNITS.toString(10); + await expect( + noteStream.withdrawFromStream( + streamId, + dividendProof, + joinSplitProof, + withrawDuration + ) + ).to.be.revertedWith('withdraw is greater than allowed'); + }); + + contextForStreamDidStartButNotEnd(provider, function () { + it('reverts if the withdrawal amount exceeds the available balance', async function () { + const withdrawDuration = STANDARD_TIME_OFFSET.multipliedBy( + 2 + ).toString(10); + const dividendProof = crypto.randomBytes(1); + const joinSplitProof = crypto.randomBytes(1); + await expect( + noteStream.withdrawFromStream( + streamId, + dividendProof, + joinSplitProof, + withdrawDuration + ) + ).to.be.revertedWith( + 'withdraw is greater than allowed' + ); + }); + it('updates the streams lastWithdrawTime parameter'); + it('emits a WithdrawFromStream event'); + }); + + contextForStreamDidEnd(provider, function () { + it('reverts if the withdrawal amount exceeds the available balance', async function () { + const withdrawDuration = bigNumberify( + STANDARD_TIME_DELTA.toString() + ) + .mul(2) + .toString(); + const dividendProof = crypto.randomBytes(1); + const joinSplitProof = crypto.randomBytes(1); + await expect( + noteStream.withdrawFromStream( + streamId, + dividendProof, + joinSplitProof, + withdrawDuration + ) + ).to.be.revertedWith( + 'withdraw is greater than allowed' + ); + }); + describe('when the balance is not withdrawn in full', function () { + it('updates the streams lastWithdrawTime parameter'); + it('emits a WithdrawFromStream event'); + }); + describe('when the balance is withdrawn in full', function () { + it('updates the streams lastWithdrawTime parameter'); + it('emits a WithdrawFromStream event'); + }); + }); + }); + + it('reverts when the withdrawal amount is zero', async function () { + const dividendProof = crypto.randomBytes(1); + const joinSplitProof = crypto.randomBytes(1); + const withdrawalDuration = '0'; + await expect( + noteStream + .connect(recipient) + .withdrawFromStream( + streamId, + dividendProof, + joinSplitProof, + withdrawalDuration + ) + ).to.be.revertedWith('zero value withdrawal'); + }); }); it('reverts when the caller is not the sender or the recipient of the stream', async function () { @@ -196,12 +202,14 @@ describe('NoteStream - withdrawFromStream', function () { const joinSplitProof = crypto.randomBytes(1); const withdrawDuration = 1; await expect( - noteStream.withdrawFromStream( - streamId, - dividendProof, - joinSplitProof, - withdrawDuration - ) + noteStream + .connect(attacker) + .withdrawFromStream( + streamId, + dividendProof, + joinSplitProof, + withdrawDuration + ) ).to.be.revertedWith('caller is not the recipient of the stream'); }); }); @@ -210,12 +218,12 @@ describe('NoteStream - withdrawFromStream', function () { const dividendProof = crypto.randomBytes(1); const joinSplitProof = crypto.randomBytes(1); const withdrawDuration = 1; - const streamId = bigNumberify(419863); + const badStreamId = bigNumberify(419863); await expect( noteStream .connect(recipient) .withdrawFromStream( - streamId, + badStreamId, dividendProof, joinSplitProof, withdrawDuration diff --git a/packages/contracts/test/StreamUtilities/getRatio.js b/packages/contracts/test/StreamUtilities/getRatio.js index b96fe77..1b763f3 100644 --- a/packages/contracts/test/StreamUtilities/getRatio.js +++ b/packages/contracts/test/StreamUtilities/getRatio.js @@ -1,8 +1,11 @@ const { waffle } = require('@nomiclabs/buidler'); -const { use } = require('chai'); +const { use, expect } = require('chai'); const { solidity, createFixtureLoader } = require('ethereum-waffle'); +const { DividendProof } = require('aztec.js'); const { StreamUtilitiesFixture } = require('../fixtures'); +const { createNote } = require('../helpers/notes/createNote'); + use(solidity); describe('StreamUtilities - getRatio', function () { @@ -16,5 +19,51 @@ describe('StreamUtilities - getRatio', function () { ({ streamUtilitiesMock } = await loadFixture(StreamUtilitiesFixture)); }); - it('returns the correct ratio'); + it('returns the correct ratio', async function () { + // 1 * 1000 = 3 * 333 + 1 + const inputNoteValue = 1000; + const withdrawNoteValue = 333; + const remainderNoteValue = 1; + const ratioNumerator = 1; + const ratioDenominator = 3; + + // This is defined on the contract + const scalingFactor = 1000000000; + + const inputNote = await createNote( + inputNoteValue, + streamUtilitiesMock.address, + [sender.address] + ); + + const withdrawNote = await createNote( + withdrawNoteValue, + sender.address, + [sender.address] + ); + + const remainderNote = await createNote( + remainderNoteValue, + streamUtilitiesMock.address, + [sender.address] + ); + + const badProofData = new DividendProof( + inputNote, + remainderNote, + withdrawNote, + streamUtilitiesMock.address, + ratioDenominator, + ratioNumerator + ).encodeABI(); + + const ratio = await streamUtilitiesMock.getRatio(badProofData); + + // We flip the ratio as we require an integer value + const expectedRatio = parseInt( + (ratioDenominator * scalingFactor) / ratioNumerator, + 10 + ); + expect(ratio).to.be.equal(expectedRatio); + }); }); diff --git a/packages/contracts/test/StreamUtilities/index.js b/packages/contracts/test/StreamUtilities/index.js index b904d14..d1e55e8 100644 --- a/packages/contracts/test/StreamUtilities/index.js +++ b/packages/contracts/test/StreamUtilities/index.js @@ -1,4 +1,5 @@ require('./getRatio.js'); +require('./processDeposit.js'); require('./validateRatioProof.js'); require('./validateJoinSplitProof.js'); require('./processWithdrawal.js'); diff --git a/packages/contracts/test/StreamUtilities/processCancellation.js b/packages/contracts/test/StreamUtilities/processCancellation.js index 7a10bf2..c683617 100644 --- a/packages/contracts/test/StreamUtilities/processCancellation.js +++ b/packages/contracts/test/StreamUtilities/processCancellation.js @@ -1,7 +1,11 @@ const { waffle } = require('@nomiclabs/buidler'); -const { use } = require('chai'); +const { use, expect } = require('chai'); const { solidity, createFixtureLoader } = require('ethereum-waffle'); +const { JoinSplitProof } = require('aztec.js'); + const { StreamUtilitiesFixture } = require('../fixtures'); +const { createNote } = require('../helpers/notes/createNote'); +const { mintZkAsset } = require('../helpers/mint/mintZkAssets'); use(solidity); @@ -10,16 +14,186 @@ describe('StreamUtilities - processCancellation', function () { const [sender, recipient] = provider.getWallets(); const loadFixture = createFixtureLoader(provider, [sender, recipient]); - // eslint-disable-next-line no-unused-vars + let ace; + let token; + let zkAsset; + let streamNote; let streamUtilitiesMock; + let streamObject; + const streamDeposit = 100000; beforeEach(async function () { - ({ streamUtilitiesMock } = await loadFixture(StreamUtilitiesFixture)); + ({ ace, streamUtilitiesMock, token, zkAsset } = await loadFixture( + StreamUtilitiesFixture + )); + + streamNote = await mintZkAsset( + streamUtilitiesMock.address, + streamDeposit, + token, + zkAsset, + ace + ); + + streamObject = { + noteHash: streamNote.noteHash, + startTime: 0, + lastWithdrawTime: 50, + stopTime: 100, + recipient: recipient.address, + sender: sender.address, + tokenAddress: zkAsset.address, + isEntity: true, + }; + }); + + const runTest = async ( + withdrawNoteOwner, + withdrawNoteViewAccess, + refundNoteOwner, + refundNoteViewAccess, + error + ) => { + const withdrawalNote = await createNote( + streamNote.k.toNumber() / 4, + withdrawNoteOwner, + [withdrawNoteViewAccess] + ); + + const refundNote = await createNote( + (streamNote.k.toNumber() * 3) / 4, + refundNoteOwner, + [refundNoteViewAccess] + ); + + const badProof = new JoinSplitProof( + [streamNote], + [withdrawalNote, refundNote], + streamUtilitiesMock.address, + 0, + withdrawNoteOwner + ); + + const badProofData = badProof.encodeABI(zkAsset.address); + + await expect( + streamUtilitiesMock.processCancellation( + ace.address, + badProofData, + withdrawalNote.noteHash, + streamObject + ) + ).to.be.revertedWith(error); + }; + + it('reverts if withdraw note is not owned by recipient', async function () { + await runTest( + sender.address, // incorrect + recipient.address, + sender.address, + sender.address, + "Stream recipient doesn't own first output note" + ); + }); + + it('reverts if refund note is not owned by sender', async function () { + await runTest( + recipient.address, + recipient.address, + recipient.address, // incorrect + sender.address, + "Stream sender doesn't own second output note" + ); + }); + + it('reverts if recipient does not have view access to the withdraw note', async function () { + await runTest( + recipient.address, + sender.address, // incorrect + sender.address, + sender.address, + "stream recipient can't view withdrawal note" + ); }); - it('reverts if withdraw note is not owned by recipient'); - it('reverts if refund note is not owned by sender'); - it('reverts if recipient does not have view access to the withdraw note'); - it('reverts if sender does not have view access to the refund note'); - it('emits a confidentialTransfer event'); - it('returns true'); + it('reverts if sender does not have view access to the refund note', async function () { + await runTest( + recipient.address, + recipient.address, + sender.address, + recipient.address, // incorrect + "stream sender can't view refund note" + ); + }); + + it('transfers the zkAssets to the sender and recipient', async function () { + const withdrawalNote = await createNote( + streamNote.k.toNumber() / 4, + recipient.address, + [recipient.address] + ); + + const refundNote = await createNote( + (streamNote.k.toNumber() * 3) / 4, + sender.address, + [sender.address] + ); + + const proof = new JoinSplitProof( + [streamNote], + [withdrawalNote, refundNote], + streamUtilitiesMock.address, + 0, + sender.address + ); + + const proofData = proof.encodeABI(zkAsset.address); + + await expect( + streamUtilitiesMock.processCancellation( + ace.address, + proofData, + withdrawalNote.noteHash, + streamObject + ) + ) + .to.emit(zkAsset, 'DestroyNote') + .withArgs(streamUtilitiesMock.address, streamNote.noteHash); + }); + + it('transfers the zkAssets to the sender and recipient and returns true', async function () { + const withdrawalNote = await createNote( + streamNote.k.toNumber() / 4, + recipient.address, + [recipient.address] + ); + + const refundNote = await createNote( + (streamNote.k.toNumber() * 3) / 4, + sender.address, + [sender.address] + ); + + const proof = new JoinSplitProof( + [streamNote], + [withdrawalNote, refundNote], + streamUtilitiesMock.address, + 0, + sender.address + ); + + const proofData = proof.encodeABI(zkAsset.address); + + await expect( + streamUtilitiesMock.processCancellation( + ace.address, + proofData, + withdrawalNote.noteHash, + streamObject + ) + ) + .to.emit(zkAsset, 'DestroyNote') + .withArgs(streamUtilitiesMock.address, streamNote.noteHash) + .and.emit(streamUtilitiesMock, 'ProcessCancellation') + .withArgs(true); + }); }); diff --git a/packages/contracts/test/StreamUtilities/processDeposit.js b/packages/contracts/test/StreamUtilities/processDeposit.js new file mode 100644 index 0000000..08b24c5 --- /dev/null +++ b/packages/contracts/test/StreamUtilities/processDeposit.js @@ -0,0 +1,242 @@ +const { waffle } = require('@nomiclabs/buidler'); +const { use, expect } = require('chai'); +const { solidity, createFixtureLoader } = require('ethereum-waffle'); +const { JoinSplitProof } = require('aztec.js'); + +const { StreamUtilitiesFixture } = require('../fixtures'); +const { mintZkAsset } = require('../helpers/mint/mintZkAssets'); +const { createNote } = require('../helpers/notes/createNote'); +const { + getStreamNote, + createStreamDepositProof, +} = require('../helpers/deposit/streamNote'); +const { signProof } = require('../helpers/signProof'); + +use(solidity); + +describe('StreamUtilities - processDeposit', function () { + const { provider } = waffle; + const [sender, recipient] = provider.getWallets(); + const loadFixture = createFixtureLoader(provider, [sender, recipient]); + + let ace; + let token; + let zkAsset; + let depositOutputNote; + let streamUtilitiesMock; + const streamDeposit = 100000; + beforeEach(async function () { + ({ + ace, + streamUtilitiesMock, + token, + zkAsset, + // depositOutputNotes, + } = await loadFixture(StreamUtilitiesFixture)); + + depositOutputNote = await mintZkAsset( + sender.address, + streamDeposit, + token, + zkAsset, + ace + ); + }); + + it('reverts if there is no output note', async function () { + const badProof = new JoinSplitProof( + [depositOutputNote], + [], + sender.address, + streamDeposit, + sender.address + ); + const { data, signature } = signProof( + zkAsset, + badProof, + streamUtilitiesMock.address, + sender.signingKey.privateKey + ); + + await expect( + streamUtilitiesMock.processDeposit( + data, + signature, + ace.address, + sender.address, + recipient.address, + zkAsset.address + ) + ).to.be.revertedWith('Incorrect number of output notes'); + }); + it('reverts if there is more than one output note', async function () { + const note1 = await getStreamNote( + streamDeposit / 2, + streamUtilitiesMock.address, + sender.address, + recipient.address + ); + const note2 = await getStreamNote( + streamDeposit / 2, + streamUtilitiesMock.address, + sender.address, + recipient.address + ); + + const badProof = new JoinSplitProof( + [depositOutputNote], + [note1, note2], + sender.address, + 0, + sender.address + ); + + const { data, signature } = signProof( + zkAsset, + badProof, + streamUtilitiesMock.address, + sender.signingKey.privateKey + ); + + await expect( + streamUtilitiesMock.processDeposit( + data, + signature, + ace.address, + sender.address, + recipient.address, + zkAsset.address + ) + ).to.be.revertedWith('Incorrect number of output notes'); + }); + it('reverts if streamNote is not owned by the contract', async function () { + const badNote = await getStreamNote( + streamDeposit, + sender.address, + sender.address, + recipient.address + ); + + const badProof = new JoinSplitProof( + [depositOutputNote], + [badNote], + sender.address, + 0, + sender.address + ); + + const { data, signature } = signProof( + zkAsset, + badProof, + streamUtilitiesMock.address, + sender.signingKey.privateKey + ); + + await expect( + streamUtilitiesMock.processDeposit( + data, + signature, + ace.address, + sender.address, + recipient.address, + zkAsset.address + ) + ).to.be.revertedWith('stream note is not owned by stream contract'); + }); + it('reverts if sender does not have view access to the streamNote', async function () { + const badNote = await createNote( + streamDeposit, + streamUtilitiesMock.address, + [recipient.address] + ); + + const badProof = new JoinSplitProof( + [depositOutputNote], + [badNote], + sender.address, + 0, + sender.address + ); + + const { data, signature } = signProof( + zkAsset, + badProof, + streamUtilitiesMock.address, + sender.signingKey.privateKey + ); + + await expect( + streamUtilitiesMock.processDeposit( + data, + signature, + ace.address, + sender.address, + recipient.address, + zkAsset.address + ) + ).to.be.revertedWith("stream sender can't view stream note"); + }); + it('reverts if recipient does not have view access to the streamNote', async function () { + const badNote = await createNote( + streamDeposit, + streamUtilitiesMock.address, + [sender.address] + ); + + const badProof = new JoinSplitProof( + [depositOutputNote], + [badNote], + sender.address, + 0, + sender.address + ); + + const { data, signature } = signProof( + zkAsset, + badProof, + streamUtilitiesMock.address, + sender.signingKey.privateKey + ); + + await expect( + streamUtilitiesMock.processDeposit( + data, + signature, + ace.address, + sender.address, + recipient.address, + zkAsset.address + ) + ).to.be.revertedWith("stream recipient can't view stream note"); + }); + it('transfers the zkAssets to the contract and returns the new stream note hash', async function () { + const { depositProof, streamNote } = await createStreamDepositProof( + [depositOutputNote], + streamUtilitiesMock.address, + sender.address, + recipient.address, + 0 + ); + + const { data, signature } = signProof( + zkAsset, + depositProof, + streamUtilitiesMock.address, + sender.signingKey.privateKey + ); + await expect( + streamUtilitiesMock.processDeposit( + data, + signature, + ace.address, + sender.address, + recipient.address, + zkAsset.address + ) + ) + .to.emit(zkAsset, 'DestroyNote') + .withArgs(sender.address, depositOutputNote.noteHash) + .and.emit(streamUtilitiesMock, 'ProcessDeposit') + .withArgs(streamNote.noteHash); + }); +}); diff --git a/packages/contracts/test/StreamUtilities/processWithdrawal.js b/packages/contracts/test/StreamUtilities/processWithdrawal.js index 7d4cdbc..5caedf4 100644 --- a/packages/contracts/test/StreamUtilities/processWithdrawal.js +++ b/packages/contracts/test/StreamUtilities/processWithdrawal.js @@ -1,7 +1,11 @@ const { waffle } = require('@nomiclabs/buidler'); -const { use } = require('chai'); +const { use, expect } = require('chai'); const { solidity, createFixtureLoader } = require('ethereum-waffle'); +const { JoinSplitProof } = require('aztec.js'); + const { StreamUtilitiesFixture } = require('../fixtures'); +const { mintZkAsset } = require('../helpers/mint/mintZkAssets'); +const { createNote } = require('../helpers/notes/createNote'); use(solidity); @@ -10,16 +14,213 @@ describe('StreamUtilities - processWithdrawal', function () { const [sender, recipient] = provider.getWallets(); const loadFixture = createFixtureLoader(provider, [sender, recipient]); - // eslint-disable-next-line no-unused-vars + let ace; + let token; + let zkAsset; + let streamNote; let streamUtilitiesMock; + let streamObject; + const streamDeposit = 100000; beforeEach(async function () { - ({ streamUtilitiesMock } = await loadFixture(StreamUtilitiesFixture)); + ({ ace, streamUtilitiesMock, token, zkAsset } = await loadFixture( + StreamUtilitiesFixture + )); + + streamNote = await mintZkAsset( + streamUtilitiesMock.address, + streamDeposit, + token, + zkAsset, + ace + ); + + streamObject = { + noteHash: streamNote.noteHash, + startTime: 0, + lastWithdrawTime: 50, + stopTime: 100, + recipient: recipient.address, + sender: sender.address, + tokenAddress: zkAsset.address, + isEntity: true, + }; + }); + + it('reverts if new streamNote is not owned by NoteStream contract', async function () { + const withdrawalNote = await createNote( + streamNote.k.toNumber() / 4, + recipient.address, + [recipient.address] + ); + + // Try to steal refund note by setting sender as owner + const refundNote = await createNote( + (streamNote.k.toNumber() * 3) / 4, + sender.address, + [sender.address, recipient.address] + ); + + const badProof = new JoinSplitProof( + [streamNote], + [withdrawalNote, refundNote], + streamUtilitiesMock.address, + 0, + sender.address + ); + const badProofData = badProof.encodeABI(zkAsset.address); + + await expect( + streamUtilitiesMock.processWithdrawal( + ace.address, + badProofData, + withdrawalNote.noteHash, + streamObject + ) + ).to.be.revertedWith( + 'change note in 2 is not owned by stream contract' + ); + }); + + // it('reverts if withdraw note is not owned by recipient', async function () { + // // Try to steal withdrawal note by setting sender as owner + // const badWithdrawalNote = await createNote( + // streamNote.k.toNumber() / 4, + // sender.address, + // [sender.address] + // ); + + // const refundNote = await createNote( + // (streamNote.k.toNumber() * 3) / 4, + // streamUtilitiesMock.address, + // [sender.address, recipient.address] + // ); + + // const badProof = new JoinSplitProof( + // [streamNote], + // [badWithdrawalNote, refundNote], + // streamUtilitiesMock.address, + // 0, + // sender.address + // ); + + // const badProofData = badProof.encodeABI(zkAsset.address); + + // await expect( + // streamUtilitiesMock.processWithdrawal( + // ace.address, + // badProofData, + // badWithdrawalNote.noteHash, + // streamObject + // ) + // ).to.be.revertedWith( + // 'change note in 2 is not owned by stream contract' + // ); + // }); + + it('reverts if sender does not have view access to the new streamNote', async function () { + // withdraw 1/4th of note + const withdrawalNote = await createNote( + streamNote.k.toNumber() / 4, + recipient.address, + [recipient.address] + ); + + // Here the sender has not given themself view access to the note + const badRefundNote = await createNote( + (streamNote.k.toNumber() * 3) / 4, + streamUtilitiesMock.address, + [recipient.address] + ); + + const badProof = new JoinSplitProof( + [streamNote], + [withdrawalNote, badRefundNote], + streamUtilitiesMock.address, + 0, + sender.address + ); + + const badProofData = badProof.encodeABI(zkAsset.address); + + await expect( + streamUtilitiesMock.processWithdrawal( + ace.address, + badProofData, + withdrawalNote.noteHash, + streamObject + ) + ).to.be.revertedWith("stream sender can't view new stream note"); }); - it('reverts if new streamNote is not owned by NoteStream contract'); - it('reverts if withdraw note is not owned by recipient'); - it('reverts if sender does not have view access to the new streamNote'); - it('reverts if recipient does not have view access to the new streamNote'); - it('emits a confidentialTransfer event'); - it('returns the hash of the first output note'); + it('reverts if recipient does not have view access to the new streamNote', async function () { + // withdraw 1/4th of note + const withdrawalNote = await createNote( + streamNote.k.toNumber() / 4, + recipient.address, + [recipient.address] + ); + + // Here the sender has not given the recipient view access to the note + const badRefundNote = await createNote( + (streamNote.k.toNumber() * 3) / 4, + streamUtilitiesMock.address, + [sender.address] + ); + + const badProof = new JoinSplitProof( + [streamNote], + [withdrawalNote, badRefundNote], + streamUtilitiesMock.address, + 0, + sender.address + ); + + const badProofData = badProof.encodeABI(zkAsset.address); + + await expect( + streamUtilitiesMock.processWithdrawal( + ace.address, + badProofData, + withdrawalNote.noteHash, + streamObject + ) + ).to.be.revertedWith("stream recipient can't view new stream note"); + }); + + it('transfers the zkAssets to the sender and recipient and returns the hash of the new stream note', async function () { + const withdrawalNote = await createNote( + streamNote.k.toNumber() / 4, + recipient.address, + [recipient.address] + ); + + const refundNote = await createNote( + (streamNote.k.toNumber() * 3) / 4, + streamUtilitiesMock.address, + [sender.address, recipient.address] + ); + + const proof = new JoinSplitProof( + [streamNote], + [withdrawalNote, refundNote], + streamUtilitiesMock.address, + 0, + sender.address + ); + + const proofData = proof.encodeABI(zkAsset.address); + + await expect( + streamUtilitiesMock.processWithdrawal( + ace.address, + proofData, + withdrawalNote.noteHash, + streamObject + ) + ) + .to.emit(zkAsset, 'DestroyNote') + .withArgs(streamUtilitiesMock.address, streamNote.noteHash) + .and.emit(streamUtilitiesMock, 'ProcessWithdrawal') + .withArgs(refundNote.noteHash); + }); }); diff --git a/packages/contracts/test/StreamUtilities/validateJoinSplitProof.js b/packages/contracts/test/StreamUtilities/validateJoinSplitProof.js index 18c671e..d5336a6 100644 --- a/packages/contracts/test/StreamUtilities/validateJoinSplitProof.js +++ b/packages/contracts/test/StreamUtilities/validateJoinSplitProof.js @@ -1,7 +1,9 @@ const { waffle } = require('@nomiclabs/buidler'); -const { use } = require('chai'); +const { use, expect } = require('chai'); const { solidity, createFixtureLoader } = require('ethereum-waffle'); +const { JoinSplitProof } = require('aztec.js'); const { StreamUtilitiesFixture } = require('../fixtures'); +const { createNote } = require('../helpers/notes/createNote'); use(solidity); @@ -10,16 +12,240 @@ describe('StreamUtilities - validateJoinSplitProof', function () { const [sender, recipient] = provider.getWallets(); const loadFixture = createFixtureLoader(provider, [sender, recipient]); - // eslint-disable-next-line no-unused-vars + let ace; let streamUtilitiesMock; + let zkAsset; + let streamObjectTemplate; beforeEach(async function () { - ({ streamUtilitiesMock } = await loadFixture(StreamUtilitiesFixture)); + ({ ace, streamUtilitiesMock, zkAsset } = await loadFixture( + StreamUtilitiesFixture + )); + streamObjectTemplate = { + startTime: 0, + lastWithdrawTime: 50, + stopTime: 100, + recipient: recipient.address, + sender: sender.address, + tokenAddress: zkAsset.address, + isEntity: true, + }; + }); + + it('reverts if proof has a non-zero public value transfer', async function () { + const inputNoteValue = 1000; + const outputNoteValue = 250; + const publicValue = 500; + + const inputNote = await createNote( + inputNoteValue, + streamUtilitiesMock.address, + [sender.address] + ); + + const outputNote1 = await createNote(outputNoteValue, sender.address, [ + sender.address, + ]); + + const outputNote2 = await createNote( + outputNoteValue, + streamUtilitiesMock.address, + [sender.address] + ); + + const badProof = new JoinSplitProof( + [inputNote], + [outputNote1, outputNote2], + streamUtilitiesMock.address, + publicValue, + sender.address + ); + const badProofData = badProof.encodeABI(zkAsset.address); + + const streamObject = { + ...streamObjectTemplate, + noteHash: inputNote.noteHash, + }; + + await expect( + streamUtilitiesMock.validateJoinSplitProof( + ace.address, + badProofData, + outputNote1.noteHash, + streamObject + ) + ).to.be.revertedWith('nonzero public value transfer'); + }); + + it('reverts if proof does not have one input note only', async function () { + const inputNoteValue = 1000; + + const inputNote1 = await createNote( + inputNoteValue, + streamUtilitiesMock.address, + [sender.address] + ); + + const inputNote2 = await createNote( + inputNoteValue, + streamUtilitiesMock.address, + [sender.address] + ); + + // We only use one output note as we exect the function to revert before it's checked + const outputNote = await createNote( + 2 * inputNoteValue, + sender.address, + [sender.address] + ); + + const badProofData = new JoinSplitProof( + [inputNote1, inputNote2], + [outputNote], + streamUtilitiesMock.address, + 0, + sender.address + ).encodeABI(zkAsset.address); + + const streamObject = { + ...streamObjectTemplate, + noteHash: inputNote1.noteHash, + }; + + await expect( + streamUtilitiesMock.validateJoinSplitProof( + ace.address, + badProofData, + outputNote.noteHash, + streamObject + ) + ).to.be.revertedWith('Incorrect number of input notes'); + }); + + it('reverts if proof does not have two output notes only', async function () { + const noteValue = 1000; + + const inputNote = await createNote( + noteValue, + streamUtilitiesMock.address, + [sender.address] + ); + + const outputNote = await createNote(noteValue, sender.address, [ + sender.address, + ]); + + const badProofData = new JoinSplitProof( + [inputNote], + [outputNote], + streamUtilitiesMock.address, + 0, + sender.address + ).encodeABI(zkAsset.address); + + const streamObject = { + ...streamObjectTemplate, + noteHash: inputNote.noteHash, + }; + + await expect( + streamUtilitiesMock.validateJoinSplitProof( + ace.address, + badProofData, + outputNote.noteHash, + streamObject + ) + ).to.be.revertedWith('Incorrect number of output notes'); + }); + + it('reverts if proof does not use same withdraw note as dividend proof', async function () { + const inputNoteValue = 1000; + const outputNoteValue = 500; + + const inputNote = await createNote( + inputNoteValue, + streamUtilitiesMock.address, + [sender.address] + ); + + const outputNote1 = await createNote(outputNoteValue, sender.address, [ + sender.address, + ]); + + const outputNote2 = await createNote( + outputNoteValue, + streamUtilitiesMock.address, + [sender.address] + ); + + const badProofData = new JoinSplitProof( + [inputNote], + [outputNote1, outputNote2], + streamUtilitiesMock.address, + 0, + sender.address + ).encodeABI(zkAsset.address); + + const streamObject = { + ...streamObjectTemplate, + noteHash: inputNote.noteHash, + }; + + // Here we pass the hash of outputNote2 + // To be a valid proof we should have usedoutputNote1 + await expect( + streamUtilitiesMock.validateJoinSplitProof( + ace.address, + badProofData, + outputNote2.noteHash, + streamObject + ) + ).to.be.revertedWith('withdraw note in 2 is not the same as 1'); + }); + + it('reverts if proof does not use stream note as input', async function () { + const inputNoteValue = 1000; + const outputNoteValue = 500; + + const inputNote = await createNote( + inputNoteValue, + streamUtilitiesMock.address, + [sender.address] + ); + + const outputNote1 = await createNote(outputNoteValue, sender.address, [ + sender.address, + ]); + + const outputNote2 = await createNote( + outputNoteValue, + streamUtilitiesMock.address, + [sender.address] + ); + + const badProofData = new JoinSplitProof( + [inputNote], + [outputNote1, outputNote2], + streamUtilitiesMock.address, + 0, + sender.address + ).encodeABI(zkAsset.address); + + const streamObject = { + ...streamObjectTemplate, + // Here we pass the output note hash as the stream note hash + // This should invalidate the proof. + noteHash: outputNote1.noteHash, + }; + + await expect( + streamUtilitiesMock.validateJoinSplitProof( + ace.address, + badProofData, + outputNote1.noteHash, + streamObject + ) + ).to.be.revertedWith('stream note in 2 is not correct'); }); - it('reverts if proof has a non-zero public value transfer'); - it('reverts if proof does not have one input note only'); - it('reverts if proof does not have two output notes only'); - it('reverts if proof does not use same withdraw note as dividend proof'); - it('reverts if proof does not use stream note as input'); it('returns output notes of proof'); }); diff --git a/packages/contracts/test/StreamUtilities/validateRatioProof.js b/packages/contracts/test/StreamUtilities/validateRatioProof.js index 51b68e1..382b4b5 100644 --- a/packages/contracts/test/StreamUtilities/validateRatioProof.js +++ b/packages/contracts/test/StreamUtilities/validateRatioProof.js @@ -1,6 +1,8 @@ const { waffle } = require('@nomiclabs/buidler'); -const { use } = require('chai'); +const { use, expect } = require('chai'); const { solidity, createFixtureLoader } = require('ethereum-waffle'); +const { DividendProof } = require('aztec.js'); +const { createNote } = require('../helpers/notes/createNote'); const { StreamUtilitiesFixture } = require('../fixtures'); use(solidity); @@ -10,13 +12,193 @@ describe('StreamUtilities - validateRatioProof', function () { const [sender, recipient] = provider.getWallets(); const loadFixture = createFixtureLoader(provider, [sender, recipient]); - // eslint-disable-next-line no-unused-vars + let ace; let streamUtilitiesMock; + let streamObjectTemplate; + let zkAsset; beforeEach(async function () { - ({ streamUtilitiesMock } = await loadFixture(StreamUtilitiesFixture)); + ({ ace, streamUtilitiesMock, zkAsset } = await loadFixture( + StreamUtilitiesFixture + )); + streamObjectTemplate = { + recipient: recipient.address, + sender: sender.address, + tokenAddress: zkAsset.address, + isEntity: true, + }; }); - it('reverts if proof ratio does not match withdrawal duration'); - it('reverts if proof does not use stream note as source'); - it('returns input and output notes of proof'); + it('reverts if proof ratio does not match withdrawal duration', async function () { + const inputNoteValue = 1000; + + const streamTotalDuration = 100; + const withdrawalDuration = 10; + + // We may then withdraw 1/10th of the note's value, i.e. 100 + // Instead we try to take half + const withdrawNoteValue = 500; + const remainderNoteValue = 0; + const ratioNumerator = 1; + const ratioDenominator = 2; + + const inputNote = await createNote( + inputNoteValue, + streamUtilitiesMock.address, + [sender.address] + ); + + const withdrawNote = await createNote( + withdrawNoteValue, + sender.address, + [sender.address] + ); + + const remainderNote = await createNote( + remainderNoteValue, + streamUtilitiesMock.address, + [sender.address] + ); + + const badProofData = new DividendProof( + inputNote, + remainderNote, + withdrawNote, + streamUtilitiesMock.address, + ratioDenominator, + ratioNumerator + ).encodeABI(); + + const streamObject = { + ...streamObjectTemplate, + noteHash: inputNote.noteHash, + startTime: 0, + lastWithdrawTime: 0, + stopTime: streamTotalDuration, + }; + + await expect( + streamUtilitiesMock.validateRatioProof( + ace.address, + badProofData, + withdrawalDuration, + streamObject + ) + ).to.be.revertedWith('ratios do not match'); + }); + + it('reverts if proof does not use stream note as source', async function () { + const inputNoteValue = 1000; + + const streamTotalDuration = 100; + const withdrawalDuration = 10; + + // We may then withdraw 1/10th of the note's value, i.e. 100 + const withdrawNoteValue = 100; + const remainderNoteValue = 0; + const ratioNumerator = 1; + const ratioDenominator = 10; + + const inputNote = await createNote( + inputNoteValue, + streamUtilitiesMock.address, + [sender.address] + ); + + const withdrawNote = await createNote( + withdrawNoteValue, + sender.address, + [sender.address] + ); + + const remainderNote = await createNote( + remainderNoteValue, + streamUtilitiesMock.address, + [sender.address] + ); + + const badProofData = new DividendProof( + inputNote, + remainderNote, + withdrawNote, + streamUtilitiesMock.address, + ratioDenominator, + ratioNumerator + ).encodeABI(); + + const streamObject = { + ...streamObjectTemplate, + noteHash: withdrawNote.noteHash, + startTime: 0, + lastWithdrawTime: 0, + stopTime: streamTotalDuration, + }; + + await expect( + streamUtilitiesMock.validateRatioProof( + ace.address, + badProofData, + withdrawalDuration, + streamObject + ) + ).to.be.revertedWith('incorrect notional note in proof 1'); + }); + + it('returns withdrawal note hash', async function () { + const inputNoteValue = 1000; + + const streamTotalDuration = 100; + const withdrawalDuration = 10; + + // We may then withdraw 1/10th of the note's value, i.e. 100 + const withdrawNoteValue = 100; + const remainderNoteValue = 0; + const ratioNumerator = 1; + const ratioDenominator = 10; + + const inputNote = await createNote( + inputNoteValue, + streamUtilitiesMock.address, + [sender.address] + ); + + const withdrawNote = await createNote( + withdrawNoteValue, + sender.address, + [sender.address] + ); + + const remainderNote = await createNote( + remainderNoteValue, + streamUtilitiesMock.address, + [sender.address] + ); + + const proofData = new DividendProof( + inputNote, + remainderNote, + withdrawNote, + streamUtilitiesMock.address, + ratioDenominator, + ratioNumerator + ).encodeABI(); + + const streamObject = { + ...streamObjectTemplate, + noteHash: inputNote.noteHash, + startTime: 0, + lastWithdrawTime: 0, + stopTime: streamTotalDuration, + }; + + await expect( + streamUtilitiesMock.validateRatioProof( + ace.address, + proofData, + withdrawalDuration, + streamObject + ) + ) + .to.emit(streamUtilitiesMock, 'ValidateRatioProof') + .withArgs(withdrawNote.noteHash); + }); }); diff --git a/packages/contracts/test/fixtures.js b/packages/contracts/test/fixtures.js index f3f5b01..7d11278 100644 --- a/packages/contracts/test/fixtures.js +++ b/packages/contracts/test/fixtures.js @@ -1,5 +1,4 @@ const { ethers } = require('ethers'); - const { deployContract } = require('ethereum-waffle'); const bn128 = require('@aztec/bn128'); @@ -71,7 +70,37 @@ async function zkAssetFixture(provider, [wallet]) { 1, ]); - // ethers.errors.setLogLevel('warn'); + // const depositAmount = '10000000000000'; + + // await token.mint(wallet.address, depositAmount); + // await token.approve(ace.address, depositAmount); + + // const { + // depositInputNotes, + // depositOutputNotes, + // depositPublicValue, + // depositInputOwnerAccounts, + // } = await getDepositNotes([100000], wallet.address); + // const publicValue = depositPublicValue * -1; + + // const proof = new JoinSplitProof( + // depositInputNotes, + // depositOutputNotes, + // wallet.address, + // publicValue, + // wallet.address + // ); + // const data = proof.encodeABI(zkAsset.address); + // const signatures = proof.constructSignatures( + // zkAsset.address, + // depositInputOwnerAccounts + // ); + + // // Approve ACE to spend tokens held by the zkAsset contract + // await ace.publicApprove(zkAsset.address, proof.hash, 100000); + + // // convert some of sender's assets to zkAssets + // await zkAsset['confidentialTransfer(bytes,bytes)'](data, signatures); return { ace, @@ -80,6 +109,7 @@ async function zkAssetFixture(provider, [wallet]) { baseFactory, token, zkAsset, + // depositOutputNotes, }; } @@ -94,6 +124,7 @@ async function noteStreamFixture(provider, [wallet]) { baseFactory, token, zkAsset, + depositOutputNotes, } = await zkAssetFixture(provider, [wallet]); const noteStream = await deployContract(wallet, NoteStream, [ace.address]); @@ -106,6 +137,7 @@ async function noteStreamFixture(provider, [wallet]) { token, zkAsset, noteStream, + depositOutputNotes, }; } @@ -120,6 +152,7 @@ async function StreamUtilitiesFixture(provider, [wallet]) { baseFactory, token, zkAsset, + depositOutputNotes, } = await zkAssetFixture(provider, [wallet]); const streamUtilitiesMock = await deployContract( @@ -134,6 +167,7 @@ async function StreamUtilitiesFixture(provider, [wallet]) { baseFactory, token, zkAsset, + depositOutputNotes, streamUtilitiesMock, }; } diff --git a/packages/contracts/test/helpers/constants.js b/packages/contracts/test/helpers/constants.js new file mode 100644 index 0000000..d42ab67 --- /dev/null +++ b/packages/contracts/test/helpers/constants.js @@ -0,0 +1,6 @@ +// Adding an address to the metadata requires a public key however as we are not decrypting notes from the registry +// we do not need to use a proper public key. We then use a constant dummy value. +const dummyLinkedPublicKey = + '0xa61d17b0dd3095664d264628a6b947721314b6999aa6a73d3c7698f041f78a4d'; + +module.exports = { dummyLinkedPublicKey }; diff --git a/packages/contracts/test/helpers/deposit/streamNote.js b/packages/contracts/test/helpers/deposit/streamNote.js new file mode 100644 index 0000000..2e77c12 --- /dev/null +++ b/packages/contracts/test/helpers/deposit/streamNote.js @@ -0,0 +1,51 @@ +const { JoinSplitProof } = require('aztec.js'); +const { createNote } = require('../notes/createNote'); + +/** + * Generate a note such that would be owned by the NoteStream contract, given the desired note value and stream sender/recipients + * + * @method getStreamNote + * @param {Number} noteValue - Number representing note value + * @param {Object} sender - Ethereum account that initiated the stream + * @param {Object} recipient - Ethereum account that is receiving the stream + * @returns {Note} - stream note + */ +const getStreamNote = (noteValue, noteOwner, sender, recipient) => { + return createNote(noteValue, noteOwner, [sender, recipient]); +}; + +const createStreamDepositProof = async ( + inputNotes, + noteOwner, + sender, + recipient, + publicValue +) => { + // console.log(sender, recipient); + const depositInputOwnerAccounts = new Array(inputNotes.length).fill(sender); + + const noteValue = inputNotes + .map((noteObj) => noteObj.k.toNumber()) + .reduce((a, b) => a + b, 0); + + const streamNote = await getStreamNote( + noteValue, + noteOwner, + sender, + recipient + ); + const depositProof = new JoinSplitProof( + inputNotes, + [streamNote], + sender, + publicValue, + sender + ); + return { + depositProof, + depositInputOwnerAccounts, + streamNote, + }; +}; + +module.exports = { getStreamNote, createStreamDepositProof }; diff --git a/packages/contracts/test/helpers/mint/getDepositNotes.js b/packages/contracts/test/helpers/mint/getDepositNotes.js new file mode 100644 index 0000000..b71d501 --- /dev/null +++ b/packages/contracts/test/helpers/mint/getDepositNotes.js @@ -0,0 +1,41 @@ +const { getNotesForAccount } = require('../notes/getNotesForAccount'); + +/** + * General purpose function that generates a set of notes to be used in a deposit join split proof. + * + * There are no inputNotes created in this function - it generates notes for a deposit proof i.e. a joinSplit + * where tokens are being converted into notes. + * + * Output notes are created. The values of these output notes is determined by the input argument + * depositOutputNoteValues + * + * @method getDepositNotes + * @param {Number[]} depositOutputNoteValues - array of note values, for which notes will be created + * @param {Number[]} depositOwnerPrivateKey - private key for address which will own the created notes + * @returns {Note[]} depositInputNotes - input notes for a deposit join split proof + * @returns {Note[]} depositOutputNotes - output notes for a deposit join split proof + * @returns {Object[]} depositInputOwnerAccounts - Ethereum accounts of the input note owners + * @returns {Object[]} depositOutputOwnerAccounts - Ethereum accounts of the output note owners + */ +const getDepositNotes = async ( + depositOutputNoteValues, + depositOwnerAddress +) => { + const depositInputNotes = []; + const depositOutputNotes = await getNotesForAccount( + depositOwnerAddress, + depositOutputNoteValues + ); + const depositPublicValue = depositOutputNoteValues.reduce((a, b) => a + b); + const depositInputOwnerAccounts = []; + const depositOutputOwnerAccounts = [depositOwnerAddress]; + return { + depositInputNotes, + depositOutputNotes, + depositPublicValue, + depositInputOwnerAccounts, + depositOutputOwnerAccounts, + }; +}; + +module.exports = { getDepositNotes }; diff --git a/packages/contracts/test/helpers/mint/mintZkAssets.js b/packages/contracts/test/helpers/mint/mintZkAssets.js new file mode 100644 index 0000000..3007205 --- /dev/null +++ b/packages/contracts/test/helpers/mint/mintZkAssets.js @@ -0,0 +1,35 @@ +const { JoinSplitProof } = require('aztec.js'); +const { getDepositNotes } = require('./getDepositNotes'); + +const mintZkAsset = async (recipientAddress, amount, token, zkAsset, ace) => { + const signerAddress = token.signer.address; + // Mint public tokens and give ACE access to move them + await token.mint(signerAddress, amount); + await token.approve(ace.address, amount); + + const { + depositInputNotes, + depositOutputNotes, + depositPublicValue, + } = await getDepositNotes([amount], recipientAddress); + const publicValue = depositPublicValue * -1; + + const proof = new JoinSplitProof( + depositInputNotes, + depositOutputNotes, + signerAddress, + publicValue, + signerAddress + ); + const data = proof.encodeABI(zkAsset.address); + + // Approve ACE to spend tokens held by the zkAsset contract + await ace.publicApprove(zkAsset.address, proof.hash, amount); + + // Note: As there are no input notes we can use an empty signature + await zkAsset['confidentialTransfer(bytes,bytes)'](data, '0x'); + + return depositOutputNotes[0]; +}; + +module.exports = { mintZkAsset }; diff --git a/packages/contracts/test/helpers/notes/createNote.js b/packages/contracts/test/helpers/notes/createNote.js new file mode 100644 index 0000000..ebc45ba --- /dev/null +++ b/packages/contracts/test/helpers/notes/createNote.js @@ -0,0 +1,17 @@ +const { note } = require('aztec.js'); +const secp256k1 = require('@aztec/secp256k1'); +const { dummyLinkedPublicKey } = require('../constants'); + +const createNote = (noteValue, noteOwner, access) => { + return note.create( + secp256k1.generateAccount().publicKey, + noteValue, + access.map((address) => ({ + address, + linkedPublicKey: dummyLinkedPublicKey, + })), + noteOwner + ); +}; + +module.exports = { createNote }; diff --git a/packages/contracts/test/helpers/notes/getNotesForAccount.js b/packages/contracts/test/helpers/notes/getNotesForAccount.js new file mode 100644 index 0000000..b9a6d8c --- /dev/null +++ b/packages/contracts/test/helpers/notes/getNotesForAccount.js @@ -0,0 +1,17 @@ +const { createNote } = require('./createNote'); + +/** + * Generate a set of notes, given the desired note values and account of the owner + * + * @method getNotesForAccount + * @param {Object} aztecAccount - Ethereum account that owns the notes to be created + * @param {Number[]} noteValues - array of note values, for which notes will be created + * @returns {Note[]} - array of notes + */ +const getNotesForAccount = async (address, noteValues) => { + return Promise.all( + noteValues.map((noteValue) => createNote(noteValue, address, [address])) + ); +}; + +module.exports = { getNotesForAccount }; diff --git a/packages/contracts/test/helpers/signProof.js b/packages/contracts/test/helpers/signProof.js new file mode 100644 index 0000000..c77c9ae --- /dev/null +++ b/packages/contracts/test/helpers/signProof.js @@ -0,0 +1,15 @@ +const { signer } = require('aztec.js'); + +const signProof = (zkAsset, proof, spender, privateKey) => { + const data = proof.encodeABI(zkAsset.address); + const signature = signer.signApprovalForProof( + zkAsset.address, + proof.eth.outputs, + spender, + true, + privateKey + ); + return { data, signature }; +}; + +module.exports = { signProof }; diff --git a/packages/contracts/test/helpers/transfer/getTransferNotes.js b/packages/contracts/test/helpers/transfer/getTransferNotes.js new file mode 100644 index 0000000..0f34022 --- /dev/null +++ b/packages/contracts/test/helpers/transfer/getTransferNotes.js @@ -0,0 +1,51 @@ +const { getNotesForAccount } = require('../notes/getNotesForAccount'); + +/** + * General purpose function that generates a set of notes to be used in a deposit joinSplit proof + * followed by a transfer joinSplit proof. + * + * The scenario is that a deposit proof is being performed, followed by a transfer proof. + * In the deposit proof, public tokens are being converted into notes. + * + * These notes are then the input to a transfer proof, where notes are transferred to a second user. + * During this proof, some note value is also converted back into public token form and withdrawn. + * + * The value of the notes created and involved in the proofs is controlled through the two input arguments: + * depositOutputNoteValues and transferOutputNoteValues + * + * @method getDepositAndTransferNotes + * @param {Number[]} transferInputNoteValues - output note values for the deposit proof + * @param {Number[]} transferOutputNoteValues - output note values for the transfer proof + * @param {Number[]} transferInputNoteValues - output note values for the deposit proof + * @param {Number[]} transferOutputNoteValues - output note values for the transfer proof + * @returns {Note[]} transferInputNotes - inputs for a transfer join split proof + * @returns {Note[]} transferOutputNotes - output notes for a transfer join split proof + * @returns {Object[]} transferInputOwnerAccounts - Ethereum accounts of the transfer input note owners + * @returns {Object[]} transferOutputOwnerAccounts - Ethereum accounts of the transfer output note owners + */ +const getTransferNotes = async ( + transferInputNotes, + transferOutputNoteValues, + senderAddress, + recipientAddress +) => { + const transferInputOwnerAccounts = new Array( + transferInputNotes.length + ).fill(senderAddress); + + const transferOutputNotes = await getNotesForAccount( + recipientAddress, + transferOutputNoteValues + ); + const transferOutputOwnerAccounts = new Array( + transferOutputNotes.length + ).fill(recipientAddress); + return { + transferInputNotes, + transferOutputNotes, + transferInputOwnerAccounts, + transferOutputOwnerAccounts, + }; +}; + +module.exports = { getTransferNotes }; diff --git a/packages/react-app/.env b/packages/react-app/.env index e7891d5..7369761 100644 --- a/packages/react-app/.env +++ b/packages/react-app/.env @@ -1,3 +1,5 @@ +BROWSER=none + REACT_APP_SUBGRAPH_URL='https://api.thegraph.com/subgraphs/name/tomafrench/notestream-rinkeby' REACT_APP_AZTEC_API_KEY = '9HRKN7S-JSZMRJM-KWSDWSY-B2VSRD9' REACT_APP_TRANSAK_API_KEY = '7acc4227-1611-4787-8349-8b32194b6dc1' diff --git a/packages/react-app/package.json b/packages/react-app/package.json index 2e8007c..add9c78 100644 --- a/packages/react-app/package.json +++ b/packages/react-app/package.json @@ -11,25 +11,26 @@ "url": "https://github.com/TomAFrench/NoteStream/issues" }, "dependencies": { - "@apollo/client": "^3.0.0-beta.41", + "@apollo/client": "^3.0.2", "@aztec/secp256k1": "^1.2.0", - "@material-ui/core": "^4.9.5", + "@ethersproject/address": "^5.0.2", + "@ethersproject/bignumber": "^5.0.5", + "@ethersproject/contracts": "^5.0.2", + "@ethersproject/providers": "^5.0.5", + "@ethersproject/units": "^5.0.2", + "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@notestream/contract-artifacts": "^1.0.1", - "@transak/transak-sdk": "^1.0.17", - "@types/testing-library__dom": "^7.5.0", - "aztec.js": "^0.17.0", - "bn.js": "^5.1.1", - "bnc-onboard": "^1.9.0", - "ethers": "^4.0.46", - "graphql": "^14.6.0", - "moment": "^2.24.0", + "bn.js": "^5.1.2", + "bnc-onboard": "^1.10.3", + "graphql": "^15.3.0", + "moment": "^2.27.0", "prop-types": "^15.7.2", - "react": "^16.13.0", + "react": "^16.13.1", "react-blockies": "^1.4.1", "react-copy-to-clipboard": "^5.0.2", "react-dom": "^16.13.0", - "react-router": "^5.1.2", + "react-router": "^5.2.0", "react-router-dom": "^5.2.0", "react-scripts": "^3.4.1", "zkasset-metadata": "^0.2.0" @@ -46,17 +47,18 @@ "@types/bn.js": "^4.11.6", "@types/react-copy-to-clipboard": "^4.3.0", "@types/react-router-dom": "^5.1.5", + "@types/testing-library__dom": "^7.5.0", "@typescript-eslint/eslint-plugin-tslint": "^2.27.0", - "eslint": "^6.8.0", - "eslint-config-airbnb-base": "^14.1.0", - "eslint-config-prettier": "^6.10.1", - "eslint-plugin-import": "^2.20.2", - "eslint-plugin-prettier": "^3.1.2", - "eslint-plugin-react": "^7.19.0", + "eslint": "^7.5.0", + "eslint-config-airbnb-base": "^14.2.0", + "eslint-config-prettier": "^6.11.0", + "eslint-plugin-import": "^2.22.0", + "eslint-plugin-prettier": "^3.1.4", + "eslint-plugin-react": "^7.20.3", "lint-staged": "^10.2.2", "prettier": "^2.0.4", "shx": "^0.3.2", - "typescript": "^3.8.3" + "typescript": "^3.9.7" }, "scripts": { "precommit": "lint-staged", diff --git a/packages/react-app/src/App.tsx b/packages/react-app/src/App.tsx index 2f91b88..5e8e4c0 100644 --- a/packages/react-app/src/App.tsx +++ b/packages/react-app/src/App.tsx @@ -12,8 +12,7 @@ import { getContractAddressesForNetwork, abis, } from '@notestream/contract-artifacts'; -import { Contract } from 'ethers'; -import { Web3Provider } from 'ethers/providers'; +import { Contract } from '@ethersproject/contracts'; import { useWalletProvider, useNetwork } from './contexts/OnboardContext'; @@ -74,11 +73,10 @@ const App = (): ReactElement => { useEffect(() => { if (appNetworkId && provider) { const { NoteStream } = getContractAddressesForNetwork(appNetworkId); - const signer = new Web3Provider(provider).getSigner(); const noteStreamContract = new Contract( NoteStream, abis.NoteStream, - signer, + provider.getSigner(), ); setStreamContract(noteStreamContract); } diff --git a/packages/react-app/src/components/Link.tsx b/packages/react-app/src/components/Link.tsx index a826efd..487fda0 100644 --- a/packages/react-app/src/components/Link.tsx +++ b/packages/react-app/src/components/Link.tsx @@ -1,16 +1,29 @@ import React, { ReactElement } from 'react'; +import PropTypes from 'prop-types'; import { Link } from 'react-router-dom'; import isExternal from '../utils/links'; -const flexLink = (props: any): ReactElement => { - return isExternal(props.to) ? ( - - {props.children} +interface Props { + to: string; + children: any; + [x: string]: any; +} + +const FlexLink = ({ to, children, ...rest }: Props): ReactElement => + isExternal(to) ? ( + + {children} ) : ( - {props.children} + + {children} + ); + +FlexLink.propTypes = { + to: PropTypes.string.isRequired, + children: PropTypes.node.isRequired, }; -export default flexLink; +export default FlexLink; diff --git a/packages/react-app/src/components/Sidebar/SideBarLinks.tsx b/packages/react-app/src/components/Sidebar/SideBarLinks.tsx index 4e3579d..b1ebc50 100644 --- a/packages/react-app/src/components/Sidebar/SideBarLinks.tsx +++ b/packages/react-app/src/components/Sidebar/SideBarLinks.tsx @@ -1,5 +1,4 @@ -import React, { ReactElement, useEffect, useState } from 'react'; -import { useTheme } from '@material-ui/core/styles'; +import React, { ReactElement } from 'react'; import List from '@material-ui/core/List'; import ListItem from '@material-ui/core/ListItem'; import ListItemIcon from '@material-ui/core/ListItemIcon'; @@ -9,17 +8,12 @@ import Divider from '@material-ui/core/Divider'; import HomeIcon from '@material-ui/icons/Home'; import LocalAtmIcon from '@material-ui/icons/LocalAtm'; import AccountBalanceWalletIcon from '@material-ui/icons/AccountBalanceWallet'; -import ShoppingCartIcon from '@material-ui/icons/ShoppingCart'; import SwapHorizIcon from '@material-ui/icons/SwapHoriz'; import HelpIcon from '@material-ui/icons/Help'; import GitHubIcon from '@material-ui/icons/GitHub'; -import TransakSDK from '@transak/transak-sdk'; import Link from '../Link'; -import setupTransak from '../../utils/transak'; -import { useAddress } from '../../contexts/OnboardContext'; - const mainLinks = [ { text: 'Home', icon: , url: '/' }, { text: 'Convert assets', icon: , url: '/exchange' }, @@ -55,42 +49,26 @@ const NavLinkItem = ({ ); -const SideBarLinks = (): ReactElement => { - const theme = useTheme(); - const userAddress = useAddress(); - const [transak, setTransak] = useState(); - - useEffect(() => { - setTransak(setupTransak(userAddress, theme.palette.primary.main)); - }, [userAddress, theme.palette.primary.main]); - - return ( - - {mainLinks.map((link, index) => ( - - ))} - - => transak.init()}> - - - - - - {secondaryLinks.map((link, index) => ( - - ))} - - ); -}; +const SideBarLinks = (): ReactElement => ( + + {mainLinks.map((link, index) => ( + + ))} + + {secondaryLinks.map((link, index) => ( + + ))} + +); export default SideBarLinks; diff --git a/packages/react-app/src/components/StreamTable/StreamRow.tsx b/packages/react-app/src/components/StreamTable/StreamRow.tsx index 0bb586d..61b0a19 100644 --- a/packages/react-app/src/components/StreamTable/StreamRow.tsx +++ b/packages/react-app/src/components/StreamTable/StreamRow.tsx @@ -7,7 +7,7 @@ import TableRow from '@material-ui/core/TableRow'; import moment from 'moment'; -import { Contract } from 'ethers'; +import { Contract } from '@ethersproject/contracts'; import { withdrawFunds, cancelStream } from '../../utils/stream'; import { Stream, ZkNote } from '../../types/types'; @@ -83,16 +83,16 @@ const StreamRow = ({ {`${displayValue} ${zkAsset.symbol}`} - {moment.unix(startTime).format('MMM D, YYYY - HH:mm')} + {moment.unix(parseInt(startTime, 10)).format('MMM D, YYYY - HH:mm')} - {moment.unix(stopTime).format('MMM D, YYYY - HH:mm')} + {moment.unix(parseInt(stopTime, 10)).format('MMM D, YYYY - HH:mm')} {button} diff --git a/packages/react-app/src/components/StreamTable/index.tsx b/packages/react-app/src/components/StreamTable/index.tsx index d0c33d5..f319108 100644 --- a/packages/react-app/src/components/StreamTable/index.tsx +++ b/packages/react-app/src/components/StreamTable/index.tsx @@ -5,7 +5,7 @@ import TableCell from '@material-ui/core/TableCell'; import TableRow from '@material-ui/core/TableRow'; import { useQuery } from '@apollo/client'; -import { Contract } from 'ethers'; +import { Contract } from '@ethersproject/contracts'; import { Button, Grid, CircularProgress } from '@material-ui/core'; import { generateColumns, STREAM_TABLE_ID, Column } from '../Table/columns'; import { cellWidth } from '../Table/TableHead'; @@ -54,10 +54,10 @@ const humanReadableStream = (stream: Stream): HumanReadableStream => { zkAsset, } = stream; const humanStartTime: string = moment - .unix(startTime) + .unix(parseInt(startTime, 10)) .format('MMM D, YYYY - HH:mm'); const humanStopTime: string = moment - .unix(stopTime) + .unix(parseInt(stopTime, 10)) .format('MMM D, YYYY - HH:mm'); const humanDeposit = ''; @@ -119,9 +119,9 @@ function NewStreamTable({ const tableContents: TableRowData[] = streamInProgress.map( (stream: Stream) => ({ ...humanReadableStream(stream), - humanStartTimeOrder: stream.startTime, - humanStopTimeOrder: stream.stopTime, - humanLastWithdrawTimeOrder: stream.lastWithdrawTime, + humanStartTimeOrder: parseInt(stream.startTime, 10), + humanStopTimeOrder: parseInt(stream.stopTime, 10), + humanLastWithdrawTimeOrder: parseInt(stream.lastWithdrawTime, 10), }), ); return ( diff --git a/packages/react-app/src/components/Table/TableHead.tsx b/packages/react-app/src/components/Table/TableHead.tsx index 39247e9..71ae749 100644 --- a/packages/react-app/src/components/Table/TableHead.tsx +++ b/packages/react-app/src/components/Table/TableHead.tsx @@ -19,7 +19,7 @@ export const cellWidth = (width?: number): object | undefined => { function TableHeader(props: any): ReactElement { const { columns, order, orderBy, onSort } = props; - const changeSort = (property: string, orderAttr: boolean) => () => { + const changeSort = (property: string, orderAttr: boolean) => (): void => { onSort(property, orderAttr); }; diff --git a/packages/react-app/src/components/form/AddressInput.tsx b/packages/react-app/src/components/form/AddressInput.tsx index e2def73..3d25a64 100644 --- a/packages/react-app/src/components/form/AddressInput.tsx +++ b/packages/react-app/src/components/form/AddressInput.tsx @@ -1,5 +1,5 @@ import React, { ReactElement, useState, useEffect } from 'react'; -import { utils } from 'ethers'; +import { getAddress } from '@ethersproject/address'; import TextField from '@material-ui/core/TextField'; import { Address, AztecSDK } from '../../types/types'; @@ -20,7 +20,7 @@ const AddressInput = (props: any): ReactElement => { useEffect(() => { const checkAddressIsValid = async (testAddress: Address): Promise => { try { - if (utils.getAddress(testAddress)) { + if (getAddress(testAddress)) { const user = await aztec.user(testAddress); setInvalidAddress(!user.registered); } diff --git a/packages/react-app/src/components/modals/CreateStreamModal.tsx b/packages/react-app/src/components/modals/CreateStreamModal.tsx index f908872..704b0c2 100644 --- a/packages/react-app/src/components/modals/CreateStreamModal.tsx +++ b/packages/react-app/src/components/modals/CreateStreamModal.tsx @@ -11,8 +11,7 @@ import DialogTitle from '@material-ui/core/DialogTitle'; import Grid from '@material-ui/core/Grid'; import moment from 'moment'; -import { Contract } from 'ethers'; -import { Web3Provider } from 'ethers/providers'; +import { Contract } from '@ethersproject/contracts'; import { createStream } from '../../utils/stream'; import AddressInput from '../form/AddressInput'; @@ -85,7 +84,7 @@ export default function CreateStreamDialog({ const linkedToken = new Contract( zkAsset.linkedTokenAddress, ERC20.abi, - new Web3Provider(provider), + provider, ); const tokenSymbol = linkedToken.symbol(); const tokenDecimals = linkedToken.decimals(); @@ -219,14 +218,6 @@ export default function CreateStreamDialog({ - - After you click "Create Stream", you will be asked to - sign two transactions. The first sends the AZTEC note to the - NoteStream contract and the second creates the stream. - - - In a later update, these two transactions will be combined. - @@ -235,21 +226,26 @@ export default function CreateStreamDialog({