{"_id":"@daisypayments/smart-contracts","_rev":"24-a0cbbf5c9805f84c053250b3b9f7603c","name":"@daisypayments/smart-contracts","dist-tags":{"latest":"0.1.1","beta":"0.4.0-beta.6"},"versions":{"0.0.1":{"name":"@daisypayments/smart-contracts","version":"0.0.1","repository":{"type":"git","url":"https://github.com/consensys/daisy-subscription-contracts"},"author":{"name":"vdrg","email":"vicente.dragicevic@consensys.net"},"license":"MIT","main":"index.js","scripts":{"compile":"truffle compile","coverage":"./scripts/coverage.sh","exec":"truffle exec","ganache":"ganache-cli","docgen":"./scripts/docgen.sh","publish-docs":"./scripts/publish-docs.sh","prepublish":"yarn compile","lint":"solhint \"contracts/**/*.sol\"","migrate":"truffle migrate","test":"./scripts/test.sh"},"devDependencies":{"@daisypayments/eslint-config":"^1.5.1","bip39":"^2.5.0","bn.js":"^4.11.8","chai":"^4.2.0","coveralls":"^3.0.5","dotenv":"^6.2.0","eslint":"^5.13.0","eslint-config-prettier":"^4.0.0","eslint-plugin-mocha":"^5.2.1","eslint-plugin-prettier":"^3.0.1","eth-gas-reporter":"0.1.10","eth-sig-util":"^2.2.0","ethereumjs-abi":"^0.6.7","ethereumjs-util":"^6.1.0","ethereumjs-wallet":"^0.6.3","ganache-cli":"^6.4.4","lodash":"^4.17.11","moment":"^2.24.0","openzeppelin-solidity":"^2.3.0","openzeppelin-test-helpers":"^0.4.0","prettier":"^1.16.3","solhint":"^2.0.0","solidity-coverage":"^0.6.0","solidity-docgen":"^0.1.1","truffle":"^5.0.25","truffle-hdwallet-provider":"^1.0.4"},"description":"[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repo","licenseText":"MIT License\n\nCopyright (c) 2019 Token Foundry\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@daisypayments/smart-contracts@0.0.1","dist":{"shasum":"3202697b5051313b6f0e48d45b11b763d7558b2f","integrity":"sha512-VI6OAI8eaL61JepXzc459CXzf/Qsr5ezNCbzPjEqaHHi92fVePfZCAIAzgMbmAG3h7ZnABKJfS2FhD8sbEy6FQ==","tarball":"https://registry.npmjs.org/@daisypayments/smart-contracts/-/smart-contracts-0.0.1.tgz","fileCount":9,"unpackedSize":2442947,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdP1VVCRA9TVsSAnZWagAABakP/2Houk+8jdB3G5mWg09Y\nVdSpJINQJ/8W0lvhTfzB8GaVo/QiyyvUPFpOP1+MocS6DGywRRNRDaGa73OA\nqKlZHoy6AuLuIpNc7wJm6boNX1dZfcdN9TKrfT2p3+rAjNKR/2qpgv2z/UZa\n/L7hvhSvmtBds2PlEhc5llvbBizHXLDxdrQAXtGuEyCny0p9OWak5nBpHLfZ\n6uXD7//i3Y8xdvOMJfEfB2HJWNKn4ymHcB6BG3hp244mLaJxTT40vj4AhEZN\nke3dJlBguVC+FhylCuRXX7MtnFlXcLBpTjCUVjTqG5KcJHzO//6mByLKfgir\nhWsoUp+9ZQ+fH2WgweWcYzI1sKGLBZpPxsxgyIPp3tfWDLK54IvuQ2eOon/8\nmKnpzH6E19JvkFvJ/V43NJkjzXqiBebhpU2mrCMC49kAaZ5de7f9RDIS/GF1\nkOtf113VPrX1e7xw/orIcXqQpyYg3NAExYBuJbfRv1kou+oZi9t4ljKulvpb\n/IAV2UYZAS8zLT2Jug39LYnk7+H9FndgPapdJVHFyt5SN/aFVGQ+bNuTatBc\nBHwA5wBtx+bM6vQWPyoQThMmLeYodSl4AC14MFLeDVNTq2HJwATS9hBWQgLl\n8Qzp4vDKG1HkG+zWQW5BvyLQOJQwla/rndMHn+EeSxoeVwCgs3ouy1J21wco\n0Oha\r\n=XxGw\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDCuhBIfgj10NxypHv4u+tH71FZsJKWvf59MMvbYpwHxQIhALgZKwdY4yrDX4PlwAGqqCqa3gv4XERsTOAwToF/EUjS"}]},"maintainers":[{"name":"nchastain","email":"nate.chastain@consensys.net"},{"name":"wachunei","email":"wachunei@gmail.com"},{"name":"lopezjurip","email":"lopezjuripatricio@gmail.com"},{"name":"vdrg","email":"vdrg@protonmail.ch"},{"name":"sloreti","email":"lhloreti@gmail.com"},{"name":"jmoreira","email":"jmoreiras@gmail.com"}],"_npmUser":{"name":"vdrg","email":"vdrg@protonmail.ch"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/smart-contracts_0.0.1_1564431701242_0.030595402286273332"},"_hasShrinkwrap":false},"0.0.2":{"name":"@daisypayments/smart-contracts","version":"0.0.2","repository":{"type":"git","url":"https://github.com/consensys/daisy-subscription-contracts"},"author":{"name":"vdrg","email":"vicente.dragicevic@consensys.net"},"license":"MIT","main":"index.js","scripts":{"compile":"truffle compile","coverage":"./scripts/coverage.sh","exec":"truffle exec","ganache":"ganache-cli","docgen":"./scripts/docgen.sh","publish-docs":"./scripts/publish-docs.sh","prepublish":"yarn compile","lint":"solhint \"contracts/**/*.sol\"","migrate":"truffle migrate","test":"./scripts/test.sh"},"devDependencies":{"@daisypayments/eslint-config":"^1.5.1","bip39":"^2.5.0","bn.js":"^4.11.8","chai":"^4.2.0","coveralls":"^3.0.5","dotenv":"^6.2.0","eslint":"^5.13.0","eslint-config-prettier":"^4.0.0","eslint-plugin-mocha":"^5.2.1","eslint-plugin-prettier":"^3.0.1","eth-gas-reporter":"0.1.10","eth-sig-util":"^2.2.0","ethereumjs-abi":"^0.6.7","ethereumjs-util":"^6.1.0","ethereumjs-wallet":"^0.6.3","ganache-cli":"^6.4.4","lodash":"^4.17.11","moment":"^2.24.0","openzeppelin-solidity":"^2.3.0","openzeppelin-test-helpers":"^0.4.0","prettier":"^1.16.3","solhint":"^2.0.0","solidity-coverage":"^0.6.0","solidity-docgen":"^0.1.1","truffle":"^5.0.25","truffle-hdwallet-provider":"^1.0.4"},"description":"[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repo","licenseText":"MIT License\n\nCopyright (c) 2019 Token Foundry\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@daisypayments/smart-contracts@0.0.2","dist":{"shasum":"52daccf0aa6f85ca44338ba85fcbf672509951a6","integrity":"sha512-mLEal+XxwMwXEwjnUlzpvX98O/TTIs2qg9ARZobVFvM/doipYgSwL+0Qyso1IflwyfTdNu//FVKJFAL+37G7MA==","tarball":"https://registry.npmjs.org/@daisypayments/smart-contracts/-/smart-contracts-0.0.2.tgz","fileCount":9,"unpackedSize":2442854,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdP4MiCRA9TVsSAnZWagAAsrQP/3uRjJLFQIagDCsZPnuw\nPhrb2ARjqfUH6E5Yv0YoFJD7aKSWiMTNVs6YcktnYMfuEe+5vEDXG12mtlKC\n2eLLfmom//50CE0YdYareoahxEA2saCMd+WSxhsDe+aMHt1e8b+Uxwoluq+5\nMhj7Ri6ltbdME9gjc6Mf6F0T1kdOA5281UBv0JDk6GCR6RGFiX7LX0Rec5Yb\nLE1DQX5jwTlri1i0myemZUVSvNzhYJRy9l0dbnJ8MbE6FcCAsLqybuEN1KAx\nqvxyyKfs7Yz1zIhhW2dNCTsDDU+OqdynzgaFYSEkmrMORshph/TQqXPIJMHB\nvTZ3mnLGxt0u3f5bcfqPscUeTRNSytpPi06CPPYgLQYrg4FxsRbweiHaTx5R\n2ROLWY766fEAfPTBnAdIhQhd7H271OXoI6Rz7jFxYZ3Mi0HS2q3oP/wZP9aM\n3Uy71ZdoEwy9G5vi1kWqnLnxK0zJ+A3EbsA0F5DEd3y8xv0rCdYwBaUVG3G4\nccnkAHv7QCQF8Sxlc702ul99AakT+t6Fvfw5fofaWRpy55SyIfE+4cesXwLu\n9jp7imffVzKO1la6z6doz99pt4RAJxzf347s2XuiHkifJhMhGtF177VBT3pN\nEMK4m+TAs7xsRFpHPPryrVaCsZ+iz+EPgvXhG+M1eSgdaXMtw7gf0Uka8UoR\nY9X5\r\n=6INj\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGZKxqJ9FdSl5w9vlWZfzU053ls1SMK4HOi2OduDD2NOAiEAum87HI7I2VX99Zk22vIXRi3TnfjKV2ZWK2EL8HesQjI="}]},"maintainers":[{"name":"jmoreira","email":"jmoreiras@gmail.com"},{"name":"lopezjurip","email":"lopezjuripatricio@gmail.com"},{"name":"nchastain","email":"nate.chastain@consensys.net"},{"name":"sloreti","email":"lhloreti@gmail.com"},{"name":"vdrg","email":"vdrg@protonmail.ch"},{"name":"wachunei","email":"wachunei@gmail.com"}],"_npmUser":{"name":"vdrg","email":"vdrg@protonmail.ch"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/smart-contracts_0.0.2_1564443425514_0.040525409473069374"},"_hasShrinkwrap":false},"0.0.3":{"name":"@daisypayments/smart-contracts","version":"0.0.3","repository":{"type":"git","url":"https://github.com/consensys/daisy-subscription-contracts"},"author":{"name":"vdrg","email":"vicente.dragicevic@consensys.net"},"license":"MIT","main":"index.js","scripts":{"compile":"truffle compile","coverage":"./scripts/coverage.sh","exec":"truffle exec","ganache":"ganache-cli","docgen":"./scripts/docgen.sh","publish-docs":"./scripts/publish-docs.sh","prepublish":"yarn compile","lint":"solhint \"contracts/**/*.sol\"","migrate":"truffle migrate","test":"./scripts/test.sh"},"devDependencies":{"@daisypayments/eslint-config":"^1.5.1","bip39":"^2.5.0","bn.js":"^4.11.8","chai":"^4.2.0","coveralls":"^3.0.5","dotenv":"^6.2.0","eslint":"^5.13.0","eslint-config-prettier":"^4.0.0","eslint-plugin-mocha":"^5.2.1","eslint-plugin-prettier":"^3.0.1","eth-gas-reporter":"0.1.10","eth-sig-util":"^2.2.0","ethereumjs-abi":"^0.6.7","ethereumjs-util":"^6.1.0","ethereumjs-wallet":"^0.6.3","ganache-cli":"^6.4.4","lodash":"^4.17.11","moment":"^2.24.0","openzeppelin-solidity":"^2.3.0","openzeppelin-test-helpers":"^0.4.0","prettier":"^1.16.3","solhint":"^2.0.0","solidity-coverage":"^0.6.0","solidity-docgen":"^0.1.1","truffle":"^5.0.25","truffle-hdwallet-provider":"^1.0.4"},"description":"[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repo","licenseText":"MIT License\n\nCopyright (c) 2019 Token Foundry\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@daisypayments/smart-contracts@0.0.3","dist":{"shasum":"c6a6a575add2dbd784e03c5d571839e1dbca3e03","integrity":"sha512-xIng0HRdZw7You4RpKaYk/cX0auhp7OoqdLrm2l/vTR2w0v0qpiiWegIMsOpUjZMpbAna/xrk8W+VRMs8KzKdA==","tarball":"https://registry.npmjs.org/@daisypayments/smart-contracts/-/smart-contracts-0.0.3.tgz","fileCount":9,"unpackedSize":2552516,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdQ1ZlCRA9TVsSAnZWagAAEv0P/376TG1x9hrR3rfbLBTt\nIRGSmhmOSg1sHaUJcz6OdvqL0+I4hGZMSLgAbXQ1E1JRNCtH+8LY4PjxvDxl\nugizWqfkxnUrlif5utA24vmhiJqseY4hMSkRpm/iq+6P2elRHk/jZdx6XsUA\nBdmyXQpL+9Ldml7ghRp7zzci5TyCIY8gW2rh8Q63OT+S8dYhUksv84BnlIkH\nwqMekBa/SummWdnv76PEI/JvL40v9gkxvuqUhYkv66oy0s/qLzf+HRKoDra8\nGPpF4d/qxEmPxMAnZ1phQWQc5VsFS5Jo/2QdJrwbQJmKqZFlmmCia91BTeEI\nLiPh4w/x4ojiUFHcbdk4/Xuxa6JlAfJh6QaBp+AhJwkJ26iG5waDO/O1gqd/\nGB698v5Npo7WzXbbXJdj3Gsmu4XlQzvWZX5fAJ2Mr1jqqVZBzUFPjAo9q23W\ny0bUZqq56d1wS8Cm2rQRBeKX8CmW/Wz1XKganxzOsA0h9jsm6E55dcp+tWYr\nfXXUI9X2FwY72SzoMFzWVRCzV+jSxKfbu1UfDpaxJM1PkE6zgCFD/IJy7OMo\nQ8adLyysNG4AZRJoc3kfh7cr8ywZlUiYhLBZ8ulphfQsXCogszlNdAqPyhEw\nSPDaMgrDItJtUmBWxXV4hU76QAX63Yqfxu7Q5x52QDSGZqSD0rxQbkQJZyCN\nalkD\r\n=9M75\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGB9VB6q+swMndFPwGXGvnOqk6wN9d1Mi5tskX4IYf3eAiEAuABecVRjeIxcyxJ/BK4qvy0fZHSq5gMuZdi5fA0gMDQ="}]},"maintainers":[{"name":"jmoreira","email":"jmoreiras@gmail.com"},{"name":"lopezjurip","email":"lopezjuripatricio@gmail.com"},{"name":"nchastain","email":"nate.chastain@consensys.net"},{"name":"sloreti","email":"lhloreti@gmail.com"},{"name":"vdrg","email":"vdrg@protonmail.ch"},{"name":"wachunei","email":"wachunei@gmail.com"}],"_npmUser":{"name":"vdrg","email":"vdrg@protonmail.ch"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/smart-contracts_0.0.3_1564694116453_0.6053355417388915"},"_hasShrinkwrap":false},"0.0.4":{"name":"@daisypayments/smart-contracts","version":"0.0.4","repository":{"type":"git","url":"https://github.com/consensys/daisy-subscription-contracts"},"author":{"name":"vdrg","email":"vicente.dragicevic@consensys.net"},"license":"MIT","main":"index.js","scripts":{"compile":"truffle compile","coverage":"./scripts/coverage.sh","exec":"truffle exec","ganache":"ganache-cli","docgen":"./scripts/docgen.sh","publish-docs":"./scripts/publish-docs.sh","prepublish":"yarn compile","lint":"solhint \"contracts/**/*.sol\"","migrate":"truffle migrate","test":"./scripts/test.sh"},"devDependencies":{"@daisypayments/eslint-config":"^1.5.1","bip39":"^2.5.0","bn.js":"^4.11.8","chai":"^4.2.0","coveralls":"^3.0.5","dotenv":"^6.2.0","eslint":"^5.13.0","eslint-config-prettier":"^4.0.0","eslint-plugin-mocha":"^5.2.1","eslint-plugin-prettier":"^3.0.1","eth-gas-reporter":"0.1.10","eth-sig-util":"^2.2.0","ethereumjs-abi":"^0.6.7","ethereumjs-util":"^6.1.0","ethereumjs-wallet":"^0.6.3","ganache-cli":"^6.4.4","lodash":"^4.17.11","moment":"^2.24.0","openzeppelin-solidity":"^2.3.0","openzeppelin-test-helpers":"^0.4.0","prettier":"^1.16.3","solhint":"^2.0.0","solidity-coverage":"^0.6.0","solidity-docgen":"^0.1.1","truffle":"^5.0.25","truffle-hdwallet-provider":"^1.0.4"},"description":"[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repo","licenseText":"MIT License\n\nCopyright (c) 2019 Token Foundry\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@daisypayments/smart-contracts@0.0.4","dist":{"shasum":"7748bfdd7c3cfd7f928e9a71ce10b8561eadb161","integrity":"sha512-4Nb89kT7jSkvCOszvaXDWvi7Ra4U0jqN8dZN4RT4H5o+6eBmxY9Cn58r53nMAnbnWXffFVYD4JZL0CpiPufLAQ==","tarball":"https://registry.npmjs.org/@daisypayments/smart-contracts/-/smart-contracts-0.0.4.tgz","fileCount":9,"unpackedSize":2594462,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdRGP0CRA9TVsSAnZWagAAPL4P/26BZxjt8tNf7yme2YYq\nJ1an5GRd5e4re/DyBHvOfGleCkUn4kIrqKgIK1IyAgu3hag46aH8bco2eFWk\n84uwth2/igccmtqqrXqrTvwGDgoX8zVmP3HsSlJWMtrktB9QA1pG3nZ0ql03\nx45Kndk7u80cD/eeDsIjXQ5SsgkLu3VzybliZOyWHR5WXGneYIK1qJtRtNXw\nuu5EZj0OnwCMKBmq3uH75JPOmY2Haoe89yYQoo7a5JoRzTZUupaEHJEgKOUm\nwad5/yqur60SVFr3wP2LkWfC3fw/zXttPqZt7RiTOitASznkwAcjSqRl9I+f\n/7UQuT3G2a376G7hiNuHAU85uIx5/ElgSF8ToFrlPn8/i56J02uB1+LbtfYs\nvFLRc7/Qy/bJm+wn/t9qnP1RPERn2U8kJIPB714+BkDWHe18H7YaOeBQJWLI\nIUiapXeEMbkPIuIqJo5kMdfh41FMBnsStJodSQcX2rX6CVy0GQShC+aiGLy4\nOj+0aMYck45LEl8yf2676rLzgZhgd+JR/IbtOUh8rbve9MtSuxYrfpl/Xm1B\nJkTh0fudz6p5yQnPa2irqU8zndeAG2Cyd/AE+GMJR9h1OGYBKsbcSVRYQ7cf\nBbOtvuFIOjsrZ7KZrE5bWsa6E+hT/Ncn5zZe5/JQrKUit7+mOlwb9OZbF53a\nXcbJ\r\n=5lRj\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDn2dar6I+G7mk5LZWYwbsfSnjCDSyV97zQheC75fx8oAiEAtqPjPECZlHP4AkAnTNyN7+sMWVGslLa8jCxNcKkH4l4="}]},"maintainers":[{"name":"jmoreira","email":"jmoreiras@gmail.com"},{"name":"lopezjurip","email":"lopezjuripatricio@gmail.com"},{"name":"nchastain","email":"nate.chastain@consensys.net"},{"name":"sloreti","email":"lhloreti@gmail.com"},{"name":"vdrg","email":"vdrg@protonmail.ch"},{"name":"wachunei","email":"wachunei@gmail.com"}],"_npmUser":{"name":"vdrg","email":"vdrg@protonmail.ch"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/smart-contracts_0.0.4_1564763123992_0.8960058649105151"},"_hasShrinkwrap":false},"0.1.0":{"name":"@daisypayments/smart-contracts","version":"0.1.0","repository":{"type":"git","url":"https://github.com/consensys/daisy-subscription-contracts"},"author":{"name":"vdrg","email":"vicente.dragicevic@consensys.net"},"license":"MIT","main":"index.js","scripts":{"compile":"truffle compile","coverage":"./scripts/coverage.sh","exec":"truffle exec","ganache":"ganache-cli","docgen":"./scripts/docgen.sh","publish-docs":"./scripts/publish-docs.sh","prepublish":"yarn compile","lint":"solhint \"contracts/**/*.sol\"","migrate":"truffle migrate","test":"./scripts/test.sh"},"devDependencies":{"@daisypayments/eslint-config":"^1.5.1","bip39":"^2.5.0","bn.js":"^4.11.8","chai":"^4.2.0","coveralls":"^3.0.5","dotenv":"^6.2.0","eslint":"^5.13.0","eslint-config-prettier":"^4.0.0","eslint-plugin-mocha":"^5.2.1","eslint-plugin-prettier":"^3.0.1","eth-gas-reporter":"0.1.10","eth-sig-util":"^2.2.0","ethereumjs-abi":"^0.6.7","ethereumjs-util":"^6.1.0","ethereumjs-wallet":"^0.6.3","ganache-cli":"^6.4.4","lodash":"^4.17.11","moment":"^2.24.0","openzeppelin-solidity":"^2.3.0","openzeppelin-test-helpers":"^0.4.0","prettier":"^1.16.3","solhint":"^2.0.0","solidity-coverage":"^0.6.0","solidity-docgen":"^0.1.1","truffle":"^5.0.25","truffle-hdwallet-provider":"^1.0.4"},"description":"[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repo","licenseText":"MIT License\n\nCopyright (c) 2019 Token Foundry\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@daisypayments/smart-contracts@0.1.0","dist":{"shasum":"96705931926b128337f441d23c38e68d76fa9cf4","integrity":"sha512-3zYBk7xWCdnCOXlgmfPssk2gom2bWlW7QyoXq3O+jwb9met77B8HjRC7wNDDiW4XhyF4/ARabV58z2a420rBiw==","tarball":"https://registry.npmjs.org/@daisypayments/smart-contracts/-/smart-contracts-0.1.0.tgz","fileCount":9,"unpackedSize":2595476,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdXV4lCRA9TVsSAnZWagAAnZUP/REzdcGghuzOF9t1kn6u\nUZDV+DCoBsAqTy9l6A0LQXgiar2b2BluxUyI23y7CluD4gSiLxbqHA4fYsGW\ngMXjlSiBuuqxSdKlAKofIm3vWj89CI9ddmLghPRJz3O9rEIBeLD9OtWavV1k\nDTasjglpRltm7sLrlUDQUd4poLnbiiPCO3AEHDk4XBGed9jd6CwqpYpkjGiO\nZOROfcgMnZctil3op9jY2ivTZCL2gvAGb9fkwfmwmph7lC8oQqHkXonACx9I\nqEKyQXttx5v/ZDy+ZDJm1l3bN2gZ1FlnOnjh9u0Cen1F/0dViiRNvAkP/ZFs\nOoAX7Jcm3RpG2g3J/W32Uch0Re54kB9L6GejhhEFUXDDeQI+EcGoUXoVW7sv\n/wOl3Q2BIQ8NO/VWePUTV8xuIwwuzWOiAVhOA5WwBpnr0NGXR21qVbu7KPAj\nAYshF4UxIVsq2dusGNn16yX+lsu5gAUS4UMwdFAToEkXSS+BFFU4JSisoM/1\n+a9fFj1ItlJal5BCy7AA+jTLWGsFr5ydWAs9/drExteKK7MKy2LOwhFaEQIu\ndvuq7vPpZPbRMYtDc3ryQKa091IJFImyU4Rxi10aE2zwQN4HET6kJ+Y0Fuup\nq0jxtNRKoFPgBxieTyXKrbwG7XCihWHie05jnZURnm7+JoeLaphT5vmDzPpr\nLtz7\r\n=3x75\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDnbDqTFZxy3WZsrdLPX1dSTWiWhRroGE2JdEc6hSJsNAiA3ZaIEbv8EISgQ7HqlFfrPH9Gsl6DYD5VjR2VbJGJfEw=="}]},"maintainers":[{"name":"jmoreira","email":"jmoreiras@gmail.com"},{"name":"lopezjurip","email":"lopezjuripatricio@gmail.com"},{"name":"nchastain","email":"nate.chastain@consensys.net"},{"name":"sloreti","email":"lhloreti@gmail.com"},{"name":"vdrg","email":"vdrg@protonmail.ch"},{"name":"wachunei","email":"wachunei@gmail.com"}],"_npmUser":{"name":"vdrg","email":"vdrg@protonmail.ch"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/smart-contracts_0.1.0_1566400036472_0.3256014360688184"},"_hasShrinkwrap":false},"0.2.0-beta":{"name":"@daisypayments/smart-contracts","version":"0.2.0-beta","repository":{"type":"git","url":"https://github.com/consensys/daisy-subscription-contracts"},"author":{"name":"vdrg","email":"vicente.dragicevic@consensys.net"},"license":"MIT","main":"index.js","scripts":{"compile":"truffle compile","coverage":"./scripts/coverage.sh","exec":"truffle exec","ganache":"ganache-cli","docgen":"./scripts/docgen.sh","publish-docs":"./scripts/publish-docs.sh","prepublish":"yarn compile","lint":"solhint \"contracts/**/*.sol\"","migrate":"truffle migrate","test":"./scripts/test.sh"},"devDependencies":{"@daisypayments/eslint-config":"^1.5.1","bip39":"^2.5.0","bn.js":"^4.11.8","chai":"^4.2.0","coveralls":"^3.0.5","dotenv":"^6.2.0","eslint":"^5.13.0","eslint-config-prettier":"^4.0.0","eslint-plugin-mocha":"^5.2.1","eslint-plugin-prettier":"^3.0.1","eth-gas-reporter":"0.1.10","eth-sig-util":"^2.2.0","ethereumjs-abi":"^0.6.7","ethereumjs-util":"^6.1.0","ethereumjs-wallet":"^0.6.3","ganache-cli":"^6.4.4","lodash":"^4.17.11","moment":"^2.24.0","openzeppelin-solidity":"^2.3.0","openzeppelin-test-helpers":"^0.4.0","prettier":"^1.16.3","solhint":"^2.0.0","solidity-coverage":"^0.6.0","solidity-docgen":"^0.1.1","truffle":"^5.0.25","truffle-hdwallet-provider":"^1.0.4"},"readmeFilename":"README.md","readme":"# Daisy Contracts\n\n[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repos/github/ConsenSys/daisy-subscription-contracts/badge.svg?t=wmZqvk)](https://coveralls.io/github/ConsenSys/daisy-subscription-contracts)\n\n## Overview\n\n### Subscriptions\n\nA subscription is composed of:\n\n* subscriber: address from which tokens will be transferred from.\n* token: address of the ERC 20 token that the subscription is denominated in.\n* price: number of tokens to transfer in each payment.\n* periodUnit: \"DAY\", \"MONTH\", or \"YEAR\".\n* periods: number of period units between payments.\n* maxExecutions: max number of payments that can be made before the subscriber must manually renew their subscription. If this value is 0, there is no execution limit.\n* planIdHash: the hash of the id of the plan the subscription belongs to.\n* credits: amount of tokens to substract from future payments. On each payment, these credits get consumed until they get to 0.\n\nA subscription can be in one of four states:\n1. Active: Once it has been executed and the next payment is in the future. A subscription is first executed upon its creation.\n2. Active and Cancelled: When it is cancelled before reaching the next payment timestamp. It will remain active until the end of the period.\n3. Cancelled: when it has been cancelled and the last billed period has ended.\n4. Deleted: the subscription data will be deleted upon execution if the subscription can't be executed anymore.\n\n### Plans\n\nA plan is just a way to group multiple subscriptions, and allows the publisher to cancel a group of subscriptions at once. A plan is identified in the contract by a bytes32. When a plan based subscription is created, it is necessary to specify the plan's identifier, and the creation only goes through if a valid authorization signature is provided.\n\nThe contract provides a function to delete a plan by providing the plan on chain id. All subscriptions with that plan get invalidated (they get deleted on the next execution).\n\n## Contracts\n\n### `SubscriptionManager.sol`\n\nHandles the creation, execution, and cancellation of subscriptions.\n\nIt also provides methods for enumerating subscriptions and subscription by subscriber. This implementation was adapted from OpenZeppelin's `EIP721Enumerable` [implementation](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC721/ERC721Enumerable.sol).\n\n### `IndexedArrayLib.sol`\n\nLibrary that provides an indexed array of bytes32. It allows us to remove items from the array by specifying the item itself that we want to remove.\n\n### `Delegated.sol`\n\nAllows child contracts to support delegated execution without changing their external APIs. See Delegation section.\n\n## Time\n\nTo support different time units (days, months and years) we use [BokkyPooBah's Date Time Library](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary).\n\n## Delegation\n\nIn order to support delegated execution through the use of EIP712 signatures, the `SubscriptionManager` inherits from `Delegated`. The key feature of the `Delegated` contract is that child contracts don't need to polute their APIs with parameters related to delegated execution.\n\nThe `Delegated` contract exposes the external `delegate` function which receives the following parameters:\n\n* `bytes data`: ABI encoded data to be used for the delegated call.\n* `bytes32 nonce`: Random value for replay protection. If the function to call is idempotent, this value is optional.\n* `uint256 signatureExpiresAt`: Timestamp in which the signature stops being valid.\n* `bytes signature`: The signature for the EIP712 type.\n\nFor example, for the `setWallet(address _wallet)` function in the `SubscriptionManager`, the EIP712 type is `SetWallet(address wallet,bytes32 nonce,uint256 signatureExpiresAt)`. This function can only be called directly by the `owner` account or by using the `delegate` function with the following parameters (pseudo code):\n\n```js\n// Data to call the setWallet function normally\nconst data = abiEncode(setWalletSelector, _wallet);\n\n// Random value for replay protection\nconst nonce = randomBytes32();\n\n// Signature expiration\nconst signatureExpiresAt = now + signatureDuration;\n\n// Owner's signature\nconst signature = signTypedData({\n  account: owner,  \n  primaryType: \"SetWallet\", // The EIP712 type\n  domain: { \n    verifyingContract: manager.address\n  },\n  message: {\n    wallet: _wallet,\n    nonce,\n    signatureExpiresAt,\n  }\n});\n\n// Call setWallet through the delegate function\nawait manager.delegate(\n  data,\n  nonce,\n  signatureExpiresAt,\n  signature,\n  {\n    from: anyone\n  }\n);\n```\n\n### delegate function and signature checks\n\nThe `delegate` function performs the following steps:\n\n1. Reentrancy guard (`delegate` can only be called once in the same transaction).\n2. Check that the signature hasn't expired (`now < signatureExpiresAt`).\n3. Store the `nonce`, `signatureExpiresAt` and `signature` parameters.\n4. Call itself with the ABI encoded data (`address(this).call(data)`);\n5. Revert if the call failed.\n6. Delete the stored parameters.\n\nAs the delegation data exists in the storage while the call is being executed, the called function in the child contract can use the internal `_delegatedCheck(bytes32 typeHash, bytes data, bool usesNonce)` function to get the address of the caller. Internally, the `_delegatedCheck` checks if `msg.sender == this` and performs the signature validation using the provided type hash. If `msg.sender != this`, it just returns the `msg.sender`. It also stores the hashed data so it can't be used again for another delegated call.\n\n## Subscription Flow with Delegated Execution\n\nThe only function where delegated execution checks are done manually (doesn't use the `Delegated` functionality) is the `create` function, used to create subscriptions. The flow for creating a subscription works as follows:\n\n1. Subscriber calls the `approve` function in the token in which the subscription is denominated in to allow the manager contract to manipulate her funds.\n2. Using EIP 712, the subscriber signs the creation of a subscription (using the EIP712 type `CreateSubscription`) and sends the data to the `authorizer` server.\n3. The `authorizer` checks that the parameters are OK depending on its own rules, signs the data and sends the data and signatures to the relayer.\n3. The relayer executes the creation by calling the method `create()`, passing the parameters and signatures.\n4. At the beggining of each payment period, anyone can execute the subscription and bill the subscriber.\n\nFor subscription services created using Daisy the platform, Daisy will be the authorizer AND the relayer in this flow. We are also working on a system that will allow clients to be the authorizers by using webhooks (Daisy will request an authorizer signature for each subscription creation request).\n\n## Off-chain service flow\n\n#### Checking if the publisher needs to provide the service\n\n1. Receive request from subscriber.\n2. Call `subscriptionManager.nextPaymentTimestamp(subscriptionId)`.\n3. If `now < nextPaymentTimestamp`, answer the request.\n\n#### Executing subscriptions\n\nTo retrieve all subscription ids from the contract (Note: if count is too large, it is possible to obtain the ids in batches):\n1. Call `subscriptionManager.subscriptionCount()`.\n2. Call `subscriptionManager.subscriptionRange(0, count)`.\n\nTo execute a batch of subscriptions:\n1. Call `subscriptionManager.executeBatch(ids)`.\n2. The following events can be present in the transaction receipt, which can be used by the service to update its state:\n    * `SubscriptionNotFound(subscriptionId)`: Subscription doesn't exist in the contract.\n    * `SubscriptionNotReady(subscriptionId, nextPayment)`: Next payment timestamp hasn't been reached yet.\n    * `SubscriptionExecuted(subscriptionId, nextPayment)`: The subscription was executed successfuly.\n    * `SubscriptionDeleted(subscriptionId, reason)`: The subscription was deleted from the contract.\n\nThe `reason` parameter in the `SubscriptionDeleted` event can correspond to:\n* 0 (CANCELLED): The subscription was cancelled before the execution.\n* 1 (EXPIRED): The subscription reached its maxExecutions in the previous execution.\n* 2 (INVALID_STATE): The state was invalid during the execution. This happens if the subscription's plan was deleted.\n* 3 (NOT_ENOUGH_FUNDS): The subscriber address doesn't have or didn't approve enough funds to perform the execution.\n\nIf the `SubscriptionExecuted` event is present, the following two events can also be present, which represent token allocations (see next section):\n* `PaymentAllocated(subscriptionId, token, recipient, amount)`\n* `FeeAllocated(subscriptionId, token, recipient, amount)`\n\n## Token Allocations and Fees\n\nThe owner of a `SubscriptionManager` can optionally set a `fee` and a `feeRecipient` (which can be changed at any point in time). On each execution, the amount of tokens to be paid to the `feeRecipient` is calculated as `feeAmount = price * fee / MAX_FEE`, and the tokens to be paid to the publisher's `wallet` becomes `price - feeAmount`. `MAX_FEE` is a constant set to `100 * 10^18`, and `fee <= MAX_FEE` always.\n\nThe `SubscriptionManager` uses a pull payment model: on each execution, tokens are always transferred from the subscriber to the manager itself, and the manager allocates tokens to the current `feeRecipient` and `wallet` by storing their payments in the `availableFunds` mapping. When an allocation happens, the `FeeAllocated` event or the `PaymentAllocated` event will be emitted, specifying the `subscriptionId`, `token`, `recipient` and `amount`.\n\nAt any time, anyone can call the `withdraw(address[] tokens, address[] recipients)` function to transfer all the available tokens to each recipient specified in the parameters.\n\n## Key Differences Between Daisy and the Current EIP 1337 Proposal\n\n#### Subscriptions creation is not standardized\n\nBy not defining how the subscription must be created, we can support multiple different use cases (e.g. plan or tier based subscriptions, or subscriptions whose prices are determined by what feautures are turned on/off).\n\n#### Subscription data is stored in the contract\n\nThis makes interoperability with other contracts/services easier, without needing to rely on a centralized data source. Subscription data is removed from the contract if it can't be executed anymore or if the user doesn't have enough funds.\n\n#### Execution of a payment only requires specifying the subscription id\n\nThis allows for easier batching of executions and makes it easier for off-chain services to execute subscriptions.\n\n#### Delegated execution is not part of the interface\n\nIn order to be compatible with other proposals for standardizing delegated execution, the core functions don't need to support delegated execution.\n\n#### `isValidSubscription()` split into `isCancelled(subscriptionId)` and `nextPaymentTimestamp(subscriptionId)`\n\nInstead of having an `isValidSubscription()` function that returns a boolean, this implementation provides a `nextPaymentTimestamp()` function that returns the unix timestamp at which the next payment can be executed. This returned value is more usable than a boolean. On the other hand, with `isCancelled` one can get more granular information about a subscription, improving interoperability.\n\n# Testing\n\nTo run the tests, clone this repo and run `yarn install` to install dependencies.\n\nRun `yarn test` to run all tests.\n\nRun `yarn coverage` to run tests and get code coverage.\n","description":"[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repo","licenseText":"MIT License\n\nCopyright (c) 2019 Token Foundry\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@daisypayments/smart-contracts@0.2.0-beta","dist":{"shasum":"753b940b6e6d9b63309cd05481cade35aaa3991e","integrity":"sha512-AVb8ROseWvtL0Cvch/iooyoAb+YFEi8oDXd7kfNmCxURxDHVvO5ujtAEKnHivUfgzv9vZV4U8eL00/fcL0GIpQ==","tarball":"https://registry.npmjs.org/@daisypayments/smart-contracts/-/smart-contracts-0.2.0-beta.tgz","fileCount":9,"unpackedSize":2595934,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdaAH7CRA9TVsSAnZWagAACysP/17qx+pNEafQE29oGOxN\nt6IrZrPGe9XkysUI43w37qL5d2lEGWrrc4TMs25F93ZC0LkCbw2NlJGoq9Rh\nbOainkjwO0XFwOu8bVj0N1BSim7+7MWrYesUy26D8lZl/rcuR8Ar3Xy/AXhF\nP6sOaip4/9R3MDpQOLzbrxWOA4uUVjPdA6OatN7dJ16ts46368Ahq8AkHbW6\nU2dgcbRB211mOcNrxpS4vxSjdKqnhz8xKoijJmhGHqGRcF6hoeEX0AZvqTTD\nXefs05yAYI0oDF4e75loKtN5O1QxBGIsX8dXc9J07/6ZG2iZXZTCw1RlXkiG\n7rs9sHH1Qjx1T5jbM6LhaXn8WSYH9bfuA/80DlXyDi6iyhEAAmwRXjPPH0sZ\ns/lwLKqPsoW3QCb4DwlPd6WB77cPLeGs/7rjXpDK6RIQmZGgaH0INaAO8fnU\naObQA45F5E8894RvDdt2IuOul/c/zPY+hSZB2cX6goDeqIXIjP8LO27A3Zju\ne86HOtv5u67zGOABBRAI3JdoVyPvN7rdbI5iA0R5+3HvK0FRuuATVJmuSs85\nPg7GF2CmH7eHj43klMIDppyceFVZSQnEdnPXXIW1HaozmTrF9oW5hqSOMLtC\nl24knRebajcFWA5jbK+yZN/eU9+igWkQ5gAMTo/GX8Zw2P/RNqF7UwGWOrer\nF2Go\r\n=0u68\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD/RoWn6oEz2iTr24tQe74d/LDuGXuK5yJfY3LFURH8TwIgFk02MJdikYp70ijHjQR+3UpJO6+JVsS7wFuLHddtLQY="}]},"maintainers":[{"name":"jmoreira","email":"jmoreiras@gmail.com"},{"name":"lopezjurip","email":"lopezjuripatricio@gmail.com"},{"name":"nchastain","email":"nate.chastain@consensys.net"},{"name":"sloreti","email":"lhloreti@gmail.com"},{"name":"vdrg","email":"vdrg@protonmail.ch"},{"name":"wachunei","email":"wachunei@gmail.com"}],"_npmUser":{"name":"vdrg","email":"vdrg@protonmail.ch"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/smart-contracts_0.2.0-beta_1567097338519_0.04651428625928267"},"_hasShrinkwrap":false},"0.2.1-beta":{"name":"@daisypayments/smart-contracts","version":"0.2.1-beta","repository":{"type":"git","url":"https://github.com/consensys/daisy-subscription-contracts"},"author":{"name":"vdrg","email":"vicente.dragicevic@consensys.net"},"license":"MIT","main":"index.js","scripts":{"compile":"truffle compile","coverage":"./scripts/coverage.sh","exec":"truffle exec","ganache":"ganache-cli","docgen":"./scripts/docgen.sh","publish-docs":"./scripts/publish-docs.sh","prepublish":"yarn compile","lint":"solhint \"contracts/**/*.sol\"","migrate":"truffle migrate","test":"./scripts/test.sh"},"devDependencies":{"@daisypayments/eslint-config":"^1.5.1","bip39":"^2.5.0","bn.js":"^4.11.8","chai":"^4.2.0","coveralls":"^3.0.5","dotenv":"^6.2.0","eslint":"^5.13.0","eslint-config-prettier":"^4.0.0","eslint-plugin-mocha":"^5.2.1","eslint-plugin-prettier":"^3.0.1","eth-gas-reporter":"0.1.10","eth-sig-util":"^2.2.0","ethereumjs-abi":"^0.6.7","ethereumjs-util":"^6.1.0","ethereumjs-wallet":"^0.6.3","ganache-cli":"^6.4.4","lodash":"^4.17.11","moment":"^2.24.0","openzeppelin-solidity":"^2.3.0","openzeppelin-test-helpers":"^0.4.0","prettier":"^1.16.3","solhint":"^2.0.0","solidity-coverage":"^0.6.0","solidity-docgen":"^0.1.1","truffle":"^5.0.25","truffle-hdwallet-provider":"^1.0.4"},"readmeFilename":"README.md","readme":"# Daisy Contracts\n\n[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repos/github/ConsenSys/daisy-subscription-contracts/badge.svg?t=wmZqvk)](https://coveralls.io/github/ConsenSys/daisy-subscription-contracts)\n\n## Overview\n\n### Subscriptions\n\nA subscription is composed of:\n\n* subscriber: address from which tokens will be transferred from.\n* token: address of the ERC 20 token that the subscription is denominated in.\n* price: number of tokens to transfer in each payment.\n* periodUnit: \"DAY\", \"MONTH\", or \"YEAR\".\n* periods: number of period units between payments.\n* maxExecutions: max number of payments that can be made before the subscriber must manually renew their subscription. If this value is 0, there is no execution limit.\n* planIdHash: the hash of the id of the plan the subscription belongs to.\n* credits: amount of tokens to substract from future payments. On each payment, these credits get consumed until they get to 0.\n\nA subscription can be in one of four states:\n1. Active: Once it has been executed and the next payment is in the future. A subscription is first executed upon its creation.\n2. Active and Cancelled: When it is cancelled before reaching the next payment timestamp. It will remain active until the end of the period.\n3. Cancelled: when it has been cancelled and the last billed period has ended.\n4. Deleted: the subscription data will be deleted upon execution if the subscription can't be executed anymore.\n\n### Plans\n\nA plan is just a way to group multiple subscriptions, and allows the publisher to cancel a group of subscriptions at once. A plan is identified in the contract by a bytes32. When a plan based subscription is created, it is necessary to specify the plan's identifier, and the creation only goes through if a valid authorization signature is provided.\n\nThe contract provides a function to delete a plan by providing the plan on chain id. All subscriptions with that plan get invalidated (they get deleted on the next execution).\n\n## Contracts\n\n### `SubscriptionManager.sol`\n\nHandles the creation, execution, and cancellation of subscriptions.\n\nIt also provides methods for enumerating subscriptions and subscription by subscriber. This implementation was adapted from OpenZeppelin's `EIP721Enumerable` [implementation](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC721/ERC721Enumerable.sol).\n\n### `IndexedArrayLib.sol`\n\nLibrary that provides an indexed array of bytes32. It allows us to remove items from the array by specifying the item itself that we want to remove.\n\n### `Delegated.sol`\n\nAllows child contracts to support delegated execution without changing their external APIs. See Delegation section.\n\n## Time\n\nTo support different time units (days, months and years) we use [BokkyPooBah's Date Time Library](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary).\n\n## Delegation\n\nIn order to support delegated execution through the use of EIP712 signatures, the `SubscriptionManager` inherits from `Delegated`. The key feature of the `Delegated` contract is that child contracts don't need to polute their APIs with parameters related to delegated execution.\n\nThe `Delegated` contract exposes the external `delegate` function which receives the following parameters:\n\n* `bytes data`: ABI encoded data to be used for the delegated call.\n* `bytes32 nonce`: Random value for replay protection. If the function to call is idempotent, this value is optional.\n* `uint256 signatureExpiresAt`: Timestamp in which the signature stops being valid.\n* `bytes signature`: The signature for the EIP712 type.\n\nFor example, for the `setWallet(address _wallet)` function in the `SubscriptionManager`, the EIP712 type is `SetWallet(address wallet,bytes32 nonce,uint256 signatureExpiresAt)`. This function can only be called directly by the `owner` account or by using the `delegate` function with the following parameters (pseudo code):\n\n```js\n// Data to call the setWallet function normally\nconst data = abiEncode(setWalletSelector, _wallet);\n\n// Random value for replay protection\nconst nonce = randomBytes32();\n\n// Signature expiration\nconst signatureExpiresAt = now + signatureDuration;\n\n// Owner's signature\nconst signature = signTypedData({\n  account: owner,  \n  primaryType: \"SetWallet\", // The EIP712 type\n  domain: { \n    verifyingContract: manager.address\n  },\n  message: {\n    wallet: _wallet,\n    nonce,\n    signatureExpiresAt,\n  }\n});\n\n// Call setWallet through the delegate function\nawait manager.delegate(\n  data,\n  nonce,\n  signatureExpiresAt,\n  signature,\n  {\n    from: anyone\n  }\n);\n```\n\n### delegate function and signature checks\n\nThe `delegate` function performs the following steps:\n\n1. Reentrancy guard (`delegate` can only be called once in the same transaction).\n2. Check that the signature hasn't expired (`now < signatureExpiresAt`).\n3. Store the `nonce`, `signatureExpiresAt` and `signature` parameters.\n4. Call itself with the ABI encoded data (`address(this).call(data)`);\n5. Revert if the call failed.\n6. Delete the stored parameters.\n\nAs the delegation data exists in the storage while the call is being executed, the called function in the child contract can use the internal `_delegatedCheck(bytes32 typeHash, bytes data, bool usesNonce)` function to get the address of the caller. Internally, the `_delegatedCheck` checks if `msg.sender == this` and performs the signature validation using the provided type hash. If `msg.sender != this`, it just returns the `msg.sender`. It also stores the hashed data so it can't be used again for another delegated call.\n\n## Subscription Flow with Delegated Execution\n\nThe only function where delegated execution checks are done manually (doesn't use the `Delegated` functionality) is the `create` function, used to create subscriptions. The flow for creating a subscription works as follows:\n\n1. Subscriber calls the `approve` function in the token in which the subscription is denominated in to allow the manager contract to manipulate her funds.\n2. Using EIP 712, the subscriber signs the creation of a subscription (using the EIP712 type `CreateSubscription`) and sends the data to the `authorizer` server.\n3. The `authorizer` checks that the parameters are OK depending on its own rules, signs the data and sends the data and signatures to the relayer.\n3. The relayer executes the creation by calling the method `create()`, passing the parameters and signatures.\n4. At the beggining of each payment period, anyone can execute the subscription and bill the subscriber.\n\nFor subscription services created using Daisy the platform, Daisy will be the authorizer AND the relayer in this flow. We are also working on a system that will allow clients to be the authorizers by using webhooks (Daisy will request an authorizer signature for each subscription creation request).\n\n## Off-chain service flow\n\n#### Checking if the publisher needs to provide the service\n\n1. Receive request from subscriber.\n2. Call `subscriptionManager.nextPaymentTimestamp(subscriptionId)`.\n3. If `now < nextPaymentTimestamp`, answer the request.\n\n#### Executing subscriptions\n\nTo retrieve all subscription ids from the contract (Note: if count is too large, it is possible to obtain the ids in batches):\n1. Call `subscriptionManager.subscriptionCount()`.\n2. Call `subscriptionManager.subscriptionRange(0, count)`.\n\nTo execute a batch of subscriptions:\n1. Call `subscriptionManager.executeBatch(ids)`.\n2. The following events can be present in the transaction receipt, which can be used by the service to update its state:\n    * `SubscriptionNotFound(subscriptionId)`: Subscription doesn't exist in the contract.\n    * `SubscriptionNotReady(subscriptionId, nextPayment)`: Next payment timestamp hasn't been reached yet.\n    * `SubscriptionExecuted(subscriptionId, nextPayment)`: The subscription was executed successfuly.\n    * `SubscriptionDeleted(subscriptionId, reason)`: The subscription was deleted from the contract.\n\nThe `reason` parameter in the `SubscriptionDeleted` event can correspond to:\n* 0 (CANCELLED): The subscription was cancelled before the execution.\n* 1 (EXPIRED): The subscription reached its maxExecutions in the previous execution.\n* 2 (INVALID_STATE): The state was invalid during the execution. This happens if the subscription's plan was deleted.\n* 3 (NOT_ENOUGH_FUNDS): The subscriber address doesn't have or didn't approve enough funds to perform the execution.\n\nIf the `SubscriptionExecuted` event is present, the following two events can also be present, which represent token allocations (see next section):\n* `PaymentAllocated(subscriptionId, token, recipient, amount)`\n* `FeeAllocated(subscriptionId, token, recipient, amount)`\n\n## Token Allocations and Fees\n\nThe owner of a `SubscriptionManager` can optionally set a `fee` and a `feeRecipient` (which can be changed at any point in time). On each execution, the amount of tokens to be paid to the `feeRecipient` is calculated as `feeAmount = price * fee / MAX_FEE`, and the tokens to be paid to the publisher's `wallet` becomes `price - feeAmount`. `MAX_FEE` is a constant set to `100 * 10^18`, and `fee <= MAX_FEE` always.\n\nThe `SubscriptionManager` uses a pull payment model: on each execution, tokens are always transferred from the subscriber to the manager itself, and the manager allocates tokens to the current `feeRecipient` and `wallet` by storing their payments in the `availableFunds` mapping. When an allocation happens, the `FeeAllocated` event or the `PaymentAllocated` event will be emitted, specifying the `subscriptionId`, `token`, `recipient` and `amount`.\n\nAt any time, anyone can call the `withdraw(address[] tokens, address[] recipients)` function to transfer all the available tokens to each recipient specified in the parameters.\n\n## Key Differences Between Daisy and the Current EIP 1337 Proposal\n\n#### Subscriptions creation is not standardized\n\nBy not defining how the subscription must be created, we can support multiple different use cases (e.g. plan or tier based subscriptions, or subscriptions whose prices are determined by what feautures are turned on/off).\n\n#### Subscription data is stored in the contract\n\nThis makes interoperability with other contracts/services easier, without needing to rely on a centralized data source. Subscription data is removed from the contract if it can't be executed anymore or if the user doesn't have enough funds.\n\n#### Execution of a payment only requires specifying the subscription id\n\nThis allows for easier batching of executions and makes it easier for off-chain services to execute subscriptions.\n\n#### Delegated execution is not part of the interface\n\nIn order to be compatible with other proposals for standardizing delegated execution, the core functions don't need to support delegated execution.\n\n#### `isValidSubscription()` split into `isCancelled(subscriptionId)` and `nextPaymentTimestamp(subscriptionId)`\n\nInstead of having an `isValidSubscription()` function that returns a boolean, this implementation provides a `nextPaymentTimestamp()` function that returns the unix timestamp at which the next payment can be executed. This returned value is more usable than a boolean. On the other hand, with `isCancelled` one can get more granular information about a subscription, improving interoperability.\n\n# Testing\n\nTo run the tests, clone this repo and run `yarn install` to install dependencies.\n\nRun `yarn test` to run all tests.\n\nRun `yarn coverage` to run tests and get code coverage.\n","description":"[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repo","licenseText":"MIT License\n\nCopyright (c) 2019 Token Foundry\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@daisypayments/smart-contracts@0.2.1-beta","dist":{"shasum":"2b78112a37b0a98679bbb1d3dda823c82dd89fd8","integrity":"sha512-/IGYpj6lniJmelWBoS0HtWJWLdDokS8AsMuj460MIKKtBPJQ/Cw7NKAnFGALu42OhoVDPRPBiS5n85IrERz0HQ==","tarball":"https://registry.npmjs.org/@daisypayments/smart-contracts/-/smart-contracts-0.2.1-beta.tgz","fileCount":9,"unpackedSize":2596005,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdaAPECRA9TVsSAnZWagAAboMP/377dC70woUxTcl+8uyV\n9whtWEbbG3jCjrB9AVEv3rbP9C3w00eFKtKD53z2Z9nrIfmPBWNm87ch7w/+\nxA1UxNn6Ri3E42ayML4V9Zn7uEdrwS+Vp0PEqmONuHBc2yntgsYaYiwC3yc8\nqEngHf5tGVV58Jn3DxV5V2JIEMvSh9rClA2P9pKQOK9q+S1UHWwD/vFoo1Km\nhzOLl2oV5qzmZ8+2AwLV3FGQsMWTFydZF4H/qj6gcfWKNEIZv6e4lQOvd/1D\nLrqDuD2XHQUINIw59327ddnMbxOt+XqzlGGTZeVPYg1gFTP97oXkrQRc9+rq\neDqdIV46iejX1eTmXPye3p+TudGjbtRJ4rlB+wZQHiCgY12rR6yWJanI5N3w\nAk1MieQXpt+lLl2ae29MH8MCfHiEsIGT/SgVkcceM1Ix7WCvl307+mCL4WQz\nR+i6Hwpi4p7QaWvPDm/dr7tVmYP9xPgjxmkfBqcKLBzJOgapcUkllpChUFyp\n6ADcfnUQmVEiLeTxV+A8ZITLhoAxLuvmo5K52orbPhFXtc+ih1LkpOdJABIX\nZaQyX3rNun8spdOmCQ7yyKQQ/NChnENVNzkAzYI0zETDefNfkThs6fZ+VPtF\nZEVgQ8IGR9b2oSzULR1b5HCW6yMh1opmNA6N7MJ7QKnALwdsO1NLbJp9t4xz\nlQY2\r\n=2osi\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFz2HQ+sxmxFmYC2x+DKNC4kCnxyC9lHc3BA5wW3rYhnAiAoqYrRy48/jJrDztxu8RpueIXXXMuxs6Wnbwub9o5ReA=="}]},"maintainers":[{"name":"jmoreira","email":"jmoreiras@gmail.com"},{"name":"lopezjurip","email":"lopezjuripatricio@gmail.com"},{"name":"nchastain","email":"nate.chastain@consensys.net"},{"name":"sloreti","email":"lhloreti@gmail.com"},{"name":"vdrg","email":"vdrg@protonmail.ch"},{"name":"wachunei","email":"wachunei@gmail.com"}],"_npmUser":{"name":"vdrg","email":"vdrg@protonmail.ch"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/smart-contracts_0.2.1-beta_1567097795521_0.23749548388402508"},"_hasShrinkwrap":false},"0.2.2-beta":{"name":"@daisypayments/smart-contracts","version":"0.2.2-beta","repository":{"type":"git","url":"https://github.com/consensys/daisy-subscription-contracts"},"author":{"name":"vdrg","email":"vicente.dragicevic@consensys.net"},"license":"MIT","main":"index.js","scripts":{"compile":"truffle compile","coverage":"./scripts/coverage.sh","exec":"truffle exec","ganache":"ganache-cli","docgen":"./scripts/docgen.sh","publish-docs":"./scripts/publish-docs.sh","prepublish":"yarn compile","lint":"solhint \"contracts/**/*.sol\"","migrate":"truffle migrate","test":"./scripts/test.sh"},"devDependencies":{"@daisypayments/eslint-config":"^1.5.1","bip39":"^2.5.0","bn.js":"^4.11.8","chai":"^4.2.0","coveralls":"^3.0.5","dotenv":"^6.2.0","eslint":"^5.13.0","eslint-config-prettier":"^4.0.0","eslint-plugin-mocha":"^5.2.1","eslint-plugin-prettier":"^3.0.1","eth-gas-reporter":"0.1.10","eth-sig-util":"^2.2.0","ethereumjs-abi":"^0.6.7","ethereumjs-util":"^6.1.0","ethereumjs-wallet":"^0.6.3","ganache-cli":"^6.4.4","lodash":"^4.17.11","moment":"^2.24.0","openzeppelin-solidity":"^2.3.0","openzeppelin-test-helpers":"^0.4.0","prettier":"^1.16.3","solhint":"^2.0.0","solidity-coverage":"^0.6.0","solidity-docgen":"^0.1.1","truffle":"^5.0.25","truffle-hdwallet-provider":"^1.0.4"},"readmeFilename":"README.md","readme":"# Daisy Contracts\n\n[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repos/github/ConsenSys/daisy-subscription-contracts/badge.svg?t=wmZqvk)](https://coveralls.io/github/ConsenSys/daisy-subscription-contracts)\n\n## Overview\n\n### Subscriptions\n\nA subscription is composed of:\n\n* subscriber: address from which tokens will be transferred from.\n* token: address of the ERC 20 token that the subscription is denominated in.\n* price: number of tokens to transfer in each payment.\n* periodUnit: \"DAY\", \"MONTH\", or \"YEAR\".\n* periods: number of period units between payments.\n* maxExecutions: max number of payments that can be made before the subscriber must manually renew their subscription. If this value is 0, there is no execution limit.\n* planIdHash: the hash of the id of the plan the subscription belongs to.\n* credits: amount of tokens to substract from future payments. On each payment, these credits get consumed until they get to 0.\n\nA subscription can be in one of four states:\n1. Active: Once it has been executed and the next payment is in the future. A subscription is first executed upon its creation.\n2. Active and Cancelled: When it is cancelled before reaching the next payment timestamp. It will remain active until the end of the period.\n3. Cancelled: when it has been cancelled and the last billed period has ended.\n4. Deleted: the subscription data will be deleted upon execution if the subscription can't be executed anymore.\n\n### Plans\n\nA plan is just a way to group multiple subscriptions, and allows the publisher to cancel a group of subscriptions at once. A plan is identified in the contract by a bytes32. When a plan based subscription is created, it is necessary to specify the plan's identifier, and the creation only goes through if a valid authorization signature is provided.\n\nThe contract provides a function to delete a plan by providing the plan on chain id. All subscriptions with that plan get invalidated (they get deleted on the next execution).\n\n## Contracts\n\n### `SubscriptionManager.sol`\n\nHandles the creation, execution, and cancellation of subscriptions.\n\nIt also provides methods for enumerating subscriptions and subscription by subscriber. This implementation was adapted from OpenZeppelin's `EIP721Enumerable` [implementation](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC721/ERC721Enumerable.sol).\n\n### `IndexedArrayLib.sol`\n\nLibrary that provides an indexed array of bytes32. It allows us to remove items from the array by specifying the item itself that we want to remove.\n\n### `Delegated.sol`\n\nAllows child contracts to support delegated execution without changing their external APIs. See Delegation section.\n\n## Time\n\nTo support different time units (days, months and years) we use [BokkyPooBah's Date Time Library](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary).\n\n## Delegation\n\nIn order to support delegated execution through the use of EIP712 signatures, the `SubscriptionManager` inherits from `Delegated`. The key feature of the `Delegated` contract is that child contracts don't need to polute their APIs with parameters related to delegated execution.\n\nThe `Delegated` contract exposes the external `delegate` function which receives the following parameters:\n\n* `bytes data`: ABI encoded data to be used for the delegated call.\n* `bytes32 nonce`: Random value for replay protection. If the function to call is idempotent, this value is optional.\n* `uint256 signatureExpiresAt`: Timestamp in which the signature stops being valid.\n* `bytes signature`: The signature for the EIP712 type.\n\nFor example, for the `setWallet(address _wallet)` function in the `SubscriptionManager`, the EIP712 type is `SetWallet(address wallet,bytes32 nonce,uint256 signatureExpiresAt)`. This function can only be called directly by the `owner` account or by using the `delegate` function with the following parameters (pseudo code):\n\n```js\n// Data to call the setWallet function normally\nconst data = abiEncode(setWalletSelector, _wallet);\n\n// Random value for replay protection\nconst nonce = randomBytes32();\n\n// Signature expiration\nconst signatureExpiresAt = now + signatureDuration;\n\n// Owner's signature\nconst signature = signTypedData({\n  account: owner,  \n  primaryType: \"SetWallet\", // The EIP712 type\n  domain: { \n    verifyingContract: manager.address\n  },\n  message: {\n    wallet: _wallet,\n    nonce,\n    signatureExpiresAt,\n  }\n});\n\n// Call setWallet through the delegate function\nawait manager.delegate(\n  data,\n  nonce,\n  signatureExpiresAt,\n  signature,\n  {\n    from: anyone\n  }\n);\n```\n\n### delegate function and signature checks\n\nThe `delegate` function performs the following steps:\n\n1. Reentrancy guard (`delegate` can only be called once in the same transaction).\n2. Check that the signature hasn't expired (`now < signatureExpiresAt`).\n3. Store the `nonce`, `signatureExpiresAt` and `signature` parameters.\n4. Call itself with the ABI encoded data (`address(this).call(data)`);\n5. Revert if the call failed.\n6. Delete the stored parameters.\n\nAs the delegation data exists in the storage while the call is being executed, the called function in the child contract can use the internal `_delegatedCheck(bytes32 typeHash, bytes data, bool usesNonce)` function to get the address of the caller. Internally, the `_delegatedCheck` checks if `msg.sender == this` and performs the signature validation using the provided type hash. If `msg.sender != this`, it just returns the `msg.sender`. It also stores the hashed data so it can't be used again for another delegated call.\n\n## Subscription Flow with Delegated Execution\n\nThe only function where delegated execution checks are done manually (doesn't use the `Delegated` functionality) is the `create` function, used to create subscriptions. The flow for creating a subscription works as follows:\n\n1. Subscriber calls the `approve` function in the token in which the subscription is denominated in to allow the manager contract to manipulate her funds.\n2. Using EIP 712, the subscriber signs the creation of a subscription (using the EIP712 type `CreateSubscription`) and sends the data to the `authorizer` server.\n3. The `authorizer` checks that the parameters are OK depending on its own rules, signs the data and sends the data and signatures to the relayer.\n3. The relayer executes the creation by calling the method `create()`, passing the parameters and signatures.\n4. At the beggining of each payment period, anyone can execute the subscription and bill the subscriber.\n\nFor subscription services created using Daisy the platform, Daisy will be the authorizer AND the relayer in this flow. We are also working on a system that will allow clients to be the authorizers by using webhooks (Daisy will request an authorizer signature for each subscription creation request).\n\n## Off-chain service flow\n\n#### Checking if the publisher needs to provide the service\n\n1. Receive request from subscriber.\n2. Call `subscriptionManager.nextPaymentTimestamp(subscriptionId)`.\n3. If `now < nextPaymentTimestamp`, answer the request.\n\n#### Executing subscriptions\n\nTo retrieve all subscription ids from the contract (Note: if count is too large, it is possible to obtain the ids in batches):\n1. Call `subscriptionManager.subscriptionCount()`.\n2. Call `subscriptionManager.subscriptionRange(0, count)`.\n\nTo execute a batch of subscriptions:\n1. Call `subscriptionManager.executeBatch(ids)`.\n2. The following events can be present in the transaction receipt, which can be used by the service to update its state:\n    * `SubscriptionNotFound(subscriptionId)`: Subscription doesn't exist in the contract.\n    * `SubscriptionNotReady(subscriptionId, nextPayment)`: Next payment timestamp hasn't been reached yet.\n    * `SubscriptionExecuted(subscriptionId, nextPayment)`: The subscription was executed successfuly.\n    * `SubscriptionDeleted(subscriptionId, reason)`: The subscription was deleted from the contract.\n\nThe `reason` parameter in the `SubscriptionDeleted` event can correspond to:\n* 0 (CANCELLED): The subscription was cancelled before the execution.\n* 1 (EXPIRED): The subscription reached its maxExecutions in the previous execution.\n* 2 (INVALID_STATE): The state was invalid during the execution. This happens if the subscription's plan was deleted.\n* 3 (NOT_ENOUGH_FUNDS): The subscriber address doesn't have or didn't approve enough funds to perform the execution.\n\nIf the `SubscriptionExecuted` event is present, the following two events can also be present, which represent token allocations (see next section):\n* `PaymentAllocated(subscriptionId, token, recipient, amount)`\n* `FeeAllocated(subscriptionId, token, recipient, amount)`\n\n## Token Allocations and Fees\n\nThe owner of a `SubscriptionManager` can optionally set a `fee` and a `feeRecipient` (which can be changed at any point in time). On each execution, the amount of tokens to be paid to the `feeRecipient` is calculated as `feeAmount = price * fee / MAX_FEE`, and the tokens to be paid to the publisher's `wallet` becomes `price - feeAmount`. `MAX_FEE` is a constant set to `100 * 10^18`, and `fee <= MAX_FEE` always.\n\nThe `SubscriptionManager` uses a pull payment model: on each execution, tokens are always transferred from the subscriber to the manager itself, and the manager allocates tokens to the current `feeRecipient` and `wallet` by storing their payments in the `availableFunds` mapping. When an allocation happens, the `FeeAllocated` event or the `PaymentAllocated` event will be emitted, specifying the `subscriptionId`, `token`, `recipient` and `amount`.\n\nAt any time, anyone can call the `withdraw(address[] tokens, address[] recipients)` function to transfer all the available tokens to each recipient specified in the parameters.\n\n## Key Differences Between Daisy and the Current EIP 1337 Proposal\n\n#### Subscriptions creation is not standardized\n\nBy not defining how the subscription must be created, we can support multiple different use cases (e.g. plan or tier based subscriptions, or subscriptions whose prices are determined by what feautures are turned on/off).\n\n#### Subscription data is stored in the contract\n\nThis makes interoperability with other contracts/services easier, without needing to rely on a centralized data source. Subscription data is removed from the contract if it can't be executed anymore or if the user doesn't have enough funds.\n\n#### Execution of a payment only requires specifying the subscription id\n\nThis allows for easier batching of executions and makes it easier for off-chain services to execute subscriptions.\n\n#### Delegated execution is not part of the interface\n\nIn order to be compatible with other proposals for standardizing delegated execution, the core functions don't need to support delegated execution.\n\n#### `isValidSubscription()` split into `isCancelled(subscriptionId)` and `nextPaymentTimestamp(subscriptionId)`\n\nInstead of having an `isValidSubscription()` function that returns a boolean, this implementation provides a `nextPaymentTimestamp()` function that returns the unix timestamp at which the next payment can be executed. This returned value is more usable than a boolean. On the other hand, with `isCancelled` one can get more granular information about a subscription, improving interoperability.\n\n# Testing\n\nTo run the tests, clone this repo and run `yarn install` to install dependencies.\n\nRun `yarn test` to run all tests.\n\nRun `yarn coverage` to run tests and get code coverage.\n","description":"[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repo","licenseText":"MIT License\n\nCopyright (c) 2019 Token Foundry\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@daisypayments/smart-contracts@0.2.2-beta","dist":{"shasum":"5d4e21f644f5d6c54444325731dae7f85f00b86d","integrity":"sha512-dHYrJEDZt6HLzg8ym454DlEcIFdtSqcrftmDPTAytqDvM+ljLCup6XPhdhmzbVsQ17yBq3dXZwC1lhCRJO4skA==","tarball":"https://registry.npmjs.org/@daisypayments/smart-contracts/-/smart-contracts-0.2.2-beta.tgz","fileCount":11,"unpackedSize":2812865,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdaBljCRA9TVsSAnZWagAAd2IP/05tK/FgAisI/fVpglWA\n10SKTbPyWrweQopD/G25sxqevCJNfZTbvXCftRfsc7hMZLeCOTkrfDIHGg4z\n7HtleivfBNU5enQSOhsC5urVaUCf0UZTk3IeBT/RPEeqwJb+z/5ySF7O4F6M\nXEG6I8euNRycgUccqQtUNT3G+aMnKMBcQ6tfVu3/dd31T8sg6mkHaSBPdw+j\nJa2LiHvZpA5dEOld6/EX0FClSZHZwHVU44c/u1rXpzCQxeee8RorsipyOLWM\nkK93SGt0ZOhaEfMaSc/5pWeTNg34q3zYq22nA/frjR4b/Vi8j+3lPNev4tC0\nq3YN1jbVawAF+xZMskqaFQrsDBJRRcXsMWVx1djhna7zw/CzOlgpe+UV87KZ\niWGKICd4M4cnUIkL0X1VtJ7SWosRw3Wfdh+H+OhAxeGCoxcKZ3vr6v/hOrCI\nol+BJTJLKAul5cOrzZlE1UxCCmvSqSMP+h65qEqM8NA0mCwTt8HJzi2PnEJu\ncVUQcPgQjsVD9NxjRHxWU8c1A+mfi4HiiCWVoV5pCucoPKuq20344/q9EPmt\n1u4yZ5MK6m/hr9K1+uCxYVwwvxRBLbH5ZpJ6+IGEyTMG6YRN3Fx1hbm8PVEw\nkfj7OP8wVTxgSg4M/v2qcgzIjX/rUV1kHfoIK+TegqH6GUymzPDZeEnW8Zr+\nSERR\r\n=iWug\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIC9xJakIV5en39OsIiJ6X/RhiGtjAPq8MKhS69sC/SbeAiBamrJmuy+ZuxbkUBX/iwQYbwoY+qk3I4qYit4ixBO2nw=="}]},"maintainers":[{"name":"jmoreira","email":"jmoreiras@gmail.com"},{"name":"lopezjurip","email":"lopezjuripatricio@gmail.com"},{"name":"nchastain","email":"nate.chastain@consensys.net"},{"name":"sloreti","email":"lhloreti@gmail.com"},{"name":"vdrg","email":"vdrg@protonmail.ch"},{"name":"wachunei","email":"wachunei@gmail.com"}],"_npmUser":{"name":"vdrg","email":"vdrg@protonmail.ch"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/smart-contracts_0.2.2-beta_1567103330342_0.09965119134654854"},"_hasShrinkwrap":false},"0.2.0-beta.1":{"name":"@daisypayments/smart-contracts","version":"0.2.0-beta.1","repository":{"type":"git","url":"https://github.com/consensys/daisy-subscription-contracts"},"author":{"name":"vdrg","email":"vicente.dragicevic@consensys.net"},"license":"MIT","main":"index.js","scripts":{"compile":"truffle compile","coverage":"./scripts/coverage.sh","exec":"truffle exec","ganache":"ganache-cli","docgen":"./scripts/docgen.sh","publish-docs":"./scripts/publish-docs.sh","prepublish":"yarn compile","lint":"solhint \"contracts/**/*.sol\"","migrate":"truffle migrate","test":"./scripts/test.sh"},"devDependencies":{"@daisypayments/eslint-config":"^1.5.1","bip39":"^2.5.0","bn.js":"^4.11.8","chai":"^4.2.0","coveralls":"^3.0.5","dotenv":"^6.2.0","eslint":"^5.13.0","eslint-config-prettier":"^4.0.0","eslint-plugin-mocha":"^5.2.1","eslint-plugin-prettier":"^3.0.1","eth-gas-reporter":"0.1.10","eth-sig-util":"^2.2.0","ethereumjs-abi":"^0.6.7","ethereumjs-util":"^6.1.0","ethereumjs-wallet":"^0.6.3","ganache-cli":"^6.4.4","lodash":"^4.17.11","moment":"^2.24.0","openzeppelin-solidity":"^2.3.0","openzeppelin-test-helpers":"^0.4.0","prettier":"^1.16.3","solhint":"^2.0.0","solidity-coverage":"^0.6.0","solidity-docgen":"^0.1.1","truffle":"^5.0.25","truffle-hdwallet-provider":"^1.0.4"},"readmeFilename":"README.md","readme":"# Daisy Contracts\n\n[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repos/github/ConsenSys/daisy-subscription-contracts/badge.svg?t=wmZqvk)](https://coveralls.io/github/ConsenSys/daisy-subscription-contracts)\n\n## Overview\n\n### Subscriptions\n\nA subscription is composed of:\n\n* subscriber: address from which tokens will be transferred from.\n* token: address of the ERC 20 token that the subscription is denominated in.\n* price: number of tokens to transfer in each payment.\n* periodUnit: \"DAY\", \"MONTH\", or \"YEAR\".\n* periods: number of period units between payments.\n* maxExecutions: max number of payments that can be made before the subscriber must manually renew their subscription. If this value is 0, there is no execution limit.\n* planIdHash: the hash of the id of the plan the subscription belongs to.\n* credits: amount of tokens to substract from future payments. On each payment, these credits get consumed until they get to 0.\n\nA subscription can be in one of four states:\n1. Active: Once it has been executed and the next payment is in the future. A subscription is first executed upon its creation.\n2. Active and Cancelled: When it is cancelled before reaching the next payment timestamp. It will remain active until the end of the period.\n3. Cancelled: when it has been cancelled and the last billed period has ended.\n4. Deleted: the subscription data will be deleted upon execution if the subscription can't be executed anymore.\n\n### Plans\n\nA plan is just a way to group multiple subscriptions, and allows the publisher to cancel a group of subscriptions at once. A plan is identified in the contract by a bytes32. When a plan based subscription is created, it is necessary to specify the plan's identifier, and the creation only goes through if a valid authorization signature is provided.\n\nThe contract provides a function to delete a plan by providing the plan on chain id. All subscriptions with that plan get invalidated (they get deleted on the next execution).\n\n## Contracts\n\n### `SubscriptionManager.sol`\n\nHandles the creation, execution, and cancellation of subscriptions.\n\nIt also provides methods for enumerating subscriptions and subscription by subscriber. This implementation was adapted from OpenZeppelin's `EIP721Enumerable` [implementation](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC721/ERC721Enumerable.sol).\n\n### `IndexedArrayLib.sol`\n\nLibrary that provides an indexed array of bytes32. It allows us to remove items from the array by specifying the item itself that we want to remove.\n\n### `Delegated.sol`\n\nAllows child contracts to support delegated execution without changing their external APIs. See Delegation section.\n\n## Time\n\nTo support different time units (days, months and years) we use [BokkyPooBah's Date Time Library](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary).\n\n## Delegation\n\nIn order to support delegated execution through the use of EIP712 signatures, the `SubscriptionManager` inherits from `Delegated`. The key feature of the `Delegated` contract is that child contracts don't need to polute their APIs with parameters related to delegated execution.\n\nThe `Delegated` contract exposes the external `delegate` function which receives the following parameters:\n\n* `bytes data`: ABI encoded data to be used for the delegated call.\n* `bytes32 nonce`: Random value for replay protection. If the function to call is idempotent, this value is optional.\n* `uint256 signatureExpiresAt`: Timestamp in which the signature stops being valid.\n* `bytes signature`: The signature for the EIP712 type.\n\nFor example, for the `setWallet(address _wallet)` function in the `SubscriptionManager`, the EIP712 type is `SetWallet(address wallet,bytes32 nonce,uint256 signatureExpiresAt)`. This function can only be called directly by the `owner` account or by using the `delegate` function with the following parameters (pseudo code):\n\n```js\n// Data to call the setWallet function normally\nconst data = abiEncode(setWalletSelector, _wallet);\n\n// Random value for replay protection\nconst nonce = randomBytes32();\n\n// Signature expiration\nconst signatureExpiresAt = now + signatureDuration;\n\n// Owner's signature\nconst signature = signTypedData({\n  account: owner,  \n  primaryType: \"SetWallet\", // The EIP712 type\n  domain: { \n    verifyingContract: manager.address\n  },\n  message: {\n    wallet: _wallet,\n    nonce,\n    signatureExpiresAt,\n  }\n});\n\n// Call setWallet through the delegate function\nawait manager.delegate(\n  data,\n  nonce,\n  signatureExpiresAt,\n  signature,\n  {\n    from: anyone\n  }\n);\n```\n\n### delegate function and signature checks\n\nThe `delegate` function performs the following steps:\n\n1. Reentrancy guard (`delegate` can only be called once in the same transaction).\n2. Check that the signature hasn't expired (`now < signatureExpiresAt`).\n3. Store the `nonce`, `signatureExpiresAt` and `signature` parameters.\n4. Call itself with the ABI encoded data (`address(this).call(data)`);\n5. Revert if the call failed.\n6. Delete the stored parameters.\n\nAs the delegation data exists in the storage while the call is being executed, the called function in the child contract can use the internal `_delegatedCheck(bytes32 typeHash, bytes data, bool usesNonce)` function to get the address of the caller. Internally, the `_delegatedCheck` checks if `msg.sender == this` and performs the signature validation using the provided type hash. If `msg.sender != this`, it just returns the `msg.sender`. It also stores the hashed data so it can't be used again for another delegated call.\n\n## Subscription Flow with Delegated Execution\n\nThe only function where delegated execution checks are done manually (doesn't use the `Delegated` functionality) is the `create` function, used to create subscriptions. The flow for creating a subscription works as follows:\n\n1. Subscriber calls the `approve` function in the token in which the subscription is denominated in to allow the manager contract to manipulate her funds.\n2. Using EIP 712, the subscriber signs the creation of a subscription (using the EIP712 type `CreateSubscription`) and sends the data to the `authorizer` server.\n3. The `authorizer` checks that the parameters are OK depending on its own rules, signs the data and sends the data and signatures to the relayer.\n3. The relayer executes the creation by calling the method `create()`, passing the parameters and signatures.\n4. At the beggining of each payment period, anyone can execute the subscription and bill the subscriber.\n\nFor subscription services created using Daisy the platform, Daisy will be the authorizer AND the relayer in this flow. We are also working on a system that will allow clients to be the authorizers by using webhooks (Daisy will request an authorizer signature for each subscription creation request).\n\n## Off-chain service flow\n\n#### Checking if the publisher needs to provide the service\n\n1. Receive request from subscriber.\n2. Call `subscriptionManager.nextPaymentTimestamp(subscriptionId)`.\n3. If `now < nextPaymentTimestamp`, answer the request.\n\n#### Executing subscriptions\n\nTo retrieve all subscription ids from the contract (Note: if count is too large, it is possible to obtain the ids in batches):\n1. Call `subscriptionManager.subscriptionCount()`.\n2. Call `subscriptionManager.subscriptionRange(0, count)`.\n\nTo execute a batch of subscriptions:\n1. Call `subscriptionManager.executeBatch(ids)`.\n2. The following events can be present in the transaction receipt, which can be used by the service to update its state:\n    * `SubscriptionNotFound(subscriptionId)`: Subscription doesn't exist in the contract.\n    * `SubscriptionNotReady(subscriptionId, nextPayment)`: Next payment timestamp hasn't been reached yet.\n    * `SubscriptionExecuted(subscriptionId, nextPayment)`: The subscription was executed successfuly.\n    * `SubscriptionDeleted(subscriptionId, reason)`: The subscription was deleted from the contract.\n\nThe `reason` parameter in the `SubscriptionDeleted` event can correspond to:\n* 0 (CANCELLED): The subscription was cancelled before the execution.\n* 1 (EXPIRED): The subscription reached its maxExecutions in the previous execution.\n* 2 (INVALID_STATE): The state was invalid during the execution. This happens if the subscription's plan was deleted.\n* 3 (NOT_ENOUGH_FUNDS): The subscriber address doesn't have or didn't approve enough funds to perform the execution.\n\nIf the `SubscriptionExecuted` event is present, the following two events can also be present, which represent token allocations (see next section):\n* `PaymentAllocated(subscriptionId, token, recipient, amount)`\n* `FeeAllocated(subscriptionId, token, recipient, amount)`\n\n## Token Allocations and Fees\n\nThe owner of a `SubscriptionManager` can optionally set a `fee` and a `feeRecipient` (which can be changed at any point in time). On each execution, the amount of tokens to be paid to the `feeRecipient` is calculated as `feeAmount = price * fee / MAX_FEE`, and the tokens to be paid to the publisher's `wallet` becomes `price - feeAmount`. `MAX_FEE` is a constant set to `100 * 10^18`, and `fee <= MAX_FEE` always.\n\nThe `SubscriptionManager` uses a pull payment model: on each execution, tokens are always transferred from the subscriber to the manager itself, and the manager allocates tokens to the current `feeRecipient` and `wallet` by storing their payments in the `availableFunds` mapping. When an allocation happens, the `FeeAllocated` event or the `PaymentAllocated` event will be emitted, specifying the `subscriptionId`, `token`, `recipient` and `amount`.\n\nAt any time, anyone can call the `withdraw(address[] tokens, address[] recipients)` function to transfer all the available tokens to each recipient specified in the parameters.\n\n## Key Differences Between Daisy and the Current EIP 1337 Proposal\n\n#### Subscriptions creation is not standardized\n\nBy not defining how the subscription must be created, we can support multiple different use cases (e.g. plan or tier based subscriptions, or subscriptions whose prices are determined by what feautures are turned on/off).\n\n#### Subscription data is stored in the contract\n\nThis makes interoperability with other contracts/services easier, without needing to rely on a centralized data source. Subscription data is removed from the contract if it can't be executed anymore or if the user doesn't have enough funds.\n\n#### Execution of a payment only requires specifying the subscription id\n\nThis allows for easier batching of executions and makes it easier for off-chain services to execute subscriptions.\n\n#### Delegated execution is not part of the interface\n\nIn order to be compatible with other proposals for standardizing delegated execution, the core functions don't need to support delegated execution.\n\n#### `isValidSubscription()` split into `isCancelled(subscriptionId)` and `nextPaymentTimestamp(subscriptionId)`\n\nInstead of having an `isValidSubscription()` function that returns a boolean, this implementation provides a `nextPaymentTimestamp()` function that returns the unix timestamp at which the next payment can be executed. This returned value is more usable than a boolean. On the other hand, with `isCancelled` one can get more granular information about a subscription, improving interoperability.\n\n# Testing\n\nTo run the tests, clone this repo and run `yarn install` to install dependencies.\n\nRun `yarn test` to run all tests.\n\nRun `yarn coverage` to run tests and get code coverage.\n","description":"[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repo","licenseText":"MIT License\n\nCopyright (c) 2019 Token Foundry\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@daisypayments/smart-contracts@0.2.0-beta.1","dist":{"shasum":"59d5f9c32075dc4926186738de296f735f44d3cf","integrity":"sha512-iH1oSFg1NYhRwLmxwnPTBfBYsXDnR/QBp0Tli+/jkAVraQbhSj2hJk55TuvShDglRlFFZmSqD34kc0yeLjY8Hg==","tarball":"https://registry.npmjs.org/@daisypayments/smart-contracts/-/smart-contracts-0.2.0-beta.1.tgz","fileCount":11,"unpackedSize":2800419,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdbrp1CRA9TVsSAnZWagAAhFsP/2IoBGbba6F0+Wyp7n6p\nwcOQavIZ3lRgO3w/UXabc8/nPVFnYNkxYfI543n6bibNVqv6znptQntfMYEQ\nFcLSvaJW4gDBd2KdVRJUnRLipHSSXVmZX0eMXRPNGbGzHMvbcsaW/uojTinT\nKSMdnB/Fhcm9V4Ta3cqUjnKnztiIxMyH49DrxwJfqi6lw2UUDa9WoWm2CNvE\nrXL7163uU0FiuHkGYm/S0oHEYfb9APfvDC3BM4tS74EKjHdiRedi1/uNmfw2\nOErRXowGf/lkJ85/bixvFmHS2VEuiyaPnBpjtQa3IBoJ9R1v1wm29u4PFrOL\n8AeplAcaYK0IE8pnHasMqAN6Q4jdf3S6M5wp7eLwzUzjA0je+iMGKR7YfaOl\nMlxJB9ZqNmoX5O5xWKtv3BAQCov1GM3ZDmgFAtFhIPMMy5EZJPuRrFs1T6FZ\njOTvfvZcNkyACRHcyJ92ZPFEA1BnESYoRiqTsrlHS58S4bud6N7+fUvn34tO\nNX3XX1MbY7VN4JflgJbdhoVIqwt67OpGiQSuF9gcRMgX96W3fS0Q+Os16peb\n9JGCIeAKZe5ty4C8OIpRIkkVs/NAiEQO1qhBVcFi4ddwK7cc+Ejikq7xl50A\nlv+4xEQ6H4/yvYcSCkJ4wCQfrA3ehvu3GFF3Bxqnkb2nYUONLF8KmhS6Qbzn\nmDIw\r\n=yFlK\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIQCO3lqbbL9ABKyPADIaX3xsVwY0ypiPMZQ6FwJYEYEw1AIfe8W5z+J/VcFOIqul/45VglO+Jk1KEFJndAt33O8W2w=="}]},"maintainers":[{"name":"jmoreira","email":"jmoreiras@gmail.com"},{"name":"lopezjurip","email":"lopezjuripatricio@gmail.com"},{"name":"nchastain","email":"nate.chastain@consensys.net"},{"name":"sloreti","email":"lhloreti@gmail.com"},{"name":"vdrg","email":"vdrg@protonmail.ch"},{"name":"wachunei","email":"wachunei@gmail.com"}],"_npmUser":{"name":"vdrg","email":"vdrg@protonmail.ch"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/smart-contracts_0.2.0-beta.1_1567537780457_0.6101786479278424"},"_hasShrinkwrap":false},"0.1.1":{"name":"@daisypayments/smart-contracts","version":"0.1.1","repository":{"type":"git","url":"https://github.com/consensys/daisy-subscription-contracts"},"author":{"name":"vdrg","email":"vicente.dragicevic@consensys.net"},"license":"MIT","main":"index.js","scripts":{"compile":"truffle compile","coverage":"./scripts/coverage.sh","exec":"truffle exec","ganache":"ganache-cli","docgen":"./scripts/docgen.sh","publish-docs":"./scripts/publish-docs.sh","prepublish":"yarn compile","lint":"solhint \"contracts/**/*.sol\"","migrate":"truffle migrate","test":"./scripts/test.sh"},"devDependencies":{"@daisypayments/eslint-config":"^1.5.1","bip39":"^2.5.0","bn.js":"^4.11.8","chai":"^4.2.0","coveralls":"^3.0.5","dotenv":"^6.2.0","eslint":"^5.13.0","eslint-config-prettier":"^4.0.0","eslint-plugin-mocha":"^5.2.1","eslint-plugin-prettier":"^3.0.1","eth-gas-reporter":"0.1.10","eth-sig-util":"^2.2.0","ethereumjs-abi":"^0.6.7","ethereumjs-util":"^6.1.0","ethereumjs-wallet":"^0.6.3","ganache-cli":"^6.4.4","lodash":"^4.17.11","moment":"^2.24.0","openzeppelin-solidity":"^2.3.0","openzeppelin-test-helpers":"^0.4.0","prettier":"^1.16.3","solhint":"^2.0.0","solidity-coverage":"^0.6.0","solidity-docgen":"^0.1.1","truffle":"^5.0.25","truffle-hdwallet-provider":"^1.0.4"},"description":"[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repo","licenseText":"MIT License\n\nCopyright (c) 2019 Token Foundry\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@daisypayments/smart-contracts@0.1.1","dist":{"shasum":"08910a4865479e366c59da81fba7724379b078a6","integrity":"sha512-78uQL93kP+n65fLj3+U5eLwhLwxV1pwoRXNqeNtVGSPxZFS7tDTrgPTN0zQKGuxpBed5U+yUWKqkAglYG9SpHg==","tarball":"https://registry.npmjs.org/@daisypayments/smart-contracts/-/smart-contracts-0.1.1.tgz","fileCount":9,"unpackedSize":2595163,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdcBGeCRA9TVsSAnZWagAAisoP/jvwH3X41pAJA74kyaZ2\n2LB/296hwCi6I48MRImujeA6lBt+N/F+4ehquswoUtNlwyzqbE4nkDSgS2xS\n8AbkDkv3uIhR2flFDgo7XsTIP3P0a5YQFfTggZ22+SFeY1T5dB7vUJE7MVzN\nodvaVA/bj18P+2XqB9rsEzkdSnoKBiC1a5NAUEjBCBpbHGXr9KYBDGDNBheJ\nsVtfT31Q4to6r/HPnCWeDdoZeYgR8E03KEO5RdCxchzbZzFFFOPfFIGAnzC/\nkpDcZLwpDC7uC2I8ZQUDHqvDOXCssO9P5RfPk6k78/ru8caF3DQ6/k0WM46L\n2xEd9ZjMUmij9EEaTYAsQsASsViNEeNyA8gVn60KBLJLeLXVTpv0RgXuOXGg\nt0kTrHtLVNFzjQQuW30UBYcTMYkLVgKtyhCVlnGzQZGzlZ7ygxbc1VV+kAT3\nJTqYsf6lgwcidOEPB9ApOkrJ/WFDjBdG1H2oqXgUl1FdS3jk2BvSGlLzoBAD\nHBH9Q8Hsdj0mnYvtNMFm+EpENYBtJ7MZKNQ87Y/ilHCtYCiCM95jfuSyyQUW\nzsdhyfyNBeNEVu3faviEEl4HuQo9VmGvSu09T8QJH2OQq4n9odML8MOEtgsl\ncHh+SqQfNWY8EWzPQJIBCmyviwLutCAzPuk/UocM2eBj7CWK/KXZAD44q2Gh\nRBxg\r\n=2r6s\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCID1Z+ksDxK29gQEe/he6cT48QuQxinFGNrBsMfx6+Pt9AiAeG+t/1lmSACAbQHflfTiWoPCAh/SG4OtGs4zDNCj29Q=="}]},"maintainers":[{"name":"jmoreira","email":"jmoreiras@gmail.com"},{"name":"lopezjurip","email":"lopezjuripatricio@gmail.com"},{"name":"nchastain","email":"nate.chastain@consensys.net"},{"name":"sloreti","email":"lhloreti@gmail.com"},{"name":"vdrg","email":"vdrg@protonmail.ch"},{"name":"wachunei","email":"wachunei@gmail.com"}],"_npmUser":{"name":"vdrg","email":"vdrg@protonmail.ch"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/smart-contracts_0.1.1_1567625629752_0.9510804991580706"},"_hasShrinkwrap":false},"0.2.0-beta.2":{"name":"@daisypayments/smart-contracts","version":"0.2.0-beta.2","repository":{"type":"git","url":"https://github.com/consensys/daisy-subscription-contracts"},"author":{"name":"vdrg","email":"vicente.dragicevic@consensys.net"},"license":"MIT","main":"index.js","scripts":{"compile":"truffle compile","coverage":"./scripts/coverage.sh","exec":"truffle exec","ganache":"ganache-cli","docgen":"./scripts/docgen.sh","publish-docs":"./scripts/publish-docs.sh","prepublish":"yarn compile","lint":"solhint \"contracts/**/*.sol\"","migrate":"truffle migrate","test":"./scripts/test.sh"},"devDependencies":{"@daisypayments/eslint-config":"^1.5.1","bip39":"^2.5.0","bn.js":"^4.11.8","chai":"^4.2.0","coveralls":"^3.0.5","dotenv":"^6.2.0","eslint":"^5.13.0","eslint-config-prettier":"^4.0.0","eslint-plugin-mocha":"^5.2.1","eslint-plugin-prettier":"^3.0.1","eth-gas-reporter":"0.1.10","eth-sig-util":"^2.2.0","ethereumjs-abi":"^0.6.7","ethereumjs-util":"^6.1.0","ethereumjs-wallet":"^0.6.3","ganache-cli":"^6.4.4","lodash":"^4.17.11","moment":"^2.24.0","openzeppelin-solidity":"^2.3.0","openzeppelin-test-helpers":"^0.4.0","prettier":"^1.16.3","solhint":"^2.0.0","solidity-coverage":"^0.6.0","solidity-docgen":"^0.1.1","truffle":"^5.0.25","truffle-hdwallet-provider":"^1.0.4"},"readmeFilename":"README.md","readme":"# Daisy Contracts\n\n[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repos/github/ConsenSys/daisy-subscription-contracts/badge.svg?t=wmZqvk)](https://coveralls.io/github/ConsenSys/daisy-subscription-contracts)\n\n## Overview\n\n### Subscriptions\n\nA subscription is composed of:\n\n* subscriber: address from which tokens will be transferred from.\n* token: address of the ERC 20 token that the subscription is denominated in.\n* price: number of tokens to transfer in each payment.\n* periodUnit: \"DAY\", \"MONTH\", or \"YEAR\".\n* periods: number of period units between payments.\n* maxExecutions: max number of payments that can be made before the subscriber must manually renew their subscription. If this value is 0, there is no execution limit.\n* planIdHash: the hash of the id of the plan the subscription belongs to.\n* credits: amount of tokens to substract from future payments. On each payment, these credits get consumed until they get to 0.\n\nA subscription can be in one of four states:\n1. Active: Once it has been executed and the next payment is in the future. A subscription is first executed upon its creation.\n2. Active and Cancelled: When it is cancelled before reaching the next payment timestamp. It will remain active until the end of the period.\n3. Cancelled: when it has been cancelled and the last billed period has ended.\n4. Deleted: the subscription data will be deleted upon execution if the subscription can't be executed anymore.\n\n### Plans\n\nA plan is just a way to group multiple subscriptions, and allows the publisher to cancel a group of subscriptions at once. A plan is identified in the contract by a bytes32. When a plan based subscription is created, it is necessary to specify the plan's identifier, and the creation only goes through if a valid authorization signature is provided.\n\nThe contract provides a function to delete a plan by providing the plan on chain id. All subscriptions with that plan get invalidated (they get deleted on the next execution).\n\n## Contracts\n\n### `SubscriptionManager.sol`\n\nHandles the creation, execution, and cancellation of subscriptions.\n\nIt also provides methods for enumerating subscriptions and subscription by subscriber. This implementation was adapted from OpenZeppelin's `EIP721Enumerable` [implementation](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC721/ERC721Enumerable.sol).\n\n### `IndexedArrayLib.sol`\n\nLibrary that provides an indexed array of bytes32. It allows us to remove items from the array by specifying the item itself that we want to remove.\n\n### `Delegated.sol`\n\nAllows child contracts to support delegated execution without changing their external APIs. See Delegation section.\n\n## Time\n\nTo support different time units (days, months and years) we use [BokkyPooBah's Date Time Library](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary).\n\n## Delegation\n\nIn order to support delegated execution through the use of EIP712 signatures, the `SubscriptionManager` inherits from `Delegated`. The key feature of the `Delegated` contract is that child contracts don't need to polute their APIs with parameters related to delegated execution.\n\nThe `Delegated` contract exposes the external `delegate` function which receives the following parameters:\n\n* `bytes data`: ABI encoded data to be used for the delegated call.\n* `bytes32 nonce`: Random value for replay protection. If the function to call is idempotent, this value is optional.\n* `uint256 signatureExpiresAt`: Timestamp in which the signature stops being valid.\n* `bytes signature`: The signature for the EIP712 type.\n\nFor example, for the `setWallet(address _wallet)` function in the `SubscriptionManager`, the EIP712 type is `SetWallet(address wallet,bytes32 nonce,uint256 signatureExpiresAt)`. This function can only be called directly by the `owner` account or by using the `delegate` function with the following parameters (pseudo code):\n\n```js\n// Data to call the setWallet function normally\nconst data = abiEncode(setWalletSelector, _wallet);\n\n// Random value for replay protection\nconst nonce = randomBytes32();\n\n// Signature expiration\nconst signatureExpiresAt = now + signatureDuration;\n\n// Owner's signature\nconst signature = signTypedData({\n  account: owner,  \n  primaryType: \"SetWallet\", // The EIP712 type\n  domain: { \n    verifyingContract: manager.address\n  },\n  message: {\n    wallet: _wallet,\n    nonce,\n    signatureExpiresAt,\n  }\n});\n\n// Call setWallet through the delegate function\nawait manager.delegate(\n  data,\n  nonce,\n  signatureExpiresAt,\n  signature,\n  {\n    from: anyone\n  }\n);\n```\n\n### delegate function and signature checks\n\nThe `delegate` function performs the following steps:\n\n1. Reentrancy guard (`delegate` can only be called once in the same transaction).\n2. Check that the signature hasn't expired (`now < signatureExpiresAt`).\n3. Store the `nonce`, `signatureExpiresAt` and `signature` parameters.\n4. Call itself with the ABI encoded data (`address(this).call(data)`);\n5. Revert if the call failed.\n6. Delete the stored parameters.\n\nAs the delegation data exists in the storage while the call is being executed, the called function in the child contract can use the internal `_delegatedCheck(bytes32 typeHash, bytes data, bool usesNonce)` function to get the address of the caller. Internally, the `_delegatedCheck` checks if `msg.sender == this` and performs the signature validation using the provided type hash. If `msg.sender != this`, it just returns the `msg.sender`. It also stores the hashed data so it can't be used again for another delegated call.\n\n## Subscription Flow with Delegated Execution\n\nThe only function where delegated execution checks are done manually (doesn't use the `Delegated` functionality) is the `create` function, used to create subscriptions. The flow for creating a subscription works as follows:\n\n1. Subscriber calls the `approve` function in the token in which the subscription is denominated in to allow the manager contract to manipulate her funds.\n2. Using EIP 712, the subscriber signs the creation of a subscription (using the EIP712 type `CreateSubscription`) and sends the data to the `authorizer` server.\n3. The `authorizer` checks that the parameters are OK depending on its own rules, signs the data and sends the data and signatures to the relayer.\n3. The relayer executes the creation by calling the method `create()`, passing the parameters and signatures.\n4. At the beggining of each payment period, anyone can execute the subscription and bill the subscriber.\n\nFor subscription services created using Daisy the platform, Daisy will be the authorizer AND the relayer in this flow. We are also working on a system that will allow clients to be the authorizers by using webhooks (Daisy will request an authorizer signature for each subscription creation request).\n\n## Off-chain service flow\n\n#### Checking if the publisher needs to provide the service\n\n1. Receive request from subscriber.\n2. Call `subscriptionManager.nextPaymentTimestamp(subscriptionId)`.\n3. If `now < nextPaymentTimestamp`, answer the request.\n\n#### Executing subscriptions\n\nTo retrieve all subscription ids from the contract (Note: if count is too large, it is possible to obtain the ids in batches):\n1. Call `subscriptionManager.subscriptionCount()`.\n2. Call `subscriptionManager.subscriptionRange(0, count)`.\n\nTo execute a batch of subscriptions:\n1. Call `subscriptionManager.executeBatch(ids)`.\n2. The following events can be present in the transaction receipt, which can be used by the service to update its state:\n    * `SubscriptionNotFound(subscriptionId)`: Subscription doesn't exist in the contract.\n    * `SubscriptionNotReady(subscriptionId, nextPayment)`: Next payment timestamp hasn't been reached yet.\n    * `SubscriptionExecuted(subscriptionId, nextPayment)`: The subscription was executed successfuly.\n    * `SubscriptionDeleted(subscriptionId, reason)`: The subscription was deleted from the contract.\n\nThe `reason` parameter in the `SubscriptionDeleted` event can correspond to:\n* 0 (CANCELLED): The subscription was cancelled before the execution.\n* 1 (EXPIRED): The subscription reached its maxExecutions in the previous execution.\n* 2 (INVALID_STATE): The state was invalid during the execution. This happens if the subscription's plan was deleted.\n* 3 (NOT_ENOUGH_FUNDS): The subscriber address doesn't have or didn't approve enough funds to perform the execution.\n\nIf the `SubscriptionExecuted` event is present, the following two events can also be present, which represent token allocations (see next section):\n* `PaymentAllocated(subscriptionId, token, recipient, amount)`\n* `FeeAllocated(subscriptionId, token, recipient, amount)`\n\n## Token Allocations and Fees\n\nThe owner of a `SubscriptionManager` can optionally set a `fee` and a `feeRecipient` (which can be changed at any point in time). On each execution, the amount of tokens to be paid to the `feeRecipient` is calculated as `feeAmount = price * fee / MAX_FEE`, and the tokens to be paid to the publisher's `wallet` becomes `price - feeAmount`. `MAX_FEE` is a constant set to `100 * 10^18`, and `fee <= MAX_FEE` always.\n\nThe `SubscriptionManager` uses a pull payment model: on each execution, tokens are always transferred from the subscriber to the manager itself, and the manager allocates tokens to the current `feeRecipient` and `wallet` by storing their payments in the `availableFunds` mapping. When an allocation happens, the `FeeAllocated` event or the `PaymentAllocated` event will be emitted, specifying the `subscriptionId`, `token`, `recipient` and `amount`.\n\nAt any time, anyone can call the `withdraw(address[] tokens, address[] recipients)` function to transfer all the available tokens to each recipient specified in the parameters.\n\n## Key Differences Between Daisy and the Current EIP 1337 Proposal\n\n#### Subscriptions creation is not standardized\n\nBy not defining how the subscription must be created, we can support multiple different use cases (e.g. plan or tier based subscriptions, or subscriptions whose prices are determined by what feautures are turned on/off).\n\n#### Subscription data is stored in the contract\n\nThis makes interoperability with other contracts/services easier, without needing to rely on a centralized data source. Subscription data is removed from the contract if it can't be executed anymore or if the user doesn't have enough funds.\n\n#### Execution of a payment only requires specifying the subscription id\n\nThis allows for easier batching of executions and makes it easier for off-chain services to execute subscriptions.\n\n#### Delegated execution is not part of the interface\n\nIn order to be compatible with other proposals for standardizing delegated execution, the core functions don't need to support delegated execution.\n\n#### `isValidSubscription()` split into `isCancelled(subscriptionId)` and `nextPaymentTimestamp(subscriptionId)`\n\nInstead of having an `isValidSubscription()` function that returns a boolean, this implementation provides a `nextPaymentTimestamp()` function that returns the unix timestamp at which the next payment can be executed. This returned value is more usable than a boolean. On the other hand, with `isCancelled` one can get more granular information about a subscription, improving interoperability.\n\n# Testing\n\nTo run the tests, clone this repo and run `yarn install` to install dependencies.\n\nRun `yarn test` to run all tests.\n\nRun `yarn coverage` to run tests and get code coverage.\n","description":"[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repo","licenseText":"MIT License\n\nCopyright (c) 2019 Token Foundry\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@daisypayments/smart-contracts@0.2.0-beta.2","dist":{"shasum":"3240cd2caae039ab2f95c597020efa82a73baa02","integrity":"sha512-R1W8K3jjMmqem/KbhidyG8UOJaewtzEiC+68hsqtRuYdMRkUN2cVtKtG9GlsvFmmE4CNhahJ5UhzS79OSOlnaw==","tarball":"https://registry.npmjs.org/@daisypayments/smart-contracts/-/smart-contracts-0.2.0-beta.2.tgz","fileCount":11,"unpackedSize":2800078,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdcsZJCRA9TVsSAnZWagAA12EP/AsWQxHANnlo4XJCeByH\n3QhVWEOqncoQp4Iqr0iIAXx++qQLYD65Fx+WVu0FKGFkrO10v8d8RvHo1w3O\nkPQ/8Dy3XICCSLCcfd4gGE4rYGWbZiM2yf6ayuYcYP6RlYfaODKn4itAjFs2\nWHhgLdxiMMoaucUB7YAEypcOtRxdCG7v9pCmcoR+lBIXY1Dc3nR76gjL8uEA\nKghBJ18XS39Em8u8vMd/DimabcIew10romERKbXccMjSmTMUvtOrnyZcUANo\nVS8VI+VUKLR0H/pZc8MvLkREYSKFtea9ke4gcohjfv2inhtpcs6ia18+oFZg\nbR7FEEI2vl0GKllgZSIeArprKlWzGDwY9heh7TQBwtAHg3cl3jCp4nulDvQ8\nCgIYA+18z2QfugL+k14tBv445SqcFmyHP/afvzNdwkXUUTtILiC3RBLvWTJj\n+FxVsmiE7QDmrb4QRQJMKKsE1zNjJrO88V2gzKOXoVtuA+rPl7hOoU9e7ccX\n2ti3tvdyXc59NbtDBsx2UVmEe64cfRWftMhqnL4E1LbTqIZPqZhKzPBBT+hO\nZbegaGCBK1ZbvSSxUVn/tV5Acpo9oUlDA4MF1lcJmsOesXHhAhs0C6L2GlZ3\nBFsMgcKVScC/mEcNBs9NziYU935q8c7surv8UZmhE1bR8BMXO2p9zo431eAh\nQ2Si\r\n=HNfJ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCuk9Yz159BWSaJqN++lzCB80XKQJBkIa0sfx/9PYWlpwIgdnXrtZ0Ft76KKBu0kcdrKgyr+WDF/niCfP/cZCE4NbA="}]},"maintainers":[{"name":"jmoreira","email":"jmoreiras@gmail.com"},{"name":"lopezjurip","email":"lopezjuripatricio@gmail.com"},{"name":"nchastain","email":"nate.chastain@consensys.net"},{"name":"sloreti","email":"lhloreti@gmail.com"},{"name":"vdrg","email":"vdrg@protonmail.ch"},{"name":"wachunei","email":"wachunei@gmail.com"}],"_npmUser":{"name":"vdrg","email":"vdrg@protonmail.ch"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/smart-contracts_0.2.0-beta.2_1567802953061_0.11301999667070572"},"_hasShrinkwrap":false},"0.2.0-beta.3":{"name":"@daisypayments/smart-contracts","version":"0.2.0-beta.3","repository":{"type":"git","url":"https://github.com/consensys/daisy-subscription-contracts"},"author":{"name":"vdrg","email":"vicente.dragicevic@consensys.net"},"license":"MIT","main":"index.js","scripts":{"compile":"truffle compile","coverage":"./scripts/coverage.sh","exec":"truffle exec","ganache":"ganache-cli","docgen":"./scripts/docgen.sh","publish-docs":"./scripts/publish-docs.sh","prepublish":"yarn compile","lint":"solhint \"contracts/**/*.sol\"","migrate":"truffle migrate","test":"./scripts/test.sh"},"devDependencies":{"@daisypayments/eslint-config":"^1.5.1","bip39":"^2.5.0","bn.js":"^4.11.8","chai":"^4.2.0","coveralls":"^3.0.5","dotenv":"^6.2.0","eslint":"^5.13.0","eslint-config-prettier":"^4.0.0","eslint-plugin-mocha":"^5.2.1","eslint-plugin-prettier":"^3.0.1","eth-gas-reporter":"0.1.10","eth-sig-util":"^2.2.0","ethereumjs-abi":"^0.6.7","ethereumjs-util":"^6.1.0","ethereumjs-wallet":"^0.6.3","ganache-cli":"^6.4.4","lodash":"^4.17.11","moment":"^2.24.0","openzeppelin-solidity":"^2.3.0","openzeppelin-test-helpers":"^0.4.0","prettier":"^1.16.3","solhint":"^2.0.0","solidity-coverage":"^0.6.0","solidity-docgen":"^0.1.1","truffle":"^5.0.25","truffle-hdwallet-provider":"^1.0.4"},"readmeFilename":"README.md","readme":"# Daisy Contracts\n\n[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repos/github/ConsenSys/daisy-subscription-contracts/badge.svg?t=wmZqvk)](https://coveralls.io/github/ConsenSys/daisy-subscription-contracts)\n\n## Overview\n\n### Subscriptions\n\nA subscription is composed of:\n\n* subscriber: address from which tokens will be transferred from.\n* token: address of the ERC 20 token that the subscription is denominated in.\n* price: number of tokens to transfer in each payment.\n* periodUnit: \"DAY\", \"MONTH\", or \"YEAR\".\n* periods: number of period units between payments.\n* maxExecutions: max number of payments that can be made before the subscriber must manually renew their subscription. If this value is 0, there is no execution limit.\n* planIdHash: the hash of the id of the plan the subscription belongs to.\n* credits: amount of tokens to substract from future payments. On each payment, these credits get consumed until they get to 0.\n\nA subscription can be in one of four states:\n1. Active: Once it has been executed and the next payment is in the future. A subscription is first executed upon its creation.\n2. Active and Cancelled: When it is cancelled before reaching the next payment timestamp. It will remain active until the end of the period.\n3. Cancelled: when it has been cancelled and the last billed period has ended.\n4. Deleted: the subscription data will be deleted upon execution if the subscription can't be executed anymore.\n\n### Plans\n\nA plan is just a way to group multiple subscriptions, and allows the publisher to cancel a group of subscriptions at once. A plan is identified in the contract by a bytes32. When a plan based subscription is created, it is necessary to specify the plan's identifier, and the creation only goes through if a valid authorization signature is provided.\n\nThe contract provides a function to delete a plan by providing the plan on chain id. All subscriptions with that plan get invalidated (they get deleted on the next execution).\n\n## Contracts\n\n### `SubscriptionManager.sol`\n\nHandles the creation, execution, and cancellation of subscriptions.\n\nIt also provides methods for enumerating subscriptions and subscription by subscriber. This implementation was adapted from OpenZeppelin's `EIP721Enumerable` [implementation](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC721/ERC721Enumerable.sol).\n\n### `IndexedArrayLib.sol`\n\nLibrary that provides an indexed array of bytes32. It allows us to remove items from the array by specifying the item itself that we want to remove.\n\n### `Delegated.sol`\n\nAllows child contracts to support delegated execution without changing their external APIs. See Delegation section.\n\n## Time\n\nTo support different time units (days, months and years) we use [BokkyPooBah's Date Time Library](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary).\n\n## Delegation\n\nIn order to support delegated execution through the use of EIP712 signatures, the `SubscriptionManager` inherits from `Delegated`. The key feature of the `Delegated` contract is that child contracts don't need to polute their APIs with parameters related to delegated execution.\n\nThe `Delegated` contract exposes the external `delegate` function which receives the following parameters:\n\n* `bytes data`: ABI encoded data to be used for the delegated call.\n* `bytes32 nonce`: Random value for replay protection. If the function to call is idempotent, this value is optional.\n* `uint256 signatureExpiresAt`: Timestamp in which the signature stops being valid.\n* `bytes signature`: The signature for the EIP712 type.\n\nFor example, for the `setWallet(address _wallet)` function in the `SubscriptionManager`, the EIP712 type is `SetWallet(address wallet,bytes32 nonce,uint256 signatureExpiresAt)`. This function can only be called directly by the `owner` account or by using the `delegate` function with the following parameters (pseudo code):\n\n```js\n// Data to call the setWallet function normally\nconst data = abiEncode(setWalletSelector, _wallet);\n\n// Random value for replay protection\nconst nonce = randomBytes32();\n\n// Signature expiration\nconst signatureExpiresAt = now + signatureDuration;\n\n// Owner's signature\nconst signature = signTypedData({\n  account: owner,  \n  primaryType: \"SetWallet\", // The EIP712 type\n  domain: { \n    verifyingContract: manager.address\n  },\n  message: {\n    wallet: _wallet,\n    nonce,\n    signatureExpiresAt,\n  }\n});\n\n// Call setWallet through the delegate function\nawait manager.delegate(\n  data,\n  nonce,\n  signatureExpiresAt,\n  signature,\n  {\n    from: anyone\n  }\n);\n```\n\n### delegate function and signature checks\n\nThe `delegate` function performs the following steps:\n\n1. Reentrancy guard (`delegate` can only be called once in the same transaction).\n2. Check that the signature hasn't expired (`now < signatureExpiresAt`).\n3. Store the `nonce`, `signatureExpiresAt` and `signature` parameters.\n4. Call itself with the ABI encoded data (`address(this).call(data)`);\n5. Revert if the call failed.\n6. Delete the stored parameters.\n\nAs the delegation data exists in the storage while the call is being executed, the called function in the child contract can use the internal `_delegatedCheck(bytes32 typeHash, bytes data, bool usesNonce)` function to get the address of the caller. Internally, the `_delegatedCheck` checks if `msg.sender == this` and performs the signature validation using the provided type hash. If `msg.sender != this`, it just returns the `msg.sender`. It also stores the hashed data so it can't be used again for another delegated call.\n\n## Subscription Flow with Delegated Execution\n\nThe only function where delegated execution checks are done manually (doesn't use the `Delegated` functionality) is the `create` function, used to create subscriptions. The flow for creating a subscription works as follows:\n\n1. Subscriber calls the `approve` function in the token in which the subscription is denominated in to allow the manager contract to manipulate her funds.\n2. Using EIP 712, the subscriber signs the creation of a subscription (using the EIP712 type `CreateSubscription`) and sends the data to the `authorizer` server.\n3. The `authorizer` checks that the parameters are OK depending on its own rules, signs the data and sends the data and signatures to the relayer.\n3. The relayer executes the creation by calling the method `create()`, passing the parameters and signatures.\n4. At the beggining of each payment period, anyone can execute the subscription and bill the subscriber.\n\nFor subscription services created using Daisy the platform, Daisy will be the authorizer AND the relayer in this flow. We are also working on a system that will allow clients to be the authorizers by using webhooks (Daisy will request an authorizer signature for each subscription creation request).\n\n## Off-chain service flow\n\n#### Checking if the publisher needs to provide the service\n\n1. Receive request from subscriber.\n2. Call `subscriptionManager.nextPaymentTimestamp(subscriptionId)`.\n3. If `now < nextPaymentTimestamp`, answer the request.\n\n#### Executing subscriptions\n\nTo retrieve all subscription ids from the contract (Note: if count is too large, it is possible to obtain the ids in batches):\n1. Call `subscriptionManager.subscriptionCount()`.\n2. Call `subscriptionManager.subscriptionRange(0, count)`.\n\nTo execute a batch of subscriptions:\n1. Call `subscriptionManager.executeBatch(ids)`.\n2. The following events can be present in the transaction receipt, which can be used by the service to update its state:\n    * `SubscriptionNotFound(subscriptionId)`: Subscription doesn't exist in the contract.\n    * `SubscriptionNotReady(subscriptionId, nextPayment)`: Next payment timestamp hasn't been reached yet.\n    * `SubscriptionExecuted(subscriptionId, nextPayment)`: The subscription was executed successfuly.\n    * `SubscriptionDeleted(subscriptionId, reason)`: The subscription was deleted from the contract.\n\nThe `reason` parameter in the `SubscriptionDeleted` event can correspond to:\n* 0 (CANCELLED): The subscription was cancelled before the execution.\n* 1 (EXPIRED): The subscription reached its maxExecutions in the previous execution.\n* 2 (INVALID_STATE): The state was invalid during the execution. This happens if the subscription's plan was deleted.\n* 3 (NOT_ENOUGH_FUNDS): The subscriber address doesn't have or didn't approve enough funds to perform the execution.\n\nIf the `SubscriptionExecuted` event is present, the following two events can also be present, which represent token allocations (see next section):\n* `PaymentAllocated(subscriptionId, token, recipient, amount)`\n* `FeeAllocated(subscriptionId, token, recipient, amount)`\n\n## Token Allocations and Fees\n\nThe owner of a `SubscriptionManager` can optionally set a `fee` and a `feeRecipient` (which can be changed at any point in time). On each execution, the amount of tokens to be paid to the `feeRecipient` is calculated as `feeAmount = price * fee / MAX_FEE`, and the tokens to be paid to the publisher's `wallet` becomes `price - feeAmount`. `MAX_FEE` is a constant set to `100 * 10^18`, and `fee <= MAX_FEE` always.\n\nThe `SubscriptionManager` uses a pull payment model: on each execution, tokens are always transferred from the subscriber to the manager itself, and the manager allocates tokens to the current `feeRecipient` and `wallet` by storing their payments in the `availableFunds` mapping. When an allocation happens, the `FeeAllocated` event or the `PaymentAllocated` event will be emitted, specifying the `subscriptionId`, `token`, `recipient` and `amount`.\n\nAt any time, anyone can call the `withdraw(address[] tokens, address[] recipients)` function to transfer all the available tokens to each recipient specified in the parameters.\n\n## Key Differences Between Daisy and the Current EIP 1337 Proposal\n\n#### Subscriptions creation is not standardized\n\nBy not defining how the subscription must be created, we can support multiple different use cases (e.g. plan or tier based subscriptions, or subscriptions whose prices are determined by what feautures are turned on/off).\n\n#### Subscription data is stored in the contract\n\nThis makes interoperability with other contracts/services easier, without needing to rely on a centralized data source. Subscription data is removed from the contract if it can't be executed anymore or if the user doesn't have enough funds.\n\n#### Execution of a payment only requires specifying the subscription id\n\nThis allows for easier batching of executions and makes it easier for off-chain services to execute subscriptions.\n\n#### Delegated execution is not part of the interface\n\nIn order to be compatible with other proposals for standardizing delegated execution, the core functions don't need to support delegated execution.\n\n#### `isValidSubscription()` split into `isCancelled(subscriptionId)` and `nextPaymentTimestamp(subscriptionId)`\n\nInstead of having an `isValidSubscription()` function that returns a boolean, this implementation provides a `nextPaymentTimestamp()` function that returns the unix timestamp at which the next payment can be executed. This returned value is more usable than a boolean. On the other hand, with `isCancelled` one can get more granular information about a subscription, improving interoperability.\n\n# Testing\n\nTo run the tests, clone this repo and run `yarn install` to install dependencies.\n\nRun `yarn test` to run all tests.\n\nRun `yarn coverage` to run tests and get code coverage.\n","description":"[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repo","licenseText":"MIT License\n\nCopyright (c) 2019 Token Foundry\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@daisypayments/smart-contracts@0.2.0-beta.3","dist":{"shasum":"096c4d11abdee3960b4d8fe6ab96d74feddb2517","integrity":"sha512-IQrjL9FYehZn0IsTc7wgdEa+yxsNVb0ticPU2vymaxH4WRYnmppNQKnlHG6Dvq6pBBLpoBUlsvIY5xUiJ9Jakg==","tarball":"https://registry.npmjs.org/@daisypayments/smart-contracts/-/smart-contracts-0.2.0-beta.3.tgz","fileCount":12,"unpackedSize":2851886,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdkmEmCRA9TVsSAnZWagAAxgAP/25YdAGBv6lt2k/vyJDT\nJHQ28Ucwgm4jVSnlTInSSp58ZOcVTxsZfbocg/jsYQv9fne0oAN2fQeu3yR2\nN82f42TKPkFFQapr5oSCGJavnEZgfXN4rJpDPoLEkQWhIlCWyZtc07IWfRw0\niFP9aor1RFyzCPIvvKtJRm4sXshqUsGb3wLnUMR/H+mEHurnL9dVpQDjAQ9o\nxY9Ql5MhrC87R8GN+HCbqeHYzrXumPOiXK5Kf5tHciEKcso4g0D1mS9wUFb2\nvPdtY01mnPMqySzy8WOLJePAPDmNpsoAGf9jDAj1ybMFcl9N/bcC1+xgb4R6\n8f3yUk0rtXRXr6nrQwdjB4yZPvKFqLV1MhPHmjNDL8X9UEYJloeVu/AlSrzI\n5do6ZVUggIw7J7x0Cia7D+ihMWtjaEvkHwWYiBPGwp/aagjIsFbSimGMjHce\nu/j69NHAQNpdgttgorXOb40jr4NO6raGqOIEyi/Ad7cguTP5r1py0erXgnGU\nm17AGjJFNQ/9w1HBz5uyjfIEPXSsovG9U8vyToWbKM99BmJAQF65FFw9cpnB\nGgDqBdz+Nf3Yw12vTN2i8hkL+oMhwUI3KHc6n9GxyTiyZrt3BMUuhjWlh0ys\nni4BCpSsPuv/92S3oWGTpNIMU4fyPEA09NVpUFZRaI2wVgZ0wrnA61Gd7Sbb\nemaw\r\n=Pdza\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICNYsis9TnwAMAVcXt9FDQpVguCjkoGRF+LDXWAsqTOUAiEA2LU6byduYTegs1HOiYGW4675Vmo2HnE10VIjvhy8CIg="}]},"maintainers":[{"name":"jmoreira","email":"jmoreiras@gmail.com"},{"name":"lopezjurip","email":"lopezjuripatricio@gmail.com"},{"name":"nchastain","email":"nate.chastain@consensys.net"},{"name":"sloreti","email":"lhloreti@gmail.com"},{"name":"vdrg","email":"vdrg@protonmail.ch"},{"name":"wachunei","email":"wachunei@gmail.com"}],"_npmUser":{"name":"vdrg","email":"vdrg@protonmail.ch"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/smart-contracts_0.2.0-beta.3_1569874213605_0.5411352519375263"},"_hasShrinkwrap":false},"0.3.0-beta.1":{"name":"@daisypayments/smart-contracts","version":"0.3.0-beta.1","repository":{"type":"git","url":"https://github.com/consensys/daisy-subscription-contracts"},"author":{"name":"vdrg","email":"vicente.dragicevic@consensys.net"},"license":"MIT","main":"index.js","scripts":{"compile":"truffle compile","coverage":"./scripts/coverage.sh","exec":"truffle exec","ganache":"ganache-cli","docgen":"./scripts/docgen.sh","publish-docs":"./scripts/publish-docs.sh","prepublish":"yarn compile","lint":"solhint \"contracts/**/*.sol\"","migrate":"truffle migrate","test":"./scripts/test.sh"},"devDependencies":{"@daisypayments/eslint-config":"^1.5.1","@openzeppelin/test-helpers":"^0.5.3","bip39":"^2.5.0","bn.js":"^4.11.8","chai":"^4.2.0","coveralls":"^3.0.5","dotenv":"^6.2.0","eslint":"^5.13.0","eslint-config-prettier":"^4.0.0","eslint-plugin-mocha":"^5.2.1","eslint-plugin-prettier":"^3.0.1","eth-gas-reporter":"^0.2.12","eth-sig-util":"^2.2.0","ethereumjs-abi":"^0.6.7","ethereumjs-util":"^6.1.0","ethereumjs-wallet":"^0.6.3","ganache-cli":"^6.4.4","lodash":"^4.17.11","moment":"^2.24.0","openzeppelin-solidity":"^2.3.0","openzeppelin-test-helpers":"^0.4.0","prettier":"^1.16.3","solhint":"^2.0.0","solidity-coverage":"^0.6.7","solidity-docgen":"^0.1.1","truffle":"^5.0.25","truffle-hdwallet-provider":"^1.0.4"},"readmeFilename":"README.md","readme":"# Daisy Contracts\n\n[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repos/github/ConsenSys/daisy-subscription-contracts/badge.svg?t=wmZqvk)](https://coveralls.io/github/ConsenSys/daisy-subscription-contracts)\n\n## Overview\n\n### Subscriptions\n\nA subscription is composed of:\n\n* subscriber: address from which tokens will be transferred from.\n* token: address of the ERC 20 token that the subscription is denominated in.\n* price: number of tokens to transfer in each payment.\n* periodUnit: \"DAY\", \"MONTH\", or \"YEAR\".\n* periods: number of period units between payments.\n* maxExecutions: max number of payments that can be made before the subscriber must manually renew their subscription. If this value is 0, there is no execution limit.\n* planIdHash: the hash of the id of the plan the subscription belongs to.\n* credits: amount of tokens to substract from future payments. On each payment, these credits get consumed until they get to 0.\n\nA subscription can be in one of four states:\n1. Active: Once it has been executed and the next payment is in the future. A subscription is first executed upon its creation.\n2. Active and Cancelled: When it is cancelled before reaching the next payment timestamp. It will remain active until the end of the period.\n3. Cancelled: when it has been cancelled and the last billed period has ended.\n4. Deleted: the subscription data will be deleted upon execution if the subscription can't be executed anymore.\n\n### Plans\n\nA plan is just a way to group multiple subscriptions, and allows the publisher to cancel a group of subscriptions at once. A plan is identified in the contract by a bytes32. When a plan based subscription is created, it is necessary to specify the plan's identifier, and the creation only goes through if a valid authorization signature is provided.\n\nThe contract provides a function to delete a plan by providing the plan on chain id. All subscriptions with that plan get invalidated (they get deleted on the next execution).\n\n## Contracts\n\n### `SubscriptionManager.sol`\n\nHandles the creation, execution, and cancellation of subscriptions.\n\nIt also provides methods for enumerating subscriptions and subscription by subscriber. This implementation was adapted from OpenZeppelin's `EIP721Enumerable` [implementation](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC721/ERC721Enumerable.sol).\n\n### `IndexedArrayLib.sol`\n\nLibrary that provides an indexed array of bytes32. It allows us to remove items from the array by specifying the item itself that we want to remove.\n\n### `Delegated.sol`\n\nAllows child contracts to support delegated execution without changing their external APIs. See Delegation section.\n\n## Time\n\nTo support different time units (days, months and years) we use [BokkyPooBah's Date Time Library](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary).\n\n## Delegation\n\nIn order to support delegated execution through the use of EIP712 signatures, the `SubscriptionManager` inherits from `Delegated`. The key feature of the `Delegated` contract is that child contracts don't need to polute their APIs with parameters related to delegated execution.\n\nThe `Delegated` contract exposes the external `delegate` function which receives the following parameters:\n\n* `bytes data`: ABI encoded data to be used for the delegated call.\n* `bytes32 nonce`: Random value for replay protection. If the function to call is idempotent, this value is optional.\n* `uint256 signatureExpiresAt`: Timestamp in which the signature stops being valid.\n* `bytes signature`: The signature for the EIP712 type.\n\nFor example, for the `setWallet(address _wallet)` function in the `SubscriptionManager`, the EIP712 type is `SetWallet(address wallet,bytes32 nonce,uint256 signatureExpiresAt)`. This function can only be called directly by the `owner` account or by using the `delegate` function with the following parameters (pseudo code):\n\n```js\n// Data to call the setWallet function normally\nconst data = abiEncode(setWalletSelector, _wallet);\n\n// Random value for replay protection\nconst nonce = randomBytes32();\n\n// Signature expiration\nconst signatureExpiresAt = now + signatureDuration;\n\n// Owner's signature\nconst signature = signTypedData({\n  account: owner,  \n  primaryType: \"SetWallet\", // The EIP712 type\n  domain: { \n    verifyingContract: manager.address\n  },\n  message: {\n    wallet: _wallet,\n    nonce,\n    signatureExpiresAt,\n  }\n});\n\n// Call setWallet through the delegate function\nawait manager.delegate(\n  data,\n  nonce,\n  signatureExpiresAt,\n  signature,\n  {\n    from: anyone\n  }\n);\n```\n\n### delegate function and signature checks\n\nThe `delegate` function performs the following steps:\n\n1. Reentrancy guard (`delegate` can only be called once in the same transaction).\n2. Check that the signature hasn't expired (`now < signatureExpiresAt`).\n3. Store the `nonce`, `signatureExpiresAt` and `signature` parameters.\n4. Call itself with the ABI encoded data (`address(this).call(data)`);\n5. Revert if the call failed.\n6. Delete the stored parameters.\n\nAs the delegation data exists in the storage while the call is being executed, the called function in the child contract can use the internal `_delegatedCheck(bytes32 typeHash, bytes data, bool usesNonce)` function to get the address of the caller. Internally, the `_delegatedCheck` checks if `msg.sender == this` and performs the signature validation using the provided type hash. If `msg.sender != this`, it just returns the `msg.sender`. It also stores the hashed data so it can't be used again for another delegated call.\n\n## Subscription Flow with Delegated Execution\n\nThe only function where delegated execution checks are done manually (doesn't use the `Delegated` functionality) is the `create` function, used to create subscriptions. The flow for creating a subscription works as follows:\n\n1. Subscriber calls the `approve` function in the token in which the subscription is denominated in to allow the manager contract to manipulate her funds.\n2. Using EIP 712, the subscriber signs the creation of a subscription (using the EIP712 type `CreateSubscription`) and sends the data to the `authorizer` server.\n3. The `authorizer` checks that the parameters are OK depending on its own rules, signs the data and sends the data and signatures to the relayer.\n3. The relayer executes the creation by calling the method `create()`, passing the parameters and signatures.\n4. At the beggining of each payment period, anyone can execute the subscription and bill the subscriber.\n\nFor subscription services created using Daisy the platform, Daisy will be the authorizer AND the relayer in this flow. We are also working on a system that will allow clients to be the authorizers by using webhooks (Daisy will request an authorizer signature for each subscription creation request).\n\n## Off-chain service flow\n\n#### Checking if the publisher needs to provide the service\n\n1. Receive request from subscriber.\n2. Call `subscriptionManager.nextPaymentTimestamp(subscriptionId)`.\n3. If `now < nextPaymentTimestamp`, answer the request.\n\n#### Executing subscriptions\n\nTo retrieve all subscription ids from the contract (Note: if count is too large, it is possible to obtain the ids in batches):\n1. Call `subscriptionManager.subscriptionCount()`.\n2. Call `subscriptionManager.subscriptionRange(0, count)`.\n\nTo execute a batch of subscriptions:\n1. Call `subscriptionManager.executeBatch(ids)`.\n2. The following events can be present in the transaction receipt, which can be used by the service to update its state:\n    * `SubscriptionNotFound(subscriptionId)`: Subscription doesn't exist in the contract.\n    * `SubscriptionNotReady(subscriptionId, nextPayment)`: Next payment timestamp hasn't been reached yet.\n    * `SubscriptionExecuted(subscriptionId, nextPayment)`: The subscription was executed successfuly.\n    * `SubscriptionDeleted(subscriptionId, reason)`: The subscription was deleted from the contract.\n\nThe `reason` parameter in the `SubscriptionDeleted` event can correspond to:\n* 0 (CANCELLED): The subscription was cancelled before the execution.\n* 1 (EXPIRED): The subscription reached its maxExecutions in the previous execution.\n* 2 (INVALID_STATE): The state was invalid during the execution. This happens if the subscription's plan was deleted.\n* 3 (NOT_ENOUGH_FUNDS): The subscriber address doesn't have or didn't approve enough funds to perform the execution.\n\nIf the `SubscriptionExecuted` event is present, the following two events can also be present, which represent token allocations (see next section):\n* `PaymentAllocated(subscriptionId, token, recipient, amount)`\n* `FeeAllocated(subscriptionId, token, recipient, amount)`\n\n## Token Allocations and Fees\n\nThe owner of a `SubscriptionManager` can optionally set a `fee` and a `feeRecipient` (which can be changed at any point in time). On each execution, the amount of tokens to be paid to the `feeRecipient` is calculated as `feeAmount = price * fee / MAX_FEE`, and the tokens to be paid to the publisher's `wallet` becomes `price - feeAmount`. `MAX_FEE` is a constant set to `100 * 10^18`, and `fee <= MAX_FEE` always.\n\nThe `SubscriptionManager` uses a pull payment model: on each execution, tokens are always transferred from the subscriber to the manager itself, and the manager allocates tokens to the current `feeRecipient` and `wallet` by storing their payments in the `availableFunds` mapping. When an allocation happens, the `FeeAllocated` event or the `PaymentAllocated` event will be emitted, specifying the `subscriptionId`, `token`, `recipient` and `amount`.\n\nAt any time, anyone can call the `withdraw(address[] tokens, address[] recipients)` function to transfer all the available tokens to each recipient specified in the parameters.\n\n## Key Differences Between Daisy and the Current EIP 1337 Proposal\n\n#### Subscriptions creation is not standardized\n\nBy not defining how the subscription must be created, we can support multiple different use cases (e.g. plan or tier based subscriptions, or subscriptions whose prices are determined by what feautures are turned on/off).\n\n#### Subscription data is stored in the contract\n\nThis makes interoperability with other contracts/services easier, without needing to rely on a centralized data source. Subscription data is removed from the contract if it can't be executed anymore or if the user doesn't have enough funds.\n\n#### Execution of a payment only requires specifying the subscription id\n\nThis allows for easier batching of executions and makes it easier for off-chain services to execute subscriptions.\n\n#### Delegated execution is not part of the interface\n\nIn order to be compatible with other proposals for standardizing delegated execution, the core functions don't need to support delegated execution.\n\n#### `isValidSubscription()` split into `isCancelled(subscriptionId)` and `nextPaymentTimestamp(subscriptionId)`\n\nInstead of having an `isValidSubscription()` function that returns a boolean, this implementation provides a `nextPaymentTimestamp()` function that returns the unix timestamp at which the next payment can be executed. This returned value is more usable than a boolean. On the other hand, with `isCancelled` one can get more granular information about a subscription, improving interoperability.\n\n# Testing\n\nTo run the tests, clone this repo and run `yarn install` to install dependencies.\n\nRun `yarn test` to run all tests.\n\nRun `yarn coverage` to run tests and get code coverage.\n","description":"[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repo","licenseText":"MIT License\n\nCopyright (c) 2019 Token Foundry\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@daisypayments/smart-contracts@0.3.0-beta.1","dist":{"shasum":"42faaf0906eb45670cee516f6e5cc5e5254b91cb","integrity":"sha512-lLNdTmJtWLwZhu8XPcmHOcWnhRvwJ4uYB4k76NdRYhWObdUTUbiZFSoTb3A+K+YT6Zi6n7ewcVvH8PkIsfPXtg==","tarball":"https://registry.npmjs.org/@daisypayments/smart-contracts/-/smart-contracts-0.3.0-beta.1.tgz","fileCount":12,"unpackedSize":3228561,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdsHP+CRA9TVsSAnZWagAA/F8P/0+Cvl/MxvgKuO2sN5kJ\nQG9d5huied5U1VO7k6EgCza8/FiBjVC+GSKux46T3ebhyHDLDs7GPgarbLAK\nLagTCgsCus/5j7Cm3Oylgb3/gqKJz05/cZau459QnH8q2DogqBjeUz+lPLWd\nqrx1FkIrvLpBwOLZo7oU+k0o8/tD/WdEgP/bxUsaagWyTcCy8L/GkDv3ayNJ\nx5g1jLre6eUnVAZdeaki2qaVU3amMgu7VEz+YxTrZ7MjHnM8DGyupwlbk+p9\nVwGqCTcD/2uPn3+59s8OPB6a6LgPN2DTCFyqnbWZB4khS5pQ9ran0Q8cGJoQ\nMq4y/mGb7Kmp6eDUd/AD8akercK0LE+jbzEn7B58Ak2+6BMUqBlqTG6ninY5\n6HCBqHWLo692FBadxpCq3EJUb9sOIEPnxuhWw3Ijg7SWb5pEraB8D4TDdXqE\nIwnQSTougIhf2CncPNW9WprFb688uEGO/1l7BINGjuuCd4ZWaD7VL1R+Uc6a\nF2LWxdgITWAvwAHHd8xjNz7S6feBA7VAqEgOTEXxcJL+qtAzcOYtz9q5jKbi\nUMBMu0mVhHBIrG9geRtDBmsVt1qgKu2B8t1n9pFuUU8ryJiUpWeU29P7O+p6\nqMImRt1+2EKBMJgxRBf1Mww5Js2eqmq6yPm80cj98nen2NyZISaUsC4tMpKi\nxd0V\r\n=/psm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICTSwm4rcBLJuD7vwItrncl+2PFf60CuI+28mdEjKJeBAiEA1KZhdXklL7LwSGvXrxctHLgD/4f+q9QBS/j7oxfzTWY="}]},"maintainers":[{"name":"jmoreira","email":"jmoreiras@gmail.com"},{"name":"lopezjurip","email":"lopezjuripatricio@gmail.com"},{"name":"nchastain","email":"nate.chastain@consensys.net"},{"name":"sloreti","email":"lhloreti@gmail.com"},{"name":"vdrg","email":"vdrg@protonmail.ch"},{"name":"wachunei","email":"wachunei@gmail.com"}],"_npmUser":{"name":"vdrg","email":"vdrg@protonmail.ch"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/smart-contracts_0.3.0-beta.1_1571845118042_0.4327800106837105"},"_hasShrinkwrap":false},"0.3.0-beta.2":{"name":"@daisypayments/smart-contracts","version":"0.3.0-beta.2","repository":{"type":"git","url":"https://github.com/consensys/daisy-subscription-contracts"},"author":{"name":"vdrg","email":"vicente.dragicevic@consensys.net"},"license":"MIT","main":"index.js","scripts":{"compile":"truffle compile","coverage":"./scripts/coverage.sh","exec":"truffle exec","ganache":"ganache-cli","docgen":"./scripts/docgen.sh","publish-docs":"./scripts/publish-docs.sh","prepublish":"yarn compile","lint":"solhint \"contracts/**/*.sol\"","migrate":"truffle migrate","test":"./scripts/test.sh"},"devDependencies":{"@daisypayments/eslint-config":"^1.5.1","@openzeppelin/test-helpers":"^0.5.3","bip39":"^2.5.0","bn.js":"^4.11.8","chai":"^4.2.0","coveralls":"^3.0.5","dotenv":"^6.2.0","eslint":"^5.13.0","eslint-config-prettier":"^4.0.0","eslint-plugin-mocha":"^5.2.1","eslint-plugin-prettier":"^3.0.1","eth-gas-reporter":"^0.2.12","eth-sig-util":"^2.2.0","ethereumjs-abi":"^0.6.7","ethereumjs-util":"^6.1.0","ethereumjs-wallet":"^0.6.3","ganache-cli":"^6.4.4","lodash":"^4.17.11","moment":"^2.24.0","openzeppelin-solidity":"^2.3.0","openzeppelin-test-helpers":"^0.4.0","prettier":"^1.16.3","solhint":"^2.0.0","solidity-coverage":"^0.6.7","solidity-docgen":"^0.1.1","truffle":"^5.0.25","truffle-hdwallet-provider":"^1.0.4"},"readmeFilename":"README.md","readme":"# Daisy Contracts\n\n[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repos/github/ConsenSys/daisy-subscription-contracts/badge.svg?t=wmZqvk)](https://coveralls.io/github/ConsenSys/daisy-subscription-contracts)\n\n## Overview\n\n### Subscriptions\n\nA subscription is composed of:\n\n* subscriber: address from which tokens will be transferred from.\n* token: address of the ERC 20 token that the subscription is denominated in.\n* price: number of tokens to transfer in each payment.\n* periodUnit: \"DAY\", \"MONTH\", or \"YEAR\".\n* periods: number of period units between payments.\n* maxExecutions: max number of payments that can be made before the subscriber must manually renew their subscription. If this value is 0, there is no execution limit.\n* planIdHash: the hash of the id of the plan the subscription belongs to.\n* credits: amount of tokens to substract from future payments. On each payment, these credits get consumed until they get to 0.\n\nA subscription can be in one of four states:\n1. Active: Once it has been executed and the next payment is in the future. A subscription is first executed upon its creation.\n2. Active and Cancelled: When it is cancelled before reaching the next payment timestamp. It will remain active until the end of the period.\n3. Cancelled: when it has been cancelled and the last billed period has ended.\n4. Deleted: the subscription data will be deleted upon execution if the subscription can't be executed anymore.\n\n### Plans\n\nA plan is just a way to group multiple subscriptions, and allows the publisher to cancel a group of subscriptions at once. A plan is identified in the contract by a bytes32. When a plan based subscription is created, it is necessary to specify the plan's identifier, and the creation only goes through if a valid authorization signature is provided.\n\nThe contract provides a function to delete a plan by providing the plan on chain id. All subscriptions with that plan get invalidated (they get deleted on the next execution).\n\n## Contracts\n\n### `SubscriptionManager.sol`\n\nHandles the creation, execution, and cancellation of subscriptions.\n\nIt also provides methods for enumerating subscriptions and subscription by subscriber. This implementation was adapted from OpenZeppelin's `EIP721Enumerable` [implementation](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC721/ERC721Enumerable.sol).\n\n### `IndexedArrayLib.sol`\n\nLibrary that provides an indexed array of bytes32. It allows us to remove items from the array by specifying the item itself that we want to remove.\n\n### `Delegated.sol`\n\nAllows child contracts to support delegated execution without changing their external APIs. See Delegation section.\n\n## Time\n\nTo support different time units (days, months and years) we use [BokkyPooBah's Date Time Library](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary).\n\n## Delegation\n\nIn order to support delegated execution through the use of EIP712 signatures, the `SubscriptionManager` inherits from `Delegated`. The key feature of the `Delegated` contract is that child contracts don't need to polute their APIs with parameters related to delegated execution.\n\nThe `Delegated` contract exposes the external `delegate` function which receives the following parameters:\n\n* `bytes data`: ABI encoded data to be used for the delegated call.\n* `bytes32 nonce`: Random value for replay protection. If the function to call is idempotent, this value is optional.\n* `uint256 signatureExpiresAt`: Timestamp in which the signature stops being valid.\n* `bytes signature`: The signature for the EIP712 type.\n\nFor example, for the `setWallet(address _wallet)` function in the `SubscriptionManager`, the EIP712 type is `SetWallet(address wallet,bytes32 nonce,uint256 signatureExpiresAt)`. This function can only be called directly by the `owner` account or by using the `delegate` function with the following parameters (pseudo code):\n\n```js\n// Data to call the setWallet function normally\nconst data = abiEncode(setWalletSelector, _wallet);\n\n// Random value for replay protection\nconst nonce = randomBytes32();\n\n// Signature expiration\nconst signatureExpiresAt = now + signatureDuration;\n\n// Owner's signature\nconst signature = signTypedData({\n  account: owner,  \n  primaryType: \"SetWallet\", // The EIP712 type\n  domain: { \n    verifyingContract: manager.address\n  },\n  message: {\n    wallet: _wallet,\n    nonce,\n    signatureExpiresAt,\n  }\n});\n\n// Call setWallet through the delegate function\nawait manager.delegate(\n  data,\n  nonce,\n  signatureExpiresAt,\n  signature,\n  {\n    from: anyone\n  }\n);\n```\n\n### delegate function and signature checks\n\nThe `delegate` function performs the following steps:\n\n1. Reentrancy guard (`delegate` can only be called once in the same transaction).\n2. Check that the signature hasn't expired (`now < signatureExpiresAt`).\n3. Store the `nonce`, `signatureExpiresAt` and `signature` parameters.\n4. Call itself with the ABI encoded data (`address(this).call(data)`);\n5. Revert if the call failed.\n6. Delete the stored parameters.\n\nAs the delegation data exists in the storage while the call is being executed, the called function in the child contract can use the internal `_delegatedCheck(bytes32 typeHash, bytes data, bool usesNonce)` function to get the address of the caller. Internally, the `_delegatedCheck` checks if `msg.sender == this` and performs the signature validation using the provided type hash. If `msg.sender != this`, it just returns the `msg.sender`. It also stores the hashed data so it can't be used again for another delegated call.\n\n## Subscription Flow with Delegated Execution\n\nThe only function where delegated execution checks are done manually (doesn't use the `Delegated` functionality) is the `create` function, used to create subscriptions. The flow for creating a subscription works as follows:\n\n1. Subscriber calls the `approve` function in the token in which the subscription is denominated in to allow the manager contract to manipulate her funds.\n2. Using EIP 712, the subscriber signs the creation of a subscription (using the EIP712 type `CreateSubscription`) and sends the data to the `authorizer` server.\n3. The `authorizer` checks that the parameters are OK depending on its own rules, signs the data and sends the data and signatures to the relayer.\n3. The relayer executes the creation by calling the method `create()`, passing the parameters and signatures.\n4. At the beggining of each payment period, anyone can execute the subscription and bill the subscriber.\n\nFor subscription services created using Daisy the platform, Daisy will be the authorizer AND the relayer in this flow. We are also working on a system that will allow clients to be the authorizers by using webhooks (Daisy will request an authorizer signature for each subscription creation request).\n\n## Off-chain service flow\n\n#### Checking if the publisher needs to provide the service\n\n1. Receive request from subscriber.\n2. Call `subscriptionManager.nextPaymentTimestamp(subscriptionId)`.\n3. If `now < nextPaymentTimestamp`, answer the request.\n\n#### Executing subscriptions\n\nTo retrieve all subscription ids from the contract (Note: if count is too large, it is possible to obtain the ids in batches):\n1. Call `subscriptionManager.subscriptionCount()`.\n2. Call `subscriptionManager.subscriptionRange(0, count)`.\n\nTo execute a batch of subscriptions:\n1. Call `subscriptionManager.executeBatch(ids)`.\n2. The following events can be present in the transaction receipt, which can be used by the service to update its state:\n    * `SubscriptionNotFound(subscriptionId)`: Subscription doesn't exist in the contract.\n    * `SubscriptionNotReady(subscriptionId, nextPayment)`: Next payment timestamp hasn't been reached yet.\n    * `SubscriptionExecuted(subscriptionId, nextPayment)`: The subscription was executed successfuly.\n    * `SubscriptionDeleted(subscriptionId, reason)`: The subscription was deleted from the contract.\n\nThe `reason` parameter in the `SubscriptionDeleted` event can correspond to:\n* 0 (CANCELLED): The subscription was cancelled before the execution.\n* 1 (EXPIRED): The subscription reached its maxExecutions in the previous execution.\n* 2 (INVALID_STATE): The state was invalid during the execution. This happens if the subscription's plan was deleted.\n* 3 (NOT_ENOUGH_FUNDS): The subscriber address doesn't have or didn't approve enough funds to perform the execution.\n\nIf the `SubscriptionExecuted` event is present, the following two events can also be present, which represent token allocations (see next section):\n* `PaymentAllocated(subscriptionId, token, recipient, amount)`\n* `FeeAllocated(subscriptionId, token, recipient, amount)`\n\n## Token Allocations and Fees\n\nThe owner of a `SubscriptionManager` can optionally set a `fee` and a `feeRecipient` (which can be changed at any point in time). On each execution, the amount of tokens to be paid to the `feeRecipient` is calculated as `feeAmount = price * fee / MAX_FEE`, and the tokens to be paid to the publisher's `wallet` becomes `price - feeAmount`. `MAX_FEE` is a constant set to `100 * 10^18`, and `fee <= MAX_FEE` always.\n\nThe `SubscriptionManager` uses a pull payment model: on each execution, tokens are always transferred from the subscriber to the manager itself, and the manager allocates tokens to the current `feeRecipient` and `wallet` by storing their payments in the `availableFunds` mapping. When an allocation happens, the `FeeAllocated` event or the `PaymentAllocated` event will be emitted, specifying the `subscriptionId`, `token`, `recipient` and `amount`.\n\nAt any time, anyone can call the `withdraw(address[] tokens, address[] recipients)` function to transfer all the available tokens to each recipient specified in the parameters.\n\n## Key Differences Between Daisy and the Current EIP 1337 Proposal\n\n#### Subscriptions creation is not standardized\n\nBy not defining how the subscription must be created, we can support multiple different use cases (e.g. plan or tier based subscriptions, or subscriptions whose prices are determined by what feautures are turned on/off).\n\n#### Subscription data is stored in the contract\n\nThis makes interoperability with other contracts/services easier, without needing to rely on a centralized data source. Subscription data is removed from the contract if it can't be executed anymore or if the user doesn't have enough funds.\n\n#### Execution of a payment only requires specifying the subscription id\n\nThis allows for easier batching of executions and makes it easier for off-chain services to execute subscriptions.\n\n#### Delegated execution is not part of the interface\n\nIn order to be compatible with other proposals for standardizing delegated execution, the core functions don't need to support delegated execution.\n\n#### `isValidSubscription()` split into `isCancelled(subscriptionId)` and `nextPaymentTimestamp(subscriptionId)`\n\nInstead of having an `isValidSubscription()` function that returns a boolean, this implementation provides a `nextPaymentTimestamp()` function that returns the unix timestamp at which the next payment can be executed. This returned value is more usable than a boolean. On the other hand, with `isCancelled` one can get more granular information about a subscription, improving interoperability.\n\n# Testing\n\nTo run the tests, clone this repo and run `yarn install` to install dependencies.\n\nRun `yarn test` to run all tests.\n\nRun `yarn coverage` to run tests and get code coverage.\n","description":"[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repo","licenseText":"MIT License\n\nCopyright (c) 2019 Token Foundry\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@daisypayments/smart-contracts@0.3.0-beta.2","dist":{"shasum":"8885ba9f5b2815b09fa0724746c4441bfdf4f332","integrity":"sha512-FO944GwAPhiRVhC8V6EiNdc8NNuN1yFGuEmzlX8GThki60BCBvQPsB6PFlssl4CrLYIJ50PrYI/HceSyO37Vog==","tarball":"https://registry.npmjs.org/@daisypayments/smart-contracts/-/smart-contracts-0.3.0-beta.2.tgz","fileCount":12,"unpackedSize":3228565,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdsIOpCRA9TVsSAnZWagAAwLwP/35qfa0fYv4J5BpEZ+e/\nog0go2pbd7JLYKXotTp+N7NgFJ8lCU0kkrIILlVe6oserfJdQ1yzSTnT+Tub\nZeJ1XreP/HN/M7tV2YOgSRQDb9NjHYYBHJcIw7e1/EJvcMAIlZEDrj19vqTK\nJ26bWgJ6qRSNenejHOaHtkoDD6UCwso0Zda7ZkXGh8mSeaPhaT6bpbD36yh/\ntT89sql88CCqz1CZ3xW6qCtVnprRXTQ1xz8WkoheiWpkqV8pmjmZbD8yUOpm\nZ8D5BoHFzwGKiOCyyXDd+WpnfLvRqbyKeJmFsfrDUyqbBOQkl41jICYv8YQc\n1Wy8uoFcwD4T+pGMi3K2kTZm7jzjMu7xZMvjbmysmbFhBDlmmdXtAlOo4jCB\nWOF/X5iwaxbPlK40S6K18nil/auEVkOlUJOdpdvYIGU2wnnhPhPzbuF5J4UC\nFjtzbBCWechDymZ3RjMyVsKgPn0jB0GvqfOBPWdU+KxUdjQWujTPnQqnXWtJ\nrFv5zKpAPRlyAzKZKyz53uv5X0bbAuD+lcRowoxxIxT2DGEcIWAiMFiXk7j7\nsjNcdhstwYit0cDTfkXvz705W/+2dzLe8hvSB60ebBfqTzXOLdsFLldQzFfn\nXTAtAJ40VVtxYov7n53SCKkg6mlk/+SYh9l624TO+Hb/OvZbtNjZ1kQFSTjL\nR9xl\r\n=+5Nf\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDlWnvW4xY7xly0pZz47gC8rEEuENEmr5Y/k+xFBwynDgIgI6911G4mKDMK0vcYOxeG8FONZwZzqNDVedCwh86g0Uc="}]},"maintainers":[{"name":"jmoreira","email":"jmoreiras@gmail.com"},{"name":"lopezjurip","email":"lopezjuripatricio@gmail.com"},{"name":"nchastain","email":"nate.chastain@consensys.net"},{"name":"sloreti","email":"lhloreti@gmail.com"},{"name":"vdrg","email":"vdrg@protonmail.ch"},{"name":"wachunei","email":"wachunei@gmail.com"}],"_npmUser":{"name":"vdrg","email":"vdrg@protonmail.ch"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/smart-contracts_0.3.0-beta.2_1571849128699_0.9657157891129349"},"_hasShrinkwrap":false},"0.3.0-beta.3":{"name":"@daisypayments/smart-contracts","version":"0.3.0-beta.3","repository":{"type":"git","url":"https://github.com/consensys/daisy-subscription-contracts"},"author":{"name":"vdrg","email":"vicente.dragicevic@consensys.net"},"license":"MIT","main":"index.js","scripts":{"compile":"truffle compile","coverage":"./scripts/coverage.sh","exec":"truffle exec","ganache":"ganache-cli","docgen":"./scripts/docgen.sh","publish-docs":"./scripts/publish-docs.sh","prepublish":"yarn compile","lint":"solhint \"contracts/**/*.sol\"","migrate":"truffle migrate","test":"./scripts/test.sh"},"devDependencies":{"@daisypayments/eslint-config":"^1.5.1","@openzeppelin/test-helpers":"^0.5.3","bip39":"^2.5.0","bn.js":"^4.11.8","chai":"^4.2.0","coveralls":"^3.0.5","dotenv":"^6.2.0","eslint":"^5.13.0","eslint-config-prettier":"^4.0.0","eslint-plugin-mocha":"^5.2.1","eslint-plugin-prettier":"^3.0.1","eth-gas-reporter":"^0.2.12","eth-sig-util":"^2.2.0","ethereumjs-abi":"^0.6.7","ethereumjs-util":"^6.1.0","ethereumjs-wallet":"^0.6.3","ganache-cli":"^6.4.4","lodash":"^4.17.11","moment":"^2.24.0","openzeppelin-solidity":"^2.3.0","openzeppelin-test-helpers":"^0.4.0","prettier":"^1.16.3","solhint":"^2.0.0","solidity-coverage":"^0.6.7","solidity-docgen":"^0.1.1","truffle":"^5.0.25","truffle-hdwallet-provider":"^1.0.4"},"readmeFilename":"README.md","readme":"# Daisy Contracts\n\n[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repos/github/ConsenSys/daisy-subscription-contracts/badge.svg?t=wmZqvk)](https://coveralls.io/github/ConsenSys/daisy-subscription-contracts)\n\n## Overview\n\n### Subscriptions\n\nA subscription is composed of:\n\n* subscriber: address from which tokens will be transferred from.\n* token: address of the ERC 20 token that the subscription is denominated in.\n* price: number of tokens to transfer in each payment.\n* periodUnit: \"DAY\", \"MONTH\", or \"YEAR\".\n* periods: number of period units between payments.\n* maxExecutions: max number of payments that can be made before the subscriber must manually renew their subscription. If this value is 0, there is no execution limit.\n* planIdHash: the hash of the id of the plan the subscription belongs to.\n* credits: amount of tokens to substract from future payments. On each payment, these credits get consumed until they get to 0.\n\nA subscription can be in one of four states:\n1. Active: Once it has been executed and the next payment is in the future. A subscription is first executed upon its creation.\n2. Active and Cancelled: When it is cancelled before reaching the next payment timestamp. It will remain active until the end of the period.\n3. Cancelled: when it has been cancelled and the last billed period has ended.\n4. Deleted: the subscription data will be deleted upon execution if the subscription can't be executed anymore.\n\n### Plans\n\nA plan is just a way to group multiple subscriptions, and allows the publisher to cancel a group of subscriptions at once. A plan is identified in the contract by a bytes32. When a plan based subscription is created, it is necessary to specify the plan's identifier, and the creation only goes through if a valid authorization signature is provided.\n\nThe contract provides a function to delete a plan by providing the plan on chain id. All subscriptions with that plan get invalidated (they get deleted on the next execution).\n\n## Contracts\n\n### `SubscriptionManager.sol`\n\nHandles the creation, execution, and cancellation of subscriptions.\n\nIt also provides methods for enumerating subscriptions and subscription by subscriber. This implementation was adapted from OpenZeppelin's `EIP721Enumerable` [implementation](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC721/ERC721Enumerable.sol).\n\n### `IndexedArrayLib.sol`\n\nLibrary that provides an indexed array of bytes32. It allows us to remove items from the array by specifying the item itself that we want to remove.\n\n### `Delegated.sol`\n\nAllows child contracts to support delegated execution without changing their external APIs. See Delegation section.\n\n## Time\n\nTo support different time units (days, months and years) we use [BokkyPooBah's Date Time Library](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary).\n\n## Delegation\n\nIn order to support delegated execution through the use of EIP712 signatures, the `SubscriptionManager` inherits from `Delegated`. The key feature of the `Delegated` contract is that child contracts don't need to polute their APIs with parameters related to delegated execution.\n\nThe `Delegated` contract exposes the external `delegate` function which receives the following parameters:\n\n* `bytes data`: ABI encoded data to be used for the delegated call.\n* `bytes32 nonce`: Random value for replay protection. If the function to call is idempotent, this value is optional.\n* `uint256 signatureExpiresAt`: Timestamp in which the signature stops being valid.\n* `bytes signature`: The signature for the EIP712 type.\n\nFor example, for the `setWallet(address _wallet)` function in the `SubscriptionManager`, the EIP712 type is `SetWallet(address wallet,bytes32 nonce,uint256 signatureExpiresAt)`. This function can only be called directly by the `owner` account or by using the `delegate` function with the following parameters (pseudo code):\n\n```js\n// Data to call the setWallet function normally\nconst data = abiEncode(setWalletSelector, _wallet);\n\n// Random value for replay protection\nconst nonce = randomBytes32();\n\n// Signature expiration\nconst signatureExpiresAt = now + signatureDuration;\n\n// Owner's signature\nconst signature = signTypedData({\n  account: owner,  \n  primaryType: \"SetWallet\", // The EIP712 type\n  domain: { \n    verifyingContract: manager.address\n  },\n  message: {\n    wallet: _wallet,\n    nonce,\n    signatureExpiresAt,\n  }\n});\n\n// Call setWallet through the delegate function\nawait manager.delegate(\n  data,\n  nonce,\n  signatureExpiresAt,\n  signature,\n  {\n    from: anyone\n  }\n);\n```\n\n### delegate function and signature checks\n\nThe `delegate` function performs the following steps:\n\n1. Reentrancy guard (`delegate` can only be called once in the same transaction).\n2. Check that the signature hasn't expired (`now < signatureExpiresAt`).\n3. Store the `nonce`, `signatureExpiresAt` and `signature` parameters.\n4. Call itself with the ABI encoded data (`address(this).call(data)`);\n5. Revert if the call failed.\n6. Delete the stored parameters.\n\nAs the delegation data exists in the storage while the call is being executed, the called function in the child contract can use the internal `_delegatedCheck(bytes32 typeHash, bytes data, bool usesNonce)` function to get the address of the caller. Internally, the `_delegatedCheck` checks if `msg.sender == this` and performs the signature validation using the provided type hash. If `msg.sender != this`, it just returns the `msg.sender`. It also stores the hashed data so it can't be used again for another delegated call.\n\n## Subscription Flow with Delegated Execution\n\nThe only function where delegated execution checks are done manually (doesn't use the `Delegated` functionality) is the `create` function, used to create subscriptions. The flow for creating a subscription works as follows:\n\n1. Subscriber calls the `approve` function in the token in which the subscription is denominated in to allow the manager contract to manipulate her funds.\n2. Using EIP 712, the subscriber signs the creation of a subscription (using the EIP712 type `CreateSubscription`) and sends the data to the `authorizer` server.\n3. The `authorizer` checks that the parameters are OK depending on its own rules, signs the data and sends the data and signatures to the relayer.\n3. The relayer executes the creation by calling the method `create()`, passing the parameters and signatures.\n4. At the beggining of each payment period, anyone can execute the subscription and bill the subscriber.\n\nFor subscription services created using Daisy the platform, Daisy will be the authorizer AND the relayer in this flow. We are also working on a system that will allow clients to be the authorizers by using webhooks (Daisy will request an authorizer signature for each subscription creation request).\n\n## Off-chain service flow\n\n#### Checking if the publisher needs to provide the service\n\n1. Receive request from subscriber.\n2. Call `subscriptionManager.nextPaymentTimestamp(subscriptionId)`.\n3. If `now < nextPaymentTimestamp`, answer the request.\n\n#### Executing subscriptions\n\nTo retrieve all subscription ids from the contract (Note: if count is too large, it is possible to obtain the ids in batches):\n1. Call `subscriptionManager.subscriptionCount()`.\n2. Call `subscriptionManager.subscriptionRange(0, count)`.\n\nTo execute a batch of subscriptions:\n1. Call `subscriptionManager.executeBatch(ids)`.\n2. The following events can be present in the transaction receipt, which can be used by the service to update its state:\n    * `SubscriptionNotFound(subscriptionId)`: Subscription doesn't exist in the contract.\n    * `SubscriptionNotReady(subscriptionId, nextPayment)`: Next payment timestamp hasn't been reached yet.\n    * `SubscriptionExecuted(subscriptionId, nextPayment)`: The subscription was executed successfuly.\n    * `SubscriptionDeleted(subscriptionId, reason)`: The subscription was deleted from the contract.\n\nThe `reason` parameter in the `SubscriptionDeleted` event can correspond to:\n* 0 (CANCELLED): The subscription was cancelled before the execution.\n* 1 (EXPIRED): The subscription reached its maxExecutions in the previous execution.\n* 2 (INVALID_STATE): The state was invalid during the execution. This happens if the subscription's plan was deleted.\n* 3 (NOT_ENOUGH_FUNDS): The subscriber address doesn't have or didn't approve enough funds to perform the execution.\n\nIf the `SubscriptionExecuted` event is present, the following two events can also be present, which represent token allocations (see next section):\n* `PaymentAllocated(subscriptionId, token, recipient, amount)`\n* `FeeAllocated(subscriptionId, token, recipient, amount)`\n\n## Token Allocations and Fees\n\nThe owner of a `SubscriptionManager` can optionally set a `fee` and a `feeRecipient` (which can be changed at any point in time). On each execution, the amount of tokens to be paid to the `feeRecipient` is calculated as `feeAmount = price * fee / MAX_FEE`, and the tokens to be paid to the publisher's `wallet` becomes `price - feeAmount`. `MAX_FEE` is a constant set to `100 * 10^18`, and `fee <= MAX_FEE` always.\n\nThe `SubscriptionManager` uses a pull payment model: on each execution, tokens are always transferred from the subscriber to the manager itself, and the manager allocates tokens to the current `feeRecipient` and `wallet` by storing their payments in the `availableFunds` mapping. When an allocation happens, the `FeeAllocated` event or the `PaymentAllocated` event will be emitted, specifying the `subscriptionId`, `token`, `recipient` and `amount`.\n\nAt any time, anyone can call the `withdraw(address[] tokens, address[] recipients)` function to transfer all the available tokens to each recipient specified in the parameters.\n\n## Key Differences Between Daisy and the Current EIP 1337 Proposal\n\n#### Subscriptions creation is not standardized\n\nBy not defining how the subscription must be created, we can support multiple different use cases (e.g. plan or tier based subscriptions, or subscriptions whose prices are determined by what feautures are turned on/off).\n\n#### Subscription data is stored in the contract\n\nThis makes interoperability with other contracts/services easier, without needing to rely on a centralized data source. Subscription data is removed from the contract if it can't be executed anymore or if the user doesn't have enough funds.\n\n#### Execution of a payment only requires specifying the subscription id\n\nThis allows for easier batching of executions and makes it easier for off-chain services to execute subscriptions.\n\n#### Delegated execution is not part of the interface\n\nIn order to be compatible with other proposals for standardizing delegated execution, the core functions don't need to support delegated execution.\n\n#### `isValidSubscription()` split into `isCancelled(subscriptionId)` and `nextPaymentTimestamp(subscriptionId)`\n\nInstead of having an `isValidSubscription()` function that returns a boolean, this implementation provides a `nextPaymentTimestamp()` function that returns the unix timestamp at which the next payment can be executed. This returned value is more usable than a boolean. On the other hand, with `isCancelled` one can get more granular information about a subscription, improving interoperability.\n\n# Testing\n\nTo run the tests, clone this repo and run `yarn install` to install dependencies.\n\nRun `yarn test` to run all tests.\n\nRun `yarn coverage` to run tests and get code coverage.\n","description":"[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repo","licenseText":"MIT License\n\nCopyright (c) 2019 Token Foundry\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@daisypayments/smart-contracts@0.3.0-beta.3","dist":{"shasum":"b8e990c1f34edb8ede98f4d42c0ed558d115ace3","integrity":"sha512-ANZs+jdVkr4wFKHOL6n5dNBksa6cbvtc54HNbsUDTaWr+4r1mhvZiWY4jLhpo2GBi0dEA9ySqj3/KJSnHXkAKA==","tarball":"https://registry.npmjs.org/@daisypayments/smart-contracts/-/smart-contracts-0.3.0-beta.3.tgz","fileCount":13,"unpackedSize":3769496,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdtyRrCRA9TVsSAnZWagAAbPkP/2XTcgddooNNq9E9Ln4L\nUe8/CSWcV38ZBFSevGYXwvRcfWHRv8H35xeA0riUw5ItQyw3Gc3+qbzsgTmR\nF3HcNy9ewYUkR80WhIXXvVesWF8CYQMpP/Wp74gBaLjeUESTXXrlGE5hMjHM\naf6Cb0bSFOktvWUqrrB/2Dg2/DAWmqLUGZHomQuVO0ESvzWZf+7UxXKz7TVR\nJ1h0nBgE493wn3aL+BfaoiQi/COO2xyn9EjhRXmY4+BpqDRRN5PxGR1gjhfy\nYbG6LZerwzyvnyxKoNPNa7wBafoHijruuSFb8qo69ihhoJ6duoaiCKtrK4hp\nSPh3hVaSUpctV9Q9F+JTm0XmySKU50061CBVEN8OjBbgt8oVRMci9W5iTUPE\nYgV8yeoEIYVdCwsePq5YXFP3cRn0PNhqtKD3fc6qhECqx+SVQH26hW3hZm06\n2GTXKWnaVCwRmGegVff6IbXLg4KZg9N11sdne9AG2+rSNwgwSdQcFqYKMu2V\n0GO97GeXWRkJB048Kt2fHSsFvLtwx/LCxxDPStl4bsfxOSWX1aeVzeATPhIy\nTFtuxoufZ4vSqo0Cv7QAgAQGTJSl6S/WjinFPLxmeB4/5AmmkT1t7yzoO5Bd\nn9wtiSPDeT0LrfCxnAPR+vAoM3Ov8jEGOjYpjyIbYGd2VP/gtrPwvTs5LyXT\n1pHi\r\n=UADX\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGBxeke7fwU8FofULBHnZutw2pRjayqD0wYAfSVTvIvgAiEAzPqYBwAbcu5dXOZmZzGFgkY+wpRdFqgF42o02Os5o1Y="}]},"maintainers":[{"name":"jmoreira","email":"jmoreiras@gmail.com"},{"name":"lopezjurip","email":"lopezjuripatricio@gmail.com"},{"name":"nchastain","email":"nate.chastain@consensys.net"},{"name":"sloreti","email":"lhloreti@gmail.com"},{"name":"vdrg","email":"vdrg@protonmail.ch"},{"name":"wachunei","email":"wachunei@gmail.com"}],"_npmUser":{"name":"vdrg","email":"vdrg@protonmail.ch"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/smart-contracts_0.3.0-beta.3_1572283499548_0.5204236274405027"},"_hasShrinkwrap":false},"0.3.0-beta.4":{"name":"@daisypayments/smart-contracts","version":"0.3.0-beta.4","repository":{"type":"git","url":"https://github.com/consensys/daisy-subscription-contracts"},"author":{"name":"vdrg","email":"vicente.dragicevic@consensys.net"},"license":"MIT","main":"index.js","scripts":{"compile":"truffle compile","coverage":"./scripts/coverage.sh","exec":"truffle exec","ganache":"ganache-cli","docgen":"./scripts/docgen.sh","publish-docs":"./scripts/publish-docs.sh","prepublish":"yarn compile","lint":"solhint \"contracts/**/*.sol\"","migrate":"truffle migrate","test":"./scripts/test.sh"},"devDependencies":{"@daisypayments/eslint-config":"^1.5.1","@openzeppelin/test-helpers":"^0.5.3","bip39":"^2.5.0","bn.js":"^4.11.8","chai":"^4.2.0","coveralls":"^3.0.5","dotenv":"^6.2.0","eslint":"^5.13.0","eslint-config-prettier":"^4.0.0","eslint-plugin-mocha":"^5.2.1","eslint-plugin-prettier":"^3.0.1","eth-gas-reporter":"^0.2.12","eth-sig-util":"^2.2.0","ethereumjs-abi":"^0.6.7","ethereumjs-util":"^6.1.0","ethereumjs-wallet":"^0.6.3","ganache-cli":"^6.4.4","lodash":"^4.17.11","moment":"^2.24.0","openzeppelin-solidity":"^2.4.0","openzeppelin-test-helpers":"^0.4.0","prettier":"^1.16.3","solhint":"^2.0.0","solidity-coverage":"^0.6.7","solidity-docgen":"^0.1.1","truffle":"^5.0.25","truffle-hdwallet-provider":"^1.0.4"},"readmeFilename":"README.md","readme":"# Daisy Contracts\n\n[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repos/github/ConsenSys/daisy-subscription-contracts/badge.svg?t=wmZqvk)](https://coveralls.io/github/ConsenSys/daisy-subscription-contracts)\n\n## Overview\n\n### Subscriptions\n\nA subscription is composed of:\n\n* subscriber: address from which tokens will be transferred from.\n* token: address of the ERC 20 token that the subscription is denominated in.\n* price: number of tokens to transfer in each payment.\n* periodUnit: \"DAY\", \"MONTH\", or \"YEAR\".\n* periods: number of period units between payments.\n* maxExecutions: max number of payments that can be made before the subscriber must manually renew their subscription. If this value is 0, there is no execution limit.\n* planIdHash: the hash of the id of the plan the subscription belongs to.\n* credits: amount of tokens to substract from future payments. On each payment, these credits get consumed until they get to 0.\n\nA subscription can be in one of four states:\n1. Active: Once it has been executed and the next payment is in the future. A subscription is first executed upon its creation.\n2. Active and Cancelled: When it is cancelled before reaching the next payment timestamp. It will remain active until the end of the period.\n3. Cancelled: when it has been cancelled and the last billed period has ended.\n4. Deleted: the subscription data will be deleted upon execution if the subscription can't be executed anymore.\n\n### Plans\n\nA plan is just a way to group multiple subscriptions, and allows the publisher to cancel a group of subscriptions at once. A plan is identified in the contract by a bytes32. When a plan based subscription is created, it is necessary to specify the plan's identifier, and the creation only goes through if a valid authorization signature is provided.\n\nThe contract provides a function to delete a plan by providing the plan on chain id. All subscriptions with that plan get invalidated (they get deleted on the next execution).\n\n## Contracts\n\n### `SubscriptionManager.sol`\n\nHandles the creation, execution, and cancellation of subscriptions.\n\nIt also provides methods for enumerating subscriptions and subscription by subscriber. This implementation was adapted from OpenZeppelin's `EIP721Enumerable` [implementation](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC721/ERC721Enumerable.sol).\n\n### `IndexedArrayLib.sol`\n\nLibrary that provides an indexed array of bytes32. It allows us to remove items from the array by specifying the item itself that we want to remove.\n\n### `Delegated.sol`\n\nAllows child contracts to support delegated execution without changing their external APIs. See Delegation section.\n\n## Time\n\nTo support different time units (days, months and years) we use [BokkyPooBah's Date Time Library](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary).\n\n## Delegation\n\nIn order to support delegated execution through the use of EIP712 signatures, the `SubscriptionManager` inherits from `Delegated`. The key feature of the `Delegated` contract is that child contracts don't need to polute their APIs with parameters related to delegated execution.\n\nThe `Delegated` contract exposes the external `delegate` function which receives the following parameters:\n\n* `bytes data`: ABI encoded data to be used for the delegated call.\n* `bytes32 nonce`: Random value for replay protection. If the function to call is idempotent, this value is optional.\n* `uint256 signatureExpiresAt`: Timestamp in which the signature stops being valid.\n* `bytes signature`: The signature for the EIP712 type.\n\nFor example, for the `setWallet(address _wallet)` function in the `SubscriptionManager`, the EIP712 type is `SetWallet(address wallet,bytes32 nonce,uint256 signatureExpiresAt)`. This function can only be called directly by the `owner` account or by using the `delegate` function with the following parameters (pseudo code):\n\n```js\n// Data to call the setWallet function normally\nconst data = abiEncode(setWalletSelector, _wallet);\n\n// Random value for replay protection\nconst nonce = randomBytes32();\n\n// Signature expiration\nconst signatureExpiresAt = now + signatureDuration;\n\n// Owner's signature\nconst signature = signTypedData({\n  account: owner,  \n  primaryType: \"SetWallet\", // The EIP712 type\n  domain: { \n    verifyingContract: manager.address\n  },\n  message: {\n    wallet: _wallet,\n    nonce,\n    signatureExpiresAt,\n  }\n});\n\n// Call setWallet through the delegate function\nawait manager.delegate(\n  data,\n  nonce,\n  signatureExpiresAt,\n  signature,\n  {\n    from: anyone\n  }\n);\n```\n\n### delegate function and signature checks\n\nThe `delegate` function performs the following steps:\n\n1. Reentrancy guard (`delegate` can only be called once in the same transaction).\n2. Check that the signature hasn't expired (`now < signatureExpiresAt`).\n3. Store the `nonce`, `signatureExpiresAt` and `signature` parameters.\n4. Call itself with the ABI encoded data (`address(this).call(data)`);\n5. Revert if the call failed.\n6. Delete the stored parameters.\n\nAs the delegation data exists in the storage while the call is being executed, the called function in the child contract can use the internal `_delegatedCheck(bytes32 typeHash, bytes data, bool usesNonce)` function to get the address of the caller. Internally, the `_delegatedCheck` checks if `msg.sender == this` and performs the signature validation using the provided type hash. If `msg.sender != this`, it just returns the `msg.sender`. It also stores the hashed data so it can't be used again for another delegated call.\n\n## Subscription Flow with Delegated Execution\n\nThe only function where delegated execution checks are done manually (doesn't use the `Delegated` functionality) is the `create` function, used to create subscriptions. The flow for creating a subscription works as follows:\n\n1. Subscriber calls the `approve` function in the token in which the subscription is denominated in to allow the manager contract to manipulate her funds.\n2. Using EIP 712, the subscriber signs the creation of a subscription (using the EIP712 type `CreateSubscription`) and sends the data to the `authorizer` server.\n3. The `authorizer` checks that the parameters are OK depending on its own rules, signs the data and sends the data and signatures to the relayer.\n3. The relayer executes the creation by calling the method `create()`, passing the parameters and signatures.\n4. At the beggining of each payment period, anyone can execute the subscription and bill the subscriber.\n\nFor subscription services created using Daisy the platform, Daisy will be the authorizer AND the relayer in this flow. We are also working on a system that will allow clients to be the authorizers by using webhooks (Daisy will request an authorizer signature for each subscription creation request).\n\n## Off-chain service flow\n\n#### Checking if the publisher needs to provide the service\n\n1. Receive request from subscriber.\n2. Call `subscriptionManager.nextPaymentTimestamp(subscriptionId)`.\n3. If `now < nextPaymentTimestamp`, answer the request.\n\n#### Executing subscriptions\n\nTo retrieve all subscription ids from the contract (Note: if count is too large, it is possible to obtain the ids in batches):\n1. Call `subscriptionManager.subscriptionCount()`.\n2. Call `subscriptionManager.subscriptionRange(0, count)`.\n\nTo execute a batch of subscriptions:\n1. Call `subscriptionManager.executeBatch(ids)`.\n2. The following events can be present in the transaction receipt, which can be used by the service to update its state:\n    * `SubscriptionNotFound(subscriptionId)`: Subscription doesn't exist in the contract.\n    * `SubscriptionNotReady(subscriptionId, nextPayment)`: Next payment timestamp hasn't been reached yet.\n    * `SubscriptionExecuted(subscriptionId, nextPayment)`: The subscription was executed successfuly.\n    * `SubscriptionDeleted(subscriptionId, reason)`: The subscription was deleted from the contract.\n\nThe `reason` parameter in the `SubscriptionDeleted` event can correspond to:\n* 0 (CANCELLED): The subscription was cancelled before the execution.\n* 1 (EXPIRED): The subscription reached its maxExecutions in the previous execution.\n* 2 (INVALID_STATE): The state was invalid during the execution. This happens if the subscription's plan was deleted.\n* 3 (NOT_ENOUGH_FUNDS): The subscriber address doesn't have or didn't approve enough funds to perform the execution.\n\nIf the `SubscriptionExecuted` event is present, the following two events can also be present, which represent token allocations (see next section):\n* `PaymentAllocated(subscriptionId, token, recipient, amount)`\n* `FeeAllocated(subscriptionId, token, recipient, amount)`\n\n## Token Allocations and Fees\n\nThe owner of a `SubscriptionManager` can optionally set a `fee` and a `feeRecipient` (which can be changed at any point in time). On each execution, the amount of tokens to be paid to the `feeRecipient` is calculated as `feeAmount = price * fee / MAX_FEE`, and the tokens to be paid to the publisher's `wallet` becomes `price - feeAmount`. `MAX_FEE` is a constant set to `100 * 10^18`, and `fee <= MAX_FEE` always.\n\nThe `SubscriptionManager` uses a pull payment model: on each execution, tokens are always transferred from the subscriber to the manager itself, and the manager allocates tokens to the current `feeRecipient` and `wallet` by storing their payments in the `availableFunds` mapping. When an allocation happens, the `FeeAllocated` event or the `PaymentAllocated` event will be emitted, specifying the `subscriptionId`, `token`, `recipient` and `amount`.\n\nAt any time, anyone can call the `withdraw(address[] tokens, address[] recipients)` function to transfer all the available tokens to each recipient specified in the parameters.\n\n## Key Differences Between Daisy and the Current EIP 1337 Proposal\n\n#### Subscriptions creation is not standardized\n\nBy not defining how the subscription must be created, we can support multiple different use cases (e.g. plan or tier based subscriptions, or subscriptions whose prices are determined by what feautures are turned on/off).\n\n#### Subscription data is stored in the contract\n\nThis makes interoperability with other contracts/services easier, without needing to rely on a centralized data source. Subscription data is removed from the contract if it can't be executed anymore or if the user doesn't have enough funds.\n\n#### Execution of a payment only requires specifying the subscription id\n\nThis allows for easier batching of executions and makes it easier for off-chain services to execute subscriptions.\n\n#### Delegated execution is not part of the interface\n\nIn order to be compatible with other proposals for standardizing delegated execution, the core functions don't need to support delegated execution.\n\n#### `isValidSubscription()` split into `isCancelled(subscriptionId)` and `nextPaymentTimestamp(subscriptionId)`\n\nInstead of having an `isValidSubscription()` function that returns a boolean, this implementation provides a `nextPaymentTimestamp()` function that returns the unix timestamp at which the next payment can be executed. This returned value is more usable than a boolean. On the other hand, with `isCancelled` one can get more granular information about a subscription, improving interoperability.\n\n# Testing\n\nTo run the tests, clone this repo and run `yarn install` to install dependencies.\n\nRun `yarn test` to run all tests.\n\nRun `yarn coverage` to run tests and get code coverage.\n","description":"[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repo","licenseText":"MIT License\n\nCopyright (c) 2019 Token Foundry\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@daisypayments/smart-contracts@0.3.0-beta.4","dist":{"shasum":"7a051a47f2a1a7e050c8c8b70df466fc81efb065","integrity":"sha512-A07R6BPh5xGxUorn68DWqTm+/apucTvn82wJebWurUGcOS257oBbMISTxBS1KuMV/6JLBAAShCeMzMyVxX2GtA==","tarball":"https://registry.npmjs.org/@daisypayments/smart-contracts/-/smart-contracts-0.3.0-beta.4.tgz","fileCount":13,"unpackedSize":3441639,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd3T2gCRA9TVsSAnZWagAAofMP/2/5Jn4V3JPVSTxWafB9\nXWQ11yFDvyVj5PWh0IpYpSuY+MDfXRGIkBOh56Df+hLieO0gUOHVrCiJGF/S\nvw8gUusAR387CxGcbutbpRZVLoclTvgJdWQ9b+jh80ND07REN479mmvsspIP\nk54s9JUgo26zMx9a5xwDJsGPhxQyK2GGIrhKkZewwPGyM8rxt0kzhFpriL+9\nKaOQt/GYRZM8jQmoySAemnsBKwm71nCcaJE4fg9SKK8q9urem//EIPGcKbXt\nnTcSNpxlJAjnQ2gtIv337MY+jNPST4u89qOg6XvXKhv44JWqZ4G1H4E7QjIh\nnSbEnieSH2Teez4flBmLpF6JTI2ZrgqN+14Hk0DJA56sFg6t75HcE8KdkHUU\nNFhNF9sx17JHrloQXfAHSrc3hdviyD61wEFBofCtovS9lVy45mwAJtBbYPTI\nDMPF4/VN20tWo2VQU8S7d59Ee1U6XoVOGWWqGwLidJM8b+GokL/SET5Z8S6R\n1gIvNThAXt84BgguyQBstCyv6s3H4xFIxkBD8uSHkse3VogiH7JUV6GkZlUV\nYiruEpeq0/mgMeloJ6hdJ0BgmryCHKYPToo47ahcD10hlBUhkxTA4cVWNOJU\nombFjWGW7cUt9ZZFvIv5/fFXWQxelPylV0qukSr/+39Bb53nQ5V34dfBWvWS\n9sOV\r\n=km4S\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC1FL43wAkNWVpUbdhlq7FG7dqYUmr8+lP3WYxr/DvaGQIhAKWRzYeynPVK5RPqz8SZVrV86Cqiwu/ZtrsiM6Xo2YU8"}]},"maintainers":[{"name":"jmoreira","email":"jmoreiras@gmail.com"},{"name":"lopezjurip","email":"lopezjuripatricio@gmail.com"},{"name":"nchastain","email":"nate.chastain@consensys.net"},{"name":"sloreti","email":"lhloreti@gmail.com"},{"name":"vdrg","email":"vdrg@protonmail.ch"},{"name":"wachunei","email":"wachunei@gmail.com"}],"_npmUser":{"name":"vdrg","email":"vdrg@protonmail.ch"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/smart-contracts_0.3.0-beta.4_1574780319799_0.022000446059181167"},"_hasShrinkwrap":false},"0.3.0-beta.5":{"name":"@daisypayments/smart-contracts","version":"0.3.0-beta.5","repository":{"type":"git","url":"https://github.com/consensys/daisy-subscription-contracts"},"author":{"name":"vdrg","email":"vicente.dragicevic@consensys.net"},"license":"MIT","main":"index.js","scripts":{"compile":"truffle compile","coverage":"./scripts/coverage.sh","exec":"truffle exec","ganache":"ganache-cli","docgen":"./scripts/docgen.sh","publish-docs":"./scripts/publish-docs.sh","prepublish":"yarn compile","lint":"solhint \"contracts/**/*.sol\"","migrate":"truffle migrate","test":"./scripts/test.sh"},"devDependencies":{"@daisypayments/eslint-config":"^1.5.1","@openzeppelin/test-helpers":"^0.5.3","bip39":"^2.5.0","bn.js":"^4.11.8","chai":"^4.2.0","coveralls":"^3.0.5","dotenv":"^6.2.0","eslint":"^5.13.0","eslint-config-prettier":"^4.0.0","eslint-plugin-mocha":"^5.2.1","eslint-plugin-prettier":"^3.0.1","eth-gas-reporter":"^0.2.12","eth-sig-util":"^2.2.0","ethereumjs-abi":"^0.6.7","ethereumjs-util":"^6.1.0","ethereumjs-wallet":"^0.6.3","ganache-cli":"^6.4.4","lodash":"^4.17.11","moment":"^2.24.0","openzeppelin-solidity":"^2.4.0","openzeppelin-test-helpers":"^0.4.0","prettier":"^1.16.3","solhint":"^2.0.0","solidity-coverage":"^0.6.7","solidity-docgen":"^0.1.1","truffle":"^5.0.25","truffle-hdwallet-provider":"^1.0.4"},"readmeFilename":"README.md","readme":"# Daisy Contracts\n\n[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repos/github/ConsenSys/daisy-subscription-contracts/badge.svg?t=wmZqvk)](https://coveralls.io/github/ConsenSys/daisy-subscription-contracts)\n\n## Overview\n\n### Subscriptions\n\nA subscription is composed of:\n\n* subscriber: address from which tokens will be transferred from.\n* token: address of the ERC 20 token that the subscription is denominated in.\n* price: number of tokens to transfer in each payment.\n* periodUnit: \"DAY\", \"MONTH\", or \"YEAR\".\n* periods: number of period units between payments.\n* maxExecutions: max number of payments that can be made before the subscriber must manually renew their subscription. If this value is 0, there is no execution limit.\n* planIdHash: the hash of the id of the plan the subscription belongs to.\n* credits: amount of tokens to substract from future payments. On each payment, these credits get consumed until they get to 0.\n\nA subscription can be in one of four states:\n1. Active: Once it has been executed and the next payment is in the future. A subscription is first executed upon its creation.\n2. Active and Cancelled: When it is cancelled before reaching the next payment timestamp. It will remain active until the end of the period.\n3. Cancelled: when it has been cancelled and the last billed period has ended.\n4. Deleted: the subscription data will be deleted upon execution if the subscription can't be executed anymore.\n\n### Plans\n\nA plan is just a way to group multiple subscriptions, and allows the publisher to cancel a group of subscriptions at once. A plan is identified in the contract by a bytes32. When a plan based subscription is created, it is necessary to specify the plan's identifier, and the creation only goes through if a valid authorization signature is provided.\n\nThe contract provides a function to delete a plan by providing the plan on chain id. All subscriptions with that plan get invalidated (they get deleted on the next execution).\n\n## Contracts\n\n### `SubscriptionManager.sol`\n\nHandles the creation, execution, and cancellation of subscriptions.\n\nIt also provides methods for enumerating subscriptions and subscription by subscriber. This implementation was adapted from OpenZeppelin's `EIP721Enumerable` [implementation](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC721/ERC721Enumerable.sol).\n\n### `IndexedArrayLib.sol`\n\nLibrary that provides an indexed array of bytes32. It allows us to remove items from the array by specifying the item itself that we want to remove.\n\n### `Delegated.sol`\n\nAllows child contracts to support delegated execution without changing their external APIs. See Delegation section.\n\n## Time\n\nTo support different time units (days, months and years) we use [BokkyPooBah's Date Time Library](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary).\n\n## Delegation\n\nIn order to support delegated execution through the use of EIP712 signatures, the `SubscriptionManager` inherits from `Delegated`. The key feature of the `Delegated` contract is that child contracts don't need to polute their APIs with parameters related to delegated execution.\n\nThe `Delegated` contract exposes the external `delegate` function which receives the following parameters:\n\n* `bytes data`: ABI encoded data to be used for the delegated call.\n* `bytes32 nonce`: Random value for replay protection. If the function to call is idempotent, this value is optional.\n* `uint256 signatureExpiresAt`: Timestamp in which the signature stops being valid.\n* `bytes signature`: The signature for the EIP712 type.\n\nFor example, for the `setWallet(address _wallet)` function in the `SubscriptionManager`, the EIP712 type is `SetWallet(address wallet,bytes32 nonce,uint256 signatureExpiresAt)`. This function can only be called directly by the `owner` account or by using the `delegate` function with the following parameters (pseudo code):\n\n```js\n// Data to call the setWallet function normally\nconst data = abiEncode(setWalletSelector, _wallet);\n\n// Random value for replay protection\nconst nonce = randomBytes32();\n\n// Signature expiration\nconst signatureExpiresAt = now + signatureDuration;\n\n// Owner's signature\nconst signature = signTypedData({\n  account: owner,  \n  primaryType: \"SetWallet\", // The EIP712 type\n  domain: { \n    verifyingContract: manager.address\n  },\n  message: {\n    wallet: _wallet,\n    nonce,\n    signatureExpiresAt,\n  }\n});\n\n// Call setWallet through the delegate function\nawait manager.delegate(\n  data,\n  nonce,\n  signatureExpiresAt,\n  signature,\n  {\n    from: anyone\n  }\n);\n```\n\n### delegate function and signature checks\n\nThe `delegate` function performs the following steps:\n\n1. Reentrancy guard (`delegate` can only be called once in the same transaction).\n2. Check that the signature hasn't expired (`now < signatureExpiresAt`).\n3. Store the `nonce`, `signatureExpiresAt` and `signature` parameters.\n4. Call itself with the ABI encoded data (`address(this).call(data)`);\n5. Revert if the call failed.\n6. Delete the stored parameters.\n\nAs the delegation data exists in the storage while the call is being executed, the called function in the child contract can use the internal `_delegatedCheck(bytes32 typeHash, bytes data, bool usesNonce)` function to get the address of the caller. Internally, the `_delegatedCheck` checks if `msg.sender == this` and performs the signature validation using the provided type hash. If `msg.sender != this`, it just returns the `msg.sender`. It also stores the hashed data so it can't be used again for another delegated call.\n\n## Subscription Flow with Delegated Execution\n\nThe only function where delegated execution checks are done manually (doesn't use the `Delegated` functionality) is the `create` function, used to create subscriptions. The flow for creating a subscription works as follows:\n\n1. Subscriber calls the `approve` function in the token in which the subscription is denominated in to allow the manager contract to manipulate her funds.\n2. Using EIP 712, the subscriber signs the creation of a subscription (using the EIP712 type `CreateSubscription`) and sends the data to the `authorizer` server.\n3. The `authorizer` checks that the parameters are OK depending on its own rules, signs the data and sends the data and signatures to the relayer.\n3. The relayer executes the creation by calling the method `create()`, passing the parameters and signatures.\n4. At the beggining of each payment period, anyone can execute the subscription and bill the subscriber.\n\nFor subscription services created using Daisy the platform, Daisy will be the authorizer AND the relayer in this flow. We are also working on a system that will allow clients to be the authorizers by using webhooks (Daisy will request an authorizer signature for each subscription creation request).\n\n## Off-chain service flow\n\n#### Checking if the publisher needs to provide the service\n\n1. Receive request from subscriber.\n2. Call `subscriptionManager.nextPaymentTimestamp(subscriptionId)`.\n3. If `now < nextPaymentTimestamp`, answer the request.\n\n#### Executing subscriptions\n\nTo retrieve all subscription ids from the contract (Note: if count is too large, it is possible to obtain the ids in batches):\n1. Call `subscriptionManager.subscriptionCount()`.\n2. Call `subscriptionManager.subscriptionRange(0, count)`.\n\nTo execute a batch of subscriptions:\n1. Call `subscriptionManager.executeBatch(ids)`.\n2. The following events can be present in the transaction receipt, which can be used by the service to update its state:\n    * `SubscriptionNotFound(subscriptionId)`: Subscription doesn't exist in the contract.\n    * `SubscriptionNotReady(subscriptionId, nextPayment)`: Next payment timestamp hasn't been reached yet.\n    * `SubscriptionExecuted(subscriptionId, nextPayment)`: The subscription was executed successfuly.\n    * `SubscriptionDeleted(subscriptionId, reason)`: The subscription was deleted from the contract.\n\nThe `reason` parameter in the `SubscriptionDeleted` event can correspond to:\n* 0 (CANCELLED): The subscription was cancelled before the execution.\n* 1 (EXPIRED): The subscription reached its maxExecutions in the previous execution.\n* 2 (INVALID_STATE): The state was invalid during the execution. This happens if the subscription's plan was deleted.\n* 3 (NOT_ENOUGH_FUNDS): The subscriber address doesn't have or didn't approve enough funds to perform the execution.\n\nIf the `SubscriptionExecuted` event is present, the following two events can also be present, which represent token allocations (see next section):\n* `PaymentAllocated(subscriptionId, token, recipient, amount)`\n* `FeeAllocated(subscriptionId, token, recipient, amount)`\n\n## Token Allocations and Fees\n\nThe owner of a `SubscriptionManager` can optionally set a `fee` and a `feeRecipient` (which can be changed at any point in time). On each execution, the amount of tokens to be paid to the `feeRecipient` is calculated as `feeAmount = price * fee / MAX_FEE`, and the tokens to be paid to the publisher's `wallet` becomes `price - feeAmount`. `MAX_FEE` is a constant set to `100 * 10^18`, and `fee <= MAX_FEE` always.\n\nThe `SubscriptionManager` uses a pull payment model: on each execution, tokens are always transferred from the subscriber to the manager itself, and the manager allocates tokens to the current `feeRecipient` and `wallet` by storing their payments in the `availableFunds` mapping. When an allocation happens, the `FeeAllocated` event or the `PaymentAllocated` event will be emitted, specifying the `subscriptionId`, `token`, `recipient` and `amount`.\n\nAt any time, anyone can call the `withdraw(address[] tokens, address[] recipients)` function to transfer all the available tokens to each recipient specified in the parameters.\n\n## Key Differences Between Daisy and the Current EIP 1337 Proposal\n\n#### Subscriptions creation is not standardized\n\nBy not defining how the subscription must be created, we can support multiple different use cases (e.g. plan or tier based subscriptions, or subscriptions whose prices are determined by what feautures are turned on/off).\n\n#### Subscription data is stored in the contract\n\nThis makes interoperability with other contracts/services easier, without needing to rely on a centralized data source. Subscription data is removed from the contract if it can't be executed anymore or if the user doesn't have enough funds.\n\n#### Execution of a payment only requires specifying the subscription id\n\nThis allows for easier batching of executions and makes it easier for off-chain services to execute subscriptions.\n\n#### Delegated execution is not part of the interface\n\nIn order to be compatible with other proposals for standardizing delegated execution, the core functions don't need to support delegated execution.\n\n#### `isValidSubscription()` split into `isCancelled(subscriptionId)` and `nextPaymentTimestamp(subscriptionId)`\n\nInstead of having an `isValidSubscription()` function that returns a boolean, this implementation provides a `nextPaymentTimestamp()` function that returns the unix timestamp at which the next payment can be executed. This returned value is more usable than a boolean. On the other hand, with `isCancelled` one can get more granular information about a subscription, improving interoperability.\n\n# Testing\n\nTo run the tests, clone this repo and run `yarn install` to install dependencies.\n\nRun `yarn test` to run all tests.\n\nRun `yarn coverage` to run tests and get code coverage.\n","description":"[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repo","licenseText":"MIT License\n\nCopyright (c) 2019 Token Foundry\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@daisypayments/smart-contracts@0.3.0-beta.5","dist":{"shasum":"90af66b881f0827f2dfd9b52d2569e3ff76d7d00","integrity":"sha512-IJ6HwVTzW01K0lfmQT2Ia3KEdDz51M4ET3Rw8N8mw7dPUE8a6aI6cB/GouUG/ilqUoM1yO1cnrGCjUQW1/0uSw==","tarball":"https://registry.npmjs.org/@daisypayments/smart-contracts/-/smart-contracts-0.3.0-beta.5.tgz","fileCount":13,"unpackedSize":3441639,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd3T8TCRA9TVsSAnZWagAAul8P/i/IDNbReZZ1RcVu/olw\nsICc8JWOdrNn/cQNV5OTqoL6D6xAxfJrGrpuX3PPj7xUzkMpsVQmp3ufL+iA\n8KwCVLsoDwhE7Rs5mVdE+ikKMg9ohduXadnWSj4BPyrKLDzM9Z9T8TEuuiWz\nMJkYI27hV8j/BrABNhdwrGqfZoTHQyC14niL7Y7iBSZGrRglxwvSJwSHSzhj\njPAtfLGJA2elLRLcFdAcZwqItzGpvnMInMRAdD+7//e9X4tDAX7Zgpp5ZPY3\nWG8741COOZ2FnuuWK45sW1yRO0u9RnuC3NdtDJNY+3UIQMIDcOXASRQfrQoT\nOc80wmsAbXhDM9/O6r2eVBhDYgllUHZ91KVxhLduOVHLij7h+m43gG0GnTqv\nI33LFbNAD+l8gC9114455rgtZiRsLJPwXqe6iTAu9zPDDEp+9z5X9Z6NL03F\nor2PfbfxSHt5F35Jje/HUcycobkzt/Jo2i7kxWvBPGsiLHGksNkAA1dxFu/L\nIa8N/h9RXE4xtgVaa86mvPb3ufJSEywGIC64NS8LvISReTaGlbnzRlFr1e+Z\nptK2PrvWVYAvknpzCC9iB7pnztxhKy8nuoe6+o7lSbyf/HoXILFF/bEDZwnG\n0KJv0+kmSdgqwuFt4cfJfDyDYEi4zm73Zq9V2COwWRs5fIeXD9Z4SkVXMrT1\nqZAC\r\n=lYPm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAOed7GjGXHLrH/2O1rUk1/yCKtNgxW9ARftoYNnFt8WAiEAk5O24eQyHOIy0NUW8KErEaUCOdsWpeChomtMOvmGFRE="}]},"maintainers":[{"name":"jmoreira","email":"jmoreiras@gmail.com"},{"name":"lopezjurip","email":"lopezjuripatricio@gmail.com"},{"name":"nchastain","email":"nate.chastain@consensys.net"},{"name":"sloreti","email":"lhloreti@gmail.com"},{"name":"vdrg","email":"vdrg@protonmail.ch"},{"name":"wachunei","email":"wachunei@gmail.com"}],"_npmUser":{"name":"vdrg","email":"vdrg@protonmail.ch"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/smart-contracts_0.3.0-beta.5_1574780691455_0.12426351085562759"},"_hasShrinkwrap":false},"0.3.0-beta.6":{"name":"@daisypayments/smart-contracts","version":"0.3.0-beta.6","repository":{"type":"git","url":"https://github.com/consensys/daisy-subscription-contracts"},"author":{"name":"vdrg","email":"vicente.dragicevic@consensys.net"},"license":"MIT","main":"index.js","scripts":{"compile":"truffle compile","coverage":"./scripts/coverage.sh","exec":"truffle exec","ganache":"ganache-cli","docgen":"./scripts/docgen.sh","publish-docs":"./scripts/publish-docs.sh","prepublish":"yarn compile","lint":"solhint \"contracts/**/*.sol\"","migrate":"truffle migrate","test":"./scripts/test.sh"},"devDependencies":{"@daisypayments/eslint-config":"^1.5.1","@openzeppelin/test-helpers":"^0.5.3","bip39":"^2.5.0","bn.js":"^4.11.8","chai":"^4.2.0","coveralls":"^3.0.5","dotenv":"^6.2.0","eslint":"^5.13.0","eslint-config-prettier":"^4.0.0","eslint-plugin-mocha":"^5.2.1","eslint-plugin-prettier":"^3.0.1","eth-gas-reporter":"^0.2.12","eth-sig-util":"^2.2.0","ethereumjs-abi":"^0.6.7","ethereumjs-util":"^6.1.0","ethereumjs-wallet":"^0.6.3","ganache-cli":"^6.4.4","lodash":"^4.17.11","moment":"^2.24.0","openzeppelin-solidity":"^2.4.0","openzeppelin-test-helpers":"^0.4.0","prettier":"^1.16.3","solhint":"^2.0.0","solidity-coverage":"^0.6.7","solidity-docgen":"^0.1.1","truffle":"^5.0.25","truffle-hdwallet-provider":"^1.0.4"},"readmeFilename":"README.md","readme":"# Daisy Contracts\n\n[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repos/github/ConsenSys/daisy-subscription-contracts/badge.svg?t=wmZqvk)](https://coveralls.io/github/ConsenSys/daisy-subscription-contracts)\n\n## Overview\n\n### Subscriptions\n\nA subscription is composed of:\n\n* subscriber: address from which tokens will be transferred from.\n* token: address of the ERC 20 token that the subscription is denominated in.\n* price: number of tokens to transfer in each payment.\n* periodUnit: \"DAY\", \"MONTH\", or \"YEAR\".\n* periods: number of period units between payments.\n* maxExecutions: max number of payments that can be made before the subscriber must manually renew their subscription. If this value is 0, there is no execution limit.\n* planIdHash: the hash of the id of the plan the subscription belongs to.\n* credits: amount of tokens to substract from future payments. On each payment, these credits get consumed until they get to 0.\n\nA subscription can be in one of four states:\n1. Active: Once it has been executed and the next payment is in the future. A subscription is first executed upon its creation.\n2. Active and Cancelled: When it is cancelled before reaching the next payment timestamp. It will remain active until the end of the period.\n3. Cancelled: when it has been cancelled and the last billed period has ended.\n4. Deleted: the subscription data will be deleted upon execution if the subscription can't be executed anymore.\n\n### Plans\n\nA plan is just a way to group multiple subscriptions, and allows the publisher to cancel a group of subscriptions at once. A plan is identified in the contract by a bytes32. When a plan based subscription is created, it is necessary to specify the plan's identifier, and the creation only goes through if a valid authorization signature is provided.\n\nThe contract provides a function to delete a plan by providing the plan on chain id. All subscriptions with that plan get invalidated (they get deleted on the next execution).\n\n## Contracts\n\n### `SubscriptionManager.sol`\n\nHandles the creation, execution, and cancellation of subscriptions.\n\nIt also provides methods for enumerating subscriptions and subscription by subscriber. This implementation was adapted from OpenZeppelin's `EIP721Enumerable` [implementation](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC721/ERC721Enumerable.sol).\n\n### `IndexedArrayLib.sol`\n\nLibrary that provides an indexed array of bytes32. It allows us to remove items from the array by specifying the item itself that we want to remove.\n\n### `Delegated.sol`\n\nAllows child contracts to support delegated execution without changing their external APIs. See Delegation section.\n\n## Time\n\nTo support different time units (days, months and years) we use [BokkyPooBah's Date Time Library](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary).\n\n## Delegation\n\nIn order to support delegated execution through the use of EIP712 signatures, the `SubscriptionManager` inherits from `Delegated`. The key feature of the `Delegated` contract is that child contracts don't need to polute their APIs with parameters related to delegated execution.\n\nThe `Delegated` contract exposes the external `delegate` function which receives the following parameters:\n\n* `bytes data`: ABI encoded data to be used for the delegated call.\n* `bytes32 nonce`: Random value for replay protection. If the function to call is idempotent, this value is optional.\n* `uint256 signatureExpiresAt`: Timestamp in which the signature stops being valid.\n* `bytes signature`: The signature for the EIP712 type.\n\nFor example, for the `setWallet(address _wallet)` function in the `SubscriptionManager`, the EIP712 type is `SetWallet(address wallet,bytes32 nonce,uint256 signatureExpiresAt)`. This function can only be called directly by the `owner` account or by using the `delegate` function with the following parameters (pseudo code):\n\n```js\n// Data to call the setWallet function normally\nconst data = abiEncode(setWalletSelector, _wallet);\n\n// Random value for replay protection\nconst nonce = randomBytes32();\n\n// Signature expiration\nconst signatureExpiresAt = now + signatureDuration;\n\n// Owner's signature\nconst signature = signTypedData({\n  account: owner,  \n  primaryType: \"SetWallet\", // The EIP712 type\n  domain: { \n    verifyingContract: manager.address\n  },\n  message: {\n    wallet: _wallet,\n    nonce,\n    signatureExpiresAt,\n  }\n});\n\n// Call setWallet through the delegate function\nawait manager.delegate(\n  data,\n  nonce,\n  signatureExpiresAt,\n  signature,\n  {\n    from: anyone\n  }\n);\n```\n\n### delegate function and signature checks\n\nThe `delegate` function performs the following steps:\n\n1. Reentrancy guard (`delegate` can only be called once in the same transaction).\n2. Check that the signature hasn't expired (`now < signatureExpiresAt`).\n3. Store the `nonce`, `signatureExpiresAt` and `signature` parameters.\n4. Call itself with the ABI encoded data (`address(this).call(data)`);\n5. Revert if the call failed.\n6. Delete the stored parameters.\n\nAs the delegation data exists in the storage while the call is being executed, the called function in the child contract can use the internal `_delegatedCheck(bytes32 typeHash, bytes data, bool usesNonce)` function to get the address of the caller. Internally, the `_delegatedCheck` checks if `msg.sender == this` and performs the signature validation using the provided type hash. If `msg.sender != this`, it just returns the `msg.sender`. It also stores the hashed data so it can't be used again for another delegated call.\n\n## Subscription Flow with Delegated Execution\n\nThe only function where delegated execution checks are done manually (doesn't use the `Delegated` functionality) is the `create` function, used to create subscriptions. The flow for creating a subscription works as follows:\n\n1. Subscriber calls the `approve` function in the token in which the subscription is denominated in to allow the manager contract to manipulate her funds.\n2. Using EIP 712, the subscriber signs the creation of a subscription (using the EIP712 type `CreateSubscription`) and sends the data to the `authorizer` server.\n3. The `authorizer` checks that the parameters are OK depending on its own rules, signs the data and sends the data and signatures to the relayer.\n3. The relayer executes the creation by calling the method `create()`, passing the parameters and signatures.\n4. At the beggining of each payment period, anyone can execute the subscription and bill the subscriber.\n\nFor subscription services created using Daisy the platform, Daisy will be the authorizer AND the relayer in this flow. We are also working on a system that will allow clients to be the authorizers by using webhooks (Daisy will request an authorizer signature for each subscription creation request).\n\n## Off-chain service flow\n\n#### Checking if the publisher needs to provide the service\n\n1. Receive request from subscriber.\n2. Call `subscriptionManager.nextPaymentTimestamp(subscriptionId)`.\n3. If `now < nextPaymentTimestamp`, answer the request.\n\n#### Executing subscriptions\n\nTo retrieve all subscription ids from the contract (Note: if count is too large, it is possible to obtain the ids in batches):\n1. Call `subscriptionManager.subscriptionCount()`.\n2. Call `subscriptionManager.subscriptionRange(0, count)`.\n\nTo execute a batch of subscriptions:\n1. Call `subscriptionManager.executeBatch(ids)`.\n2. The following events can be present in the transaction receipt, which can be used by the service to update its state:\n    * `SubscriptionNotFound(subscriptionId)`: Subscription doesn't exist in the contract.\n    * `SubscriptionNotReady(subscriptionId, nextPayment)`: Next payment timestamp hasn't been reached yet.\n    * `SubscriptionExecuted(subscriptionId, nextPayment)`: The subscription was executed successfuly.\n    * `SubscriptionDeleted(subscriptionId, reason)`: The subscription was deleted from the contract.\n\nThe `reason` parameter in the `SubscriptionDeleted` event can correspond to:\n* 0 (CANCELLED): The subscription was cancelled before the execution.\n* 1 (EXPIRED): The subscription reached its maxExecutions in the previous execution.\n* 2 (INVALID_STATE): The state was invalid during the execution. This happens if the subscription's plan was deleted.\n* 3 (NOT_ENOUGH_FUNDS): The subscriber address doesn't have or didn't approve enough funds to perform the execution.\n\nIf the `SubscriptionExecuted` event is present, the following two events can also be present, which represent token allocations (see next section):\n* `PaymentAllocated(subscriptionId, token, recipient, amount)`\n* `FeeAllocated(subscriptionId, token, recipient, amount)`\n\n## Token Allocations and Fees\n\nThe owner of a `SubscriptionManager` can optionally set a `fee` and a `feeRecipient` (which can be changed at any point in time). On each execution, the amount of tokens to be paid to the `feeRecipient` is calculated as `feeAmount = price * fee / MAX_FEE`, and the tokens to be paid to the publisher's `wallet` becomes `price - feeAmount`. `MAX_FEE` is a constant set to `100 * 10^18`, and `fee <= MAX_FEE` always.\n\nThe `SubscriptionManager` uses a pull payment model: on each execution, tokens are always transferred from the subscriber to the manager itself, and the manager allocates tokens to the current `feeRecipient` and `wallet` by storing their payments in the `availableFunds` mapping. When an allocation happens, the `FeeAllocated` event or the `PaymentAllocated` event will be emitted, specifying the `subscriptionId`, `token`, `recipient` and `amount`.\n\nAt any time, anyone can call the `withdraw(address[] tokens, address[] recipients)` function to transfer all the available tokens to each recipient specified in the parameters.\n\n## Key Differences Between Daisy and the Current EIP 1337 Proposal\n\n#### Subscriptions creation is not standardized\n\nBy not defining how the subscription must be created, we can support multiple different use cases (e.g. plan or tier based subscriptions, or subscriptions whose prices are determined by what feautures are turned on/off).\n\n#### Subscription data is stored in the contract\n\nThis makes interoperability with other contracts/services easier, without needing to rely on a centralized data source. Subscription data is removed from the contract if it can't be executed anymore or if the user doesn't have enough funds.\n\n#### Execution of a payment only requires specifying the subscription id\n\nThis allows for easier batching of executions and makes it easier for off-chain services to execute subscriptions.\n\n#### Delegated execution is not part of the interface\n\nIn order to be compatible with other proposals for standardizing delegated execution, the core functions don't need to support delegated execution.\n\n#### `isValidSubscription()` split into `isCancelled(subscriptionId)` and `nextPaymentTimestamp(subscriptionId)`\n\nInstead of having an `isValidSubscription()` function that returns a boolean, this implementation provides a `nextPaymentTimestamp()` function that returns the unix timestamp at which the next payment can be executed. This returned value is more usable than a boolean. On the other hand, with `isCancelled` one can get more granular information about a subscription, improving interoperability.\n\n# Testing\n\nTo run the tests, clone this repo and run `yarn install` to install dependencies.\n\nRun `yarn test` to run all tests.\n\nRun `yarn coverage` to run tests and get code coverage.\n","description":"[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repo","licenseText":"MIT License\n\nCopyright (c) 2019 Token Foundry\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@daisypayments/smart-contracts@0.3.0-beta.6","dist":{"shasum":"ea6996669cd793983d787abcef2f99d48ea2bbfc","integrity":"sha512-xAp83LRM+4EYam2pcae+Dt/XMJs9Jij7T8WZcRPFiUk7nYnBD2Z62zjLfTZrJzgcsNk4UEtjP4mOAmUcNMRtXg==","tarball":"https://registry.npmjs.org/@daisypayments/smart-contracts/-/smart-contracts-0.3.0-beta.6.tgz","fileCount":14,"unpackedSize":3820864,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd3qg2CRA9TVsSAnZWagAAw78QAILQdwnOuh/mG3+0zaFu\noCuH41TbTBApG9H5pK1gx264/Mu4udjUWJ1Pe3bGqlaLeJery0Jk1e/MDS68\nTsx04i4jzyTpMOBSfHR3I6wA5VfuKtnGX706oN3DLlktP+C6oZ0rEib4sqvc\nPlh/vugMaRwSlTCDWBktLnhsIUPXqS+7IE4pc+MvTFYS1inh/n/+LlhWvNSf\nYRtME18PU6yk7s5/PE4teznarnYSsdR0i26P+xobMDKWCGGJ34meoY9LJtSk\nYq/wERtpJp4sVtISv1M7ZAebeE4ARg5ir5fVOvd8CSSHmsBEGybhI0xOQBHR\nHUS5BjxF46zqAcCt7hfXZGh4UljaJFb3g57kp+iq+vKhqf7MWvXWzZa5qyrv\n2rB/G6FeBvMM6EdHypwvWOBqEZfLO/h50kaathKKpzDEt6niPofHHaOxO51y\ne6iPyz63hu8+jXExFnonPeisYTF8T+4dwQMSKwgNyskr25SmUqGhEGTV6zju\n/UPZrFkbirzLi/fzd9628ccv62B6VhioNwdo3qegTNOkp4V0xJdHSEyhoiHX\nmOdCTZ6Xu/qSChgHjOImf3tFkwpGlnEZxADvyq9Ka+1m9GHmm5+CEE8TbNAl\nFv7bHLiW7HsulKlgr4GtvA4oYqVQp76T8WuCJfBwqNYpEZmuu7xw9u6e8zdc\nXfRj\r\n=+91t\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDMGsLdrlNHRVVps/iLb939hIzwbnNSCeCVJyYFuCzJSQIhAJFwekPc+XBOgWYORQkOhZ1xct/l4p2YDiRiOBvbDTk1"}]},"maintainers":[{"name":"jmoreira","email":"jmoreiras@gmail.com"},{"name":"lopezjurip","email":"lopezjuripatricio@gmail.com"},{"name":"nchastain","email":"nate.chastain@consensys.net"},{"name":"sloreti","email":"lhloreti@gmail.com"},{"name":"vdrg","email":"vdrg@protonmail.ch"},{"name":"wachunei","email":"wachunei@gmail.com"}],"_npmUser":{"name":"vdrg","email":"vdrg@protonmail.ch"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/smart-contracts_0.3.0-beta.6_1574873142216_0.226297635672577"},"_hasShrinkwrap":false},"0.4.0-beta.1":{"name":"@daisypayments/smart-contracts","version":"0.4.0-beta.1","repository":{"type":"git","url":"https://github.com/consensys/daisy-subscription-contracts"},"author":{"name":"vdrg","email":"vicente.dragicevic@consensys.net"},"license":"MIT","main":"index.js","scripts":{"build":"yarn compile && tsc -p ./tsconfig.build.json","compile":"truffle compile","coverage":"truffle run coverage","exec":"truffle exec","docgen":"./scripts/docgen.sh","publish-docs":"./scripts/publish-docs.sh","prepublish":"yarn build","lint":"solhint \"contracts/**/*.sol\"","migrate":"truffle migrate","test":"truffle test"},"devDependencies":{"@daisypayments/eslint-config":"^2.1.1","@openzeppelin/contracts":"^3.0.0-rc.1","@openzeppelin/test-environment":"^0.1.2","@openzeppelin/test-helpers":"^0.5.4","@types/lodash":"^4.14.149","@types/web3":"^1.2.2","bip39":"^2.5.0","bn.js":"^4.11.8","chai":"^4.2.0","coveralls":"^3.0.5","dotenv":"^6.2.0","eslint":"^6.8.0","eslint-plugin-mocha":"^6.3.0","eslint-plugin-prettier":"^3.1.3","eth-gas-reporter":"^0.2.17","eth-sig-util":"^2.2.0","ethereumjs-abi":"^0.6.7","ethereumjs-util":"^6.1.0","ethereumjs-wallet":"^0.6.3","ganache-cli":"^6.9.1","lodash":"^4.17.11","mocha":"^7.0.0","moment":"^2.24.0","prettier":"^1.16.3","solhint":"^2.0.0","solidity-coverage":"^0.7.4","solidity-docgen":"^0.1.1","truffle":"^5.1.21","truffle-hdwallet-provider":"^1.0.4","truffle-typings":"^1.0.8","ts-node":"^8.8.2","typescript":"^3.8.3"},"dependencies":{"@types/chai":"^4.2.11"},"readmeFilename":"README.md","readme":"# Daisy Contracts\n\n[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repos/github/ConsenSys/daisy-subscription-contracts/badge.svg?t=wmZqvk)](https://coveralls.io/github/ConsenSys/daisy-subscription-contracts)\n\n## Overview\n\n### Transfer Proxy\n\nA transfer proxy is a simple smart contract that allows its owner to withdraw any token from any set of addresses that have previously approved tokens to it. It also supports transferring tokens and ether that has been sent directly to the contract. It is the base layer for the subscriptions and one time payments system.\n\n### Payment Manager\n\nThe Payment Manager  is a contract that allows daisy to execute payments by deploying Transfer Proxies when a payment is executed. A payment is composed by a set of parameters that will determine the address of the Transfer Proxy that will be used, and by two variable parameters that can change between executions for the same Transfer Proxy.\n\nThe main function corresponds to `execute(Payment[] payments, bytes sig)`, which takes an array of `Payment`s and a signature, and tries to execute them.\n\n### Payment execution\n\nThe manager handles the execution of recurrent payments by providing a function that receives an array of Payments. Payments are structs that contain information about the current execution. The hash of this array of invoices needs to be signed by a special address set in this contract.\n\nThe parameters of each `Payment` are used to compute the address of Transfer Proxy, and if the Transfer Proxy doesn't exist then it gets deployed using the `CREATE2` opcode. After the contract is deployed, the parameters of the `Payment` are used to execute the payment and enforce certain conditions. The main idea behind using create2 is that when a user approves tokens to the address of a Transfer Proxy, she is implicitly agreeing to the terms before the contract is even created, as the address is deterministically computed from said terms. Also, it reduces the amount of transactions Daisy needs to send as we can safely compute Transfer Proxy addresses off-chain, and we only send transactions if we are sure that the payment will go through.\n\nPayment struct (parameters marked as \"variable\" are not used to compute the Transfer Proxy address used for the payment):\n* IERC20 token: address of the ERC 20 token that will be used to perform the payment.\n* address wallet: wallet where funds will be transferred.\n* uint256 maxAmount: maximum number of tokens to transfer in each payment.\n* uint256 periods: number of period units between payments.\n* PeriodUnit periodUnit: \"NONE\", \"DAY\", \"WEEK\", \"MONTH\", or \"YEAR\".\n* uint256 startsAt: timestamps in which the first payment can be executed.\n* bytes32 salt: number of times a payment has been executed.\n* address callback: address that will be called after a payment is successfuly executed.\n* bytes callbackData: data passed to the callback contract.\n* (variable) address[] from: array of address to transfer tokens from (not supported for ether).\n* (variable) uint256 amount: amount of tokens/wei\n\nIn order to execute a payment, the following condition has to hold: `addPeriods(startsAt, executions * periods, periodUnit) <= now`. The addresses provided on each payment execution can be any set of addresses that have approved tokens to the transfer proxy contract, and off-chain services can obtain them by reading the event logs of the `token` contract. If we want to transfer tokens or ether held by the transfer proxy, an empty array of addresses can be passed to the execute function.\n\nAs the amount to be transferred on each execution is set by the authorized addresses (can't go over the maxAmount parameter), this allows us to support the following usecases:\n1. Applying discounts for a number of periods (handled off-chain), even after the recurrent payment has been created.\n2. Metered billing: as the amounts stored in the terms are actually the maximum amounts that can be charged on an execution, we can vary the amount to be transferred depending on the reported usage by the merchant.\n\n#### Paying with Ether directly\n\n\n\n#### Paying with ERC20 directly\n#### Paying with ERC20 by approving\n\n## Contracts\n\n### `PaymentsManager.sol`\n\nHandles the creation, batched execution, and cancellation of recurrent payments.\n\n### `TransferProxy.sol`\n\nIts main objective is to withdraw funds from a set of addresses that have previously approved tokens to it. The transfers can only happen if the current period has passed.\n\n### `IndexedArrayLib.sol`\n\nLibrary that provides an indexed array of bytes32. It allows us to remove items from the array by specifying the item itself that we want to remove.\n\n### `Delegated.sol`\n\nAllows child contracts to support delegated execution without changing their external APIs. See Delegation section.\n\n## Time\n\nTo support different time units (days, months and years) we use [BokkyPooBah's Date Time Library](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary).\n\n## Delegation\n\nIn order to support delegated execution through the use of EIP712 signatures, the `Delegated` contract can be used. The key feature of the `Delegated` contract is that child contracts don't need to polute their APIs with parameters related to delegated execution.\n\nThe `Delegated` contract exposes the external `delegate` function which receives the following parameters:\n\n* `bytes data`: ABI encoded data to be used for the delegated call.\n* `bytes32 nonce`: Random value for replay protection. If the function to call is idempotent, this value is optional.\n* `uint256 signatureExpiresAt`: Timestamp in which the signature stops being valid.\n* `bytes signature`: The signature for the EIP712 type.\n\nFor example, for the `setWallet(address _wallet)` function in the `SubscriptionManager`, the EIP712 type is `SetWallet(address wallet,bytes32 nonce,uint256 signatureExpiresAt)`. This function can only be called directly by the `owner` account or by using the `delegate` function with the following parameters (pseudo code):\n\n```js\n// Data to call the setWallet function normally\nconst data = abiEncode(setWalletSelector, _wallet);\n\n// Random value for replay protection\nconst nonce = randomBytes32();\n\n// Signature expiration\nconst signatureExpiresAt = now + signatureDuration;\n\n// Owner's signature\nconst signature = signTypedData({\n  account: owner,  \n  primaryType: \"SetWallet\", // The EIP712 type\n  domain: { \n    verifyingContract: manager.address\n  },\n  message: {\n    wallet: _wallet,\n    nonce,\n    signatureExpiresAt,\n  }\n});\n\n// Call setWallet through the delegate function\nawait manager.delegate(\n  data,\n  nonce,\n  signatureExpiresAt,\n  signature,\n  {\n    from: anyone\n  }\n);\n```\n\n### delegate function and signature checks\n\nThe `delegate` function performs the following steps:\n\n1. Reentrancy guard (`delegate` can only be called once in the same transaction).\n2. Check that the signature hasn't expired (`now < signatureExpiresAt`).\n3. Store the `nonce`, `signatureExpiresAt` and `signature` parameters.\n4. Call itself with the ABI encoded data (`address(this).call(data)`);\n5. Revert if the call failed.\n6. Delete the stored parameters.\n\nAs the delegation data exists in the storage while the call is being executed, the called function in the child contract can use the internal `_delegatedCheck(bytes32 typeHash, bytes data, bool usesNonce)` function to get the address of the caller. Internally, the `_delegatedCheck` checks if `msg.sender == this` and performs the signature validation using the provided type hash. If `msg.sender != this`, it just returns the `msg.sender`. It also stores the hashed data so it can't be used again for another delegated call.\n\n## Flow for creating a recurrent payment\n\nThe only function where delegated execution checks are done manually (doesn't use the `Delegated` functionality) is the `create` function, used to create subscriptions. The flow for creating a subscription works as follows:\n1. Gather the parameters for the new recurrent payment to be created.\n2. Compute the address of the recurrent payment contract from the parameters.\n3. The user approves tokens to the computed address.\n4. Once the approval has been confirmed, send a transaction to create the recurring payment contract and begin withdrawing funds from the user every period.\n\n## Daisy\n\nFor subscription services created using Daisy the platform, Daisy will be the authorizer AND the relayer for payments.\n\n# Testing\n\nTo run the tests, clone this repo and run `yarn install` to install dependencies.\n\nRun `yarn test` to run all tests.\n\nRun `yarn coverage` to run tests and get code coverage.\n","description":"[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repo","licenseText":"MIT License\n\nCopyright (c) 2019 Token Foundry\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@daisypayments/smart-contracts@0.4.0-beta.1","dist":{"shasum":"8855b80f024c8804b34287c9ce2cad09857550d0","integrity":"sha512-lHbno/yedluZ97YHKudksieqiRGDstc7ZJsJbDuYSdCC/YN/DpzFi+BsV2qYVbiI8dPg3tzrsbZpLPXIUzxk7A==","tarball":"https://registry.npmjs.org/@daisypayments/smart-contracts/-/smart-contracts-0.4.0-beta.1.tgz","fileCount":13,"unpackedSize":1044019,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJemguLCRA9TVsSAnZWagAAg8wP/0iqto4rT2wF7bjqmZpB\n6PAWa7VqRAnCslZMi3RvvURN+cYHFlvxHSP/WVFCAodXEfoYGlzwztYujFxB\nXDGSYkVFz0nqpfLDNsRcvEf+y7oqRzSuaMRV56dD/CxsrEIyFu1Gb8U9Bopm\n7NV+nNsntuiolt3C/FzI7RcCqBQz3Qq69bp/nL8lenoeJSLQO870NXSR+2m1\nwR0pllHXSdyfiTZXnaLvYlTMGUbt1dh5slDXlHOrGamNwXX+h9KlpQgo9OAs\n53pOziDeX29LZpNOj0vT9noXLB6KV2LmvvukkZ++UhZtqU43UPBFbHjwchuE\nNfcc5JRBgzdduobKcXbEzP66f9kMAwfa57gwfBS6vY0RusVwK3r/ORaZFNaf\nMQhtIEUi1CBSB4Sv+Gl26H4wnXIQ4Ytzqtp6zCQhbFdgbriiK2uTfyqQRnRd\n59kQ9vL95JMSTGKDR4aHKnwhb47snieAiUSMJq7s0g5SmUgpsbT3+Lw1nfoB\nOGvZtuyKltEKWbEBwYUl01RS1W5iiFqQPpCS3vwUBZ8yBtssAUzJ9voM55ud\nFKCjB2zsTDBe1/JIE8mYdQkNauCMPWIfFDDwIA1ntyezxGha/qGZioxD0g6/\ng43/KQgwkI7raQ9MpWRKysrw322hclyhA6whvKUWAQY/3az0gspNGmrhiUNv\nN+Q4\r\n=gZQG\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC+1LLMbllpXKBSF23Mee1G2nG6Z5KHZxbiUF4B5/y97wIgEVjDPdILINUb2KZwJvTUprS5F/mFhp/haoSwVskL7oM="}]},"maintainers":[{"name":"jmoreira","email":"jmoreiras@gmail.com"},{"name":"lopezjurip","email":"lopezjuripatricio@gmail.com"},{"name":"nchastain","email":"nate.chastain@consensys.net"},{"name":"sloreti","email":"lhloreti@gmail.com"},{"name":"vdrg","email":"vdrg@protonmail.ch"},{"name":"wachunei","email":"wachunei@gmail.com"}],"_npmUser":{"name":"vdrg","email":"vdrg@protonmail.ch"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/smart-contracts_0.4.0-beta.1_1587153803335_0.951270805601262"},"_hasShrinkwrap":false},"0.4.0-beta.2":{"name":"@daisypayments/smart-contracts","version":"0.4.0-beta.2","repository":{"type":"git","url":"https://github.com/consensys/daisy-subscription-contracts"},"author":{"name":"vdrg","email":"vicente.dragicevic@consensys.net"},"license":"MIT","main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"yarn compile && tsc -p ./tsconfig.build.json","compile":"truffle compile","coverage":"truffle run coverage","exec":"truffle exec","docgen":"./scripts/docgen.sh","publish-docs":"./scripts/publish-docs.sh","prepublish":"yarn build","lint":"solhint \"contracts/**/*.sol\"","migrate":"truffle migrate","test":"truffle test"},"devDependencies":{"@daisypayments/eslint-config":"^2.1.1","@openzeppelin/contracts":"^3.0.0-rc.1","@openzeppelin/test-environment":"^0.1.2","@openzeppelin/test-helpers":"^0.5.4","@types/chai":"^4.2.11","@types/lodash":"^4.14.149","@types/web3":"^1.2.2","bip39":"^2.5.0","bn.js":"^4.11.8","chai":"^4.2.0","coveralls":"^3.0.5","dotenv":"^6.2.0","eslint":"^6.8.0","eslint-plugin-mocha":"^6.3.0","eslint-plugin-prettier":"^3.1.3","eth-gas-reporter":"^0.2.17","eth-sig-util":"^2.2.0","ethereumjs-abi":"^0.6.7","ethereumjs-util":"^6.1.0","ethereumjs-wallet":"^0.6.3","ganache-cli":"^6.9.1","lodash":"^4.17.11","mocha":"^7.0.0","moment":"^2.24.0","prettier":"^1.16.3","solhint":"^2.0.0","solidity-coverage":"^0.7.4","solidity-docgen":"^0.1.1","truffle":"^5.1.21","truffle-hdwallet-provider":"^1.0.4","truffle-typings":"^1.0.8","ts-node":"^8.8.2","typescript":"^3.8.3"},"readmeFilename":"README.md","readme":"# Daisy Contracts\n\n[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repos/github/ConsenSys/daisy-subscription-contracts/badge.svg?t=wmZqvk)](https://coveralls.io/github/ConsenSys/daisy-subscription-contracts)\n\n## Overview\n\n### Transfer Proxy\n\nA transfer proxy is a simple smart contract that allows its owner to withdraw any token from any set of addresses that have previously approved tokens to it. It also supports transferring tokens and ether that has been sent directly to the contract. It is the base layer for the subscriptions and one time payments system.\n\n### Payment Manager\n\nThe Payment Manager  is a contract that allows daisy to execute payments by deploying Transfer Proxies when a payment is executed. A payment is composed by a set of parameters that will determine the address of the Transfer Proxy that will be used, and by two variable parameters that can change between executions for the same Transfer Proxy.\n\nThe main function corresponds to `execute(Payment[] payments, bytes sig)`, which takes an array of `Payment`s and a signature, and tries to execute them.\n\n### Payment execution\n\nThe manager handles the execution of recurrent payments by providing a function that receives an array of Payments. Payments are structs that contain information about the current execution. The hash of this array of invoices needs to be signed by a special address set in this contract.\n\nThe parameters of each `Payment` are used to compute the address of Transfer Proxy, and if the Transfer Proxy doesn't exist then it gets deployed using the `CREATE2` opcode. After the contract is deployed, the parameters of the `Payment` are used to execute the payment and enforce certain conditions. The main idea behind using create2 is that when a user approves tokens to the address of a Transfer Proxy, she is implicitly agreeing to the terms before the contract is even created, as the address is deterministically computed from said terms. Also, it reduces the amount of transactions Daisy needs to send as we can safely compute Transfer Proxy addresses off-chain, and we only send transactions if we are sure that the payment will go through.\n\nPayment struct (parameters marked as \"variable\" are not used to compute the Transfer Proxy address used for the payment):\n* IERC20 token: address of the ERC 20 token that will be used to perform the payment.\n* address wallet: wallet where funds will be transferred.\n* uint256 maxAmount: maximum number of tokens to transfer in each payment.\n* uint256 periods: number of period units between payments.\n* PeriodUnit periodUnit: \"NONE\", \"DAY\", \"WEEK\", \"MONTH\", or \"YEAR\".\n* uint256 startsAt: timestamps in which the first payment can be executed.\n* bytes32 salt: number of times a payment has been executed.\n* address callback: address that will be called after a payment is successfuly executed.\n* bytes callbackData: data passed to the callback contract.\n* (variable) address[] from: array of address to transfer tokens from (not supported for ether).\n* (variable) uint256 amount: amount of tokens/wei\n\nIn order to execute a payment, the following condition has to hold: `addPeriods(startsAt, executions * periods, periodUnit) <= now`. The addresses provided on each payment execution can be any set of addresses that have approved tokens to the transfer proxy contract, and off-chain services can obtain them by reading the event logs of the `token` contract. If we want to transfer tokens or ether held by the transfer proxy, an empty array of addresses can be passed to the execute function.\n\nAs the amount to be transferred on each execution is set by the authorized addresses (can't go over the maxAmount parameter), this allows us to support the following usecases:\n1. Applying discounts for a number of periods (handled off-chain), even after the recurrent payment has been created.\n2. Metered billing: as the amounts stored in the terms are actually the maximum amounts that can be charged on an execution, we can vary the amount to be transferred depending on the reported usage by the merchant.\n\n#### Paying with Ether directly\n\n\n\n#### Paying with ERC20 directly\n#### Paying with ERC20 by approving\n\n## Contracts\n\n### `PaymentsManager.sol`\n\nHandles the creation, batched execution, and cancellation of recurrent payments.\n\n### `TransferProxy.sol`\n\nIts main objective is to withdraw funds from a set of addresses that have previously approved tokens to it. The transfers can only happen if the current period has passed.\n\n### `IndexedArrayLib.sol`\n\nLibrary that provides an indexed array of bytes32. It allows us to remove items from the array by specifying the item itself that we want to remove.\n\n### `Delegated.sol`\n\nAllows child contracts to support delegated execution without changing their external APIs. See Delegation section.\n\n## Time\n\nTo support different time units (days, months and years) we use [BokkyPooBah's Date Time Library](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary).\n\n## Delegation\n\nIn order to support delegated execution through the use of EIP712 signatures, the `Delegated` contract can be used. The key feature of the `Delegated` contract is that child contracts don't need to polute their APIs with parameters related to delegated execution.\n\nThe `Delegated` contract exposes the external `delegate` function which receives the following parameters:\n\n* `bytes data`: ABI encoded data to be used for the delegated call.\n* `bytes32 nonce`: Random value for replay protection. If the function to call is idempotent, this value is optional.\n* `uint256 signatureExpiresAt`: Timestamp in which the signature stops being valid.\n* `bytes signature`: The signature for the EIP712 type.\n\nFor example, for the `setWallet(address _wallet)` function in the `SubscriptionManager`, the EIP712 type is `SetWallet(address wallet,bytes32 nonce,uint256 signatureExpiresAt)`. This function can only be called directly by the `owner` account or by using the `delegate` function with the following parameters (pseudo code):\n\n```js\n// Data to call the setWallet function normally\nconst data = abiEncode(setWalletSelector, _wallet);\n\n// Random value for replay protection\nconst nonce = randomBytes32();\n\n// Signature expiration\nconst signatureExpiresAt = now + signatureDuration;\n\n// Owner's signature\nconst signature = signTypedData({\n  account: owner,  \n  primaryType: \"SetWallet\", // The EIP712 type\n  domain: { \n    verifyingContract: manager.address\n  },\n  message: {\n    wallet: _wallet,\n    nonce,\n    signatureExpiresAt,\n  }\n});\n\n// Call setWallet through the delegate function\nawait manager.delegate(\n  data,\n  nonce,\n  signatureExpiresAt,\n  signature,\n  {\n    from: anyone\n  }\n);\n```\n\n### delegate function and signature checks\n\nThe `delegate` function performs the following steps:\n\n1. Reentrancy guard (`delegate` can only be called once in the same transaction).\n2. Check that the signature hasn't expired (`now < signatureExpiresAt`).\n3. Store the `nonce`, `signatureExpiresAt` and `signature` parameters.\n4. Call itself with the ABI encoded data (`address(this).call(data)`);\n5. Revert if the call failed.\n6. Delete the stored parameters.\n\nAs the delegation data exists in the storage while the call is being executed, the called function in the child contract can use the internal `_delegatedCheck(bytes32 typeHash, bytes data, bool usesNonce)` function to get the address of the caller. Internally, the `_delegatedCheck` checks if `msg.sender == this` and performs the signature validation using the provided type hash. If `msg.sender != this`, it just returns the `msg.sender`. It also stores the hashed data so it can't be used again for another delegated call.\n\n## Flow for creating a recurrent payment\n\nThe only function where delegated execution checks are done manually (doesn't use the `Delegated` functionality) is the `create` function, used to create subscriptions. The flow for creating a subscription works as follows:\n1. Gather the parameters for the new recurrent payment to be created.\n2. Compute the address of the recurrent payment contract from the parameters.\n3. The user approves tokens to the computed address.\n4. Once the approval has been confirmed, send a transaction to create the recurring payment contract and begin withdrawing funds from the user every period.\n\n## Daisy\n\nFor subscription services created using Daisy the platform, Daisy will be the authorizer AND the relayer for payments.\n\n# Testing\n\nTo run the tests, clone this repo and run `yarn install` to install dependencies.\n\nRun `yarn test` to run all tests.\n\nRun `yarn coverage` to run tests and get code coverage.\n","description":"[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repo","licenseText":"MIT License\n\nCopyright (c) 2019 Token Foundry\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@daisypayments/smart-contracts@0.4.0-beta.2","dist":{"shasum":"2c08b04e465bfd4fba44b851d2a6c744a6384234","integrity":"sha512-VnY7RA00oJ1m2NbKcx674gCozkiqSOEdzrHvlmpF6MJBUO1sNpJy2tHbMOMQAI0rGnC7dNgIA37ocZmQyAR2zQ==","tarball":"https://registry.npmjs.org/@daisypayments/smart-contracts/-/smart-contracts-0.4.0-beta.2.tgz","fileCount":21,"unpackedSize":4611329,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJemhOICRA9TVsSAnZWagAApooP/icrlf780nKQqfleO+Id\nzHchkxTcJgMbtDTmK4ZdoZW4FkaB65pS+9G3LgljVxVmHB56fchKNWYQye4K\nxvk7dmnKdUxhhe+8PzcAn1rXp98bXNaYOXVpioXLMVPj4LPkunRKwFs/yMn4\nQvDr9r1MuUw2siYiW9+oS6jdcBmFml2+zP6/Ihdot5+QSa4XydYSnWjzOmMd\n1hYecZFnlgJM1gjaXXFUGrfoGcsG+PgEIUqymRNyvsb1WVWPZOZPN+TCzhq+\nP+J6aYzxbJDvHjkorLSWJE1xj8kOiS+sTtlf4TYRC6OFojtJRZ8xDi1qIdpY\nsHNfHTN5Wy+JitbyAdhQ36TqJWt/0A80L2eg8BmyIygHGvw0CrIZcGcKOsF7\nUVqFJtx48Ptabkm8KxjzbI2J4mUSJQSbvYO1xziDKPUbcD/i/0wwZBv3gXoB\nnF7SK64v4NQnzvu5rhobcHqC4Vu3xmOHlRxXeFTgdoRQ17QcTggHEiJU/3XH\n5seWPCpPgioeYyzjSx2eBQ36rwNACstJboYVKDOE3K2HjsIHs+RUJK2pzHat\nr87OjCVEY0kcM9uUr+bZrv2i6ffGDyY/OywS+NfuKKWBG354T7KSJiGHnIzg\nn0oqSFE6CLZYeu7zlVJO3dzmh3L+s0Hzsf25YRPjrM7OVSlxr+3C5Cau54Co\nLKGV\r\n=Byf6\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCoqNoRWjzdNJPO6jQ7pGGnT9YCJKakRjgGXnOnsToraQIhAJ9IzbPUjSyk653xxZfpo5yQ3G7hV3Wx26mYVnMHB9sl"}]},"maintainers":[{"name":"jmoreira","email":"jmoreiras@gmail.com"},{"name":"lopezjurip","email":"lopezjuripatricio@gmail.com"},{"name":"nchastain","email":"nate.chastain@consensys.net"},{"name":"sloreti","email":"lhloreti@gmail.com"},{"name":"vdrg","email":"vdrg@protonmail.ch"},{"name":"wachunei","email":"wachunei@gmail.com"}],"_npmUser":{"name":"vdrg","email":"vdrg@protonmail.ch"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/smart-contracts_0.4.0-beta.2_1587155848030_0.48278149121564673"},"_hasShrinkwrap":false},"0.4.0-beta.3":{"name":"@daisypayments/smart-contracts","version":"0.4.0-beta.3","repository":{"type":"git","url":"https://github.com/consensys/daisy-subscription-contracts"},"author":{"name":"vdrg","email":"vicente.dragicevic@consensys.net"},"license":"MIT","main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"yarn compile && tsc -p ./tsconfig.build.json","compile":"truffle compile","coverage":"truffle run coverage","exec":"truffle exec","docgen":"./scripts/docgen.sh","publish-docs":"./scripts/publish-docs.sh","prepublish":"yarn build","lint":"solhint \"contracts/**/*.sol\"","migrate":"truffle migrate","test":"truffle test"},"devDependencies":{"@daisypayments/eslint-config":"^2.1.1","@openzeppelin/contracts":"^3.0.0-rc.1","@openzeppelin/test-environment":"^0.1.2","@openzeppelin/test-helpers":"^0.5.4","@types/chai":"^4.2.11","@types/lodash":"^4.14.149","bip39":"^2.5.0","bn.js":"^4.11.8","chai":"^4.2.0","coveralls":"^3.0.5","dotenv":"^6.2.0","eslint":"^6.8.0","eslint-plugin-mocha":"^6.3.0","eslint-plugin-prettier":"^3.1.3","eth-gas-reporter":"^0.2.17","eth-sig-util":"^2.2.0","ethereumjs-abi":"^0.6.7","ethereumjs-util":"^6.1.0","ethereumjs-wallet":"^0.6.3","ganache-cli":"^6.9.1","lodash":"^4.17.11","mocha":"^7.0.0","moment":"^2.24.0","prettier":"^1.16.3","solhint":"^2.0.0","solidity-coverage":"^0.7.4","solidity-docgen":"^0.1.1","truffle":"^5.1.21","truffle-hdwallet-provider":"^1.0.4","truffle-typings":"^1.0.8","ts-node":"^8.8.2","typescript":"^3.8.3"},"peerDependencies":{"web3":"^1.2.6"},"readmeFilename":"README.md","readme":"# Daisy Contracts\n\n[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repos/github/ConsenSys/daisy-subscription-contracts/badge.svg?t=wmZqvk)](https://coveralls.io/github/ConsenSys/daisy-subscription-contracts)\n\n## Overview\n\n### Transfer Proxy\n\nA transfer proxy is a simple smart contract that allows its owner to withdraw any token from any set of addresses that have previously approved tokens to it. It also supports transferring tokens and ether that has been sent directly to the contract. It is the base layer for the subscriptions and one time payments system.\n\n### Payment Manager\n\nThe Payment Manager  is a contract that allows daisy to execute payments by deploying Transfer Proxies when a payment is executed. A payment is composed by a set of parameters that will determine the address of the Transfer Proxy that will be used, and by two variable parameters that can change between executions for the same Transfer Proxy.\n\nThe main function corresponds to `execute(Payment[] payments, bytes sig)`, which takes an array of `Payment`s and a signature, and tries to execute them.\n\n### Payment execution\n\nThe manager handles the execution of recurrent payments by providing a function that receives an array of Payments. Payments are structs that contain information about the current execution. The hash of this array of invoices needs to be signed by a special address set in this contract.\n\nThe parameters of each `Payment` are used to compute the address of Transfer Proxy, and if the Transfer Proxy doesn't exist then it gets deployed using the `CREATE2` opcode. After the contract is deployed, the parameters of the `Payment` are used to execute the payment and enforce certain conditions. The main idea behind using create2 is that when a user approves tokens to the address of a Transfer Proxy, she is implicitly agreeing to the terms before the contract is even created, as the address is deterministically computed from said terms. Also, it reduces the amount of transactions Daisy needs to send as we can safely compute Transfer Proxy addresses off-chain, and we only send transactions if we are sure that the payment will go through.\n\nPayment struct (parameters marked as \"variable\" are not used to compute the Transfer Proxy address used for the payment):\n* IERC20 token: address of the ERC 20 token that will be used to perform the payment.\n* address wallet: wallet where funds will be transferred.\n* uint256 maxAmount: maximum number of tokens to transfer in each payment.\n* uint256 periods: number of period units between payments.\n* PeriodUnit periodUnit: \"NONE\", \"DAY\", \"WEEK\", \"MONTH\", or \"YEAR\".\n* uint256 startsAt: timestamps in which the first payment can be executed.\n* bytes32 salt: number of times a payment has been executed.\n* address callback: address that will be called after a payment is successfuly executed.\n* bytes callbackData: data passed to the callback contract.\n* (variable) address[] from: array of address to transfer tokens from (not supported for ether).\n* (variable) uint256 amount: amount of tokens/wei\n\nIn order to execute a payment, the following condition has to hold: `addPeriods(startsAt, executions * periods, periodUnit) <= now`. The addresses provided on each payment execution can be any set of addresses that have approved tokens to the transfer proxy contract, and off-chain services can obtain them by reading the event logs of the `token` contract. If we want to transfer tokens or ether held by the transfer proxy, an empty array of addresses can be passed to the execute function.\n\nAs the amount to be transferred on each execution is set by the authorized addresses (can't go over the maxAmount parameter), this allows us to support the following usecases:\n1. Applying discounts for a number of periods (handled off-chain), even after the recurrent payment has been created.\n2. Metered billing: as the amounts stored in the terms are actually the maximum amounts that can be charged on an execution, we can vary the amount to be transferred depending on the reported usage by the merchant.\n\n#### Paying with Ether directly\n\n\n\n#### Paying with ERC20 directly\n#### Paying with ERC20 by approving\n\n## Contracts\n\n### `PaymentsManager.sol`\n\nHandles the creation, batched execution, and cancellation of recurrent payments.\n\n### `TransferProxy.sol`\n\nIts main objective is to withdraw funds from a set of addresses that have previously approved tokens to it. The transfers can only happen if the current period has passed.\n\n### `IndexedArrayLib.sol`\n\nLibrary that provides an indexed array of bytes32. It allows us to remove items from the array by specifying the item itself that we want to remove.\n\n### `Delegated.sol`\n\nAllows child contracts to support delegated execution without changing their external APIs. See Delegation section.\n\n## Time\n\nTo support different time units (days, months and years) we use [BokkyPooBah's Date Time Library](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary).\n\n## Delegation\n\nIn order to support delegated execution through the use of EIP712 signatures, the `Delegated` contract can be used. The key feature of the `Delegated` contract is that child contracts don't need to polute their APIs with parameters related to delegated execution.\n\nThe `Delegated` contract exposes the external `delegate` function which receives the following parameters:\n\n* `bytes data`: ABI encoded data to be used for the delegated call.\n* `bytes32 nonce`: Random value for replay protection. If the function to call is idempotent, this value is optional.\n* `uint256 signatureExpiresAt`: Timestamp in which the signature stops being valid.\n* `bytes signature`: The signature for the EIP712 type.\n\nFor example, for the `setWallet(address _wallet)` function in the `SubscriptionManager`, the EIP712 type is `SetWallet(address wallet,bytes32 nonce,uint256 signatureExpiresAt)`. This function can only be called directly by the `owner` account or by using the `delegate` function with the following parameters (pseudo code):\n\n```js\n// Data to call the setWallet function normally\nconst data = abiEncode(setWalletSelector, _wallet);\n\n// Random value for replay protection\nconst nonce = randomBytes32();\n\n// Signature expiration\nconst signatureExpiresAt = now + signatureDuration;\n\n// Owner's signature\nconst signature = signTypedData({\n  account: owner,  \n  primaryType: \"SetWallet\", // The EIP712 type\n  domain: { \n    verifyingContract: manager.address\n  },\n  message: {\n    wallet: _wallet,\n    nonce,\n    signatureExpiresAt,\n  }\n});\n\n// Call setWallet through the delegate function\nawait manager.delegate(\n  data,\n  nonce,\n  signatureExpiresAt,\n  signature,\n  {\n    from: anyone\n  }\n);\n```\n\n### delegate function and signature checks\n\nThe `delegate` function performs the following steps:\n\n1. Reentrancy guard (`delegate` can only be called once in the same transaction).\n2. Check that the signature hasn't expired (`now < signatureExpiresAt`).\n3. Store the `nonce`, `signatureExpiresAt` and `signature` parameters.\n4. Call itself with the ABI encoded data (`address(this).call(data)`);\n5. Revert if the call failed.\n6. Delete the stored parameters.\n\nAs the delegation data exists in the storage while the call is being executed, the called function in the child contract can use the internal `_delegatedCheck(bytes32 typeHash, bytes data, bool usesNonce)` function to get the address of the caller. Internally, the `_delegatedCheck` checks if `msg.sender == this` and performs the signature validation using the provided type hash. If `msg.sender != this`, it just returns the `msg.sender`. It also stores the hashed data so it can't be used again for another delegated call.\n\n## Flow for creating a recurrent payment\n\nThe only function where delegated execution checks are done manually (doesn't use the `Delegated` functionality) is the `create` function, used to create subscriptions. The flow for creating a subscription works as follows:\n1. Gather the parameters for the new recurrent payment to be created.\n2. Compute the address of the recurrent payment contract from the parameters.\n3. The user approves tokens to the computed address.\n4. Once the approval has been confirmed, send a transaction to create the recurring payment contract and begin withdrawing funds from the user every period.\n\n## Daisy\n\nFor subscription services created using Daisy the platform, Daisy will be the authorizer AND the relayer for payments.\n\n# Testing\n\nTo run the tests, clone this repo and run `yarn install` to install dependencies.\n\nRun `yarn test` to run all tests.\n\nRun `yarn coverage` to run tests and get code coverage.\n","description":"[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repo","licenseText":"MIT License\n\nCopyright (c) 2019 Token Foundry\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@daisypayments/smart-contracts@0.4.0-beta.3","dist":{"shasum":"396e1ea384d1276c90168a8e16ffb69fdd3c8e2f","integrity":"sha512-c6OG5Ows81yyIo/PAOJXTSkkcq7g28XM/B/8lmyy2epqtOLviF7E1rsD/uKMRd5gD6LoRHbU94+7PBJR6VYgng==","tarball":"https://registry.npmjs.org/@daisypayments/smart-contracts/-/smart-contracts-0.4.0-beta.3.tgz","fileCount":21,"unpackedSize":4613693,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJemiNJCRA9TVsSAnZWagAAqikP/jEXFvVThzWwp+ofFUTF\nkWL04R1QtTuq6x5O6Lc1fpiScLSnR3QoFTo9kJEzlu+aXgZBW3zXnB7lm+Ht\nc9uDCz9QqSCSleqQavEnV8Sd1B7MH/QlPkVcZXpiJqPhLvVTzU35orPTSJK5\nqo2KVX88TGD/VlNYsPsCtKvGI31jSVofqtUfGVHE4VlJcE1DSHDAJNYY5TRv\nZz6lSm9cCwx7VdK7TwEndBz2p3089Ynj9LpW5Vxl/3anw2kfcyFBnpZaqSjV\nasH3hvOjfePMbQjHongI8dZpZtwkiyeSTjbZcHHGniuXWwJ5OFXcwoMGbRdv\nhHZcNBfh6ztLIKCctge8Pml0xBBqR5TaMdN0gPwxTXJmN0ZNsJO4t9fN+Umf\nxT9wM9VMWs/e7I9WFx/whuTiiBferg6Dbo1J3PbTZKd2tqWuqsNr80tTE536\nYGf+b3XoQ9z5D55/U6NFvRwudloVMs02gP3r1BpaSxO8Bd3GZ5bJP+6ex/J/\nVuvJuFbTg9x7JrDDPbhvSLhq0rMWx4l6Aa5+jPx1vTB0WSHHJF7wQFTLejy5\naxA6a6P8b9EQi4FU/Cm9Ao/N54dlcOtKYFtlebm/nhvuWwYQnbTLaM91Fp/9\n/sblwJLTKUAdH5BM2EpR+UBsd0O39kjghX9wHIh7JGr478NEI2IZIqv4whuw\nihBo\r\n=awk8\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBnzVHWb27dyXUrNire+bAi7jNK4l6bYVCwWI37kVJe/AiEAyQL/F6TfgII0tEx6DkrrmDkE1Swf3l2sqlToSmdL9vE="}]},"maintainers":[{"name":"jmoreira","email":"jmoreiras@gmail.com"},{"name":"lopezjurip","email":"lopezjuripatricio@gmail.com"},{"name":"nchastain","email":"nate.chastain@consensys.net"},{"name":"sloreti","email":"lhloreti@gmail.com"},{"name":"vdrg","email":"vdrg@protonmail.ch"},{"name":"wachunei","email":"wachunei@gmail.com"}],"_npmUser":{"name":"vdrg","email":"vdrg@protonmail.ch"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/smart-contracts_0.4.0-beta.3_1587159881333_0.08398708491243423"},"_hasShrinkwrap":false},"0.4.0-beta.4":{"name":"@daisypayments/smart-contracts","version":"0.4.0-beta.4","repository":{"type":"git","url":"https://github.com/consensys/daisy-subscription-contracts"},"author":{"name":"vdrg","email":"vicente.dragicevic@consensys.net"},"license":"MIT","main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"yarn compile && tsc -p ./tsconfig.build.json","compile":"truffle compile","coverage":"truffle run coverage","exec":"truffle exec","docgen":"./scripts/docgen.sh","publish-docs":"./scripts/publish-docs.sh","prepublish":"yarn build","lint":"solhint \"contracts/**/*.sol\"","migrate":"truffle migrate","test":"truffle test"},"devDependencies":{"@daisypayments/eslint-config":"^2.1.1","@openzeppelin/contracts":"^3.0.0","@openzeppelin/test-environment":"^0.1.2","@openzeppelin/test-helpers":"^0.5.4","@types/chai":"^4.2.11","@types/lodash":"^4.14.149","bip39":"^2.5.0","bn.js":"^4.11.8","chai":"^4.2.0","coveralls":"^3.0.5","dotenv":"^6.2.0","eslint":"^6.8.0","eslint-plugin-mocha":"^6.3.0","eslint-plugin-prettier":"^3.1.3","eth-gas-reporter":"^0.2.17","eth-sig-util":"^2.2.0","ethereumjs-abi":"^0.6.7","ethereumjs-util":"^6.1.0","ethereumjs-wallet":"^0.6.3","ganache-cli":"^6.9.1","lodash":"^4.17.11","mocha":"^7.0.0","moment":"^2.24.0","prettier":"^1.16.3","solhint":"^2.0.0","solidity-coverage":"^0.7.4","solidity-docgen":"^0.1.1","truffle":"^5.1.21","truffle-hdwallet-provider":"^1.0.4","truffle-typings":"^1.0.8","ts-node":"^8.8.2","typescript":"^3.8.3"},"peerDependencies":{"web3":"^1.2.6"},"readmeFilename":"README.md","readme":"# Daisy Contracts\n\n[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repos/github/ConsenSys/daisy-subscription-contracts/badge.svg?t=wmZqvk)](https://coveralls.io/github/ConsenSys/daisy-subscription-contracts)\n\n## Overview\n\n### Transfer Proxy\n\nA transfer proxy is a simple smart contract that allows its owner to withdraw any token from any set of addresses that have previously approved tokens to it. It also supports transferring tokens and ether that has been sent directly to the contract. It is the base layer for the subscriptions and one time payments system.\n\n### Payment Manager\n\nThe Payment Manager  is a contract that allows daisy to execute payments by deploying Transfer Proxies when a payment is executed. A payment is composed by a set of parameters that will determine the address of the Transfer Proxy that will be used, and by two variable parameters that can change between executions for the same Transfer Proxy.\n\nThe main function corresponds to `execute(Payment[] payments, bytes sig)`, which takes an array of `Payment`s and a signature, and tries to execute them.\n\n### Payment execution\n\nThe manager handles the execution of recurrent payments by providing a function that receives an array of Payments. Payments are structs that contain information about the current execution. The hash of this array of invoices needs to be signed by a special address set in this contract.\n\nThe parameters of each `Payment` are used to compute the address of Transfer Proxy, and if the Transfer Proxy doesn't exist then it gets deployed using the `CREATE2` opcode. After the contract is deployed, the parameters of the `Payment` are used to execute the payment and enforce certain conditions. The main idea behind using create2 is that when a user approves tokens to the address of a Transfer Proxy, she is implicitly agreeing to the terms before the contract is even created, as the address is deterministically computed from said terms. Also, it reduces the amount of transactions Daisy needs to send as we can safely compute Transfer Proxy addresses off-chain, and we only send transactions if we are sure that the payment will go through.\n\nPayment struct (parameters marked as \"variable\" are not used to compute the Transfer Proxy address used for the payment):\n* IERC20 token: address of the ERC 20 token that will be used to perform the payment.\n* address wallet: wallet where funds will be transferred.\n* uint256 maxAmount: maximum number of tokens to transfer in each payment.\n* uint256 periods: number of period units between payments.\n* PeriodUnit periodUnit: \"NONE\", \"DAY\", \"WEEK\", \"MONTH\", or \"YEAR\".\n* uint256 startsAt: timestamps in which the first payment can be executed.\n* bytes32 salt: number of times a payment has been executed.\n* address callback: address that will be called after a payment is successfuly executed.\n* bytes callbackData: data passed to the callback contract.\n* (variable) address[] from: array of address to transfer tokens from (not supported for ether).\n* (variable) uint256 amount: amount of tokens/wei\n\nIn order to execute a payment, the following condition has to hold: `addPeriods(startsAt, executions * periods, periodUnit) <= now`. The addresses provided on each payment execution can be any set of addresses that have approved tokens to the transfer proxy contract, and off-chain services can obtain them by reading the event logs of the `token` contract. If we want to transfer tokens or ether held by the transfer proxy, an empty array of addresses can be passed to the execute function.\n\nAs the amount to be transferred on each execution is set by the authorized addresses (can't go over the maxAmount parameter), this allows us to support the following usecases:\n1. Applying discounts for a number of periods (handled off-chain), even after the recurrent payment has been created.\n2. Metered billing: as the amounts stored in the terms are actually the maximum amounts that can be charged on an execution, we can vary the amount to be transferred depending on the reported usage by the merchant.\n\n#### Paying with Ether directly\n\n\n\n#### Paying with ERC20 directly\n#### Paying with ERC20 by approving\n\n## Contracts\n\n### `PaymentsManager.sol`\n\nHandles the creation, batched execution, and cancellation of recurrent payments.\n\n### `TransferProxy.sol`\n\nIts main objective is to withdraw funds from a set of addresses that have previously approved tokens to it. The transfers can only happen if the current period has passed.\n\n### `IndexedArrayLib.sol`\n\nLibrary that provides an indexed array of bytes32. It allows us to remove items from the array by specifying the item itself that we want to remove.\n\n### `Delegated.sol`\n\nAllows child contracts to support delegated execution without changing their external APIs. See Delegation section.\n\n## Time\n\nTo support different time units (days, months and years) we use [BokkyPooBah's Date Time Library](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary).\n\n## Delegation\n\nIn order to support delegated execution through the use of EIP712 signatures, the `Delegated` contract can be used. The key feature of the `Delegated` contract is that child contracts don't need to polute their APIs with parameters related to delegated execution.\n\nThe `Delegated` contract exposes the external `delegate` function which receives the following parameters:\n\n* `bytes data`: ABI encoded data to be used for the delegated call.\n* `bytes32 nonce`: Random value for replay protection. If the function to call is idempotent, this value is optional.\n* `uint256 signatureExpiresAt`: Timestamp in which the signature stops being valid.\n* `bytes signature`: The signature for the EIP712 type.\n\nFor example, for the `setWallet(address _wallet)` function in the `SubscriptionManager`, the EIP712 type is `SetWallet(address wallet,bytes32 nonce,uint256 signatureExpiresAt)`. This function can only be called directly by the `owner` account or by using the `delegate` function with the following parameters (pseudo code):\n\n```js\n// Data to call the setWallet function normally\nconst data = abiEncode(setWalletSelector, _wallet);\n\n// Random value for replay protection\nconst nonce = randomBytes32();\n\n// Signature expiration\nconst signatureExpiresAt = now + signatureDuration;\n\n// Owner's signature\nconst signature = signTypedData({\n  account: owner,  \n  primaryType: \"SetWallet\", // The EIP712 type\n  domain: { \n    verifyingContract: manager.address\n  },\n  message: {\n    wallet: _wallet,\n    nonce,\n    signatureExpiresAt,\n  }\n});\n\n// Call setWallet through the delegate function\nawait manager.delegate(\n  data,\n  nonce,\n  signatureExpiresAt,\n  signature,\n  {\n    from: anyone\n  }\n);\n```\n\n### delegate function and signature checks\n\nThe `delegate` function performs the following steps:\n\n1. Reentrancy guard (`delegate` can only be called once in the same transaction).\n2. Check that the signature hasn't expired (`now < signatureExpiresAt`).\n3. Store the `nonce`, `signatureExpiresAt` and `signature` parameters.\n4. Call itself with the ABI encoded data (`address(this).call(data)`);\n5. Revert if the call failed.\n6. Delete the stored parameters.\n\nAs the delegation data exists in the storage while the call is being executed, the called function in the child contract can use the internal `_delegatedCheck(bytes32 typeHash, bytes data, bool usesNonce)` function to get the address of the caller. Internally, the `_delegatedCheck` checks if `msg.sender == this` and performs the signature validation using the provided type hash. If `msg.sender != this`, it just returns the `msg.sender`. It also stores the hashed data so it can't be used again for another delegated call.\n\n## Flow for creating a recurrent payment\n\nThe only function where delegated execution checks are done manually (doesn't use the `Delegated` functionality) is the `create` function, used to create subscriptions. The flow for creating a subscription works as follows:\n1. Gather the parameters for the new recurrent payment to be created.\n2. Compute the address of the recurrent payment contract from the parameters.\n3. The user approves tokens to the computed address.\n4. Once the approval has been confirmed, send a transaction to create the recurring payment contract and begin withdrawing funds from the user every period.\n\n## Daisy\n\nFor subscription services created using Daisy the platform, Daisy will be the authorizer AND the relayer for payments.\n\n# Testing\n\nTo run the tests, clone this repo and run `yarn install` to install dependencies.\n\nRun `yarn test` to run all tests.\n\nRun `yarn coverage` to run tests and get code coverage.\n","description":"[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repo","licenseText":"MIT License\n\nCopyright (c) 2019 Token Foundry\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@daisypayments/smart-contracts@0.4.0-beta.4","dist":{"shasum":"c589a7bf5e8f09bf947f4e32d64310c7acd7ab24","integrity":"sha512-HqvKf9sPs+F5iptr/JoKC4TZHxsss4n2yDDg5BSOYxJvkZUcAgK0gDYkr6N6P1hTMMWxMmxiTVZ9LlgVD62LEg==","tarball":"https://registry.npmjs.org/@daisypayments/smart-contracts/-/smart-contracts-0.4.0-beta.4.tgz","fileCount":21,"unpackedSize":3911260,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeoG3NCRA9TVsSAnZWagAAJCwP/06IzXqOgALqIY7etqAu\naxsKm0y9g9HBHOfhn2gzP7Y6OBBssYnII+JmH1WcJQKvQEvlhq/ntpEKdY0T\n2oggY7rW8t9c42TR4GJf8hX10xTefpOva7fCRCSB9w8xcie13MU/ZI5k2DbH\nfT0UAVpq18UyeL5diJIXbxuZWid7+8fDXRnvL+sFkKV+oYAJUviHK3RqR3Hg\nQcCsmYr+9s7Gffa8QEgHc6i/5vF2Tv0TOSVTrcJAMlmsh6FP0RzynjC0tvQG\ngaZjH/UN1UoE17EEK1NUQa0uUvUew5wMbHVUnhftGtwDCpGN1P5S4U+9Jm5z\nHs6N9Sc5NkT/fmto1yBU2zvhvQSO/2Xsn0lqum6vNBey4Glbe9gecRy5mavA\nyioKpHoALtvIypAVSviaKY0XbA3rTW/lhce0zBzaEuMXaF4GBPlcSjVnfIfU\nAIVd6gpTBgGD3cAK1L2TL8UVrbY4cTczUKRupLciKy7Er1BrJHGx22tMJ4WP\nr/fLt9oW+TnxFucMJSvkKcA1vmjfuvoCAMqLYssprNguXiqWwsKagSEZFXdB\nKoqR35Keq6inv/gQCbvwPcg6tLJARr7WJp+iZcMVvICHNfJ2xEEOxIR+OCd6\nMgo5mfHyJ3zlRV5jR1nlIdf7zWB4V7l/V4+1P6lLU33l6I9mt/9Z1sD4QR1y\nR5aV\r\n=fqzf\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD7PvUrpPsJE5CHvKaEtjsJrEMVUkbxp682K+6wCtikGQIhAOIZQKI9f9pftzWNSHF4QsHXBVtRypqHuUoXX4dt2q0r"}]},"maintainers":[{"name":"jmoreira","email":"jmoreiras@gmail.com"},{"name":"lopezjurip","email":"lopezjuripatricio@gmail.com"},{"name":"nchastain","email":"nate.chastain@consensys.net"},{"name":"sloreti","email":"lhloreti@gmail.com"},{"name":"vdrg","email":"vdrg@protonmail.ch"},{"name":"wachunei","email":"wachunei@gmail.com"}],"_npmUser":{"name":"vdrg","email":"vdrg@protonmail.ch"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/smart-contracts_0.4.0-beta.4_1587572172984_0.3142900955509309"},"_hasShrinkwrap":false},"0.4.0-beta.5":{"name":"@daisypayments/smart-contracts","version":"0.4.0-beta.5","repository":{"type":"git","url":"https://github.com/consensys/daisy-subscription-contracts"},"author":{"name":"vdrg","email":"vicente.dragicevic@consensys.net"},"license":"MIT","main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"yarn compile && tsc -p ./tsconfig.build.json","compile":"truffle compile","coverage":"truffle run coverage","exec":"truffle exec","docgen":"./scripts/docgen.sh","publish-docs":"./scripts/publish-docs.sh","prepublish":"yarn build","lint":"solhint \"contracts/**/*.sol\"","migrate":"truffle migrate","test":"truffle test"},"devDependencies":{"@daisypayments/eslint-config":"^2.1.1","@openzeppelin/contracts":"^3.0.0","@openzeppelin/test-environment":"^0.1.2","@openzeppelin/test-helpers":"^0.5.4","@types/chai":"^4.2.11","@types/lodash":"^4.14.149","bip39":"^2.5.0","bn.js":"^4.11.8","chai":"^4.2.0","coveralls":"^3.0.5","dotenv":"^6.2.0","eslint":"^6.8.0","eslint-plugin-mocha":"^6.3.0","eslint-plugin-prettier":"^3.1.3","eth-gas-reporter":"^0.2.17","eth-sig-util":"^2.2.0","ethereumjs-abi":"^0.6.7","ethereumjs-util":"^6.1.0","ethereumjs-wallet":"^0.6.3","ganache-cli":"^6.9.1","lodash":"^4.17.11","mocha":"^7.0.0","moment":"^2.24.0","prettier":"^1.16.3","solhint":"^2.0.0","solidity-coverage":"^0.7.4","solidity-docgen":"^0.1.1","truffle":"^5.1.21","truffle-hdwallet-provider":"^1.0.4","truffle-typings":"^1.0.8","ts-node":"^8.8.2","typescript":"^3.8.3"},"peerDependencies":{"web3":"^1.2.6"},"readmeFilename":"README.md","readme":"# Daisy Contracts\n\n[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repos/github/ConsenSys/daisy-subscription-contracts/badge.svg?t=wmZqvk)](https://coveralls.io/github/ConsenSys/daisy-subscription-contracts)\n\n## Overview\n\n### Transfer Proxy\n\nA transfer proxy is a simple smart contract that allows its owner to withdraw any token from any set of addresses that have previously approved tokens to it. It also supports transferring tokens and ether that has been sent directly to the contract. It is the base layer for the subscriptions and one time payments system.\n\n### Payment Manager\n\nThe Payment Manager  is a contract that allows daisy to execute payments by deploying Transfer Proxies when a payment is executed. A payment is composed by a set of parameters that will determine the address of the Transfer Proxy that will be used, and by two variable parameters that can change between executions for the same Transfer Proxy.\n\nThe main function corresponds to `execute(Payment[] payments, bytes sig)`, which takes an array of `Payment`s and a signature, and tries to execute them.\n\n### Payment execution\n\nThe manager handles the execution of recurrent payments by providing a function that receives an array of Payments. Payments are structs that contain information about the current execution. The hash of this array of invoices needs to be signed by a special address set in this contract.\n\nThe parameters of each `Payment` are used to compute the address of Transfer Proxy, and if the Transfer Proxy doesn't exist then it gets deployed using the `CREATE2` opcode. After the contract is deployed, the parameters of the `Payment` are used to execute the payment and enforce certain conditions. The main idea behind using create2 is that when a user approves tokens to the address of a Transfer Proxy, she is implicitly agreeing to the terms before the contract is even created, as the address is deterministically computed from said terms. Also, it reduces the amount of transactions Daisy needs to send as we can safely compute Transfer Proxy addresses off-chain, and we only send transactions if we are sure that the payment will go through.\n\nPayment struct (parameters marked as \"variable\" are not used to compute the Transfer Proxy address used for the payment):\n* IERC20 token: address of the ERC 20 token that will be used to perform the payment.\n* address wallet: wallet where funds will be transferred.\n* uint256 maxAmount: maximum number of tokens to transfer in each payment.\n* uint256 periods: number of period units between payments.\n* PeriodUnit periodUnit: \"NONE\", \"DAY\", \"WEEK\", \"MONTH\", or \"YEAR\".\n* uint256 startsAt: timestamps in which the first payment can be executed.\n* bytes32 salt: number of times a payment has been executed.\n* address callback: address that will be called after a payment is successfuly executed.\n* bytes callbackData: data passed to the callback contract.\n* (variable) address[] from: array of address to transfer tokens from (not supported for ether).\n* (variable) uint256 amount: amount of tokens/wei\n\nIn order to execute a payment, the following condition has to hold: `addPeriods(startsAt, executions * periods, periodUnit) <= now`. The addresses provided on each payment execution can be any set of addresses that have approved tokens to the transfer proxy contract, and off-chain services can obtain them by reading the event logs of the `token` contract. If we want to transfer tokens or ether held by the transfer proxy, an empty array of addresses can be passed to the execute function.\n\nAs the amount to be transferred on each execution is set by the authorized addresses (can't go over the maxAmount parameter), this allows us to support the following usecases:\n1. Applying discounts for a number of periods (handled off-chain), even after the recurrent payment has been created.\n2. Metered billing: as the amounts stored in the terms are actually the maximum amounts that can be charged on an execution, we can vary the amount to be transferred depending on the reported usage by the merchant.\n\n#### Paying with Ether directly\n\n\n\n#### Paying with ERC20 directly\n#### Paying with ERC20 by approving\n\n## Contracts\n\n### `PaymentsManager.sol`\n\nHandles the creation, batched execution, and cancellation of recurrent payments.\n\n### `TransferProxy.sol`\n\nIts main objective is to withdraw funds from a set of addresses that have previously approved tokens to it. The transfers can only happen if the current period has passed.\n\n### `IndexedArrayLib.sol`\n\nLibrary that provides an indexed array of bytes32. It allows us to remove items from the array by specifying the item itself that we want to remove.\n\n### `Delegated.sol`\n\nAllows child contracts to support delegated execution without changing their external APIs. See Delegation section.\n\n## Time\n\nTo support different time units (days, months and years) we use [BokkyPooBah's Date Time Library](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary).\n\n## Delegation\n\nIn order to support delegated execution through the use of EIP712 signatures, the `Delegated` contract can be used. The key feature of the `Delegated` contract is that child contracts don't need to polute their APIs with parameters related to delegated execution.\n\nThe `Delegated` contract exposes the external `delegate` function which receives the following parameters:\n\n* `bytes data`: ABI encoded data to be used for the delegated call.\n* `bytes32 nonce`: Random value for replay protection. If the function to call is idempotent, this value is optional.\n* `uint256 signatureExpiresAt`: Timestamp in which the signature stops being valid.\n* `bytes signature`: The signature for the EIP712 type.\n\nFor example, for the `setWallet(address _wallet)` function in the `SubscriptionManager`, the EIP712 type is `SetWallet(address wallet,bytes32 nonce,uint256 signatureExpiresAt)`. This function can only be called directly by the `owner` account or by using the `delegate` function with the following parameters (pseudo code):\n\n```js\n// Data to call the setWallet function normally\nconst data = abiEncode(setWalletSelector, _wallet);\n\n// Random value for replay protection\nconst nonce = randomBytes32();\n\n// Signature expiration\nconst signatureExpiresAt = now + signatureDuration;\n\n// Owner's signature\nconst signature = signTypedData({\n  account: owner,  \n  primaryType: \"SetWallet\", // The EIP712 type\n  domain: { \n    verifyingContract: manager.address\n  },\n  message: {\n    wallet: _wallet,\n    nonce,\n    signatureExpiresAt,\n  }\n});\n\n// Call setWallet through the delegate function\nawait manager.delegate(\n  data,\n  nonce,\n  signatureExpiresAt,\n  signature,\n  {\n    from: anyone\n  }\n);\n```\n\n### delegate function and signature checks\n\nThe `delegate` function performs the following steps:\n\n1. Reentrancy guard (`delegate` can only be called once in the same transaction).\n2. Check that the signature hasn't expired (`now < signatureExpiresAt`).\n3. Store the `nonce`, `signatureExpiresAt` and `signature` parameters.\n4. Call itself with the ABI encoded data (`address(this).call(data)`);\n5. Revert if the call failed.\n6. Delete the stored parameters.\n\nAs the delegation data exists in the storage while the call is being executed, the called function in the child contract can use the internal `_delegatedCheck(bytes32 typeHash, bytes data, bool usesNonce)` function to get the address of the caller. Internally, the `_delegatedCheck` checks if `msg.sender == this` and performs the signature validation using the provided type hash. If `msg.sender != this`, it just returns the `msg.sender`. It also stores the hashed data so it can't be used again for another delegated call.\n\n## Flow for creating a recurrent payment\n\nThe only function where delegated execution checks are done manually (doesn't use the `Delegated` functionality) is the `create` function, used to create subscriptions. The flow for creating a subscription works as follows:\n1. Gather the parameters for the new recurrent payment to be created.\n2. Compute the address of the recurrent payment contract from the parameters.\n3. The user approves tokens to the computed address.\n4. Once the approval has been confirmed, send a transaction to create the recurring payment contract and begin withdrawing funds from the user every period.\n\n## Daisy\n\nFor subscription services created using Daisy the platform, Daisy will be the authorizer AND the relayer for payments.\n\n# Testing\n\nTo run the tests, clone this repo and run `yarn install` to install dependencies.\n\nRun `yarn test` to run all tests.\n\nRun `yarn coverage` to run tests and get code coverage.\n","description":"[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repo","licenseText":"MIT License\n\nCopyright (c) 2019 Token Foundry\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@daisypayments/smart-contracts@0.4.0-beta.5","dist":{"shasum":"d0d502f40116df69ba5def768b99a717f168ddf6","integrity":"sha512-ocVjfZEhau3gc2PiaCpTB/AEM7IaWJxFcBaOCQnzwr55hw5thNmWG0WekD9UiFEyAyVjV+TKn4QEZKsBaLIyQQ==","tarball":"https://registry.npmjs.org/@daisypayments/smart-contracts/-/smart-contracts-0.4.0-beta.5.tgz","fileCount":21,"unpackedSize":3911595,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeoH/cCRA9TVsSAnZWagAATcIP/2yq7RZwxNZ1wJTU9H3v\nzDy7sNqepT0zozmMk3j/OtcSqc1/Ye/Fm86+UFjW95XS39E8SYNDfDKKFSMT\nEJwh4mL0iLLKyFm9BkKyd4A/j4TuBMm6zxGA0L1Pp96wgdManElmk7oO3aW+\n6gKfWut0ZfnmBmB3J1fFrrvBo/p1XJYZH3uqoUh3lShVSluFSdd5cV9cI6nD\nQKgCbrUMswqbonrrVlfZSYteGCpsIMbf83y0xX514675nXV89h3BAA5CFGuX\nLsK/bI6+ArayPcPBAciAjc/5oUCznHg9pbX8TmHxyH9tGDLOcGV5SFA4rxsl\n27N0ecIJ362W9VlQLXtsjRu5qIjGKddsXY25dolqECDfT3A+CvDd1UQILDEZ\nPqtIQ9Cq85KNEygUFf8WLfLEEfK1qGlKfUd/Vw1I9o9TCFbMOcRw8Sf29dAQ\n3Fnu2sqrEQoXVjP6wFyUUC0S0qyIcn9nozPITGjGtes6Fhj3yU9Bzhh+QXtA\nIR7YB5uGpESkg4UP7qPCiQaCC8TnFlQdxlfiUav/PeuBp8i2zCpMpZ2LHMFE\nWnbJOBNDpPFZtNr6h9qIzrLI+tPpy/w5DyTTJtpAZTyh+G6opPat34j+0MxE\nvvbDscaHTOaad4Su1agrVfuhp5Y/zUiWq7WjuUgbBUXj/5p6iuKYanDJjDeX\nPKGl\r\n=qiBr\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBrYj8+e6aAcYRwclmEyZcL5zUTfZJ7cz5Jd5YsWPMQlAiEAiW+iqKQmqyQVvaY6Wuw2wqwlaQD7octaFiJ3MzaQvHI="}]},"maintainers":[{"name":"jmoreira","email":"jmoreiras@gmail.com"},{"name":"lopezjurip","email":"lopezjuripatricio@gmail.com"},{"name":"nchastain","email":"nate.chastain@consensys.net"},{"name":"sloreti","email":"lhloreti@gmail.com"},{"name":"vdrg","email":"vdrg@protonmail.ch"},{"name":"wachunei","email":"wachunei@gmail.com"}],"_npmUser":{"name":"vdrg","email":"vdrg@protonmail.ch"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/smart-contracts_0.4.0-beta.5_1587576795980_0.12648516902995133"},"_hasShrinkwrap":false},"0.4.0-beta.6":{"name":"@daisypayments/smart-contracts","version":"0.4.0-beta.6","repository":{"type":"git","url":"https://github.com/consensys/daisy-subscription-contracts"},"author":{"name":"vdrg","email":"vicente.dragicevic@consensys.net"},"license":"MIT","main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"yarn compile && tsc -p ./tsconfig.build.json","compile":"truffle compile","coverage":"truffle run coverage","exec":"truffle exec","docgen":"./scripts/docgen.sh","publish-docs":"./scripts/publish-docs.sh","prepublish":"yarn build","lint":"solhint \"contracts/**/*.sol\"","migrate":"truffle migrate","test":"truffle test"},"devDependencies":{"@daisypayments/eslint-config":"^2.1.1","@openzeppelin/contracts":"^3.0.0","@openzeppelin/test-environment":"^0.1.2","@openzeppelin/test-helpers":"^0.5.4","@types/chai":"^4.2.11","@types/lodash":"^4.14.149","bip39":"^2.5.0","bn.js":"^4.11.8","chai":"^4.2.0","coveralls":"^3.0.5","dotenv":"^6.2.0","eslint":"^6.8.0","eslint-plugin-mocha":"^6.3.0","eslint-plugin-prettier":"^3.1.3","eth-gas-reporter":"^0.2.17","eth-sig-util":"^2.2.0","ethereumjs-abi":"^0.6.7","ethereumjs-util":"^6.1.0","ethereumjs-wallet":"^0.6.3","ganache-cli":"^6.9.1","lodash":"^4.17.11","mocha":"^7.0.0","moment":"^2.24.0","prettier":"^1.16.3","solhint":"^2.0.0","solidity-coverage":"^0.7.4","solidity-docgen":"^0.1.1","truffle":"^5.1.21","truffle-hdwallet-provider":"^1.0.4","truffle-typings":"^1.0.8","ts-node":"^8.8.2","typescript":"^3.8.3"},"peerDependencies":{"web3":"^1.2.6"},"readmeFilename":"README.md","readme":"# Daisy Contracts\n\n[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repos/github/ConsenSys/daisy-subscription-contracts/badge.svg?t=wmZqvk)](https://coveralls.io/github/ConsenSys/daisy-subscription-contracts)\n\n## Overview\n\n### Transfer Proxy\n\nA transfer proxy is a simple smart contract that allows its owner to withdraw any token from any set of addresses that have previously approved tokens to it. It also supports transferring tokens and ether that has been sent directly to the contract. It is the base layer for the subscriptions and one time payments system.\n\n### Payment Manager\n\nThe Payment Manager  is a contract that allows daisy to execute payments by deploying Transfer Proxies when a payment is executed. A payment is composed by a set of parameters that will determine the address of the Transfer Proxy that will be used, and by two variable parameters that can change between executions for the same Transfer Proxy.\n\nThe main function corresponds to `execute(Payment[] payments, bytes sig)`, which takes an array of `Payment`s and a signature, and tries to execute them.\n\n### Payment execution\n\nThe manager handles the execution of recurrent payments by providing a function that receives an array of Payments. Payments are structs that contain information about the current execution. The hash of this array of invoices needs to be signed by a special address set in this contract.\n\nThe parameters of each `Payment` are used to compute the address of Transfer Proxy, and if the Transfer Proxy doesn't exist then it gets deployed using the `CREATE2` opcode. After the contract is deployed, the parameters of the `Payment` are used to execute the payment and enforce certain conditions. The main idea behind using create2 is that when a user approves tokens to the address of a Transfer Proxy, she is implicitly agreeing to the terms before the contract is even created, as the address is deterministically computed from said terms. Also, it reduces the amount of transactions Daisy needs to send as we can safely compute Transfer Proxy addresses off-chain, and we only send transactions if we are sure that the payment will go through.\n\nPayment struct (parameters marked as \"variable\" are not used to compute the Transfer Proxy address used for the payment):\n* IERC20 token: address of the ERC 20 token that will be used to perform the payment.\n* address wallet: wallet where funds will be transferred.\n* uint256 maxAmount: maximum number of tokens to transfer in each payment.\n* uint256 periods: number of period units between payments.\n* PeriodUnit periodUnit: \"NONE\", \"DAY\", \"WEEK\", \"MONTH\", or \"YEAR\".\n* uint256 startsAt: timestamps in which the first payment can be executed.\n* bytes32 salt: number of times a payment has been executed.\n* address callback: address that will be called after a payment is successfuly executed.\n* bytes callbackData: data passed to the callback contract.\n* (variable) address[] from: array of address to transfer tokens from (not supported for ether).\n* (variable) uint256 amount: amount of tokens/wei\n\nIn order to execute a payment, the following condition has to hold: `addPeriods(startsAt, executions * periods, periodUnit) <= now`. The addresses provided on each payment execution can be any set of addresses that have approved tokens to the transfer proxy contract, and off-chain services can obtain them by reading the event logs of the `token` contract. If we want to transfer tokens or ether held by the transfer proxy, an empty array of addresses can be passed to the execute function.\n\nAs the amount to be transferred on each execution is set by the authorized addresses (can't go over the maxAmount parameter), this allows us to support the following usecases:\n1. Applying discounts for a number of periods (handled off-chain), even after the recurrent payment has been created.\n2. Metered billing: as the amounts stored in the terms are actually the maximum amounts that can be charged on an execution, we can vary the amount to be transferred depending on the reported usage by the merchant.\n\n#### Paying with Ether directly\n\n\n\n#### Paying with ERC20 directly\n#### Paying with ERC20 by approving\n\n## Contracts\n\n### `PaymentsManager.sol`\n\nHandles the creation, batched execution, and cancellation of recurrent payments.\n\n### `TransferProxy.sol`\n\nIts main objective is to withdraw funds from a set of addresses that have previously approved tokens to it. The transfers can only happen if the current period has passed.\n\n### `IndexedArrayLib.sol`\n\nLibrary that provides an indexed array of bytes32. It allows us to remove items from the array by specifying the item itself that we want to remove.\n\n### `Delegated.sol`\n\nAllows child contracts to support delegated execution without changing their external APIs. See Delegation section.\n\n## Time\n\nTo support different time units (days, months and years) we use [BokkyPooBah's Date Time Library](https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary).\n\n## Delegation\n\nIn order to support delegated execution through the use of EIP712 signatures, the `Delegated` contract can be used. The key feature of the `Delegated` contract is that child contracts don't need to polute their APIs with parameters related to delegated execution.\n\nThe `Delegated` contract exposes the external `delegate` function which receives the following parameters:\n\n* `bytes data`: ABI encoded data to be used for the delegated call.\n* `bytes32 nonce`: Random value for replay protection. If the function to call is idempotent, this value is optional.\n* `uint256 signatureExpiresAt`: Timestamp in which the signature stops being valid.\n* `bytes signature`: The signature for the EIP712 type.\n\nFor example, for the `setWallet(address _wallet)` function in the `SubscriptionManager`, the EIP712 type is `SetWallet(address wallet,bytes32 nonce,uint256 signatureExpiresAt)`. This function can only be called directly by the `owner` account or by using the `delegate` function with the following parameters (pseudo code):\n\n```js\n// Data to call the setWallet function normally\nconst data = abiEncode(setWalletSelector, _wallet);\n\n// Random value for replay protection\nconst nonce = randomBytes32();\n\n// Signature expiration\nconst signatureExpiresAt = now + signatureDuration;\n\n// Owner's signature\nconst signature = signTypedData({\n  account: owner,  \n  primaryType: \"SetWallet\", // The EIP712 type\n  domain: { \n    verifyingContract: manager.address\n  },\n  message: {\n    wallet: _wallet,\n    nonce,\n    signatureExpiresAt,\n  }\n});\n\n// Call setWallet through the delegate function\nawait manager.delegate(\n  data,\n  nonce,\n  signatureExpiresAt,\n  signature,\n  {\n    from: anyone\n  }\n);\n```\n\n### delegate function and signature checks\n\nThe `delegate` function performs the following steps:\n\n1. Reentrancy guard (`delegate` can only be called once in the same transaction).\n2. Check that the signature hasn't expired (`now < signatureExpiresAt`).\n3. Store the `nonce`, `signatureExpiresAt` and `signature` parameters.\n4. Call itself with the ABI encoded data (`address(this).call(data)`);\n5. Revert if the call failed.\n6. Delete the stored parameters.\n\nAs the delegation data exists in the storage while the call is being executed, the called function in the child contract can use the internal `_delegatedCheck(bytes32 typeHash, bytes data, bool usesNonce)` function to get the address of the caller. Internally, the `_delegatedCheck` checks if `msg.sender == this` and performs the signature validation using the provided type hash. If `msg.sender != this`, it just returns the `msg.sender`. It also stores the hashed data so it can't be used again for another delegated call.\n\n## Flow for creating a recurrent payment\n\nThe only function where delegated execution checks are done manually (doesn't use the `Delegated` functionality) is the `create` function, used to create subscriptions. The flow for creating a subscription works as follows:\n1. Gather the parameters for the new recurrent payment to be created.\n2. Compute the address of the recurrent payment contract from the parameters.\n3. The user approves tokens to the computed address.\n4. Once the approval has been confirmed, send a transaction to create the recurring payment contract and begin withdrawing funds from the user every period.\n\n## Daisy\n\nFor subscription services created using Daisy the platform, Daisy will be the authorizer AND the relayer for payments.\n\n# Testing\n\nTo run the tests, clone this repo and run `yarn install` to install dependencies.\n\nRun `yarn test` to run all tests.\n\nRun `yarn coverage` to run tests and get code coverage.\n","description":"[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repo","licenseText":"MIT License\n\nCopyright (c) 2019 Token Foundry\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@daisypayments/smart-contracts@0.4.0-beta.6","dist":{"shasum":"6673cbb64e1086a9fa025df64515a377995e01d5","integrity":"sha512-gumKsY76fd5OUKCcVL/BytIFiD3vre50kYg62DHuMxo0kSbDE284zIzYYTYauvik20ebzalkm7yF8fKgKUho8g==","tarball":"https://registry.npmjs.org/@daisypayments/smart-contracts/-/smart-contracts-0.4.0-beta.6.tgz","fileCount":21,"unpackedSize":3911614,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeoK3FCRA9TVsSAnZWagAAWroQAIfyLv9mlutQDeXTCg0h\ng3JvEagaGsR8BXwOo5pp0lRt+IqCbVWArpObactEsyJgkC4H2R7/gJ2PRdOu\nfwUgKS8JV4Xc6cIyfizJ1Tqvg/FwtyDCAVivQnogbfMIMGNQ93cThhyEIIi7\nmIThvvGoguffywTIXV/CtPCuiLReD8BNwVM3eORWwK03x7S6gyFXj0nKweYc\ngqOILPrG43J5K4nUtL4XJgJ57JUEX0CpeardlHLrizLGosEs9Ys9BhFIM+En\n5jym8fzBJzGx8I50hiZ4+ZbFbmihz2iSDsQnJPiqWjYP4gaGOafjne7GPp3j\nfJdoIfk++eduzsVVuAdj9rZBuLeRtqYL2HGK1UQdLD7HCHJKIGvwkPXAsMcF\nDWQRdXI3gdCfGZp51+ppE9c2xl5lYnOYCEShyUP9wmycCLff0olF8ze410lL\n+AJrvb/H2sMfq+amN5ouuLIkKv5nUAiKgrw1M6UVStrRvQ2Hk/J7ox0ZfL/H\nmDyop8Lfzg0DGdL7y1Bq32zEcFNgh3NYmwQTvHzDtookKvqsAXTyQjZiZsuK\npX/gtTdWdyUyfuVTU10SlSPVGlUgf7i23YJkccPWmiqmOfqnnULqyDVXMx9I\nDarqInyWVRQm0BlEti1R5ib8kbkaksBtRFngiSkZRhOZ/UY2qf64JLOluPKU\nNZH/\r\n=bzrF\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCOgqxiNQ29fmGhdIm15vXuffHT+mNNOhDf0P7p1u3m4gIhANr673BEGKuY3SmluHscd1nmbgF2Rh7lp5p1LzxGVuCo"}]},"maintainers":[{"name":"jmoreira","email":"jmoreiras@gmail.com"},{"name":"lopezjurip","email":"lopezjuripatricio@gmail.com"},{"name":"nchastain","email":"nate.chastain@consensys.net"},{"name":"sloreti","email":"lhloreti@gmail.com"},{"name":"vdrg","email":"vdrg@protonmail.ch"},{"name":"wachunei","email":"wachunei@gmail.com"}],"_npmUser":{"name":"vdrg","email":"vdrg@protonmail.ch"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/smart-contracts_0.4.0-beta.6_1587588548937_0.08753963619335914"},"_hasShrinkwrap":false}},"time":{"created":"2019-07-29T20:21:41.038Z","0.0.1":"2019-07-29T20:21:41.388Z","modified":"2022-04-05T02:36:46.812Z","0.0.2":"2019-07-29T23:37:05.753Z","0.0.3":"2019-08-01T21:15:16.700Z","0.0.4":"2019-08-02T16:25:24.206Z","0.1.0":"2019-08-21T15:07:16.657Z","0.2.0-beta":"2019-08-29T16:48:58.694Z","0.2.1-beta":"2019-08-29T16:56:35.682Z","0.2.2-beta":"2019-08-29T18:28:50.551Z","0.2.0-beta.1":"2019-09-03T19:09:40.664Z","0.1.1":"2019-09-04T19:33:49.929Z","0.2.0-beta.2":"2019-09-06T20:49:13.296Z","0.2.0-beta.3":"2019-09-30T20:10:13.754Z","0.3.0-beta.1":"2019-10-23T15:38:38.224Z","0.3.0-beta.2":"2019-10-23T16:45:28.886Z","0.3.0-beta.3":"2019-10-28T17:24:59.676Z","0.3.0-beta.4":"2019-11-26T14:58:40.049Z","0.3.0-beta.5":"2019-11-26T15:04:51.651Z","0.3.0-beta.6":"2019-11-27T16:45:42.401Z","0.4.0-beta.1":"2020-04-17T20:03:23.529Z","0.4.0-beta.2":"2020-04-17T20:37:28.176Z","0.4.0-beta.3":"2020-04-17T21:44:41.481Z","0.4.0-beta.4":"2020-04-22T16:16:13.211Z","0.4.0-beta.5":"2020-04-22T17:33:16.252Z","0.4.0-beta.6":"2020-04-22T20:49:09.157Z"},"maintainers":[{"name":"jmoreira","email":"jmoreiras@gmail.com"},{"name":"lopezjurip","email":"lopezjuripatricio@gmail.com"},{"name":"nchastain","email":"nate.chastain@consensys.net"},{"name":"sloreti","email":"lhloreti@gmail.com"},{"name":"vdrg","email":"vdrg@protonmail.ch"},{"name":"wachunei","email":"wachunei@gmail.com"}],"description":"[![CircleCI](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts.svg?style=svg&circle-token=f12a017b0a243543bc99636fb003238bdc290dd5)](https://circleci.com/gh/ConsenSys/daisy-subscription-contracts) [![Coverage Status](https://coveralls.io/repo","repository":{"type":"git","url":"https://github.com/consensys/daisy-subscription-contracts"},"author":{"name":"vdrg","email":"vicente.dragicevic@consensys.net"},"license":"MIT","readme":"","readmeFilename":""}