diff --git a/.gitmodules b/.gitmodules index bc35d51f..55105ee4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,6 +2,10 @@ branch = "main" path = "repos/airdrops" url = "https://github.com/sablier-labs/airdrops" +[submodule "repos/evm-utils"] + branch = main + path = repos/evm-utils + url = https://github.com/sablier-labs/evm-utils [submodule "repos/flow"] branch = "main" path = "repos/flow" diff --git a/bun.lock b/bun.lock index 8d3cce6d..a996e8fb 100644 --- a/bun.lock +++ b/bun.lock @@ -70,7 +70,7 @@ "@ai-sdk/react": ["@ai-sdk/react@2.0.76", "", { "dependencies": { "@ai-sdk/provider-utils": "3.0.12", "ai": "5.0.76", "swr": "^2.2.5", "throttleit": "2.1.0" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "zod": "^3.25.76 || ^4.1.8" }, "optionalPeers": ["zod"] }, "sha512-ggAPzyaKJTqUWigpxMzI5DuC0Y3iEpDUPCgz6/6CpnKZY/iok+x5xiZhDemeaP0ILw5IQekV0kdgBR8JPgI8zQ=="], - "@algolia/abtesting": ["@algolia/abtesting@1.6.1", "", { "dependencies": { "@algolia/client-common": "5.40.1", "@algolia/requester-browser-xhr": "5.40.1", "@algolia/requester-fetch": "5.40.1", "@algolia/requester-node-http": "5.40.1" } }, "sha512-wV/gNRkzb7sI9vs1OneG129hwe3Q5zPj7zigz3Ps7M5Lpo2hSorrOnXNodHEOV+yXE/ks4Pd+G3CDFIjFTWhMQ=="], + "@algolia/abtesting": ["@algolia/abtesting@1.7.0", "", { "dependencies": { "@algolia/client-common": "5.41.0", "@algolia/requester-browser-xhr": "5.41.0", "@algolia/requester-fetch": "5.41.0", "@algolia/requester-node-http": "5.41.0" } }, "sha512-hOEItTFOvNLI6QX6TSGu7VE4XcUcdoKZT8NwDY+5mWwu87rGhkjlY7uesKTInlg6Sh8cyRkDBYRumxbkoBbBhA=="], "@algolia/autocomplete-core": ["@algolia/autocomplete-core@1.19.2", "", { "dependencies": { "@algolia/autocomplete-plugin-algolia-insights": "1.19.2", "@algolia/autocomplete-shared": "1.19.2" } }, "sha512-mKv7RyuAzXvwmq+0XRK8HqZXt9iZ5Kkm2huLjgn5JoCPtDy+oh9yxUMfDDaVCw0oyzZ1isdJBc7l9nuCyyR7Nw=="], @@ -78,33 +78,33 @@ "@algolia/autocomplete-shared": ["@algolia/autocomplete-shared@1.19.2", "", { "peerDependencies": { "@algolia/client-search": ">= 4.9.1 < 6", "algoliasearch": ">= 4.9.1 < 6" } }, "sha512-jEazxZTVD2nLrC+wYlVHQgpBoBB5KPStrJxLzsIFl6Kqd1AlG9sIAGl39V5tECLpIQzB3Qa2T6ZPJ1ChkwMK/w=="], - "@algolia/client-abtesting": ["@algolia/client-abtesting@5.40.1", "", { "dependencies": { "@algolia/client-common": "5.40.1", "@algolia/requester-browser-xhr": "5.40.1", "@algolia/requester-fetch": "5.40.1", "@algolia/requester-node-http": "5.40.1" } }, "sha512-cxKNATPY5t+Mv8XAVTI57altkaPH+DZi4uMrnexPxPHODMljhGYY+GDZyHwv9a+8CbZHcY372OkxXrDMZA4Lnw=="], + "@algolia/client-abtesting": ["@algolia/client-abtesting@5.41.0", "", { "dependencies": { "@algolia/client-common": "5.41.0", "@algolia/requester-browser-xhr": "5.41.0", "@algolia/requester-fetch": "5.41.0", "@algolia/requester-node-http": "5.41.0" } }, "sha512-iRuvbEyuHCAhIMkyzG3tfINLxTS7mSKo7q8mQF+FbQpWenlAlrXnfZTN19LRwnVjx0UtAdZq96ThMWGS6cQ61A=="], - "@algolia/client-analytics": ["@algolia/client-analytics@5.40.1", "", { "dependencies": { "@algolia/client-common": "5.40.1", "@algolia/requester-browser-xhr": "5.40.1", "@algolia/requester-fetch": "5.40.1", "@algolia/requester-node-http": "5.40.1" } }, "sha512-XP008aMffJCRGAY8/70t+hyEyvqqV7YKm502VPu0+Ji30oefrTn2al7LXkITz7CK6I4eYXWRhN6NaIUi65F1OA=="], + "@algolia/client-analytics": ["@algolia/client-analytics@5.41.0", "", { "dependencies": { "@algolia/client-common": "5.41.0", "@algolia/requester-browser-xhr": "5.41.0", "@algolia/requester-fetch": "5.41.0", "@algolia/requester-node-http": "5.41.0" } }, "sha512-OIPVbGfx/AO8l1V70xYTPSeTt/GCXPEl6vQICLAXLCk9WOUbcLGcy6t8qv0rO7Z7/M/h9afY6Af8JcnI+FBFdQ=="], - "@algolia/client-common": ["@algolia/client-common@5.40.1", "", {}, "sha512-gWfQuQUBtzUboJv/apVGZMoxSaB0M4Imwl1c9Ap+HpCW7V0KhjBddqF2QQt5tJZCOFsfNIgBbZDGsEPaeKUosw=="], + "@algolia/client-common": ["@algolia/client-common@5.41.0", "", {}, "sha512-8Mc9niJvfuO8dudWN5vSUlYkz7U3M3X3m1crDLc9N7FZrIVoNGOUETPk3TTHviJIh9y6eKZKbq1hPGoGY9fqPA=="], - "@algolia/client-insights": ["@algolia/client-insights@5.40.1", "", { "dependencies": { "@algolia/client-common": "5.40.1", "@algolia/requester-browser-xhr": "5.40.1", "@algolia/requester-fetch": "5.40.1", "@algolia/requester-node-http": "5.40.1" } }, "sha512-RTLjST/t+lsLMouQ4zeLJq2Ss+UNkLGyNVu+yWHanx6kQ3LT5jv8UvPwyht9s7R6jCPnlSI77WnL80J32ZuyJg=="], + "@algolia/client-insights": ["@algolia/client-insights@5.41.0", "", { "dependencies": { "@algolia/client-common": "5.41.0", "@algolia/requester-browser-xhr": "5.41.0", "@algolia/requester-fetch": "5.41.0", "@algolia/requester-node-http": "5.41.0" } }, "sha512-vXzvCGZS6Ixxn+WyzGUVDeR3HO/QO5POeeWy1kjNJbEf6f+tZSI+OiIU9Ha+T3ntV8oXFyBEuweygw4OLmgfiQ=="], - "@algolia/client-personalization": ["@algolia/client-personalization@5.40.1", "", { "dependencies": { "@algolia/client-common": "5.40.1", "@algolia/requester-browser-xhr": "5.40.1", "@algolia/requester-fetch": "5.40.1", "@algolia/requester-node-http": "5.40.1" } }, "sha512-2FEK6bUomBzEYkTKzD0iRs7Ljtjb45rKK/VSkyHqeJnG+77qx557IeSO0qVFE3SfzapNcoytTofnZum0BQ6r3Q=="], + "@algolia/client-personalization": ["@algolia/client-personalization@5.41.0", "", { "dependencies": { "@algolia/client-common": "5.41.0", "@algolia/requester-browser-xhr": "5.41.0", "@algolia/requester-fetch": "5.41.0", "@algolia/requester-node-http": "5.41.0" } }, "sha512-tkymXhmlcc7w/HEvLRiHcpHxLFcUB+0PnE9FcG6hfFZ1ZXiWabH+sX+uukCVnluyhfysU9HRU2kUmUWfucx1Dg=="], - "@algolia/client-query-suggestions": ["@algolia/client-query-suggestions@5.40.1", "", { "dependencies": { "@algolia/client-common": "5.40.1", "@algolia/requester-browser-xhr": "5.40.1", "@algolia/requester-fetch": "5.40.1", "@algolia/requester-node-http": "5.40.1" } }, "sha512-Nju4NtxAvXjrV2hHZNLKVJLXjOlW6jAXHef/CwNzk1b2qIrCWDO589ELi5ZHH1uiWYoYyBXDQTtHmhaOVVoyXg=="], + "@algolia/client-query-suggestions": ["@algolia/client-query-suggestions@5.41.0", "", { "dependencies": { "@algolia/client-common": "5.41.0", "@algolia/requester-browser-xhr": "5.41.0", "@algolia/requester-fetch": "5.41.0", "@algolia/requester-node-http": "5.41.0" } }, "sha512-vyXDoz3kEZnosNeVQQwf0PbBt5IZJoHkozKRIsYfEVm+ylwSDFCW08qy2YIVSHdKy69/rWN6Ue/6W29GgVlmKQ=="], - "@algolia/client-search": ["@algolia/client-search@5.40.1", "", { "dependencies": { "@algolia/client-common": "5.40.1", "@algolia/requester-browser-xhr": "5.40.1", "@algolia/requester-fetch": "5.40.1", "@algolia/requester-node-http": "5.40.1" } }, "sha512-Mw6pAUF121MfngQtcUb5quZVqMC68pSYYjCRZkSITC085S3zdk+h/g7i6FxnVdbSU6OztxikSDMh1r7Z+4iPlA=="], + "@algolia/client-search": ["@algolia/client-search@5.41.0", "", { "dependencies": { "@algolia/client-common": "5.41.0", "@algolia/requester-browser-xhr": "5.41.0", "@algolia/requester-fetch": "5.41.0", "@algolia/requester-node-http": "5.41.0" } }, "sha512-G9I2atg1ShtFp0t7zwleP6aPS4DcZvsV4uoQOripp16aR6VJzbEnKFPLW4OFXzX7avgZSpYeBAS+Zx4FOgmpPw=="], "@algolia/events": ["@algolia/events@4.0.1", "", {}, "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ=="], - "@algolia/ingestion": ["@algolia/ingestion@1.40.1", "", { "dependencies": { "@algolia/client-common": "5.40.1", "@algolia/requester-browser-xhr": "5.40.1", "@algolia/requester-fetch": "5.40.1", "@algolia/requester-node-http": "5.40.1" } }, "sha512-z+BPlhs45VURKJIxsR99NNBWpUEEqIgwt10v/fATlNxc4UlXvALdOsWzaFfe89/lbP5Bu4+mbO59nqBC87ZM/g=="], + "@algolia/ingestion": ["@algolia/ingestion@1.41.0", "", { "dependencies": { "@algolia/client-common": "5.41.0", "@algolia/requester-browser-xhr": "5.41.0", "@algolia/requester-fetch": "5.41.0", "@algolia/requester-node-http": "5.41.0" } }, "sha512-sxU/ggHbZtmrYzTkueTXXNyifn+ozsLP+Wi9S2hOBVhNWPZ8uRiDTDcFyL7cpCs1q72HxPuhzTP5vn4sUl74cQ=="], - "@algolia/monitoring": ["@algolia/monitoring@1.40.1", "", { "dependencies": { "@algolia/client-common": "5.40.1", "@algolia/requester-browser-xhr": "5.40.1", "@algolia/requester-fetch": "5.40.1", "@algolia/requester-node-http": "5.40.1" } }, "sha512-VJMUMbO0wD8Rd2VVV/nlFtLJsOAQvjnVNGkMkspFiFhpBA7s/xJOb+fJvvqwKFUjbKTUA7DjiSi1ljSMYBasXg=="], + "@algolia/monitoring": ["@algolia/monitoring@1.41.0", "", { "dependencies": { "@algolia/client-common": "5.41.0", "@algolia/requester-browser-xhr": "5.41.0", "@algolia/requester-fetch": "5.41.0", "@algolia/requester-node-http": "5.41.0" } }, "sha512-UQ86R6ixraHUpd0hn4vjgTHbViNO8+wA979gJmSIsRI3yli2v89QSFF/9pPcADR6PbtSio/99PmSNxhZy+CR3Q=="], - "@algolia/recommend": ["@algolia/recommend@5.40.1", "", { "dependencies": { "@algolia/client-common": "5.40.1", "@algolia/requester-browser-xhr": "5.40.1", "@algolia/requester-fetch": "5.40.1", "@algolia/requester-node-http": "5.40.1" } }, "sha512-ehvJLadKVwTp9Scg9NfzVSlBKH34KoWOQNTaN8i1Ac64AnO6iH2apJVSP6GOxssaghZ/s8mFQsDH3QIZoluFHA=="], + "@algolia/recommend": ["@algolia/recommend@5.41.0", "", { "dependencies": { "@algolia/client-common": "5.41.0", "@algolia/requester-browser-xhr": "5.41.0", "@algolia/requester-fetch": "5.41.0", "@algolia/requester-node-http": "5.41.0" } }, "sha512-DxP9P8jJ8whJOnvmyA5mf1wv14jPuI0L25itGfOHSU6d4ZAjduVfPjTS3ROuUN5CJoTdlidYZE+DtfWHxJwyzQ=="], - "@algolia/requester-browser-xhr": ["@algolia/requester-browser-xhr@5.40.1", "", { "dependencies": { "@algolia/client-common": "5.40.1" } }, "sha512-PbidVsPurUSQIr6X9/7s34mgOMdJnn0i6p+N6Ab+lsNhY5eiu+S33kZEpZwkITYBCIbhzDLOvb7xZD3gDi+USA=="], + "@algolia/requester-browser-xhr": ["@algolia/requester-browser-xhr@5.41.0", "", { "dependencies": { "@algolia/client-common": "5.41.0" } }, "sha512-C21J+LYkE48fDwtLX7YXZd2Fn7Fe0/DOEtvohSfr/ODP8dGDhy9faaYeWB0n1AvmZltugjkjAXT7xk0CYNIXsQ=="], - "@algolia/requester-fetch": ["@algolia/requester-fetch@5.40.1", "", { "dependencies": { "@algolia/client-common": "5.40.1" } }, "sha512-ThZ5j6uOZCF11fMw9IBkhigjOYdXGXQpj6h4k+T9UkZrF2RlKcPynFzDeRgaLdpYk8Yn3/MnFbwUmib7yxj5Lw=="], + "@algolia/requester-fetch": ["@algolia/requester-fetch@5.41.0", "", { "dependencies": { "@algolia/client-common": "5.41.0" } }, "sha512-FhJy/+QJhMx1Hajf2LL8og4J7SqOAHiAuUXq27cct4QnPhSIuIGROzeRpfDNH5BUbq22UlMuGd44SeD4HRAqvA=="], - "@algolia/requester-node-http": ["@algolia/requester-node-http@5.40.1", "", { "dependencies": { "@algolia/client-common": "5.40.1" } }, "sha512-H1gYPojO6krWHnUXu/T44DrEun/Wl95PJzMXRcM/szstNQczSbwq6wIFJPI9nyE95tarZfUNU3rgorT+wZ6iCQ=="], + "@algolia/requester-node-http": ["@algolia/requester-node-http@5.41.0", "", { "dependencies": { "@algolia/client-common": "5.41.0" } }, "sha512-tYv3rGbhBS0eZ5D8oCgV88iuWILROiemk+tQ3YsAKZv2J4kKUNvKkrX/If/SreRy4MGP2uJzMlyKcfSfO2mrsQ=="], "@antfu/install-pkg": ["@antfu/install-pkg@1.1.0", "", { "dependencies": { "package-manager-detector": "^1.3.0", "tinyexec": "^1.0.1" } }, "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ=="], @@ -560,7 +560,7 @@ "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g=="], - "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="], + "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="], "@eslint/compat": ["@eslint/compat@1.4.0", "", { "dependencies": { "@eslint/core": "^0.16.0" }, "peerDependencies": { "eslint": "^8.40 || 9" }, "optionalPeers": ["eslint"] }, "sha512-DEzm5dKeDBPm3r08Ixli/0cmxr8LkRdwxMRUIJBlSCpAwSrvFEJpVBzV+66JhDxiaqKxnRzCXhtiMiczF7Hglg=="], @@ -778,7 +778,7 @@ "@rspack/lite-tapable": ["@rspack/lite-tapable@1.0.1", "", {}, "sha512-VynGOEsVw2s8TAlLf/uESfrgfrq2+rcXB1muPJYBWbsm1Oa6r5qVQhjA5ggM6z/coYPrsVMgovl3Ff7Q7OCp1w=="], - "@sablier/devkit": ["@sablier/devkit@github:sablier-labs/devkit#5de9cc0", {}, "sablier-labs-devkit-5de9cc0"], + "@sablier/devkit": ["@sablier/devkit@github:sablier-labs/devkit#a25a472", {}, "sablier-labs-devkit-a25a472"], "@sablier/docusaurus-plugin-llms": ["@sablier/docusaurus-plugin-llms@0.3.0", "", { "dependencies": { "gray-matter": "^4.0.3", "minimatch": "^9.0.3", "yaml": "^2.8.1" }, "peerDependencies": { "@docusaurus/core": "^3.0.0" } }, "sha512-5AwcuaQGEolcbpENM+QBXa581hhF4gzfoaM67AOp1Rvs9O8DsqC/As/8W0ABvdQdoXcoBAlpmrF/gBacuyhFzw=="], @@ -882,7 +882,7 @@ "@szmarczak/http-timer": ["@szmarczak/http-timer@5.0.1", "", { "dependencies": { "defer-to-connect": "^2.0.1" } }, "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw=="], - "@theguild/federation-composition": ["@theguild/federation-composition@0.20.1", "", { "dependencies": { "constant-case": "^3.0.4", "debug": "4.4.1", "json5": "^2.2.3", "lodash.sortby": "^4.7.0" }, "peerDependencies": { "graphql": "^16.0.0" } }, "sha512-lwYYKCeHmstOtbMtzxC0BQKWsUPYbEVRVdJ3EqR4jSpcF4gvNf3MOJv6yuvq6QsKqgYZURKRBszmg7VEDoi5Aw=="], + "@theguild/federation-composition": ["@theguild/federation-composition@0.20.2", "", { "dependencies": { "constant-case": "^3.0.4", "debug": "4.4.3", "json5": "^2.2.3", "lodash.sortby": "^4.7.0" }, "peerDependencies": { "graphql": "^16.0.0" } }, "sha512-QI4iSdrc4JvCWnMb1QbiHnEpdD33KGdiU66qfWOcM8ENebRGHkGjXDnUrVJ8F9g1dmCRMTNfn2NFGqTcDpeYXw=="], "@tootallnate/once": ["@tootallnate/once@2.0.0", "", {}, "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A=="], @@ -1178,7 +1178,7 @@ "ajv-keywords": ["ajv-keywords@5.1.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3" }, "peerDependencies": { "ajv": "^8.8.2" } }, "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw=="], - "algoliasearch": ["algoliasearch@5.40.1", "", { "dependencies": { "@algolia/abtesting": "1.6.1", "@algolia/client-abtesting": "5.40.1", "@algolia/client-analytics": "5.40.1", "@algolia/client-common": "5.40.1", "@algolia/client-insights": "5.40.1", "@algolia/client-personalization": "5.40.1", "@algolia/client-query-suggestions": "5.40.1", "@algolia/client-search": "5.40.1", "@algolia/ingestion": "1.40.1", "@algolia/monitoring": "1.40.1", "@algolia/recommend": "5.40.1", "@algolia/requester-browser-xhr": "5.40.1", "@algolia/requester-fetch": "5.40.1", "@algolia/requester-node-http": "5.40.1" } }, "sha512-iUNxcXUNg9085TJx0HJLjqtDE0r1RZ0GOGrt8KNQqQT5ugu8lZsHuMUYW/e0lHhq6xBvmktU9Bw4CXP9VQeKrg=="], + "algoliasearch": ["algoliasearch@5.41.0", "", { "dependencies": { "@algolia/abtesting": "1.7.0", "@algolia/client-abtesting": "5.41.0", "@algolia/client-analytics": "5.41.0", "@algolia/client-common": "5.41.0", "@algolia/client-insights": "5.41.0", "@algolia/client-personalization": "5.41.0", "@algolia/client-query-suggestions": "5.41.0", "@algolia/client-search": "5.41.0", "@algolia/ingestion": "1.41.0", "@algolia/monitoring": "1.41.0", "@algolia/recommend": "5.41.0", "@algolia/requester-browser-xhr": "5.41.0", "@algolia/requester-fetch": "5.41.0", "@algolia/requester-node-http": "5.41.0" } }, "sha512-9E4b3rJmYbBkn7e3aAPt1as+VVnRhsR4qwRRgOzpeyz4PAOuwKh0HI4AN6mTrqK0S0M9fCCSTOUnuJ8gPY/tvA=="], "algoliasearch-helper": ["algoliasearch-helper@3.26.0", "", { "dependencies": { "@algolia/events": "^4.0.1" }, "peerDependencies": { "algoliasearch": ">= 3.1 < 6" } }, "sha512-Rv2x3GXleQ3ygwhkhJubhhYGsICmShLAiqtUuJTUkr9uOCOXyF2E71LVT4XDnVffbknv8XgScP4U0Oxtgm+hIw=="], @@ -1256,7 +1256,7 @@ "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], - "browserslist": ["browserslist@4.26.3", "", { "dependencies": { "baseline-browser-mapping": "^2.8.9", "caniuse-lite": "^1.0.30001746", "electron-to-chromium": "^1.5.227", "node-releases": "^2.0.21", "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w=="], + "browserslist": ["browserslist@4.27.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.19", "caniuse-lite": "^1.0.30001751", "electron-to-chromium": "^1.5.238", "node-releases": "^2.0.26", "update-browserslist-db": "^1.1.4" }, "bin": { "browserslist": "cli.js" } }, "sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw=="], "buffer-crc32": ["buffer-crc32@0.2.13", "", {}, "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ=="], @@ -1608,7 +1608,7 @@ "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], - "electron-to-chromium": ["electron-to-chromium@1.5.238", "", {}, "sha512-khBdc+w/Gv+cS8e/Pbnaw/FXcBUeKrRVik9IxfXtgREOWyJhR4tj43n3amkVogJ/yeQUqzkrZcFhtIxIdqmmcQ=="], + "electron-to-chromium": ["electron-to-chromium@1.5.239", "", {}, "sha512-1y5w0Zsq39MSPmEjHjbizvhYoTaulVtivpxkp5q5kaPmQtsK6/2nvAzGRxNMS9DoYySp9PkW0MAQDwU1m764mg=="], "elkjs": ["elkjs@0.9.3", "", {}, "sha512-f/ZeWvW/BCXbhGEf1Ujp29EASo/lk1FDnETgNKwJrsVvGZhUWCZyg3xLJjAsxfOmt8KjswHmI5EwCQcPMpOYhQ=="], @@ -2160,7 +2160,7 @@ "lines-and-columns": ["lines-and-columns@2.0.4", "", {}, "sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A=="], - "lint-staged": ["lint-staged@16.2.5", "", { "dependencies": { "commander": "^14.0.1", "listr2": "^9.0.4", "micromatch": "^4.0.8", "nano-spawn": "^2.0.0", "pidtree": "^0.6.0", "string-argv": "^0.3.2", "yaml": "^2.8.1" }, "bin": { "lint-staged": "bin/lint-staged.js" } }, "sha512-o36wH3OX0jRWqDw5dOa8a8x6GXTKaLM+LvhRaucZxez0IxA+KNDUCiyjBfNgsMNmchwSX6urLSL7wShcUqAang=="], + "lint-staged": ["lint-staged@16.2.6", "", { "dependencies": { "commander": "^14.0.1", "listr2": "^9.0.5", "micromatch": "^4.0.8", "nano-spawn": "^2.0.0", "pidtree": "^0.6.0", "string-argv": "^0.3.2", "yaml": "^2.8.1" }, "bin": { "lint-staged": "bin/lint-staged.js" } }, "sha512-s1gphtDbV4bmW1eylXpVMk2u7is7YsrLl8hzrtvC70h4ByhcMLZFY01Fx05ZUDNuv1H8HO4E+e2zgejV1jVwNw=="], "listr2": ["listr2@9.0.5", "", { "dependencies": { "cli-truncate": "^5.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", "log-update": "^6.1.0", "rfdc": "^1.4.1", "wrap-ansi": "^9.0.0" } }, "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g=="], @@ -3130,7 +3130,7 @@ "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], - "update-browserslist-db": ["update-browserslist-db@1.1.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="], + "update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="], "update-notifier": ["update-notifier@6.0.2", "", { "dependencies": { "boxen": "^7.0.0", "chalk": "^5.0.1", "configstore": "^6.0.0", "has-yarn": "^3.0.0", "import-lazy": "^4.0.0", "is-ci": "^3.0.1", "is-installed-globally": "^0.4.0", "is-npm": "^6.0.0", "is-yarn-global": "^0.4.0", "latest-version": "^7.0.0", "pupa": "^3.1.0", "semver": "^7.3.7", "semver-diff": "^4.0.0", "xdg-basedir": "^5.1.0" } }, "sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og=="], @@ -3360,8 +3360,6 @@ "@slorber/remark-comment/micromark-util-symbol": ["micromark-util-symbol@1.1.0", "", {}, "sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag=="], - "@theguild/federation-composition/debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="], - "@types/serve-static/@types/send": ["@types/send@0.17.5", "", { "dependencies": { "@types/mime": "^1", "@types/node": "*" } }, "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w=="], "@vercel/fun/debug": ["debug@4.3.4", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ=="], @@ -3428,6 +3426,8 @@ "cli-truncate/string-width": ["string-width@8.1.0", "", { "dependencies": { "get-east-asian-width": "^1.3.0", "strip-ansi": "^7.1.0" } }, "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg=="], + "compressible/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], + "compression/bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], "compression/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], diff --git a/cli/autogen-reference.sh b/cli/autogen-reference.sh index d3136d1a..b55d5fe9 100755 --- a/cli/autogen-reference.sh +++ b/cli/autogen-reference.sh @@ -23,16 +23,26 @@ find $airdrops -type f -name "*.md" -delete find $flow -type f -name "*.md" -delete find $lockup -type f -name "*.md" -delete +set_sidebar_position() { + local file=$1 + local position=$2 + echo "$(echo -en '---\nsidebar_position: '$position'\n---\n'; cat $file)" > $file +} + lint() { contracts=docs/reference/$1/contracts - # Format the docs with Prettier - bun prettier --log-level silent --write $contracts + # Cache find result to avoid redundant filesystem scan + all_md_files=$(find $contracts -type f -name "*.md") - # Remove the italic asterisks added by `forge doc`: https://github.com/foundry-rs/foundry/issues/4540 - sd --string-mode "\*" "" $(find $contracts -type f -name "*.md") + # Fix malformed code block endings with asterisks (e.g., ```* should be ```) + # This pattern appears in forge-generated docs and breaks markdown rendering + sd '```\*' '```' $all_md_files - # Re-format the docs with Prettier + # Remove remaining italic asterisks added by `forge doc`: https://github.com/foundry-rs/foundry/issues/4540 + sd --string-mode "\*" "" $all_md_files + + # Format the docs with Prettier bun prettier --log-level silent --write $contracts } @@ -55,9 +65,6 @@ run() { # Define the contracts directory contracts=docs/reference/$repo/contracts - # Delete the current contracts references - find $contracts -type f -name "*.md" -delete - # Copy over the auto-generated files rsync --archive \ --exclude "README.md" \ @@ -71,30 +78,77 @@ run() { # Delete empty *.sol directories find $contracts -type d -empty -delete + # Cache find result to avoid redundant filesystem scans throughout this function + all_md_files=$(find $contracts -type f -name "*.md") + # Replace the interface with hyperlinks - sd "\{I(\w+)\}" "[I\$1](/$contracts/interfaces/interface.I\$1.md)" $(find $contracts -type f -name "*.md") + sd "\{I(\w+)\}" "[I\$1](/$contracts/interfaces/interface.I\$1.md)" $all_md_files if [ "$repo" = "airdrops" ]; then + # Airdrops-specific abstract patterns + sd "\{Sablier(\w+)Base\}" "[Sablier\${1}Base]($contracts/abstracts/abstract.Sablier\${1}Base.md)" $all_md_files + sd "\{SablierFactoryMerkle(\w+)\}" "[SablierFactoryMerkle\$1](/$contracts/contract.SablierFactoryMerkle\$1.md)" $all_md_files + sd "\{SablierMerkleLockup\}" "[SablierMerkleLockup]($contracts/abstracts/abstract.SablierMerkleLockup.md)" $all_md_files + # The Airdrops has certain references to the Lockup - sd "\{SablierLockup\}" "[SablierLockup](/reference/lockup/contracts/contract.SablierLockup.md)" $(find $airdrops -type f -name "*.md") + sd "\{SablierLockup\}" "[SablierLockup](/reference/lockup/contracts/contract.SablierLockup.md)" $all_md_files + + # Airdrops-only evm-utils abstract + sd "\bAdminable\b" "[Adminable](/$contracts/abstracts/abstract.Adminable.md)" $all_md_files fi if [ "$repo" = "lockup" ]; then + # Lockup-specific abstract patterns + sd "\{SablierLockup(Dynamic|Linear|Tranched)\}" "[SablierLockup\$1]($contracts/abstracts/abstract.SablierLockup\$1.md)" $all_md_files + sd "\{SablierLockup(Dynamic|Linear|Tranched)\.(\w+)\}" "[SablierLockup\$1.\$2]($contracts/abstracts/abstract.SablierLockup\$1.md#\$2)" $all_md_files + + # Fix anchor casing for createWith* functions in types/ (Docusaurus lowercases all anchors) + types_files=$(find $contracts/types -type f -name "*.md") + sd "(#createWithDurationsLD)" "#createwithdurationsld" $types_files + sd "(#createWithDurationsLL)" "#createwithdurationsll" $types_files + sd "(#createWithDurationsLT)" "#createwithdurationslt" $types_files + sd "(#createWithTimestampsLD)" "#createwithtimestampsld" $types_files + sd "(#createWithTimestampsLL)" "#createwithtimestampsll" $types_files + sd "(#createWithTimestampsLT)" "#createwithtimestampslt" $types_files + # Fix some invalid references in Lockup - sd "InvalidWithdrawalInWithdrawMultiple.md" "ISablierLockupBase.md#invalidwithdrawalinwithdrawmultiple" $(find $contracts -type f -name "*.md") - sd "/node_modules/forge-std/src/mocks/MockERC721.sol/contract.MockERC721.md" "https://eips.ethereum.org/EIPS/eip-165" $(find $contracts -type f -name "*.md") + sd "InvalidWithdrawalInWithdrawMultiple.md" "ISablierLockup.md#invalidwithdrawalinwithdrawmultiple" $all_md_files + sd "/docs/reference/lockup/contracts/interfaces/interface.InvalidStreamInCancelMultiple.md" "/docs/reference/lockup/contracts/interfaces/interface.ISablierLockup.md#invalidstreamincancelmultiple" $all_md_files + sd "/node_modules/forge-std/src/mocks/MockERC721.sol/contract.MockERC721.md" "https://eips.ethereum.org/EIPS/eip-165" $all_md_files + sd "/node_modules/@arbitrum/token-bridge-contracts/contracts/tokenbridge/libraries/ERC165.sol/abstract.ERC165.md#supportsinterface" "https://eips.ethereum.org/EIPS/eip-165" $all_md_files + fi + + if [ "$repo" = "flow" ]; then + # Flow-specific abstract patterns + sd "\{SablierFlowState\}" "[SablierFlowState]($contracts/abstracts/abstract.SablierFlowState.md)" $all_md_files + fi + + # Link to evm-utils abstracts (plain text - copied locally) + # Comptrollerable: all repos (airdrops, lockup, flow) + sd "\bComptrollerable\b" "[Comptrollerable](/$contracts/abstracts/abstract.Comptrollerable.md)" $all_md_files + + # Batch and NoDelegateCall: lockup and flow only + if [ "$repo" = "lockup" ] || [ "$repo" = "flow" ]; then + sd "\bBatch\b" "[Batch](/$contracts/abstracts/abstract.Batch.md)" $all_md_files + sd "\bNoDelegateCall\b" "[NoDelegateCall](/$contracts/abstracts/abstract.NoDelegateCall.md)" $all_md_files fi + # Replace the abstract contract references with hyperlinks (global fallback) + sd "\{Sablier(\w+)State\}" "[Sablier\${1}State]($contracts/abstracts/abstract.Sablier\${1}State.md)" $all_md_files + # Replace the contract references with hyperlinks - # Note: abstract contracts won't work - sd "\{Sablier(\w+)Base\}" "[Sablier\${1}Base]($contracts/abstracts/abstract.Sablier\${1}Base.md)" $(find $contracts -type f -name "*.md") - sd "\{Sablier(\w+)\}" "[Sablier\$1](/$contracts/contract.Sablier\$1.md)" $(find $contracts -type f -name "*.md") + sd "\{Sablier(\w+)\}" "[Sablier\$1](/$contracts/contract.Sablier\$1.md)" $all_md_files + + # Fix external contract references that don't have docs + if [ "$repo" = "lockup" ]; then + sd "\[SablierComptroller\]\(/docs/reference/lockup/contracts/contract\.SablierComptroller\.md\)" "**SablierComptroller**" $all_md_files + fi # Update the hyperlinks to use the directory structure of the docs website # We need the capturing group to avoid replacing the "Git Source" URLs - sd "src/abstracts/\w+\.sol/([\w.]+)" $contracts'/abstracts/$1' $(find $contracts -type f -name "*.md") - sd "src/interfaces/\w+\.sol/([\w.]+)" $contracts'/interfaces/$1' $(find $contracts -type f -name "*.md") - sd "src/\w+\.sol/([\w.]+)" $contracts/'$1' $(find $contracts -type f -name "*.md") + sd "src/abstracts/\w+\.sol/([\w.]+)" $contracts'/abstracts/$1' $all_md_files + sd "src/interfaces/\w+\.sol/([\w.]+)" $contracts'/interfaces/$1' $all_md_files + sd "src/\w+\.sol/([\w.]+)" $contracts/'$1' $all_md_files } # ---------------------------------------------------------------------------- # @@ -105,14 +159,9 @@ run() { run "lockup" # Reorder the contracts in the sidebar -contract=$lockup/contract.SablierLockup.md -echo "$(echo -en '---\nsidebar_position: 1\n---\n'; cat $contract)" > $contract - -contract=$lockup/contract.SablierBatchLockup.md -echo "$(echo -en '---\nsidebar_position: 1\n---\n'; cat $contract)" > $contract - -contract=$lockup/contract.LockupNFTDescriptor.md -echo "$(echo -en '---\nsidebar_position: 3\n---\n'; cat $contract)" > $contract +set_sidebar_position $lockup/contract.SablierLockup.md 1 +set_sidebar_position $lockup/contract.SablierBatchLockup.md 1 +set_sidebar_position $lockup/contract.LockupNFTDescriptor.md 3 lint "lockup" @@ -124,17 +173,14 @@ lint "lockup" run "airdrops" # Reorder the contracts in the sidebar -contract=$airdrops/contract.SablierMerkleFactory.md -echo "$(echo -en '---\nsidebar_position: 2\n---\n'; cat $contract)" > $contract - -contract=$airdrops/contract.SablierMerkleInstant.md -echo "$(echo -en '---\nsidebar_position: 3\n---\n'; cat $contract)" > $contract - -contract=$airdrops/contract.SablierMerkleLL.md -echo "$(echo -en '---\nsidebar_position: 3\n---\n'; cat $contract)" > $contract - -contract=$airdrops/contract.SablierMerkleLT.md -echo "$(echo -en '---\nsidebar_position: 3\n---\n'; cat $contract)" > $contract +set_sidebar_position $airdrops/contract.SablierFactoryMerkleInstant.md 2 +set_sidebar_position $airdrops/contract.SablierFactoryMerkleLL.md 2 +set_sidebar_position $airdrops/contract.SablierFactoryMerkleLT.md 2 +set_sidebar_position $airdrops/contract.SablierFactoryMerkleVCA.md 2 +set_sidebar_position $airdrops/contract.SablierMerkleInstant.md 3 +set_sidebar_position $airdrops/contract.SablierMerkleLL.md 3 +set_sidebar_position $airdrops/contract.SablierMerkleLT.md 3 +set_sidebar_position $airdrops/contract.SablierMerkleVCA.md 3 lint "airdrops" @@ -146,10 +192,44 @@ lint "airdrops" run "flow" # Reorder the contracts in the sidebar -contract=$flow/contract.SablierFlow.md -echo "$(echo -en '---\nsidebar_position: 1\n---\n'; cat $contract)" > $contract - -contract=$flow/contract.FlowNFTDescriptor.md -echo "$(echo -en '---\nsidebar_position: 2\n---\n'; cat $contract)" > $contract +set_sidebar_position $flow/contract.SablierFlow.md 1 +set_sidebar_position $flow/contract.FlowNFTDescriptor.md 2 lint "flow" + +# ---------------------------------------------------------------------------- # +# EVM Utils # +# ---------------------------------------------------------------------------- # + +# Generate the raw docs with Forge for evm-utils (temporarily) +cd repos/evm-utils +rm -rf ./docs +forge doc +cd ../../ + +# Define evm-utils contracts directory (temporary) +evmutils_temp=repos/evm-utils/docs/src/src + +# Copy relevant evm-utils abstracts to each repo +# Airdrops: Adminable, Comptrollerable +cp $evmutils_temp/Adminable.sol/abstract.Adminable.md $airdrops/abstracts/ 2>/dev/null || true +cp $evmutils_temp/Comptrollerable.sol/abstract.Comptrollerable.md $airdrops/abstracts/ 2>/dev/null || true + +# Lockup: Batch, Comptrollerable, NoDelegateCall +cp $evmutils_temp/Batch.sol/abstract.Batch.md $lockup/abstracts/ 2>/dev/null || true +cp $evmutils_temp/Comptrollerable.sol/abstract.Comptrollerable.md $lockup/abstracts/ 2>/dev/null || true +cp $evmutils_temp/NoDelegateCall.sol/abstract.NoDelegateCall.md $lockup/abstracts/ 2>/dev/null || true + +# Flow: Batch, Comptrollerable, NoDelegateCall +cp $evmutils_temp/Batch.sol/abstract.Batch.md $flow/abstracts/ 2>/dev/null || true +cp $evmutils_temp/Comptrollerable.sol/abstract.Comptrollerable.md $flow/abstracts/ 2>/dev/null || true +cp $evmutils_temp/NoDelegateCall.sol/abstract.NoDelegateCall.md $flow/abstracts/ 2>/dev/null || true + +# Fix broken links in copied evm-utils abstracts (remove interface links that don't exist) +sd "\[IAdminable\]\(/src/interfaces/IAdminable\.sol/interface\.IAdminable\.md\)" "IAdminable" $airdrops/abstracts/abstract.Adminable.md +sd "\[IComptrollerable\]\(/src/interfaces/IComptrollerable\.sol/interface\.IComptrollerable\.md\)" "IComptrollerable" $airdrops/abstracts/abstract.Comptrollerable.md $lockup/abstracts/abstract.Comptrollerable.md $flow/abstracts/abstract.Comptrollerable.md +sd "\[IBatch\]\(/src/interfaces/IBatch\.sol/interface\.IBatch\.md\)" "IBatch" $lockup/abstracts/abstract.Batch.md $flow/abstracts/abstract.Batch.md +sd "\[INoDelegateCall\]\(/src/interfaces/INoDelegateCall\.sol/interface\.INoDelegateCall\.md\)" "INoDelegateCall" $lockup/abstracts/abstract.NoDelegateCall.md $flow/abstracts/abstract.NoDelegateCall.md + +# Clean up the evm-utils temp docs (we don't need to keep them) +rm -rf repos/evm-utils/docs diff --git a/docs/api/03-identifiers.mdx b/docs/api/03-identifiers.mdx index 01acccbf..92473f18 100644 --- a/docs/api/03-identifiers.mdx +++ b/docs/api/03-identifiers.mdx @@ -8,11 +8,11 @@ title: "Identifiers" ### Contracts -Onchain, each Lockup and Flow contract assigns a [`streamId`](/reference/lockup/contracts/abstracts/abstract.SablierLockupBase#nextstreamid) to each stream, which is the same as the ERC-721 [`tokenId`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721) (each stream is tokenized as an ERC-721). +Onchain, each Lockup and Flow contract assigns a [`streamId`](/reference/lockup/contracts/abstracts/abstract.SablierLockupState#nextstreamid) to each stream, which is the same as the ERC-721 [`tokenId`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721) (each stream is tokenized as an ERC-721). The `streamId`/ `tokenId` in the contract is a simple numerical value (a `uint256`). For example, number `42` is a valid `streamId`/ `tokenId`. -You will always need this value when interacting with Sablier via a JSON-RPC endpoint because it is required by every contract method associated with a stream, e.g. [`streamedAmountOf`](/reference/lockup/contracts/interfaces/interface.ISablierLockupBase#streamedamountof). +You will always need this value when interacting with Sablier via a JSON-RPC endpoint because it is required by every contract method associated with a stream, e.g. [`streamedAmountOf`](/reference/lockup/contracts/interfaces/interface.ISablierLockup#streamedamountof). ### Indexers diff --git a/docs/concepts/14-glossary.md b/docs/concepts/14-glossary.md index cb08bfde..8b7d734c 100644 --- a/docs/concepts/14-glossary.md +++ b/docs/concepts/14-glossary.md @@ -194,7 +194,7 @@ A data object that encapsulates amounts to be unlocked at the start of the strea ### Vesting Math -[A public library](/reference/lockup/contracts/libraries/library.VestingMath) used by the Lockup protocol to calculate +[A public library](/reference/lockup/contracts/libraries/library.LockupMath) used by the Lockup protocol to calculate the amount of vested tokens at any given time. ## Merkle Airdrop diff --git a/docs/concepts/lockup/04-tranches.md b/docs/concepts/lockup/04-tranches.md index 5c6b24fc..7bc482e8 100644 --- a/docs/concepts/lockup/04-tranches.md +++ b/docs/concepts/lockup/04-tranches.md @@ -33,8 +33,6 @@ Where: - The sum of all tranche amounts must equal the deposit amount. - The block gas limit enforces a limit to how many tranches there can be in a stream. - If someone creates a stream with an excessively large number of tranches, the transaction would revert as it - wouldn't fit within a block. You can fetch the limit using - [MAX_TRANCHE_COUNT](/reference/lockup/contracts/contract.SablierLockup#max_count). Alternatively, you can find the - limit for each chain [here](https://github.com/sablier-labs/lockup/blob/main/script/Base.s.sol#L90-L131). + wouldn't fit within a block. In such cases, make sure to simulate the transaction first. - The timestamps must be sorted in ascending order. It's not possible for the $(i-1)^{th}$ timestamp to be greater than $i^{th}$ timestamp (given that we're dealing with an increasing monotonic function). diff --git a/docs/guides/05-snapshot-voting.md b/docs/guides/05-snapshot-voting.md index 4673fdba..93bd3e41 100644 --- a/docs/guides/05-snapshot-voting.md +++ b/docs/guides/05-snapshot-voting.md @@ -107,8 +107,7 @@ For the best results, we recommend using the primary policies. The withdrawable amount counts tokens that have been streamed but not withdrawn yet by the recipient. This is provided using the -[`withdrawableAmountOf`](/reference/lockup/contracts/abstracts/abstract.SablierLockupBase#withdrawableamountof) contract -method. +[`withdrawableAmountOf`](/reference/lockup/contracts/contract.SablierLockup#withdrawableamountof) contract method. Voting power: realized (present). @@ -151,7 +150,7 @@ Aggregates historical amounts that have already been streamed to the recipient. included. It relies on the `streamedAmountOf` method in the -[SablierLockupBase](/reference/lockup/contracts/abstracts/abstract.SablierLockupBase#streamedamountof) contract. +[SablierLockup](/reference/lockup/contracts/contract.SablierLockup#streamedamountof) contract. :::caution Caveats diff --git a/docs/guides/lockup/examples/05-hooks.mdx b/docs/guides/lockup/examples/05-hooks.mdx index bdc3cd7f..7198e506 100644 --- a/docs/guides/lockup/examples/05-hooks.mdx +++ b/docs/guides/lockup/examples/05-hooks.mdx @@ -12,7 +12,7 @@ Lockup contract's admin. :::info -[`allowToHook`](/reference/lockup/contracts/interfaces/interface.ISablierLockupBase#allowtohook) is an irreversible +[`allowToHook`](/reference/lockup/contracts/interfaces/interface.ISablierLockup#allowtohook) is an irreversible operation, i.e., once a contract has been added to the allowlist, it can never be removed. This is to ensure stronger immutability and decentralization guarantees. Once a recipient contract is allowlisted, integrators should NOT have to trust us to keep their contract on the allowlist. diff --git a/docs/guides/lockup/examples/stream-management/02-withdraw.mdx b/docs/guides/lockup/examples/stream-management/02-withdraw.mdx index 1ca2fc6f..11c3b1cd 100644 --- a/docs/guides/lockup/examples/stream-management/02-withdraw.mdx +++ b/docs/guides/lockup/examples/stream-management/02-withdraw.mdx @@ -25,13 +25,13 @@ the withdrawal to an alternative address of their choice. There are four withdrawal functions: -1. [`withdraw`](/reference/lockup/contracts/abstracts/abstract.SablierLockupBase#withdraw): withdraws a specific amount +1. [`withdraw`](/reference/lockup/contracts/contract.SablierLockup#withdraw): withdraws a specific amount of tokens. -2. [`withdrawMax`](/reference/lockup/contracts/abstracts/abstract.SablierLockupBase#withdrawmax): withdraws the maximum +2. [`withdrawMax`](/reference/lockup/contracts/contract.SablierLockup#withdrawmax): withdraws the maximum withdrawable amount of tokens. -3. [`withdrawMaxAndTransfer`](/reference/lockup/contracts/abstracts/abstract.SablierLockupBase#withdrawmaxandtransfer): +3. [`withdrawMaxAndTransfer`](/reference/lockup/contracts/contract.SablierLockup#withdrawmaxandtransfer): withdraws the maximum withdrawable amount and transfers the NFT. -4. [`withdrawMultiple`](/reference/lockup/contracts/abstracts/abstract.SablierLockupBase#withdrawmultiple): withdraws +4. [`withdrawMultiple`](/reference/lockup/contracts/contract.SablierLockup#withdrawmultiple): withdraws specific amounts of tokens from multiple streams at once. To call any of these functions, you need to have created a stream. If you don't have one yet, go back to the @@ -44,7 +44,7 @@ assigning the `StreamManagement` contract as the recipient. Then, you can use th In this example, the withdrawal address and withdrawal amount are hard-coded for demonstration purposes. However, in a production environment, these values would likely be adjustable parameters determined by the user. Alternatively, you -can use [`withdrawableAmountOf`](/reference/lockup/contracts/abstracts/abstract.SablierLockupBase#withdrawableamountof) +can use [`withdrawableAmountOf`](/reference/lockup/contracts/contract.SablierLockup#withdrawableamountof) function to determine how much amount of tokens is available to withdraw. In addition to the `withdraw` function, there is the `withdrawMax` function, which you can use to withdraw the maximum @@ -55,7 +55,7 @@ withdrawable amount of tokens at the time of invocation: What `withdrawMax` does is call the -[`withdrawableAmountOf`](/reference/lockup/contracts/abstracts/abstract.SablierLockupBase#withdrawableamountof) function +[`withdrawableAmountOf`](/reference/lockup/contracts/contract.SablierLockup#withdrawableamountof) function and pass its value to `withdraw`. Similar to `withdrawMax`, you can use `withdrawMaxAndTransfer` to withdraw the maximum withdrawable tokens and at the diff --git a/docs/guides/lockup/examples/stream-management/03-cancel.mdx b/docs/guides/lockup/examples/stream-management/03-cancel.mdx index 1940c48e..c4225db6 100644 --- a/docs/guides/lockup/examples/stream-management/03-cancel.mdx +++ b/docs/guides/lockup/examples/stream-management/03-cancel.mdx @@ -25,8 +25,8 @@ recipient will need to withdraw it. There are two functions that can be used to cancel streams: -1. [`cancel`](/reference/lockup/contracts/abstracts/abstract.SablierLockupBase#cancel): cancels a single stream -2. [`cancelMultiple`](/reference/lockup/contracts/abstracts/abstract.SablierLockupBase#cancelmultiple): cancels multiple +1. [`cancel`](/reference/lockup/contracts/contract.SablierLockup#cancel): cancels a single stream +2. [`cancelMultiple`](/reference/lockup/contracts/contract.SablierLockup#cancelmultiple): cancels multiple streams at once To call any of these functions, you need to have created a cancelable stream. If you don't have one yet, go back to the diff --git a/docs/guides/lockup/examples/stream-management/04-renounce.mdx b/docs/guides/lockup/examples/stream-management/04-renounce.mdx index f538396b..3f71da6a 100644 --- a/docs/guides/lockup/examples/stream-management/04-renounce.mdx +++ b/docs/guides/lockup/examples/stream-management/04-renounce.mdx @@ -17,7 +17,7 @@ Renouncing a stream means that the sender of the stream will no longer be able t sender wants to give up control of the stream. To renounce a stream, you can use -[`renounce`](/reference/lockup/contracts/abstracts/abstract.SablierLockupBase#renounce). +[`renounce`](/reference/lockup/contracts/contract.SablierLockup#renounce). Before invoking this function, ensure that you have an active, cancelable stream with the sender set to the `StreamManagement` contract. Once the stream is created, you can use the `renounce` function like this: diff --git a/docs/guides/lockup/examples/stream-management/05-transfer.mdx b/docs/guides/lockup/examples/stream-management/05-transfer.mdx index 7e7107ed..dbf5fa7e 100644 --- a/docs/guides/lockup/examples/stream-management/05-transfer.mdx +++ b/docs/guides/lockup/examples/stream-management/05-transfer.mdx @@ -26,7 +26,7 @@ that the recipient of the stream has the ability to transfer the NFT to a differ streaming of tokens to that new address. To transfer ownership of a stream, it is recommended to invoke the -[`withdrawMaxAndTransfer`](/reference/lockup/contracts/abstracts/abstract.SablierLockupBase#withdrawmaxandtransfer) +[`withdrawMaxAndTransfer`](/reference/lockup/contracts/contract.SablierLockup#withdrawmaxandtransfer) function, which withdraws all the unclaimed funds to the current recipient prior to transferring ownership to the new recipient: diff --git a/docs/reference/01-overview.md b/docs/reference/01-overview.md index 86536a8a..ba800b90 100644 --- a/docs/reference/01-overview.md +++ b/docs/reference/01-overview.md @@ -28,7 +28,7 @@ Creates multiple streams in a single transaction. Library to validate input parameters across lockup streams. -> [**VestingMath Library**](./lockup/contracts/libraries/library.VestingMath) +> [**LockupMath Library**](./lockup/contracts/libraries/library.LockupMath) Library to calculate vested amount across lockup streams. @@ -52,11 +52,14 @@ The Merkle Airdrops repo is a collection of contracts to create various kinds of campaigns make use of the Lockup protocol to create what we call [Airstreams](/concepts/airdrops). This repo consists of airdrops related contracts such as MerkleFactory, MerkleInstant, MerkleLL, and MerkleLT. -### MerkleFactory +### Factories -> [**MerkleFactory Reference**](./airdrops/contracts/contract.SablierMerkleFactory) +> [**MerkleInstant Reference**](./airdrops/contracts/contract.SablierFactoryMerkleInstant) +> [**MerkleLL Reference**](./airdrops/contracts/contract.SablierFactoryMerkleLL) +> [**MerkleLT Reference**](./airdrops/contracts/contract.SablierFactoryMerkleLT) +> [**MerkleVCA Reference**](./airdrops/contracts/contract.SablierFactoryMerkleVCA) -Factory contract to deploy Merkle airdrop campaigns. +Factory contracts to deploy various Merkle campaigns. ### MerkleInstant @@ -76,6 +79,13 @@ Enables airdrops with a vesting period powered by the Lockup Linear distribution Enables airdrops with a vesting period powered by the Lockup Tranched distribution model. +### MerkleVCA + +> [**MerkleVCA Reference**](./airdrops/contracts/contract.SablierMerkleVCA) + +Enables airdrops where the claim amount increases linearly until the airdrop period ends. Claiming early results in +forgoing the remaining amount, whereas claiming after the period grants the full amount that was allocated. + ## Flow > [**Flow Source Code**](https://github.com/sablier-labs/flow/tree/release) diff --git a/docs/reference/lockup/contracts/abstracts/abstract.Adminable.md b/docs/reference/airdrops/contracts/abstracts/abstract.Adminable.md similarity index 65% rename from docs/reference/lockup/contracts/abstracts/abstract.Adminable.md rename to docs/reference/airdrops/contracts/abstracts/abstract.Adminable.md index 47c69fb5..d247879d 100644 --- a/docs/reference/lockup/contracts/abstracts/abstract.Adminable.md +++ b/docs/reference/airdrops/contracts/abstracts/abstract.Adminable.md @@ -1,10 +1,10 @@ # Adminable -[Git Source](https://github.com/sablier-labs/lockup/blob/463278dbb461b1733d6424cf0aeee3b8d6bc036a/src/abstracts/Adminable.sol) +[Git Source](https://github.com/sablier-labs/evm-utils/blob/d7d6c051a39cbacadef672e92ed9d57628c80dc4/src/Adminable.sol) -**Inherits:** [IAdminable](/docs/reference/lockup/contracts/interfaces/interface.IAdminable.md) +**Inherits:** IAdminable -See the documentation in [IAdminable](/docs/reference/lockup/contracts/interfaces/interface.IAdminable.md). +See the documentation in {IAdminable}. ## State Variables @@ -44,12 +44,12 @@ constructor(address initialAdmin); Transfers the contract admin to a new address. -Notes: +\*Notes: - Does not revert if the admin is the same. - This function can potentially leave the contract without an admin, thereby removing any functionality that is only available to the admin. Requirements: -- `msg.sender` must be the contract admin. +- `msg.sender` must be the contract admin.\* ```solidity function transferAdmin(address newAdmin) public virtual override onlyAdmin; @@ -60,3 +60,20 @@ function transferAdmin(address newAdmin) public virtual override onlyAdmin; | Name | Type | Description | | ---------- | --------- | ----------------------------- | | `newAdmin` | `address` | The address of the new admin. | + +### \_transferAdmin + +_An internal function to transfer the admin._ + +```solidity +function _transferAdmin(address oldAdmin, address newAdmin) internal; +``` + +### \_onlyAdmin + +_A private function is used instead of inlining this logic in a modifier because Solidity copies modifiers into every +function that uses them._ + +```solidity +function _onlyAdmin() private view; +``` diff --git a/docs/reference/airdrops/contracts/abstracts/abstract.Comptrollerable.md b/docs/reference/airdrops/contracts/abstracts/abstract.Comptrollerable.md new file mode 100644 index 00000000..6335e17b --- /dev/null +++ b/docs/reference/airdrops/contracts/abstracts/abstract.Comptrollerable.md @@ -0,0 +1,95 @@ +# Comptrollerable + +[Git Source](https://github.com/sablier-labs/evm-utils/blob/d7d6c051a39cbacadef672e92ed9d57628c80dc4/src/Comptrollerable.sol) + +**Inherits:** IComptrollerable + +See the documentation in {IComptrollerable}. + +## State Variables + +### comptroller + +Retrieves the address of the comptroller contract. + +```solidity +ISablierComptroller public override comptroller; +``` + +## Functions + +### onlyComptroller + +Reverts if called by any account other than the comptroller. + +```solidity +modifier onlyComptroller(); +``` + +### constructor + +```solidity +constructor(address initialComptroller); +``` + +**Parameters** + +| Name | Type | Description | +| -------------------- | --------- | ------------------------------------------------ | +| `initialComptroller` | `address` | The address of the initial comptroller contract. | + +### setComptroller + +Sets the comptroller to a new address. + +\*Emits a {SetComptroller} event. Requirements: + +- `msg.sender` must be the current comptroller. +- The new comptroller must return `true` from {supportsInterface} with the comptroller's minimal interface ID which is + defined as the XOR of the following function selectors: + +1. {calculateMinFeeWeiFor} +2. {convertUSDFeeToWei} +3. {execute} +4. {getMinFeeUSDFor}\* + +```solidity +function setComptroller(ISablierComptroller newComptroller) external override onlyComptroller; +``` + +**Parameters** + +| Name | Type | Description | +| ---------------- | --------------------- | -------------------------------------------- | +| `newComptroller` | `ISablierComptroller` | The address of the new comptroller contract. | + +### transferFeesToComptroller + +Transfers the fees to the comptroller contract. + +_Emits a {TransferFeesToComptroller} event._ + +```solidity +function transferFeesToComptroller() external override; +``` + +### \_checkComptroller + +_See the documentation for the user-facing functions that call this private function._ + +```solidity +function _checkComptroller() private view; +``` + +### \_setComptroller + +_See the documentation for the user-facing functions that call this private function._ + +```solidity +function _setComptroller( + ISablierComptroller previousComptroller, + ISablierComptroller newComptroller, + bytes4 minimalInterfaceId +) + private; +``` diff --git a/docs/reference/airdrops/contracts/abstracts/abstract.SablierFactoryMerkleBase.md b/docs/reference/airdrops/contracts/abstracts/abstract.SablierFactoryMerkleBase.md new file mode 100644 index 00000000..38fac833 --- /dev/null +++ b/docs/reference/airdrops/contracts/abstracts/abstract.SablierFactoryMerkleBase.md @@ -0,0 +1,69 @@ +# SablierFactoryMerkleBase + +[Git Source](https://github.com/sablier-labs/airdrops/blob/077c6b9766ef7693ba9e82a9e001dc0097709c01/src/abstracts/SablierFactoryMerkleBase.sol) + +**Inherits:** [Comptrollerable](/docs/reference/airdrops/contracts/abstracts/abstract.Comptrollerable.md), +[ISablierFactoryMerkleBase](/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleBase.md) + +See the documentation in +[ISablierFactoryMerkleBase](/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleBase.md). + +## State Variables + +### nativeToken + +Retrieves the address of the ERC-20 interface of the native token, if it exists. + +_The native tokens on some chains have a dual interface as ERC-20. For example, on Polygon the $POL token is the native +token and has an ERC-20 version at 0x0000000000000000000000000000000000001010. This means that `address(this).balance` +returns the same value as `balanceOf(address(this))`. To avoid any unintended behavior, these tokens cannot be used in +Sablier. As an alternative, users can use the Wrapped version of the token, i.e. WMATIC, which is a standard ERC-20 +token._ + +```solidity +address public override nativeToken; +``` + +## Functions + +### constructor + +```solidity +constructor(address initialComptroller) [Comptrollerable](/docs/reference/airdrops/contracts/abstracts/abstract.Comptrollerable.md)(initialComptroller); +``` + +**Parameters** + +| Name | Type | Description | +| -------------------- | --------- | ------------------------------------------------ | +| `initialComptroller` | `address` | The address of the initial comptroller contract. | + +### setNativeToken + +Sets the native token address. Once set, it cannot be changed. + +\*For more information, see the documentation for {nativeToken}. Emits a {SetNativeToken} event. Requirements: + +- `msg.sender` must be the comptroller. +- `newNativeToken` must not be zero address. +- The native token must not be already set.\* + +```solidity +function setNativeToken(address newNativeToken) external override onlyComptroller; +``` + +**Parameters** + +| Name | Type | Description | +| ---------------- | --------- | -------------------------------- | +| `newNativeToken` | `address` | The address of the native token. | + +### \_forbidNativeToken + +Checks that the provided token is not the native token. + +_Reverts if the provided token is the native token._ + +```solidity +function _forbidNativeToken(address token) internal view; +``` diff --git a/docs/reference/airdrops/contracts/abstracts/abstract.SablierMerkleBase.md b/docs/reference/airdrops/contracts/abstracts/abstract.SablierMerkleBase.md index dfbc769d..c54313e3 100644 --- a/docs/reference/airdrops/contracts/abstracts/abstract.SablierMerkleBase.md +++ b/docs/reference/airdrops/contracts/abstracts/abstract.SablierMerkleBase.md @@ -1,66 +1,79 @@ # SablierMerkleBase -[Git Source](https://github.com/sablier-labs/airdrops/blob/f9a358c0a5bccfec77601d4490ef9117e0488068/src/abstracts/SablierMerkleBase.sol) +[Git Source](https://github.com/sablier-labs/airdrops/blob/077c6b9766ef7693ba9e82a9e001dc0097709c01/src/abstracts/SablierMerkleBase.sol) **Inherits:** [ISablierMerkleBase](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleBase.md), -Adminable +[Adminable](/docs/reference/airdrops/contracts/abstracts/abstract.Adminable.md) See the documentation in [ISablierMerkleBase](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleBase.md). ## State Variables -### CAMPAIGN_NAME +### \_CACHED_CHAIN_ID -_The name of the campaign stored as bytes32._ +_Cache the chain ID in order to invalidate the cached domain separator if the chain ID changes in case of a chain +split._ ```solidity -bytes32 internal immutable CAMPAIGN_NAME; +uint256 private immutable _CACHED_CHAIN_ID; ``` -### EXPIRATION +### \_CACHED_DOMAIN_SEPARATOR -The cut-off point for the campaign, as a Unix timestamp. A value of zero means there is no expiration. +_The domain separator, as required by EIP-712 and EIP-1271, used for signing claim to prevent replay attacks across +different campaigns._ + +```solidity +bytes32 private immutable _CACHED_DOMAIN_SEPARATOR; +``` + +### CAMPAIGN_START_TIME + +The timestamp at which campaign starts and claim begins. _This is an immutable state variable._ ```solidity -uint40 public immutable override EXPIRATION; +uint40 public immutable override CAMPAIGN_START_TIME; ``` -### FACTORY +### COMPTROLLER -Retrieves the address of the factory contract. +Retrieves the address of the comptroller contract. ```solidity -address public immutable override FACTORY; +address public immutable override COMPTROLLER; ``` -### FEE +### EXPIRATION + +The cut-off point for the campaign, as a Unix timestamp. A value of zero means there is no expiration. -Retrieves the minimum fee required to claim the airdrop, which is paid in the native token of the chain, e.g. ETH for -Ethereum Mainnet. +_This is an immutable state variable._ ```solidity -uint256 public immutable override FEE; +uint40 public immutable override EXPIRATION; ``` -### MERKLE_ROOT +### IS_SABLIER_MERKLE -The root of the Merkle tree used to validate the proofs of inclusion. +Returns `true` indicating that this campaign contract is deployed using the Sablier Factory. -_This is an immutable state variable._ +_This is a constant state variable._ ```solidity -bytes32 public immutable override MERKLE_ROOT; +bool public constant override IS_SABLIER_MERKLE = true; ``` -### SHAPE +### MERKLE_ROOT -_The shape of Lockup stream stored as bytes32._ +The root of the Merkle tree used to validate the proofs of inclusion. + +_This is an immutable state variable._ ```solidity -bytes32 internal immutable SHAPE; +bytes32 public immutable override MERKLE_ROOT; ``` ### TOKEN @@ -73,14 +86,42 @@ _This is an immutable state variable._ IERC20 public immutable override TOKEN; ``` +### campaignName + +Retrieves the name of the campaign. + +```solidity +string public override campaignName; +``` + +### firstClaimTime + +Retrieves the timestamp when the first claim is made, and zero if no claim was made yet. + +```solidity +uint40 public override firstClaimTime; +``` + ### ipfsCID The content identifier for indexing the campaign on IPFS. +_An empty value may break certain UI features that depend upon the IPFS CID._ + ```solidity string public override ipfsCID; ``` +### minFeeUSD + +Retrieves the min USD fee required to claim the airdrop, denominated in 8 decimals. + +_The denomination is based on Chainlink's 8-decimal format for USD prices, where 1e8 is $1._ + +```solidity +uint256 public override minFeeUSD; +``` + ### \_claimedBitMap _Packed booleans that record the history of claims._ @@ -89,38 +130,50 @@ _Packed booleans that record the history of claims._ BitMaps.BitMap internal _claimedBitMap; ``` -### \_firstClaimTime +## Functions + +### notZeroAddress -_The timestamp when the first claim is made._ +_Modifier to check that `to` is not zero address._ ```solidity -uint40 internal _firstClaimTime; +modifier notZeroAddress(address to); ``` -## Functions - ### constructor Constructs the contract by initializing the immutable state variables. ```solidity -constructor(MerkleBase.ConstructorParams memory params, address campaignCreator) Adminable(params.initialAdmin); +constructor( + address campaignCreator, + string memory campaignName_, + uint40 campaignStartTime, + address comptroller, + uint40 expiration, + address initialAdmin, + string memory ipfsCID_, + bytes32 merkleRoot, + IERC20 token +) + [Adminable](/docs/reference/airdrops/contracts/abstracts/abstract.Adminable.md)(initialAdmin); ``` -### campaignName +### calculateMinFeeWei -Retrieves the name of the campaign. +Calculates the minimum fee in wei required to claim the airdrop. ```solidity -function campaignName() external view override returns (string memory); +function calculateMinFeeWei() external view override returns (uint256); ``` -### getFirstClaimTime +### domainSeparator -Returns the timestamp when the first claim is made. +The domain separator, as required by EIP-712 and EIP-1271, used for signing claim to prevent replay attacks across +different campaigns. ```solidity -function getFirstClaimTime() external view override returns (uint40); +function domainSeparator() external view override returns (bytes32); ``` ### hasClaimed @@ -147,56 +200,15 @@ Returns a flag indicating whether the campaign has expired. function hasExpired() public view override returns (bool); ``` -### shape - -Retrieves the shape of the lockup stream that the campaign produces upon claiming. - -```solidity -function shape() external view override returns (string memory); -``` - -### claim - -Makes the claim. - -Depending on the Merkle campaign, it either transfers tokens to the recipient or creates a Lockup stream with an NFT -minted to the recipient. Requirements: - -- The campaign must not have expired. -- The stream must not have been claimed already. -- The Merkle proof must be valid. -- The `msg.value` must not be less than `FEE`. - -```solidity -function claim( - uint256 index, - address recipient, - uint128 amount, - bytes32[] calldata merkleProof -) - external - payable - override; -``` - -**Parameters** - -| Name | Type | Description | -| ------------- | ----------- | --------------------------------------------------------------- | -| `index` | `uint256` | The index of the recipient in the Merkle tree. | -| `recipient` | `address` | The address of the airdrop recipient. | -| `amount` | `uint128` | The amount of ERC-20 tokens to be transferred to the recipient. | -| `merkleProof` | `bytes32[]` | The proof of inclusion in the Merkle tree. | - ### clawback -Claws back the unclaimed tokens from the campaign. +Claws back the unclaimed tokens. -Emits a {Clawback} event. Requirements: +\*Emits a {Clawback} event. Requirements: - `msg.sender` must be the admin. - No claim must be made, OR The current timestamp must not exceed 7 days after the first claim, OR The campaign must be - expired. + expired.\* ```solidity function clawback(address to, uint128 amount) external override onlyAdmin; @@ -209,27 +221,49 @@ function clawback(address to, uint128 amount) external override onlyAdmin; | `to` | `address` | The address to receive the tokens. | | `amount` | `uint128` | The amount of tokens to claw back. | -### collectFees +### lowerMinFeeUSD -Collects the accrued fees by transferring them to `FACTORY` admin. Requirements: +Lowers the min USD fee. -- `msg.sender` must be the `FACTORY` contract. +\*Emits a {LowerMinFeeUSD} event. Requirements: + +- `msg.sender` must be the comptroller. +- The new fee must be less than the current {minFeeUSD}.\* ```solidity -function collectFees(address factoryAdmin) external override returns (uint256 feeAmount); +function lowerMinFeeUSD(uint256 newMinFeeUSD) external override; ``` **Parameters** -| Name | Type | Description | -| -------------- | --------- | ----------------------------------- | -| `factoryAdmin` | `address` | The address of the `FACTORY` admin. | +| Name | Type | Description | +| -------------- | --------- | ------------------------------------------------------ | +| `newMinFeeUSD` | `uint256` | The new min USD fee to set, denominated in 8 decimals. | + +### \_checkSignature -**Returns** +_Verifies the signature against the provided parameters. It supports both EIP-712 and EIP-1271 signatures._ -| Name | Type | Description | -| ----------- | --------- | ---------------------------------------------------------- | -| `feeAmount` | `uint256` | The amount of native tokens (e.g., ETH) collected as fees. | +```solidity +function _checkSignature( + uint256 index, + address recipient, + address to, + uint128 amount, + uint40 validFrom, + bytes calldata signature +) + internal + view; +``` + +### \_domainSeparator + +_Returns the domain separator for the current chain._ + +```solidity +function _domainSeparator() private view returns (bytes32); +``` ### \_hasGracePeriodPassed @@ -238,13 +272,21 @@ Returns a flag indicating whether the grace period has passed. _The grace period is 7 days after the first claim._ ```solidity -function _hasGracePeriodPassed() internal view returns (bool); +function _hasGracePeriodPassed() private view returns (bool); +``` + +### \_revertIfToZeroAddress + +_This function checks if `to` is zero address._ + +```solidity +function _revertIfToZeroAddress(address to) private pure; ``` -### \_claim +### \_preProcessClaim -_This function is implemented by child contracts, so the logic varies depending on the model._ +_See the documentation for the user-facing functions that call this internal function._ ```solidity -function _claim(uint256 index, address recipient, uint128 amount) internal virtual; +function _preProcessClaim(uint256 index, address recipient, uint128 amount, bytes32[] calldata merkleProof) internal; ``` diff --git a/docs/reference/airdrops/contracts/abstracts/abstract.SablierMerkleLockup.md b/docs/reference/airdrops/contracts/abstracts/abstract.SablierMerkleLockup.md new file mode 100644 index 00000000..ce96b9aa --- /dev/null +++ b/docs/reference/airdrops/contracts/abstracts/abstract.SablierMerkleLockup.md @@ -0,0 +1,99 @@ +# SablierMerkleLockup + +[Git Source](https://github.com/sablier-labs/airdrops/blob/077c6b9766ef7693ba9e82a9e001dc0097709c01/src/abstracts/SablierMerkleLockup.sol) + +**Inherits:** [ISablierMerkleLockup](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleLockup.md), +[SablierMerkleBase](/docs/reference/airdrops/contracts/abstracts/abstract.SablierMerkleBase.md) + +See the documentation in +[ISablierMerkleLockup](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleLockup.md). + +## State Variables + +### SABLIER_LOCKUP + +The address of the [SablierLockup](/reference/lockup/contracts/contract.SablierLockup.md) contract. + +```solidity +ISablierLockup public immutable override SABLIER_LOCKUP; +``` + +### STREAM_CANCELABLE + +A flag indicating whether the streams can be canceled. + +_This is an immutable state variable._ + +```solidity +bool public immutable override STREAM_CANCELABLE; +``` + +### STREAM_TRANSFERABLE + +A flag indicating whether the stream NFTs are transferable. + +_This is an immutable state variable._ + +```solidity +bool public immutable override STREAM_TRANSFERABLE; +``` + +### streamShape + +Retrieves the shape of the Lockup stream created upon claiming. + +```solidity +string public override streamShape; +``` + +### \_claimedStreams + +_A mapping between recipient addresses and Lockup streams created through the claim function._ + +```solidity +mapping(address recipient => uint256[] streamIds) internal _claimedStreams; +``` + +## Functions + +### constructor + +_Constructs the contract by initializing the immutable state vars, and max approving the Lockup contract._ + +```solidity +constructor( + address campaignCreator, + string memory campaignName, + uint40 campaignStartTime, + bool cancelable, + address comptroller, + ISablierLockup sablierLockup, + uint40 expiration, + address initialAdmin, + string memory ipfsCID, + bytes32 merkleRoot, + string memory shape_, + IERC20 token, + bool transferable +) + SablierMerkleBase( + campaignCreator, + campaignName, + campaignStartTime, + comptroller, + expiration, + initialAdmin, + ipfsCID, + merkleRoot, + token + ); +``` + +### claimedStreams + +Retrieves the stream IDs associated with the airdrops claimed by the provided recipient. In practice, most campaigns +will only have one stream per recipient. + +```solidity +function claimedStreams(address recipient) external view override returns (uint256[] memory); +``` diff --git a/docs/reference/airdrops/contracts/contract.SablierFactoryMerkleInstant.md b/docs/reference/airdrops/contracts/contract.SablierFactoryMerkleInstant.md new file mode 100644 index 00000000..cad094ca --- /dev/null +++ b/docs/reference/airdrops/contracts/contract.SablierFactoryMerkleInstant.md @@ -0,0 +1,82 @@ +--- +sidebar_position: 2 +--- + +# SablierFactoryMerkleInstant + +[Git Source](https://github.com/sablier-labs/airdrops/blob/077c6b9766ef7693ba9e82a9e001dc0097709c01/src/SablierFactoryMerkleInstant.sol) + +**Inherits:** +[ISablierFactoryMerkleInstant](/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleInstant.md), +[SablierFactoryMerkleBase](/docs/reference/airdrops/contracts/abstracts/abstract.SablierFactoryMerkleBase.md) + +See the documentation in +[ISablierFactoryMerkleInstant](/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleInstant.md). + +## Functions + +### constructor + +```solidity +constructor(address initialComptroller) SablierFactoryMerkleBase(initialComptroller); +``` + +**Parameters** + +| Name | Type | Description | +| -------------------- | --------- | ------------------------------------------------ | +| `initialComptroller` | `address` | The address of the initial comptroller contract. | + +### computeMerkleInstant + +Computes the deterministic address where +[SablierMerkleInstant](/docs/reference/airdrops/contracts/contract.SablierMerkleInstant.md) campaign will be deployed. + +_Reverts if the requirements from {createMerkleInstant} are not met._ + +```solidity +function computeMerkleInstant( + address campaignCreator, + MerkleInstant.ConstructorParams calldata params +) + external + view + override + returns (address merkleInstant); +``` + +### createMerkleInstant + +Creates a new MerkleInstant campaign for instant distribution of tokens. + +\*Emits a {CreateMerkleInstant} event. Notes: + +- The contract is created with CREATE2. +- The campaign's fee will be set to the min USD fee unless a custom fee is set for `msg.sender`. +- A value of zero for `params.expiration` means the campaign does not expire. Requirements: +- `params.token` must not be the forbidden native token.\* + +```solidity +function createMerkleInstant( + MerkleInstant.ConstructorParams calldata params, + uint256 aggregateAmount, + uint256 recipientCount +) + external + override + returns (ISablierMerkleInstant merkleInstant); +``` + +**Parameters** + +| Name | Type | Description | +| ----------------- | --------------------------------- | ------------------------------------------------------------------------------- | +| `params` | `MerkleInstant.ConstructorParams` | Struct encapsulating the input parameters, which are documented in {DataTypes}. | +| `aggregateAmount` | `uint256` | The total amount of ERC-20 tokens to be distributed to all recipients. | +| `recipientCount` | `uint256` | The total number of recipient addresses eligible for the airdrop. | + +**Returns** + +| Name | Type | Description | +| --------------- | ----------------------- | -------------------------------------------------------- | +| `merkleInstant` | `ISablierMerkleInstant` | The address of the newly created MerkleInstant contract. | diff --git a/docs/reference/airdrops/contracts/contract.SablierFactoryMerkleLL.md b/docs/reference/airdrops/contracts/contract.SablierFactoryMerkleLL.md new file mode 100644 index 00000000..7f7fe727 --- /dev/null +++ b/docs/reference/airdrops/contracts/contract.SablierFactoryMerkleLL.md @@ -0,0 +1,82 @@ +--- +sidebar_position: 2 +--- + +# SablierFactoryMerkleLL + +[Git Source](https://github.com/sablier-labs/airdrops/blob/077c6b9766ef7693ba9e82a9e001dc0097709c01/src/SablierFactoryMerkleLL.sol) + +**Inherits:** +[ISablierFactoryMerkleLL](/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleLL.md), +[SablierFactoryMerkleBase](/docs/reference/airdrops/contracts/abstracts/abstract.SablierFactoryMerkleBase.md) + +See the documentation in +[ISablierFactoryMerkleLL](/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleLL.md). + +## Functions + +### constructor + +```solidity +constructor(address initialComptroller) SablierFactoryMerkleBase(initialComptroller); +``` + +**Parameters** + +| Name | Type | Description | +| -------------------- | --------- | ------------------------------------------------ | +| `initialComptroller` | `address` | The address of the initial comptroller contract. | + +### computeMerkleLL + +Computes the deterministic address where +[SablierMerkleLL](/docs/reference/airdrops/contracts/contract.SablierMerkleLL.md) campaign will be deployed. + +_Reverts if the requirements from {createMerkleLL} are not met._ + +```solidity +function computeMerkleLL( + address campaignCreator, + MerkleLL.ConstructorParams calldata params +) + external + view + override + returns (address merkleLL); +``` + +### createMerkleLL + +Creates a new Merkle Lockup campaign with a Lockup Linear distribution. + +\*Emits a {CreateMerkleLL} event. Notes: + +- The contract is created with CREATE2. +- The campaign's fee will be set to the min USD fee unless a custom fee is set for `msg.sender`. +- A value of zero for `params.expiration` means the campaign does not expire. Requirements: +- `params.token` must not be the forbidden native token.\* + +```solidity +function createMerkleLL( + MerkleLL.ConstructorParams calldata params, + uint256 aggregateAmount, + uint256 recipientCount +) + external + override + returns (ISablierMerkleLL merkleLL); +``` + +**Parameters** + +| Name | Type | Description | +| ----------------- | ---------------------------- | ------------------------------------------------------------------------------- | +| `params` | `MerkleLL.ConstructorParams` | Struct encapsulating the input parameters, which are documented in {DataTypes}. | +| `aggregateAmount` | `uint256` | The total amount of ERC-20 tokens to be distributed to all recipients. | +| `recipientCount` | `uint256` | The total number of recipient addresses eligible for the airdrop. | + +**Returns** + +| Name | Type | Description | +| ---------- | ------------------ | -------------------------------------------------------- | +| `merkleLL` | `ISablierMerkleLL` | The address of the newly created Merkle Lockup contract. | diff --git a/docs/reference/airdrops/contracts/contract.SablierFactoryMerkleLT.md b/docs/reference/airdrops/contracts/contract.SablierFactoryMerkleLT.md new file mode 100644 index 00000000..04e17731 --- /dev/null +++ b/docs/reference/airdrops/contracts/contract.SablierFactoryMerkleLT.md @@ -0,0 +1,128 @@ +--- +sidebar_position: 2 +--- + +# SablierFactoryMerkleLT + +[Git Source](https://github.com/sablier-labs/airdrops/blob/077c6b9766ef7693ba9e82a9e001dc0097709c01/src/SablierFactoryMerkleLT.sol) + +**Inherits:** +[ISablierFactoryMerkleLT](/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleLT.md), +[SablierFactoryMerkleBase](/docs/reference/airdrops/contracts/abstracts/abstract.SablierFactoryMerkleBase.md) + +See the documentation in +[ISablierFactoryMerkleLT](/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleLT.md). + +## Functions + +### constructor + +```solidity +constructor(address initialComptroller) SablierFactoryMerkleBase(initialComptroller); +``` + +**Parameters** + +| Name | Type | Description | +| -------------------- | --------- | ------------------------------------------------ | +| `initialComptroller` | `address` | The address of the initial comptroller contract. | + +### computeMerkleLT + +Computes the deterministic address where +[SablierMerkleLT](/docs/reference/airdrops/contracts/contract.SablierMerkleLT.md) campaign will be deployed. + +_Reverts if the requirements from {createMerkleLT} are not met._ + +```solidity +function computeMerkleLT( + address campaignCreator, + MerkleLT.ConstructorParams calldata params +) + external + view + override + returns (address merkleLT); +``` + +### isPercentagesSum100 + +Verifies if the sum of percentages in `tranches` equals 100%, i.e., 1e18. + +_This is a helper function for the frontend. It is not used anywhere in the contracts._ + +```solidity +function isPercentagesSum100(MerkleLT.TrancheWithPercentage[] calldata tranches) + external + pure + override + returns (bool result); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | ---------------------------------- | ------------------------------------------------------ | +| `tranches` | `MerkleLT.TrancheWithPercentage[]` | The tranches with their respective unlock percentages. | + +**Returns** + +| Name | Type | Description | +| -------- | ------ | ------------------------------------------------------------ | +| `result` | `bool` | True if the sum of percentages equals 100%, otherwise false. | + +### createMerkleLT + +Creates a new Merkle Lockup campaign with a Lockup Tranched distribution. + +\*Emits a {CreateMerkleLT} event. Notes: + +- The contract is created with CREATE2. +- The campaign's fee will be set to the min USD fee unless a custom fee is set for `msg.sender`. +- A value of zero for `params.expiration` means the campaign does not expire. Requirements: +- `params.token` must not be the forbidden native token. +- The sum of percentages of the tranches must equal 100%.\* + +```solidity +function createMerkleLT( + MerkleLT.ConstructorParams calldata params, + uint256 aggregateAmount, + uint256 recipientCount +) + external + override + returns (ISablierMerkleLT merkleLT); +``` + +**Parameters** + +| Name | Type | Description | +| ----------------- | ---------------------------- | ------------------------------------------------------------------------------- | +| `params` | `MerkleLT.ConstructorParams` | Struct encapsulating the input parameters, which are documented in {DataTypes}. | +| `aggregateAmount` | `uint256` | The total amount of ERC-20 tokens to be distributed to all recipients. | +| `recipientCount` | `uint256` | The total number of recipient addresses eligible for the airdrop. | + +**Returns** + +| Name | Type | Description | +| ---------- | ------------------ | -------------------------------------------------------- | +| `merkleLT` | `ISablierMerkleLT` | The address of the newly created Merkle Lockup contract. | + +### \_calculateTrancheTotals + +_Calculate the total duration and total percentage of the tranches._ + +```solidity +function _calculateTrancheTotals(MerkleLT.TrancheWithPercentage[] memory tranches) + private + pure + returns (uint256 totalDuration, uint64 totalPercentage); +``` + +### \_checkDeploymentParams + +_Validate the token and the total percentage._ + +```solidity +function _checkDeploymentParams(address token, uint64 totalPercentage) private view; +``` diff --git a/docs/reference/airdrops/contracts/contract.SablierFactoryMerkleVCA.md b/docs/reference/airdrops/contracts/contract.SablierFactoryMerkleVCA.md new file mode 100644 index 00000000..c4c1db95 --- /dev/null +++ b/docs/reference/airdrops/contracts/contract.SablierFactoryMerkleVCA.md @@ -0,0 +1,103 @@ +--- +sidebar_position: 2 +--- + +# SablierFactoryMerkleVCA + +[Git Source](https://github.com/sablier-labs/airdrops/blob/077c6b9766ef7693ba9e82a9e001dc0097709c01/src/SablierFactoryMerkleVCA.sol) + +**Inherits:** +[ISablierFactoryMerkleVCA](/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleVCA.md), +[SablierFactoryMerkleBase](/docs/reference/airdrops/contracts/abstracts/abstract.SablierFactoryMerkleBase.md) + +See the documentation in +[ISablierFactoryMerkleVCA](/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleVCA.md). + +## Functions + +### constructor + +```solidity +constructor(address initialComptroller) SablierFactoryMerkleBase(initialComptroller); +``` + +**Parameters** + +| Name | Type | Description | +| -------------------- | --------- | ------------------------------------------------ | +| `initialComptroller` | `address` | The address of the initial comptroller contract. | + +### computeMerkleVCA + +Computes the deterministic address where +[SablierMerkleVCA](/docs/reference/airdrops/contracts/contract.SablierMerkleVCA.md) campaign will be deployed. + +_Reverts if the requirements from {createMerkleVCA} are not met._ + +```solidity +function computeMerkleVCA( + address campaignCreator, + MerkleVCA.ConstructorParams calldata params +) + external + view + override + returns (address merkleVCA); +``` + +### createMerkleVCA + +Creates a new MerkleVCA campaign for variable distribution of tokens. + +\*Emits a {CreateMerkleVCA} event. Notes: + +- The contract is created with CREATE2. +- The campaign's fee will be set to the min USD fee unless a custom fee is set for `msg.sender`. +- Users interested into funding the campaign before its deployment must meet the below requirements, otherwise the + campaign deployment will revert. Requirements: +- `params.token` must not be the forbidden native token. +- `params.expiration` must be greater than 0. +- `params.expiration` must be at least 1 week beyond the end time to ensure loyal recipients have enough time to claim. +- `params.vestingEndTime` must be greater than `params.vestingStartTime`. +- Both `params.vestingStartTime` and `params.vestingEndTime` must be greater than 0. +- `params.unlockPercentage` must not be greater than 1e18, equivalent to 100%.\* + +```solidity +function createMerkleVCA( + MerkleVCA.ConstructorParams calldata params, + uint256 aggregateAmount, + uint256 recipientCount +) + external + returns (ISablierMerkleVCA merkleVCA); +``` + +**Parameters** + +| Name | Type | Description | +| ----------------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `params` | `MerkleVCA.ConstructorParams` | Struct encapsulating the [SablierMerkleVCA](/docs/reference/airdrops/contracts/contract.SablierMerkleVCA.md) parameters, which are documented in {DataTypes}. | +| `aggregateAmount` | `uint256` | The total amount of ERC-20 tokens to be distributed to all recipients. | +| `recipientCount` | `uint256` | The total number of recipient addresses eligible for the airdrop. | + +**Returns** + +| Name | Type | Description | +| ----------- | ------------------- | ---------------------------------------------------- | +| `merkleVCA` | `ISablierMerkleVCA` | The address of the newly created MerkleVCA campaign. | + +### \_checkDeploymentParams + +_Validate the deployment parameters._ + +```solidity +function _checkDeploymentParams( + address token, + uint40 vestingStartTime, + uint40 vestingEndTime, + uint40 expiration, + UD60x18 unlockPercentage +) + private + view; +``` diff --git a/docs/reference/airdrops/contracts/contract.SablierMerkleFactory.md b/docs/reference/airdrops/contracts/contract.SablierMerkleFactory.md deleted file mode 100644 index 77708a8e..00000000 --- a/docs/reference/airdrops/contracts/contract.SablierMerkleFactory.md +++ /dev/null @@ -1,329 +0,0 @@ ---- -sidebar_position: 2 ---- - -# SablierMerkleFactory - -[Git Source](https://github.com/sablier-labs/airdrops/blob/f9a358c0a5bccfec77601d4490ef9117e0488068/src/SablierMerkleFactory.sol) - -**Inherits:** [ISablierMerkleFactory](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleFactory.md), -Adminable - -See the documentation in -[ISablierMerkleFactory](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleFactory.md). - -## State Variables - -### defaultFee - -Retrieves the default fee charged for claiming an airdrop. - -_The fee is denominated in the native token of the chain, e.g., ETH for Ethereum Mainnet._ - -```solidity -uint256 public override defaultFee; -``` - -### \_customFees - -_A mapping of custom fees mapped by campaign creator addresses._ - -```solidity -mapping(address campaignCreator => MerkleFactory.CustomFee customFee) private _customFees; -``` - -## Functions - -### constructor - -```solidity -constructor(address initialAdmin) Adminable(initialAdmin); -``` - -**Parameters** - -| Name | Type | Description | -| -------------- | --------- | ------------------------------------------ | -| `initialAdmin` | `address` | The address of the initial contract admin. | - -### getCustomFee - -Retrieves the custom fee struct for the provided campaign creator. - -_The fee is denominated in the native token of the chain, e.g., ETH for Ethereum Mainnet._ - -```solidity -function getCustomFee(address campaignCreator) external view override returns (MerkleFactory.CustomFee memory); -``` - -**Parameters** - -| Name | Type | Description | -| ----------------- | --------- | ------------------------------------ | -| `campaignCreator` | `address` | The address of the campaign creator. | - -### getFee - -Retrieves the fee for the provided campaign creator, using the default fee if no custom fee is set. - -_The fee is denominated in the native token of the chain, e.g., ETH for Ethereum Mainnet._ - -```solidity -function getFee(address campaignCreator) external view returns (uint256); -``` - -**Parameters** - -| Name | Type | Description | -| ----------------- | --------- | ------------------------------------ | -| `campaignCreator` | `address` | The address of the campaign creator. | - -### isPercentagesSum100 - -Verifies if the sum of percentages in `tranches` equals 100%, i.e., 1e18. - -_This is a helper function for the frontend. It is not used anywhere in the contracts._ - -```solidity -function isPercentagesSum100(MerkleLT.TrancheWithPercentage[] calldata tranches) - external - pure - override - returns (bool result); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | ---------------------------------- | ------------------------------------------------------ | -| `tranches` | `MerkleLT.TrancheWithPercentage[]` | The tranches with their respective unlock percentages. | - -**Returns** - -| Name | Type | Description | -| -------- | ------ | ------------------------------------------------------------ | -| `result` | `bool` | True if the sum of percentages equals 100%, otherwise false. | - -### collectFees - -Collects the fees accrued in the `merkleBase` contract, and transfers them to the factory admin. - -Emits a {CollectFees} event. Notes: - -- If the admin is a contract, it must be able to receive native token payments, e.g., ETH for Ethereum Mainnet. - -```solidity -function collectFees(ISablierMerkleBase merkleBase) external override; -``` - -**Parameters** - -| Name | Type | Description | -| ------------ | -------------------- | --------------------------------------------------------------------- | -| `merkleBase` | `ISablierMerkleBase` | The address of the Merkle contract where the fees are collected from. | - -### createMerkleInstant - -Creates a new MerkleInstant campaign for instant distribution of tokens. - -Emits a {CreateMerkleInstant} event. Notes: - -- The MerkleInstant contract is created with CREATE2. -- The immutable fee will be set to the default value unless a custom fee is set. - -```solidity -function createMerkleInstant( - MerkleBase.ConstructorParams memory baseParams, - uint256 aggregateAmount, - uint256 recipientCount -) - external - override - returns (ISablierMerkleInstant merkleInstant); -``` - -**Parameters** - -| Name | Type | Description | -| ----------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `baseParams` | `MerkleBase.ConstructorParams` | Struct encapsulating the [SablierMerkleBase](docs/reference/airdrops/contracts/abstracts/abstract.SablierMerkleBase.md) parameters, which are documented in {DataTypes}. | -| `aggregateAmount` | `uint256` | The total amount of ERC-20 tokens to be distributed to all recipients. | -| `recipientCount` | `uint256` | The total number of recipients who are eligible to claim. | - -**Returns** - -| Name | Type | Description | -| --------------- | ----------------------- | -------------------------------------------------------- | -| `merkleInstant` | `ISablierMerkleInstant` | The address of the newly created MerkleInstant contract. | - -### createMerkleLL - -Creates a new Merkle Lockup campaign with a Lockup Linear distribution. - -Emits a {CreateMerkleLL} event. Notes: - -- The MerkleLL contract is created with CREATE2. -- The immutable fee will be set to the default value unless a custom fee is set. - -```solidity -function createMerkleLL( - MerkleBase.ConstructorParams memory baseParams, - ISablierLockup lockup, - bool cancelable, - bool transferable, - MerkleLL.Schedule memory schedule, - uint256 aggregateAmount, - uint256 recipientCount -) - external - override - returns (ISablierMerkleLL merkleLL); -``` - -**Parameters** - -| Name | Type | Description | -| ----------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `baseParams` | `MerkleBase.ConstructorParams` | Struct encapsulating the [SablierMerkleBase](docs/reference/airdrops/contracts/abstracts/abstract.SablierMerkleBase.md) parameters, which are documented in {DataTypes}. | -| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/reference/lockup/contracts/contract.SablierLockup.md) contract. | -| `cancelable` | `bool` | Indicates if the stream will be cancelable after claiming. | -| `transferable` | `bool` | Indicates if the stream will be transferable after claiming. | -| `schedule` | `MerkleLL.Schedule` | Struct encapsulating the unlocks schedule, which are documented in {DataTypes}. | -| `aggregateAmount` | `uint256` | The total amount of ERC-20 tokens to be distributed to all recipients. | -| `recipientCount` | `uint256` | The total number of recipients who are eligible to claim. | - -**Returns** - -| Name | Type | Description | -| ---------- | ------------------ | -------------------------------------------------------- | -| `merkleLL` | `ISablierMerkleLL` | The address of the newly created Merkle Lockup contract. | - -### createMerkleLT - -Creates a new Merkle Lockup campaign with a Lockup Tranched distribution. - -Emits a {CreateMerkleLT} event. Notes: - -- The MerkleLT contract is created with CREATE2. -- The immutable fee will be set to the default value unless a custom fee is set. - -```solidity -function createMerkleLT( - MerkleBase.ConstructorParams memory baseParams, - ISablierLockup lockup, - bool cancelable, - bool transferable, - uint40 streamStartTime, - MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages, - uint256 aggregateAmount, - uint256 recipientCount -) - external - override - returns (ISablierMerkleLT merkleLT); -``` - -**Parameters** - -| Name | Type | Description | -| ------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `baseParams` | `MerkleBase.ConstructorParams` | Struct encapsulating the [SablierMerkleBase](docs/reference/airdrops/contracts/abstracts/abstract.SablierMerkleBase.md) parameters, which are documented in {DataTypes}. | -| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/reference/lockup/contracts/contract.SablierLockup.md) contract. | -| `cancelable` | `bool` | Indicates if the stream will be cancelable after claiming. | -| `transferable` | `bool` | Indicates if the stream will be transferable after claiming. | -| `streamStartTime` | `uint40` | The start time of the streams created through {SablierMerkleBase.claim}. | -| `tranchesWithPercentages` | `MerkleLT.TrancheWithPercentage[]` | The tranches with their respective unlock percentages. | -| `aggregateAmount` | `uint256` | The total amount of ERC-20 tokens to be distributed to all recipients. | -| `recipientCount` | `uint256` | The total number of recipients who are eligible to claim. | - -**Returns** - -| Name | Type | Description | -| ---------- | ------------------ | -------------------------------------------------------- | -| `merkleLT` | `ISablierMerkleLT` | The address of the newly created Merkle Lockup contract. | - -### resetCustomFee - -Resets the custom fee for the provided campaign creator to the default fee. - -Emits a {ResetCustomFee} event. Notes: - -- The default fee will only be applied to future campaigns. Requirements: -- `msg.sender` must be the admin. - -```solidity -function resetCustomFee(address campaignCreator) external override onlyAdmin; -``` - -**Parameters** - -| Name | Type | Description | -| ----------------- | --------- | --------------------------------------- | -| `campaignCreator` | `address` | The user for whom the fee is reset for. | - -### setCustomFee - -Sets a custom fee for the provided campaign creator. - -Emits a {SetCustomFee} event. Notes: - -- The new fee will only be applied to future campaigns. Requirements: -- `msg.sender` must be the admin. - -```solidity -function setCustomFee(address campaignCreator, uint256 newFee) external override onlyAdmin; -``` - -**Parameters** - -| Name | Type | Description | -| ----------------- | --------- | --------------------------------- | -| `campaignCreator` | `address` | The user for whom the fee is set. | -| `newFee` | `uint256` | The new fee to be set. | - -### setDefaultFee - -Sets the default fee to be applied when claiming airdrops. - -Emits a {SetDefaultFee} event. Notes: - -- The new default fee will only be applied to the future campaigns and will not affect the ones already deployed. - Requirements: -- `msg.sender` must be the admin. - -```solidity -function setDefaultFee(uint256 defaultFee_) external override onlyAdmin; -``` - -**Parameters** - -| Name | Type | Description | -| ------------- | --------- | ----------- | -| `defaultFee_` | `uint256` | | - -### \_getFee - -Retrieves the fee for the provided campaign creator, using the default fee if no custom fee is set. - -```solidity -function _getFee(address campaignCreator) private view returns (uint256); -``` - -### \_deployMerkleLT - -Deploys a new MerkleLT contract with CREATE2. - -_We need a separate function to prevent the stack too deep error._ - -```solidity -function _deployMerkleLT( - MerkleBase.ConstructorParams memory baseParams, - ISablierLockup lockup, - bool cancelable, - bool transferable, - uint40 streamStartTime, - MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages -) - private - returns (ISablierMerkleLT merkleLT); -``` diff --git a/docs/reference/airdrops/contracts/contract.SablierMerkleInstant.md b/docs/reference/airdrops/contracts/contract.SablierMerkleInstant.md index 6233f46e..45de890e 100644 --- a/docs/reference/airdrops/contracts/contract.SablierMerkleInstant.md +++ b/docs/reference/airdrops/contracts/contract.SablierMerkleInstant.md @@ -4,7 +4,7 @@ sidebar_position: 3 # SablierMerkleInstant -[Git Source](https://github.com/sablier-labs/airdrops/blob/f9a358c0a5bccfec77601d4490ef9117e0488068/src/SablierMerkleInstant.sol) +[Git Source](https://github.com/sablier-labs/airdrops/blob/077c6b9766ef7693ba9e82a9e001dc0097709c01/src/SablierMerkleInstant.sol) **Inherits:** [ISablierMerkleInstant](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleInstant.md), [SablierMerkleBase](/docs/reference/airdrops/contracts/abstracts/abstract.SablierMerkleBase.md) @@ -20,16 +20,164 @@ _Constructs the contract by initializing the immutable state variables._ ```solidity constructor( - MerkleBase.ConstructorParams memory baseParams, - address campaignCreator + MerkleInstant.ConstructorParams memory params, + address campaignCreator, + address comptroller ) - SablierMerkleBase(baseParams, campaignCreator); + SablierMerkleBase( + campaignCreator, + params.campaignName, + params.campaignStartTime, + comptroller, + params.expiration, + params.initialAdmin, + params.ipfsCID, + params.merkleRoot, + params.token + ); ``` -### \_claim +### claim -_This function is implemented by child contracts, so the logic varies depending on the model._ +Claim airdrop on behalf of eligible recipient and transfer it to the recipient address. + +\*It emits a {ClaimInstant} event. Requirements: + +- The current time must be greater than or equal to the campaign start time. +- The campaign must not have expired. +- `msg.value` must not be less than the value returned by {COMPTROLLER.calculateMinFeeWei}. +- The `index` must not be claimed already. +- The Merkle proof must be valid.\* + +```solidity +function claim( + uint256 index, + address recipient, + uint128 amount, + bytes32[] calldata merkleProof +) + external + payable + override; +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | ----------- | ------------------------------------------------------- | +| `index` | `uint256` | The index of the recipient in the Merkle tree. | +| `recipient` | `address` | The address of the airdrop recipient. | +| `amount` | `uint128` | The amount of ERC-20 tokens allocated to the recipient. | +| `merkleProof` | `bytes32[]` | The proof of inclusion in the Merkle tree. | + +### claimTo + +Claim airdrop and transfer the tokens to the `to` address. + +\*It emits a {ClaimInstant} event. Requirements: + +- `msg.sender` must be the airdrop recipient. +- The `to` must not be the zero address. +- Refer to the requirements in {claim}.\* + +```solidity +function claimTo( + uint256 index, + address to, + uint128 amount, + bytes32[] calldata merkleProof +) + external + payable + override + notZeroAddress(to); +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | ----------- | ------------------------------------------------------------------ | +| `index` | `uint256` | The index of the `msg.sender` in the Merkle tree. | +| `to` | `address` | The address receiving the ERC-20 tokens on behalf of `msg.sender`. | +| `amount` | `uint128` | The amount of ERC-20 tokens allocated to the `msg.sender`. | +| `merkleProof` | `bytes32[]` | The proof of inclusion in the Merkle tree. | + +### claimViaSig + +Claim airdrop on behalf of eligible recipient using an EIP-712 or EIP-1271 signature, and transfer the tokens to the +`to` address. + +\*It emits a {ClaimInstant} event. Requirements: + +- If `recipient` is an EOA, it must match the recovered signer. +- If `recipient` is a contract, it must implement the IERC-1271 interface. +- The `to` must not be the zero address. +- The `validFrom` must be less than or equal to the current block timestamp. +- Refer to the requirements in {claim}. Below is the example of typed data to be signed by the airdrop recipient, + referenced from https://docs.metamask.io/wallet/how-to/sign-data/#example. + +```json +types: { +EIP712Domain: [ +{ name: "name", type: "string" }, +{ name: "chainId", type: "uint256" }, +{ name: "verifyingContract", type: "address" }, +], +Claim: [ +{ name: "index", type: "uint256" }, +{ name: "recipient", type: "address" }, +{ name: "to", type: "address" }, +{ name: "amount", type: "uint128" }, +{ name: "validFrom", type: "uint40" }, +], +}, +domain: { +name: "Sablier Airdrops Protocol", +chainId: 1, // Chain on which the contract is deployed +verifyingContract: "0xTheAddressOfThisContract", // The address of this contract +}, +primaryType: "Claim", +message: { +index: 2, // The index of the signer in the Merkle tree +recipient: "0xTheAddressOfTheRecipient", // The address of the airdrop recipient +to: "0xTheAddressReceivingTheTokens", // The address where recipient wants to transfer the tokens +amount: "1000000000000000000000", // The amount of tokens allocated to the recipient +validFrom: 1752425637 // The timestamp from which the claim signature is valid +}, +``` + +```solidity +function claimViaSig( + uint256 index, + address recipient, + address to, + uint128 amount, + uint40 validFrom, + bytes32[] calldata merkleProof, + bytes calldata signature +) + external + payable + override + notZeroAddress(to); +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | ----------- | -------------------------------------------------------------------- | +| `index` | `uint256` | The index of the recipient in the Merkle tree. | +| `recipient` | `address` | The address of the airdrop recipient who is providing the signature. | +| `to` | `address` | The address receiving the ERC-20 tokens on behalf of the recipient. | +| `amount` | `uint128` | The amount of ERC-20 tokens allocated to the recipient. | +| `validFrom` | `uint40` | The timestamp from which the claim signature is valid. | +| `merkleProof` | `bytes32[]` | The proof of inclusion in the Merkle tree. | +| `signature` | `bytes` | The EIP-712 or EIP-1271 signature from the airdrop recipient. | + +### \_postProcessClaim + +_Post-processes the claim execution by handling the tokens transfer and emitting an event._ ```solidity -function _claim(uint256 index, address recipient, uint128 amount) internal override; +function _postProcessClaim(uint256 index, address recipient, address to, uint128 amount, bool viaSig) private; ``` diff --git a/docs/reference/airdrops/contracts/contract.SablierMerkleLL.md b/docs/reference/airdrops/contracts/contract.SablierMerkleLL.md index ee63104a..6c40f046 100644 --- a/docs/reference/airdrops/contracts/contract.SablierMerkleLL.md +++ b/docs/reference/airdrops/contracts/contract.SablierMerkleLL.md @@ -4,50 +4,56 @@ sidebar_position: 3 # SablierMerkleLL -[Git Source](https://github.com/sablier-labs/airdrops/blob/f9a358c0a5bccfec77601d4490ef9117e0488068/src/SablierMerkleLL.sol) +[Git Source](https://github.com/sablier-labs/airdrops/blob/077c6b9766ef7693ba9e82a9e001dc0097709c01/src/SablierMerkleLL.sol) **Inherits:** [ISablierMerkleLL](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleLL.md), -[SablierMerkleBase](/docs/reference/airdrops/contracts/abstracts/abstract.SablierMerkleBase.md) +[SablierMerkleLockup](/docs/reference/airdrops/contracts/abstracts/abstract.SablierMerkleLockup.md) See the documentation in [ISablierMerkleLL](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleLL.md). ## State Variables -### LOCKUP +### VESTING_CLIFF_DURATION -The address of the [SablierLockup](/reference/lockup/contracts/contract.SablierLockup.md) contract. +Retrieves the cliff duration of the vesting stream, in seconds. ```solidity -ISablierLockup public immutable override LOCKUP; +uint40 public immutable override VESTING_CLIFF_DURATION; ``` -### STREAM_CANCELABLE +### VESTING_CLIFF_UNLOCK_PERCENTAGE -A flag indicating whether the streams can be canceled. - -_This is an immutable state variable._ +Retrieves the percentage of the claim amount due to be unlocked at the vesting cliff time, as a fixed-point number where +1e18 is 100%. ```solidity -bool public immutable override STREAM_CANCELABLE; +UD60x18 public immutable override VESTING_CLIFF_UNLOCK_PERCENTAGE; ``` -### STREAM_TRANSFERABLE +### VESTING_START_TIME + +Retrieves the start time of the vesting stream, as a Unix timestamp. Zero is a sentinel value for `block.timestamp`. -A flag indicating whether the stream NFTs are transferable. +```solidity +uint40 public immutable override VESTING_START_TIME; +``` -_This is an immutable state variable._ +### VESTING_START_UNLOCK_PERCENTAGE + +Retrieves the percentage of the claim amount due to be unlocked at the vesting start time, as a fixed-point number where +1e18 is 100%. ```solidity -bool public immutable override STREAM_TRANSFERABLE; +UD60x18 public immutable override VESTING_START_UNLOCK_PERCENTAGE; ``` -### \_schedule +### VESTING_TOTAL_DURATION -_See the documentation in {ISablierMerkleLL.getSchedule}._ +Retrieves the total duration of the vesting stream, in seconds. ```solidity -MerkleLL.Schedule private _schedule; +uint40 public immutable override VESTING_TOTAL_DURATION; ``` ## Functions @@ -58,31 +64,172 @@ _Constructs the contract by initializing the immutable state variables, and max ```solidity constructor( - MerkleBase.ConstructorParams memory baseParams, + MerkleLL.ConstructorParams memory params, address campaignCreator, - ISablierLockup lockup, - bool cancelable, - bool transferable, - MerkleLL.Schedule memory schedule + address comptroller ) - SablierMerkleBase(baseParams, campaignCreator); + SablierMerkleLockup( + campaignCreator, + params.campaignName, + params.campaignStartTime, + params.cancelable, + comptroller, + params.lockup, + params.expiration, + params.initialAdmin, + params.ipfsCID, + params.merkleRoot, + params.shape, + params.token, + params.transferable + ); ``` -### getSchedule +### claim + +Claim airdrop on behalf of eligible recipient. If the vesting end time is in the future, it creates a Lockup Linear +stream, otherwise it transfers the tokens directly to the recipient address. -A tuple containing the start time, start unlock percentage, cliff duration, cliff unlock percentage, and end duration. -These values are used to calculate the vesting schedule in `Lockup.CreateWithTimestampsLL`. +\*It emits either {ClaimLLWithTransfer} or {ClaimLLWithVesting} event. Requirements: -_A start time value of zero will be considered as `block.timestamp`._ +- The current time must be greater than or equal to the campaign start time. +- The campaign must not have expired. +- `msg.value` must not be less than the value returned by {COMPTROLLER.calculateMinFeeWei}. +- The `index` must not be claimed already. +- The Merkle proof must be valid. +- All requirements from {ISablierLockupLinear.createWithTimestampsLL} must be met.\* ```solidity -function getSchedule() external view override returns (MerkleLL.Schedule memory); +function claim( + uint256 index, + address recipient, + uint128 amount, + bytes32[] calldata merkleProof +) + external + payable + override; ``` -### \_claim +**Parameters** + +| Name | Type | Description | +| ------------- | ----------- | ------------------------------------------------------- | +| `index` | `uint256` | The index of the recipient in the Merkle tree. | +| `recipient` | `address` | The address of the airdrop recipient. | +| `amount` | `uint128` | The amount of ERC-20 tokens allocated to the recipient. | +| `merkleProof` | `bytes32[]` | The proof of inclusion in the Merkle tree. | + +### claimTo + +Claim airdrop. If the vesting end time is in the future, it creates a Lockup Linear stream with `to` address as the +stream recipient, otherwise it transfers the tokens directly to the `to` address. + +\*It emits either {ClaimLLWithTransfer} or {ClaimLLWithVesting} event. Requirements: + +- `msg.sender` must be the airdrop recipient. +- The `to` must not be the zero address. +- Refer to the requirements in {claim}.\* + +```solidity +function claimTo( + uint256 index, + address to, + uint128 amount, + bytes32[] calldata merkleProof +) + external + payable + override + notZeroAddress(to); +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | ----------- | ------------------------------------------------------------------------------------------- | +| `index` | `uint256` | The index of the `msg.sender` in the Merkle tree. | +| `to` | `address` | The address to which Lockup stream or ERC-20 tokens will be sent on behalf of `msg.sender`. | +| `amount` | `uint128` | The amount of ERC-20 tokens allocated to the `msg.sender`. | +| `merkleProof` | `bytes32[]` | The proof of inclusion in the Merkle tree. | + +### claimViaSig + +Claim airdrop on behalf of eligible recipient using an EIP-712 or EIP-1271 signature. If the vesting end time is in the +future, it creates a Lockup Linear stream with `to` address as the stream recipient, otherwise it transfers the tokens +directly to the `to` address. + +\*It emits either {ClaimLLWithTransfer} or {ClaimLLWithVesting} event. Requirements: + +- If `recipient` is an EOA, it must match the recovered signer. +- If `recipient` is a contract, it must implement the IERC-1271 interface. +- The `to` must not be the zero address. +- The `validFrom` must be less than or equal to the current block timestamp. +- Refer to the requirements in {claim}. Below is the example of typed data to be signed by the airdrop recipient, + referenced from https://docs.metamask.io/wallet/how-to/sign-data/#example. + +```json +types: { +EIP712Domain: [ +{ name: "name", type: "string" }, +{ name: "chainId", type: "uint256" }, +{ name: "verifyingContract", type: "address" }, +], +Claim: [ +{ name: "index", type: "uint256" }, +{ name: "recipient", type: "address" }, +{ name: "to", type: "address" }, +{ name: "amount", type: "uint128" }, +{ name: "validFrom", type: "uint40" }, +], +}, +domain: { +name: "Sablier Airdrops Protocol", +chainId: 1, // Chain on which the contract is deployed +verifyingContract: "0xTheAddressOfThisContract", // The address of this contract +}, +primaryType: "Claim", +message: { +index: 2, // The index of the signer in the Merkle tree +recipient: "0xTheAddressOfTheRecipient", // The address of the airdrop recipient +to: "0xTheAddressReceivingTheTokens", // The address where recipient wants to transfer the tokens +amount: "1000000000000000000000", // The amount of tokens allocated to the recipient +validFrom: 1752425637 // The timestamp from which the claim signature is valid +}, +``` + +```solidity +function claimViaSig( + uint256 index, + address recipient, + address to, + uint128 amount, + uint40 validFrom, + bytes32[] calldata merkleProof, + bytes calldata signature +) + external + payable + override + notZeroAddress(to); +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | ----------- | -------------------------------------------------------------------------------------------- | +| `index` | `uint256` | The index of the recipient in the Merkle tree. | +| `recipient` | `address` | The address of the airdrop recipient who is providing the signature. | +| `to` | `address` | The address to which Lockup stream or ERC-20 tokens will be sent on behalf of the recipient. | +| `amount` | `uint128` | The amount of ERC-20 tokens allocated to the recipient. | +| `validFrom` | `uint40` | The timestamp from which the claim signature is valid. | +| `merkleProof` | `bytes32[]` | The proof of inclusion in the Merkle tree. | +| `signature` | `bytes` | The EIP-712 or EIP-1271 signature from the airdrop recipient. | + +### \_postProcessClaim -_This function is implemented by child contracts, so the logic varies depending on the model._ +_Post-processes the claim execution by creating the stream or transferring the tokens directly and emitting an event._ ```solidity -function _claim(uint256 index, address recipient, uint128 amount) internal override; +function _postProcessClaim(uint256 index, address recipient, address to, uint128 amount, bool viaSig) private; ``` diff --git a/docs/reference/airdrops/contracts/contract.SablierMerkleLT.md b/docs/reference/airdrops/contracts/contract.SablierMerkleLT.md index 5f2873b0..7f59a3eb 100644 --- a/docs/reference/airdrops/contracts/contract.SablierMerkleLT.md +++ b/docs/reference/airdrops/contracts/contract.SablierMerkleLT.md @@ -4,112 +4,226 @@ sidebar_position: 3 # SablierMerkleLT -[Git Source](https://github.com/sablier-labs/airdrops/blob/f9a358c0a5bccfec77601d4490ef9117e0488068/src/SablierMerkleLT.sol) +[Git Source](https://github.com/sablier-labs/airdrops/blob/077c6b9766ef7693ba9e82a9e001dc0097709c01/src/SablierMerkleLT.sol) **Inherits:** [ISablierMerkleLT](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleLT.md), -[SablierMerkleBase](/docs/reference/airdrops/contracts/abstracts/abstract.SablierMerkleBase.md) +[SablierMerkleLockup](/docs/reference/airdrops/contracts/abstracts/abstract.SablierMerkleLockup.md) See the documentation in [ISablierMerkleLT](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleLT.md). ## State Variables -### LOCKUP +### VESTING_START_TIME -The address of the [SablierLockup](/reference/lockup/contracts/contract.SablierLockup.md) contract. +Retrieves the start time of the vesting stream, as a Unix timestamp. Zero is a sentinel value for `block.timestamp`. ```solidity -ISablierLockup public immutable override LOCKUP; +uint40 public immutable override VESTING_START_TIME; ``` -### STREAM_CANCELABLE - -A flag indicating whether the streams can be canceled. +### \_tranchesWithPercentages -_This is an immutable state variable._ +_The tranches with their respective unlock percentages and durations._ ```solidity -bool public immutable override STREAM_CANCELABLE; +MerkleLT.TrancheWithPercentage[] private _tranchesWithPercentages; ``` -### STREAM_START_TIME +## Functions -The start time of the streams created through {SablierMerkleBase.claim} function. +### constructor -_A start time value of zero will be treated as `block.timestamp`._ +_Constructs the contract by initializing the immutable state variables, and max approving the Lockup contract._ ```solidity -uint40 public immutable override STREAM_START_TIME; +constructor( + MerkleLT.ConstructorParams memory params, + address campaignCreator, + address comptroller +) + SablierMerkleLockup( + campaignCreator, + params.campaignName, + params.campaignStartTime, + params.cancelable, + comptroller, + params.lockup, + params.expiration, + params.initialAdmin, + params.ipfsCID, + params.merkleRoot, + params.shape, + params.token, + params.transferable + ); ``` -### STREAM_TRANSFERABLE +### tranchesWithPercentages -A flag indicating whether the stream NFTs are transferable. - -_This is an immutable state variable._ +Retrieves the tranches with their respective unlock percentages and durations. ```solidity -bool public immutable override STREAM_TRANSFERABLE; +function tranchesWithPercentages() external view override returns (MerkleLT.TrancheWithPercentage[] memory); ``` -### TOTAL_PERCENTAGE +### claim + +Claim airdrop on behalf of eligible recipient. If the vesting end time is in the future, it creates a Lockup Tranched +stream, otherwise it transfers the tokens directly to the recipient address. -The total percentage of the tranches. +\*It emits either {ClaimLTWithTransfer} or {ClaimLTWithVesting} event. Requirements: + +- The current time must be greater than or equal to the campaign start time. +- The campaign must not have expired. +- `msg.value` must not be less than the value returned by {COMPTROLLER.calculateMinFeeWei}. +- The `index` must not be claimed already. +- The Merkle proof must be valid. +- All requirements from {ISablierLockupTranched.createWithTimestampsLT} must be met.\* ```solidity -uint64 public immutable override TOTAL_PERCENTAGE; +function claim( + uint256 index, + address recipient, + uint128 amount, + bytes32[] calldata merkleProof +) + external + payable + override; ``` -### \_tranchesWithPercentages +**Parameters** -_The tranches with their respective unlock percentages and durations._ +| Name | Type | Description | +| ------------- | ----------- | ------------------------------------------------------- | +| `index` | `uint256` | The index of the recipient in the Merkle tree. | +| `recipient` | `address` | The address of the airdrop recipient. | +| `amount` | `uint128` | The amount of ERC-20 tokens allocated to the recipient. | +| `merkleProof` | `bytes32[]` | The proof of inclusion in the Merkle tree. | -```solidity -MerkleLT.TrancheWithPercentage[] internal _tranchesWithPercentages; -``` +### claimTo -## Functions +Claim airdrop. If the vesting end time is in the future, it creates a Lockup Tranched stream with `to` address as the +stream recipient, otherwise it transfers the tokens directly to the `to` address. -### constructor +\*It emits either {ClaimLTWithTransfer} or {ClaimLTWithVesting} event. Requirements: -_Constructs the contract by initializing the immutable state variables, and max approving the Lockup contract._ +- `msg.sender` must be the airdrop recipient. +- The `to` must not be the zero address. +- Refer to the requirements in {claim}.\* ```solidity -constructor( - MerkleBase.ConstructorParams memory baseParams, - address campaignCreator, - ISablierLockup lockup, - bool cancelable, - bool transferable, - uint40 streamStartTime, - MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages +function claimTo( + uint256 index, + address to, + uint128 amount, + bytes32[] calldata merkleProof ) - SablierMerkleBase(baseParams, campaignCreator); + external + payable + override + notZeroAddress(to); ``` -### getTranchesWithPercentages - -Retrieves the tranches with their respective unlock percentages and durations. +**Parameters** + +| Name | Type | Description | +| ------------- | ----------- | ------------------------------------------------------------------------------------------- | +| `index` | `uint256` | The index of the `msg.sender` in the Merkle tree. | +| `to` | `address` | The address to which Lockup stream or ERC-20 tokens will be sent on behalf of `msg.sender`. | +| `amount` | `uint128` | The amount of ERC-20 tokens allocated to the `msg.sender`. | +| `merkleProof` | `bytes32[]` | The proof of inclusion in the Merkle tree. | + +### claimViaSig + +Claim airdrop on behalf of eligible recipient using an EIP-712 or EIP-1271 signature. If the vesting end time is in the +future, it creates a Lockup Tranched stream with `to` address as the stream recipient, otherwise it transfers the tokens +directly to the `to` address. + +\*It emits either {ClaimLTWithTransfer} or {ClaimLTWithVesting} event. Requirements: + +- If `recipient` is an EOA, it must match the recovered signer. +- If `recipient` is a contract, it must implement the IERC-1271 interface. +- The `to` must not be the zero address. +- The `validFrom` must be less than or equal to the current block timestamp. +- Refer to the requirements in {claim}. Below is the example of typed data to be signed by the airdrop recipient, + referenced from https://docs.metamask.io/wallet/how-to/sign-data/#example. + +```json +types: { +EIP712Domain: [ +{ name: "name", type: "string" }, +{ name: "chainId", type: "uint256" }, +{ name: "verifyingContract", type: "address" }, +], +Claim: [ +{ name: "index", type: "uint256" }, +{ name: "recipient", type: "address" }, +{ name: "to", type: "address" }, +{ name: "amount", type: "uint128" }, +{ name: "validFrom", type: "uint40" }, +], +}, +domain: { +name: "Sablier Airdrops Protocol", +chainId: 1, // Chain on which the contract is deployed +verifyingContract: "0xTheAddressOfThisContract", // The address of this contract +}, +primaryType: "Claim", +message: { +index: 2, // The index of the signer in the Merkle tree +recipient: "0xTheAddressOfTheRecipient", // The address of the airdrop recipient +to: "0xTheAddressReceivingTheTokens", // The address where recipient wants to transfer the tokens +amount: "1000000000000000000000", // The amount of tokens allocated to the recipient +validFrom: 1752425637 // The timestamp from which the claim signature is valid +}, +``` ```solidity -function getTranchesWithPercentages() external view override returns (MerkleLT.TrancheWithPercentage[] memory); +function claimViaSig( + uint256 index, + address recipient, + address to, + uint128 amount, + uint40 validFrom, + bytes32[] calldata merkleProof, + bytes calldata signature +) + external + payable + override + notZeroAddress(to); ``` -### \_claim +**Parameters** -_This function is implemented by child contracts, so the logic varies depending on the model._ - -```solidity -function _claim(uint256 index, address recipient, uint128 amount) internal override; -``` +| Name | Type | Description | +| ------------- | ----------- | -------------------------------------------------------------------------------------------- | +| `index` | `uint256` | The index of the recipient in the Merkle tree. | +| `recipient` | `address` | The address of the airdrop recipient who is providing the signature. | +| `to` | `address` | The address to which Lockup stream or ERC-20 tokens will be sent on behalf of the recipient. | +| `amount` | `uint128` | The amount of ERC-20 tokens allocated to the recipient. | +| `validFrom` | `uint40` | The timestamp from which the claim signature is valid. | +| `merkleProof` | `bytes32[]` | The proof of inclusion in the Merkle tree. | +| `signature` | `bytes` | The EIP-712 or EIP-1271 signature from the airdrop recipient. | ### \_calculateStartTimeAndTranches -_Calculates the start time, and the tranches based on the claim amount and the unlock percentages for each tranche._ +_Calculates the vesting start time, and the tranches based on the claim amount and the unlock percentages for each +tranche._ ```solidity function _calculateStartTimeAndTranches(uint128 claimAmount) - internal + private view - returns (uint40 startTime, LockupTranched.Tranche[] memory tranches); + returns (uint40 vestingStartTime, LockupTranched.Tranche[] memory tranches); +``` + +### \_postProcessClaim + +_Post-processes the claim execution by creating the stream or transferring the tokens directly and emitting an event._ + +```solidity +function _postProcessClaim(uint256 index, address recipient, address to, uint128 amount, bool viaSig) private; ``` diff --git a/docs/reference/airdrops/contracts/contract.SablierMerkleVCA.md b/docs/reference/airdrops/contracts/contract.SablierMerkleVCA.md new file mode 100644 index 00000000..6134ac24 --- /dev/null +++ b/docs/reference/airdrops/contracts/contract.SablierMerkleVCA.md @@ -0,0 +1,247 @@ +--- +sidebar_position: 3 +--- + +# SablierMerkleVCA + +[Git Source](https://github.com/sablier-labs/airdrops/blob/077c6b9766ef7693ba9e82a9e001dc0097709c01/src/SablierMerkleVCA.sol) + +**Inherits:** [ISablierMerkleVCA](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleVCA.md), +[SablierMerkleBase](/docs/reference/airdrops/contracts/abstracts/abstract.SablierMerkleBase.md) + +See the documentation in +[ISablierMerkleVCA](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleVCA.md). + +## State Variables + +### UNLOCK_PERCENTAGE + +Retrieves the percentage of the full amount that will unlock immediately at the start time. The value is denominated as +a fixed-point number where 1e18 is 100%. + +```solidity +UD60x18 public immutable override UNLOCK_PERCENTAGE; +``` + +### VESTING_END_TIME + +Retrieves the time when the VCA airdrop is fully vested, as a Unix timestamp. + +```solidity +uint40 public immutable override VESTING_END_TIME; +``` + +### VESTING_START_TIME + +Retrieves the time when the VCA airdrop begins to unlock, as a Unix timestamp. + +```solidity +uint40 public immutable override VESTING_START_TIME; +``` + +### totalForgoneAmount + +Retrieves the total amount of tokens forgone by early claimers. + +```solidity +uint256 public override totalForgoneAmount; +``` + +## Functions + +### constructor + +_Constructs the contract by initializing the immutable state variables._ + +```solidity +constructor( + MerkleVCA.ConstructorParams memory params, + address campaignCreator, + address comptroller +) + SablierMerkleBase( + campaignCreator, + params.campaignName, + params.campaignStartTime, + comptroller, + params.expiration, + params.initialAdmin, + params.ipfsCID, + params.merkleRoot, + params.token + ); +``` + +### calculateClaimAmount + +Calculates the amount that would be claimed if the claim were made at `claimTime`. + +_This is for informational purposes only. To actually claim the airdrop, a Merkle proof is required._ + +```solidity +function calculateClaimAmount(uint128 fullAmount, uint40 claimTime) external view returns (uint128); +``` + +**Parameters** + +| Name | Type | Description | +| ------------ | --------- | ----------------------------------------------------------------------------------------------- | +| `fullAmount` | `uint128` | The amount of tokens allocated to a user, denominated in the token's decimals. | +| `claimTime` | `uint40` | A hypothetical time at which to make the claim. Zero is a sentinel value for `block.timestamp`. | + +**Returns** + +| Name | Type | Description | +| -------- | --------- | ---------------------------------------------------------------------- | +| `` | `uint128` | The amount that would be claimed, denominated in the token's decimals. | + +### calculateForgoneAmount + +Calculates the amount that would be forgone if the claim were made at `claimTime`. + +_This is for informational purposes only. Reverts if the claim time is less than the vesting start time, since the claim +cannot be made, no amount can be forgone._ + +```solidity +function calculateForgoneAmount(uint128 fullAmount, uint40 claimTime) external view returns (uint128); +``` + +**Parameters** + +| Name | Type | Description | +| ------------ | --------- | ----------------------------------------------------------------------------------------------- | +| `fullAmount` | `uint128` | The amount of tokens allocated to a user, denominated in the token's decimals. | +| `claimTime` | `uint40` | A hypothetical time at which to make the claim. Zero is a sentinel value for `block.timestamp`. | + +**Returns** + +| Name | Type | Description | +| -------- | --------- | ---------------------------------------------------------------------- | +| `` | `uint128` | The amount that would be forgone, denominated in the token's decimals. | + +### claimTo + +Claim airdrop. If the vesting end time is in the future, it calculates the claim amount to transfer to the `to` address, +otherwise it transfers the full amount. + +\*It emits a {ClaimVCA} event. Requirements: + +- The current time must be greater than or equal to the campaign start time. +- The campaign must not have expired. +- `msg.value` must not be less than the value returned by {COMPTROLLER.calculateMinFeeWei}. +- The `index` must not be claimed already. +- The Merkle proof must be valid. +- The claim amount must be greater than zero. +- `msg.sender` must be the airdrop recipient. +- The `to` must not be the zero address.\* + +```solidity +function claimTo( + uint256 index, + address to, + uint128 fullAmount, + bytes32[] calldata merkleProof +) + external + payable + override + notZeroAddress(to); +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | ----------- | ------------------------------------------------------------------ | +| `index` | `uint256` | The index of the `msg.sender` in the Merkle tree. | +| `to` | `address` | The address receiving the ERC-20 tokens on behalf of `msg.sender`. | +| `fullAmount` | `uint128` | The total amount of ERC-20 tokens allocated to the recipient. | +| `merkleProof` | `bytes32[]` | The proof of inclusion in the Merkle tree. | + +### claimViaSig + +Claim airdrop on behalf of eligible recipient using an EIP-712 or EIP-1271 signature. If the vesting end time is in the +future, it calculates the claim amount to transfer to the `to` address, otherwise it transfers the full amount. + +\*It emits a {ClaimVCA} event. Requirements: + +- If `recipient` is an EOA, it must match the recovered signer. +- If `recipient` is a contract, it must implement the IERC-1271 interface. +- The `to` must not be the zero address. +- The `validFrom` must be less than or equal to the current block timestamp. +- Refer to the requirements in {claimTo} except that there are no restrictions on `msg.sender`. Below is the example of + typed data to be signed by the airdrop recipient, referenced from + https://docs.metamask.io/wallet/how-to/sign-data/#example. + +```json +types: { +EIP712Domain: [ +{ name: "name", type: "string" }, +{ name: "chainId", type: "uint256" }, +{ name: "verifyingContract", type: "address" }, +], +Claim: [ +{ name: "index", type: "uint256" }, +{ name: "recipient", type: "address" }, +{ name: "to", type: "address" }, +{ name: "amount", type: "uint128" }, +{ name: "validFrom", type: "uint40" }, +], +}, +domain: { +name: "Sablier Airdrops Protocol", +chainId: 1, // Chain on which the contract is deployed +verifyingContract: "0xTheAddressOfThisContract", // The address of this contract +}, +primaryType: "Claim", +message: { +index: 2, // The index of the signer in the Merkle tree +recipient: "0xTheAddressOfTheRecipient", // The address of the airdrop recipient +to: "0xTheAddressReceivingTheTokens", // The address where recipient wants to transfer the tokens +amount: "1000000000000000000000", // The amount of tokens allocated to the recipient +validFrom: 1752425637 // The timestamp from which the claim signature is valid +}, +``` + +```solidity +function claimViaSig( + uint256 index, + address recipient, + address to, + uint128 fullAmount, + uint40 validFrom, + bytes32[] calldata merkleProof, + bytes calldata signature +) + external + payable + override + notZeroAddress(to); +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | ----------- | -------------------------------------------------------------------- | +| `index` | `uint256` | The index of the recipient in the Merkle tree. | +| `recipient` | `address` | The address of the airdrop recipient who is providing the signature. | +| `to` | `address` | The address receiving the ERC-20 tokens on behalf of the recipient. | +| `fullAmount` | `uint128` | The total amount of ERC-20 tokens allocated to the recipient. | +| `validFrom` | `uint40` | The timestamp from which the claim signature is valid. | +| `merkleProof` | `bytes32[]` | The proof of inclusion in the Merkle tree. | +| `signature` | `bytes` | The EIP-712 or EIP-1271 signature from the airdrop recipient. | + +### \_calculateClaimAmount + +_See the documentation for the user-facing functions that call this internal function._ + +```solidity +function _calculateClaimAmount(uint128 fullAmount, uint40 claimTime) private view returns (uint128); +``` + +### \_postProcessClaim + +_Post-processes the claim execution by handling the tokens transfer and emitting an event._ + +```solidity +function _postProcessClaim(uint256 index, address recipient, address to, uint128 fullAmount, bool viaSig) private; +``` diff --git a/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleBase.md b/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleBase.md new file mode 100644 index 00000000..c3cb75a1 --- /dev/null +++ b/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleBase.md @@ -0,0 +1,55 @@ +# ISablierFactoryMerkleBase + +[Git Source](https://github.com/sablier-labs/airdrops/blob/077c6b9766ef7693ba9e82a9e001dc0097709c01/src/interfaces/ISablierFactoryMerkleBase.sol) + +**Inherits:** IComptrollerable + +_Common interface between factories that deploy campaign contracts. The contracts are deployed using CREATE2._ + +## Functions + +### nativeToken + +Retrieves the address of the ERC-20 interface of the native token, if it exists. + +_The native tokens on some chains have a dual interface as ERC-20. For example, on Polygon the $POL token is the native +token and has an ERC-20 version at 0x0000000000000000000000000000000000001010. This means that `address(this).balance` +returns the same value as `balanceOf(address(this))`. To avoid any unintended behavior, these tokens cannot be used in +Sablier. As an alternative, users can use the Wrapped version of the token, i.e. WMATIC, which is a standard ERC-20 +token._ + +```solidity +function nativeToken() external view returns (address); +``` + +### setNativeToken + +Sets the native token address. Once set, it cannot be changed. + +\*For more information, see the documentation for +[nativeToken](/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleBase.md#nativetoken). Emits a +{SetNativeToken} event. Requirements: + +- `msg.sender` must be the comptroller. +- `newNativeToken` must not be zero address. +- The native token must not be already set.\* + +```solidity +function setNativeToken(address newNativeToken) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---------------- | --------- | -------------------------------- | +| `newNativeToken` | `address` | The address of the native token. | + +## Events + +### SetNativeToken + +Emitted when the native token address is set by the comptroller. + +```solidity +event SetNativeToken(address indexed comptroller, address nativeToken); +``` diff --git a/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleInstant.md b/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleInstant.md new file mode 100644 index 00000000..0348a959 --- /dev/null +++ b/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleInstant.md @@ -0,0 +1,87 @@ +# ISablierFactoryMerkleInstant + +[Git Source](https://github.com/sablier-labs/airdrops/blob/077c6b9766ef7693ba9e82a9e001dc0097709c01/src/interfaces/ISablierFactoryMerkleInstant.sol) + +**Inherits:** +[ISablierFactoryMerkleBase](/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleBase.md) + +A factory that deploys MerkleInstant campaign contracts. + +_See the documentation in +[ISablierMerkleInstant](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleInstant.md)._ + +## Functions + +### computeMerkleInstant + +Computes the deterministic address where +[SablierMerkleInstant](/docs/reference/airdrops/contracts/contract.SablierMerkleInstant.md) campaign will be deployed. + +_Reverts if the requirements from +[createMerkleInstant](/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleInstant.md#createmerkleinstant) +are not met._ + +```solidity +function computeMerkleInstant( + address campaignCreator, + MerkleInstant.ConstructorParams memory params +) + external + view + returns (address merkleInstant); +``` + +### createMerkleInstant + +Creates a new MerkleInstant campaign for instant distribution of tokens. + +\*Emits a +[CreateMerkleInstant](/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleInstant.md#createmerkleinstant) +event. Notes: + +- The contract is created with CREATE2. +- The campaign's fee will be set to the min USD fee unless a custom fee is set for `msg.sender`. +- A value of zero for `params.expiration` means the campaign does not expire. Requirements: +- `params.token` must not be the forbidden native token.\* + +```solidity +function createMerkleInstant( + MerkleInstant.ConstructorParams memory params, + uint256 aggregateAmount, + uint256 recipientCount +) + external + returns (ISablierMerkleInstant merkleInstant); +``` + +**Parameters** + +| Name | Type | Description | +| ----------------- | --------------------------------- | ------------------------------------------------------------------------------- | +| `params` | `MerkleInstant.ConstructorParams` | Struct encapsulating the input parameters, which are documented in {DataTypes}. | +| `aggregateAmount` | `uint256` | The total amount of ERC-20 tokens to be distributed to all recipients. | +| `recipientCount` | `uint256` | The total number of recipient addresses eligible for the airdrop. | + +**Returns** + +| Name | Type | Description | +| --------------- | ----------------------- | -------------------------------------------------------- | +| `merkleInstant` | `ISablierMerkleInstant` | The address of the newly created MerkleInstant contract. | + +## Events + +### CreateMerkleInstant + +Emitted when a [SablierMerkleInstant](/docs/reference/airdrops/contracts/contract.SablierMerkleInstant.md) campaign is +created. + +```solidity +event CreateMerkleInstant( + ISablierMerkleInstant indexed merkleInstant, + MerkleInstant.ConstructorParams params, + uint256 aggregateAmount, + uint256 recipientCount, + address comptroller, + uint256 minFeeUSD +); +``` diff --git a/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleLL.md b/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleLL.md new file mode 100644 index 00000000..99da2258 --- /dev/null +++ b/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleLL.md @@ -0,0 +1,86 @@ +# ISablierFactoryMerkleLL + +[Git Source](https://github.com/sablier-labs/airdrops/blob/077c6b9766ef7693ba9e82a9e001dc0097709c01/src/interfaces/ISablierFactoryMerkleLL.sol) + +**Inherits:** +[ISablierFactoryMerkleBase](/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleBase.md) + +A factory that deploys MerkleLL campaign contracts. + +_See the documentation in +[ISablierMerkleLL](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleLL.md)._ + +## Functions + +### computeMerkleLL + +Computes the deterministic address where +[SablierMerkleLL](/docs/reference/airdrops/contracts/contract.SablierMerkleLL.md) campaign will be deployed. + +_Reverts if the requirements from +[createMerkleLL](/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleLL.md#createmerklell) are +not met._ + +```solidity +function computeMerkleLL( + address campaignCreator, + MerkleLL.ConstructorParams memory params +) + external + view + returns (address merkleLL); +``` + +### createMerkleLL + +Creates a new Merkle Lockup campaign with a Lockup Linear distribution. + +\*Emits a +[CreateMerkleLL](/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleLL.md#createmerklell) +event. Notes: + +- The contract is created with CREATE2. +- The campaign's fee will be set to the min USD fee unless a custom fee is set for `msg.sender`. +- A value of zero for `params.expiration` means the campaign does not expire. Requirements: +- `params.token` must not be the forbidden native token.\* + +```solidity +function createMerkleLL( + MerkleLL.ConstructorParams memory params, + uint256 aggregateAmount, + uint256 recipientCount +) + external + returns (ISablierMerkleLL merkleLL); +``` + +**Parameters** + +| Name | Type | Description | +| ----------------- | ---------------------------- | ------------------------------------------------------------------------------- | +| `params` | `MerkleLL.ConstructorParams` | Struct encapsulating the input parameters, which are documented in {DataTypes}. | +| `aggregateAmount` | `uint256` | The total amount of ERC-20 tokens to be distributed to all recipients. | +| `recipientCount` | `uint256` | The total number of recipient addresses eligible for the airdrop. | + +**Returns** + +| Name | Type | Description | +| ---------- | ------------------ | -------------------------------------------------------- | +| `merkleLL` | `ISablierMerkleLL` | The address of the newly created Merkle Lockup contract. | + +## Events + +### CreateMerkleLL + +Emitted when a [SablierMerkleLL](/docs/reference/airdrops/contracts/contract.SablierMerkleLL.md) campaign is created. + +```solidity +event CreateMerkleLL( + ISablierMerkleLL indexed merkleLL, + MerkleLL.ConstructorParams params, + uint256 aggregateAmount, + uint256 recipientCount, + address comptroller, + uint256 minFeeUSD +); +``` diff --git a/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleLT.md b/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleLT.md new file mode 100644 index 00000000..99f608ca --- /dev/null +++ b/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleLT.md @@ -0,0 +1,110 @@ +# ISablierFactoryMerkleLT + +[Git Source](https://github.com/sablier-labs/airdrops/blob/077c6b9766ef7693ba9e82a9e001dc0097709c01/src/interfaces/ISablierFactoryMerkleLT.sol) + +**Inherits:** +[ISablierFactoryMerkleBase](/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleBase.md) + +A factory that deploys MerkleLT campaign contracts. + +_See the documentation in +[ISablierMerkleLT](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleLT.md)._ + +## Functions + +### isPercentagesSum100 + +Verifies if the sum of percentages in `tranches` equals 100%, i.e., 1e18. + +_This is a helper function for the frontend. It is not used anywhere in the contracts._ + +```solidity +function isPercentagesSum100(MerkleLT.TrancheWithPercentage[] calldata tranches) external pure returns (bool result); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | ---------------------------------- | ------------------------------------------------------ | +| `tranches` | `MerkleLT.TrancheWithPercentage[]` | The tranches with their respective unlock percentages. | + +**Returns** + +| Name | Type | Description | +| -------- | ------ | ------------------------------------------------------------ | +| `result` | `bool` | True if the sum of percentages equals 100%, otherwise false. | + +### computeMerkleLT + +Computes the deterministic address where +[SablierMerkleLT](/docs/reference/airdrops/contracts/contract.SablierMerkleLT.md) campaign will be deployed. + +_Reverts if the requirements from +[createMerkleLT](/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleLT.md#createmerklelt) are +not met._ + +```solidity +function computeMerkleLT( + address campaignCreator, + MerkleLT.ConstructorParams memory params +) + external + view + returns (address merkleLT); +``` + +### createMerkleLT + +Creates a new Merkle Lockup campaign with a Lockup Tranched distribution. + +\*Emits a +[CreateMerkleLT](/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleLT.md#createmerklelt) +event. Notes: + +- The contract is created with CREATE2. +- The campaign's fee will be set to the min USD fee unless a custom fee is set for `msg.sender`. +- A value of zero for `params.expiration` means the campaign does not expire. Requirements: +- `params.token` must not be the forbidden native token. +- The sum of percentages of the tranches must equal 100%.\* + +```solidity +function createMerkleLT( + MerkleLT.ConstructorParams memory params, + uint256 aggregateAmount, + uint256 recipientCount +) + external + returns (ISablierMerkleLT merkleLT); +``` + +**Parameters** + +| Name | Type | Description | +| ----------------- | ---------------------------- | ------------------------------------------------------------------------------- | +| `params` | `MerkleLT.ConstructorParams` | Struct encapsulating the input parameters, which are documented in {DataTypes}. | +| `aggregateAmount` | `uint256` | The total amount of ERC-20 tokens to be distributed to all recipients. | +| `recipientCount` | `uint256` | The total number of recipient addresses eligible for the airdrop. | + +**Returns** + +| Name | Type | Description | +| ---------- | ------------------ | -------------------------------------------------------- | +| `merkleLT` | `ISablierMerkleLT` | The address of the newly created Merkle Lockup contract. | + +## Events + +### CreateMerkleLT + +Emitted when a [SablierMerkleLT](/docs/reference/airdrops/contracts/contract.SablierMerkleLT.md) campaign is created. + +```solidity +event CreateMerkleLT( + ISablierMerkleLT indexed merkleLT, + MerkleLT.ConstructorParams params, + uint256 aggregateAmount, + uint256 totalDuration, + uint256 recipientCount, + address comptroller, + uint256 minFeeUSD +); +``` diff --git a/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleVCA.md b/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleVCA.md new file mode 100644 index 00000000..ac5dee83 --- /dev/null +++ b/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleVCA.md @@ -0,0 +1,92 @@ +# ISablierFactoryMerkleVCA + +[Git Source](https://github.com/sablier-labs/airdrops/blob/077c6b9766ef7693ba9e82a9e001dc0097709c01/src/interfaces/ISablierFactoryMerkleVCA.sol) + +**Inherits:** +[ISablierFactoryMerkleBase](/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleBase.md) + +A factory that deploys MerkleVCA campaign contracts. + +_See the documentation in +[ISablierMerkleVCA](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleVCA.md)._ + +## Functions + +### computeMerkleVCA + +Computes the deterministic address where +[SablierMerkleVCA](/docs/reference/airdrops/contracts/contract.SablierMerkleVCA.md) campaign will be deployed. + +_Reverts if the requirements from +[createMerkleVCA](/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleVCA.md#createmerklevca) +are not met._ + +```solidity +function computeMerkleVCA( + address campaignCreator, + MerkleVCA.ConstructorParams memory params +) + external + view + returns (address merkleVCA); +``` + +### createMerkleVCA + +Creates a new MerkleVCA campaign for variable distribution of tokens. + +\*Emits a +[CreateMerkleVCA](/docs/reference/airdrops/contracts/interfaces/interface.ISablierFactoryMerkleVCA.md#createmerklevca) +event. Notes: + +- The contract is created with CREATE2. +- The campaign's fee will be set to the min USD fee unless a custom fee is set for `msg.sender`. +- Users interested into funding the campaign before its deployment must meet the below requirements, otherwise the + campaign deployment will revert. Requirements: +- `params.token` must not be the forbidden native token. +- `params.expiration` must be greater than 0. +- `params.expiration` must be at least 1 week beyond the end time to ensure loyal recipients have enough time to claim. +- `params.vestingEndTime` must be greater than `params.vestingStartTime`. +- Both `params.vestingStartTime` and `params.vestingEndTime` must be greater than 0. +- `params.unlockPercentage` must not be greater than 1e18, equivalent to 100%.\* + +```solidity +function createMerkleVCA( + MerkleVCA.ConstructorParams memory params, + uint256 aggregateAmount, + uint256 recipientCount +) + external + returns (ISablierMerkleVCA merkleVCA); +``` + +**Parameters** + +| Name | Type | Description | +| ----------------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `params` | `MerkleVCA.ConstructorParams` | Struct encapsulating the [SablierMerkleVCA](/docs/reference/airdrops/contracts/contract.SablierMerkleVCA.md) parameters, which are documented in {DataTypes}. | +| `aggregateAmount` | `uint256` | The total amount of ERC-20 tokens to be distributed to all recipients. | +| `recipientCount` | `uint256` | The total number of recipient addresses eligible for the airdrop. | + +**Returns** + +| Name | Type | Description | +| ----------- | ------------------- | ---------------------------------------------------- | +| `merkleVCA` | `ISablierMerkleVCA` | The address of the newly created MerkleVCA campaign. | + +## Events + +### CreateMerkleVCA + +Emitted when a [SablierMerkleVCA](/docs/reference/airdrops/contracts/contract.SablierMerkleVCA.md) campaign is created. + +```solidity +event CreateMerkleVCA( + ISablierMerkleVCA indexed merkleVCA, + MerkleVCA.ConstructorParams params, + uint256 aggregateAmount, + uint256 recipientCount, + address comptroller, + uint256 minFeeUSD +); +``` diff --git a/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleBase.md b/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleBase.md index 8aeb5e84..7f356007 100644 --- a/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleBase.md +++ b/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleBase.md @@ -1,38 +1,49 @@ # ISablierMerkleBase -[Git Source](https://github.com/sablier-labs/airdrops/blob/f9a358c0a5bccfec77601d4490ef9117e0488068/src/interfaces/ISablierMerkleBase.sol) +[Git Source](https://github.com/sablier-labs/airdrops/blob/077c6b9766ef7693ba9e82a9e001dc0097709c01/src/interfaces/ISablierMerkleBase.sol) **Inherits:** IAdminable -_Common interface between Merkle Lockups and Merkle Instant._ +_Common interface between campaign contracts._ ## Functions -### EXPIRATION +### CAMPAIGN_START_TIME -The cut-off point for the campaign, as a Unix timestamp. A value of zero means there is no expiration. +The timestamp at which campaign starts and claim begins. _This is an immutable state variable._ ```solidity -function EXPIRATION() external returns (uint40); +function CAMPAIGN_START_TIME() external view returns (uint40); +``` + +### COMPTROLLER + +Retrieves the address of the comptroller contract. + +```solidity +function COMPTROLLER() external view returns (address); ``` -### FACTORY +### EXPIRATION + +The cut-off point for the campaign, as a Unix timestamp. A value of zero means there is no expiration. -Retrieves the address of the factory contract. +_This is an immutable state variable._ ```solidity -function FACTORY() external view returns (address); +function EXPIRATION() external view returns (uint40); ``` -### FEE +### IS_SABLIER_MERKLE + +Returns `true` indicating that this campaign contract is deployed using the Sablier Factory. -Retrieves the minimum fee required to claim the airdrop, which is paid in the native token of the chain, e.g. ETH for -Ethereum Mainnet. +_This is a constant state variable._ ```solidity -function FEE() external view returns (uint256); +function IS_SABLIER_MERKLE() external view returns (bool); ``` ### MERKLE_ROOT @@ -42,7 +53,7 @@ The root of the Merkle tree used to validate the proofs of inclusion. _This is an immutable state variable._ ```solidity -function MERKLE_ROOT() external returns (bytes32); +function MERKLE_ROOT() external view returns (bytes32); ``` ### TOKEN @@ -52,7 +63,15 @@ The ERC-20 token to distribute. _This is an immutable state variable._ ```solidity -function TOKEN() external returns (IERC20); +function TOKEN() external view returns (IERC20); +``` + +### calculateMinFeeWei + +Calculates the minimum fee in wei required to claim the airdrop. + +```solidity +function calculateMinFeeWei() external view returns (uint256); ``` ### campaignName @@ -63,12 +82,21 @@ Retrieves the name of the campaign. function campaignName() external view returns (string memory); ``` -### getFirstClaimTime +### domainSeparator + +The domain separator, as required by EIP-712 and EIP-1271, used for signing claim to prevent replay attacks across +different campaigns. + +```solidity +function domainSeparator() external view returns (bytes32); +``` + +### firstClaimTime -Returns the timestamp when the first claim is made. +Retrieves the timestamp when the first claim is made, and zero if no claim was made yet. ```solidity -function getFirstClaimTime() external view returns (uint40); +function firstClaimTime() external view returns (uint40); ``` ### hasClaimed @@ -78,7 +106,7 @@ Returns a flag indicating whether a claim has been made for a given index. _Uses a bitmap to save gas._ ```solidity -function hasClaimed(uint256 index) external returns (bool); +function hasClaimed(uint256 index) external view returns (bool); ``` **Parameters** @@ -99,53 +127,32 @@ function hasExpired() external view returns (bool); The content identifier for indexing the campaign on IPFS. -```solidity -function ipfsCID() external view returns (string memory); -``` - -### shape - -Retrieves the shape of the lockup stream that the campaign produces upon claiming. +_An empty value may break certain UI features that depend upon the IPFS CID._ ```solidity -function shape() external view returns (string memory); +function ipfsCID() external view returns (string memory); ``` -### claim +### minFeeUSD -Makes the claim. +Retrieves the min USD fee required to claim the airdrop, denominated in 8 decimals. -Depending on the Merkle campaign, it either transfers tokens to the recipient or creates a Lockup stream with an NFT -minted to the recipient. Requirements: - -- The campaign must not have expired. -- The stream must not have been claimed already. -- The Merkle proof must be valid. -- The `msg.value` must not be less than `FEE`. +_The denomination is based on Chainlink's 8-decimal format for USD prices, where 1e8 is $1._ ```solidity -function claim(uint256 index, address recipient, uint128 amount, bytes32[] calldata merkleProof) external payable; +function minFeeUSD() external view returns (uint256); ``` -**Parameters** - -| Name | Type | Description | -| ------------- | ----------- | --------------------------------------------------------------- | -| `index` | `uint256` | The index of the recipient in the Merkle tree. | -| `recipient` | `address` | The address of the airdrop recipient. | -| `amount` | `uint128` | The amount of ERC-20 tokens to be transferred to the recipient. | -| `merkleProof` | `bytes32[]` | The proof of inclusion in the Merkle tree. | - ### clawback -Claws back the unclaimed tokens from the campaign. +Claws back the unclaimed tokens. -Emits a [Clawback](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleBase.md#clawback) event. +\*Emits a [Clawback](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleBase.md#clawback) event. Requirements: - `msg.sender` must be the admin. - No claim must be made, OR The current timestamp must not exceed 7 days after the first claim, OR The campaign must be - expired. + expired.\* ```solidity function clawback(address to, uint128 amount) external; @@ -158,27 +165,25 @@ function clawback(address to, uint128 amount) external; | `to` | `address` | The address to receive the tokens. | | `amount` | `uint128` | The amount of tokens to claw back. | -### collectFees +### lowerMinFeeUSD + +Lowers the min USD fee. -Collects the accrued fees by transferring them to `FACTORY` admin. Requirements: +\*Emits a [LowerMinFeeUSD](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleBase.md#lowerminfeeusd) +event. Requirements: -- `msg.sender` must be the `FACTORY` contract. +- `msg.sender` must be the comptroller. +- The new fee must be less than the current {minFeeUSD}.\* ```solidity -function collectFees(address factoryAdmin) external returns (uint256 feeAmount); +function lowerMinFeeUSD(uint256 newMinFeeUSD) external; ``` **Parameters** -| Name | Type | Description | -| -------------- | --------- | ----------------------------------- | -| `factoryAdmin` | `address` | The address of the `FACTORY` admin. | - -**Returns** - -| Name | Type | Description | -| ----------- | --------- | ---------------------------------------------------------- | -| `feeAmount` | `uint256` | The amount of native tokens (e.g., ETH) collected as fees. | +| Name | Type | Description | +| -------------- | --------- | ------------------------------------------------------ | +| `newMinFeeUSD` | `uint256` | The new min USD fee to set, denominated in 8 decimals. | ## Events @@ -189,3 +194,11 @@ Emitted when the admin claws back the unclaimed tokens. ```solidity event Clawback(address indexed admin, address indexed to, uint128 amount); ``` + +### LowerMinFeeUSD + +Emitted when the min USD fee is lowered by the comptroller. + +```solidity +event LowerMinFeeUSD(address indexed comptroller, uint256 newMinFeeUSD, uint256 previousMinFeeUSD); +``` diff --git a/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleFactory.md b/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleFactory.md deleted file mode 100644 index 4376da46..00000000 --- a/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleFactory.md +++ /dev/null @@ -1,370 +0,0 @@ -# ISablierMerkleFactory - -[Git Source](https://github.com/sablier-labs/airdrops/blob/f9a358c0a5bccfec77601d4490ef9117e0488068/src/interfaces/ISablierMerkleFactory.sol) - -**Inherits:** IAdminable - -A contract that deploys Merkle Lockups and Merkle Instant campaigns. Both use Merkle proofs for token distribution. -Merkle Lockup enable Airstreams, a portmanteau of "airdrop" and "stream", an airdrop model where the tokens are -distributed over time, as opposed to all at once. On the other hand, Merkle Instant enables instant airdrops where -tokens are unlocked and distributed immediately. See the Sablier docs for more guidance: https://docs.sablier.com - -_The contracts are deployed using CREATE2._ - -## Functions - -### defaultFee - -Retrieves the default fee charged for claiming an airdrop. - -_The fee is denominated in the native token of the chain, e.g., ETH for Ethereum Mainnet._ - -```solidity -function defaultFee() external view returns (uint256); -``` - -### getCustomFee - -Retrieves the custom fee struct for the provided campaign creator. - -_The fee is denominated in the native token of the chain, e.g., ETH for Ethereum Mainnet._ - -```solidity -function getCustomFee(address campaignCreator) external view returns (MerkleFactory.CustomFee memory); -``` - -**Parameters** - -| Name | Type | Description | -| ----------------- | --------- | ------------------------------------ | -| `campaignCreator` | `address` | The address of the campaign creator. | - -### getFee - -Retrieves the fee for the provided campaign creator, using the default fee if no custom fee is set. - -_The fee is denominated in the native token of the chain, e.g., ETH for Ethereum Mainnet._ - -```solidity -function getFee(address campaignCreator) external view returns (uint256); -``` - -**Parameters** - -| Name | Type | Description | -| ----------------- | --------- | ------------------------------------ | -| `campaignCreator` | `address` | The address of the campaign creator. | - -### isPercentagesSum100 - -Verifies if the sum of percentages in `tranches` equals 100%, i.e., 1e18. - -_This is a helper function for the frontend. It is not used anywhere in the contracts._ - -```solidity -function isPercentagesSum100(MerkleLT.TrancheWithPercentage[] calldata tranches) external pure returns (bool result); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | ---------------------------------- | ------------------------------------------------------ | -| `tranches` | `MerkleLT.TrancheWithPercentage[]` | The tranches with their respective unlock percentages. | - -**Returns** - -| Name | Type | Description | -| -------- | ------ | ------------------------------------------------------------ | -| `result` | `bool` | True if the sum of percentages equals 100%, otherwise false. | - -### collectFees - -Collects the fees accrued in the `merkleBase` contract, and transfers them to the factory admin. - -Emits a [CollectFees](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleFactory.md#collectfees) -event. Notes: - -- If the admin is a contract, it must be able to receive native token payments, e.g., ETH for Ethereum Mainnet. - -```solidity -function collectFees(ISablierMerkleBase merkleBase) external; -``` - -**Parameters** - -| Name | Type | Description | -| ------------ | -------------------- | --------------------------------------------------------------------- | -| `merkleBase` | `ISablierMerkleBase` | The address of the Merkle contract where the fees are collected from. | - -### createMerkleInstant - -Creates a new MerkleInstant campaign for instant distribution of tokens. - -Emits a -[CreateMerkleInstant](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleFactory.md#createmerkleinstant) -event. Notes: - -- The MerkleInstant contract is created with CREATE2. -- The immutable fee will be set to the default value unless a custom fee is set. - -```solidity -function createMerkleInstant( - MerkleBase.ConstructorParams memory baseParams, - uint256 aggregateAmount, - uint256 recipientCount -) - external - returns (ISablierMerkleInstant merkleInstant); -``` - -**Parameters** - -| Name | Type | Description | -| ----------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `baseParams` | `MerkleBase.ConstructorParams` | Struct encapsulating the [SablierMerkleBase](docs/reference/airdrops/contracts/abstracts/abstract.SablierMerkleBase.md) parameters, which are documented in {DataTypes}. | -| `aggregateAmount` | `uint256` | The total amount of ERC-20 tokens to be distributed to all recipients. | -| `recipientCount` | `uint256` | The total number of recipients who are eligible to claim. | - -**Returns** - -| Name | Type | Description | -| --------------- | ----------------------- | -------------------------------------------------------- | -| `merkleInstant` | `ISablierMerkleInstant` | The address of the newly created MerkleInstant contract. | - -### createMerkleLL - -Creates a new Merkle Lockup campaign with a Lockup Linear distribution. - -Emits a -[CreateMerkleLL](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleFactory.md#createmerklell) event. -Notes: - -- The MerkleLL contract is created with CREATE2. -- The immutable fee will be set to the default value unless a custom fee is set. - -```solidity -function createMerkleLL( - MerkleBase.ConstructorParams memory baseParams, - ISablierLockup lockup, - bool cancelable, - bool transferable, - MerkleLL.Schedule memory schedule, - uint256 aggregateAmount, - uint256 recipientCount -) - external - returns (ISablierMerkleLL merkleLL); -``` - -**Parameters** - -| Name | Type | Description | -| ----------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `baseParams` | `MerkleBase.ConstructorParams` | Struct encapsulating the [SablierMerkleBase](docs/reference/airdrops/contracts/abstracts/abstract.SablierMerkleBase.md) parameters, which are documented in {DataTypes}. | -| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/reference/lockup/contracts/contract.SablierLockup.md) contract. | -| `cancelable` | `bool` | Indicates if the stream will be cancelable after claiming. | -| `transferable` | `bool` | Indicates if the stream will be transferable after claiming. | -| `schedule` | `MerkleLL.Schedule` | Struct encapsulating the unlocks schedule, which are documented in {DataTypes}. | -| `aggregateAmount` | `uint256` | The total amount of ERC-20 tokens to be distributed to all recipients. | -| `recipientCount` | `uint256` | The total number of recipients who are eligible to claim. | - -**Returns** - -| Name | Type | Description | -| ---------- | ------------------ | -------------------------------------------------------- | -| `merkleLL` | `ISablierMerkleLL` | The address of the newly created Merkle Lockup contract. | - -### createMerkleLT - -Creates a new Merkle Lockup campaign with a Lockup Tranched distribution. - -Emits a -[CreateMerkleLT](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleFactory.md#createmerklelt) event. -Notes: - -- The MerkleLT contract is created with CREATE2. -- The immutable fee will be set to the default value unless a custom fee is set. - -```solidity -function createMerkleLT( - MerkleBase.ConstructorParams memory baseParams, - ISablierLockup lockup, - bool cancelable, - bool transferable, - uint40 streamStartTime, - MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages, - uint256 aggregateAmount, - uint256 recipientCount -) - external - returns (ISablierMerkleLT merkleLT); -``` - -**Parameters** - -| Name | Type | Description | -| ------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `baseParams` | `MerkleBase.ConstructorParams` | Struct encapsulating the [SablierMerkleBase](docs/reference/airdrops/contracts/abstracts/abstract.SablierMerkleBase.md) parameters, which are documented in {DataTypes}. | -| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/reference/lockup/contracts/contract.SablierLockup.md) contract. | -| `cancelable` | `bool` | Indicates if the stream will be cancelable after claiming. | -| `transferable` | `bool` | Indicates if the stream will be transferable after claiming. | -| `streamStartTime` | `uint40` | The start time of the streams created through {SablierMerkleBase.claim}. | -| `tranchesWithPercentages` | `MerkleLT.TrancheWithPercentage[]` | The tranches with their respective unlock percentages. | -| `aggregateAmount` | `uint256` | The total amount of ERC-20 tokens to be distributed to all recipients. | -| `recipientCount` | `uint256` | The total number of recipients who are eligible to claim. | - -**Returns** - -| Name | Type | Description | -| ---------- | ------------------ | -------------------------------------------------------- | -| `merkleLT` | `ISablierMerkleLT` | The address of the newly created Merkle Lockup contract. | - -### resetCustomFee - -Resets the custom fee for the provided campaign creator to the default fee. - -Emits a -[ResetCustomFee](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleFactory.md#resetcustomfee) event. -Notes: - -- The default fee will only be applied to future campaigns. Requirements: -- `msg.sender` must be the admin. - -```solidity -function resetCustomFee(address campaignCreator) external; -``` - -**Parameters** - -| Name | Type | Description | -| ----------------- | --------- | --------------------------------------- | -| `campaignCreator` | `address` | The user for whom the fee is reset for. | - -### setCustomFee - -Sets a custom fee for the provided campaign creator. - -Emits a [SetCustomFee](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleFactory.md#setcustomfee) -event. Notes: - -- The new fee will only be applied to future campaigns. Requirements: -- `msg.sender` must be the admin. - -```solidity -function setCustomFee(address campaignCreator, uint256 newFee) external; -``` - -**Parameters** - -| Name | Type | Description | -| ----------------- | --------- | --------------------------------- | -| `campaignCreator` | `address` | The user for whom the fee is set. | -| `newFee` | `uint256` | The new fee to be set. | - -### setDefaultFee - -Sets the default fee to be applied when claiming airdrops. - -Emits a [SetDefaultFee](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleFactory.md#setdefaultfee) -event. Notes: - -- The new default fee will only be applied to the future campaigns and will not affect the ones already deployed. - Requirements: -- `msg.sender` must be the admin. - -```solidity -function setDefaultFee(uint256 defaultFee) external; -``` - -**Parameters** - -| Name | Type | Description | -| ------------ | --------- | ------------------------------ | -| `defaultFee` | `uint256` | The new default fee to be set. | - -## Events - -### CollectFees - -Emitted when the accrued fees are collected. - -```solidity -event CollectFees(address indexed admin, ISablierMerkleBase indexed merkleBase, uint256 feeAmount); -``` - -### CreateMerkleInstant - -Emitted when a [SablierMerkleInstant](/docs/reference/airdrops/contracts/contract.SablierMerkleInstant.md) campaign is -created. - -```solidity -event CreateMerkleInstant( - ISablierMerkleInstant indexed merkleInstant, - MerkleBase.ConstructorParams baseParams, - uint256 aggregateAmount, - uint256 recipientCount, - uint256 fee -); -``` - -### CreateMerkleLL - -Emitted when a [SablierMerkleLL](/docs/reference/airdrops/contracts/contract.SablierMerkleLL.md) campaign is created. - -```solidity -event CreateMerkleLL( - ISablierMerkleLL indexed merkleLL, - MerkleBase.ConstructorParams baseParams, - ISablierLockup lockup, - bool cancelable, - bool transferable, - MerkleLL.Schedule schedule, - uint256 aggregateAmount, - uint256 recipientCount, - uint256 fee -); -``` - -### CreateMerkleLT - -Emitted when a [SablierMerkleLT](/docs/reference/airdrops/contracts/contract.SablierMerkleLT.md) campaign is created. - -```solidity -event CreateMerkleLT( - ISablierMerkleLT indexed merkleLT, - MerkleBase.ConstructorParams baseParams, - ISablierLockup lockup, - bool cancelable, - bool transferable, - uint40 streamStartTime, - MerkleLT.TrancheWithPercentage[] tranchesWithPercentages, - uint256 totalDuration, - uint256 aggregateAmount, - uint256 recipientCount, - uint256 fee -); -``` - -### ResetCustomFee - -Emitted when the admin resets the custom fee for the provided campaign creator to the default fee. - -```solidity -event ResetCustomFee(address indexed admin, address indexed campaignCreator); -``` - -### SetCustomFee - -Emitted when the admin sets a custom fee for the provided campaign creator. - -```solidity -event SetCustomFee(address indexed admin, address indexed campaignCreator, uint256 customFee); -``` - -### SetDefaultFee - -Emitted when the default fee is set by the admin. - -```solidity -event SetDefaultFee(address indexed admin, uint256 defaultFee); -``` diff --git a/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleInstant.md b/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleInstant.md index 302fd3a4..1b3c84f5 100644 --- a/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleInstant.md +++ b/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleInstant.md @@ -1,17 +1,153 @@ # ISablierMerkleInstant -[Git Source](https://github.com/sablier-labs/airdrops/blob/f9a358c0a5bccfec77601d4490ef9117e0488068/src/interfaces/ISablierMerkleInstant.sol) +[Git Source](https://github.com/sablier-labs/airdrops/blob/077c6b9766ef7693ba9e82a9e001dc0097709c01/src/interfaces/ISablierMerkleInstant.sol) **Inherits:** [ISablierMerkleBase](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleBase.md) -MerkleInstant enables airdrop distributions where the tokens are claimed directly to the users' wallets. +MerkleInstant enables an airdrop model where eligible users receive the tokens as soon as they claim. + +## Functions + +### claim + +Claim airdrop on behalf of eligible recipient and transfer it to the recipient address. + +\*It emits a +[ClaimInstant](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleInstant.md#claiminstant) event. +Requirements: + +- The current time must be greater than or equal to the campaign start time. +- The campaign must not have expired. +- `msg.value` must not be less than the value returned by {COMPTROLLER.calculateMinFeeWei}. +- The `index` must not be claimed already. +- The Merkle proof must be valid.\* + +```solidity +function claim(uint256 index, address recipient, uint128 amount, bytes32[] calldata merkleProof) external payable; +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | ----------- | ------------------------------------------------------- | +| `index` | `uint256` | The index of the recipient in the Merkle tree. | +| `recipient` | `address` | The address of the airdrop recipient. | +| `amount` | `uint128` | The amount of ERC-20 tokens allocated to the recipient. | +| `merkleProof` | `bytes32[]` | The proof of inclusion in the Merkle tree. | + +### claimTo + +Claim airdrop and transfer the tokens to the `to` address. + +\*It emits a +[ClaimInstant](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleInstant.md#claiminstant) event. +Requirements: + +- `msg.sender` must be the airdrop recipient. +- The `to` must not be the zero address. +- Refer to the requirements in {claim}.\* + +```solidity +function claimTo(uint256 index, address to, uint128 amount, bytes32[] calldata merkleProof) external payable; +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | ----------- | ------------------------------------------------------------------ | +| `index` | `uint256` | The index of the `msg.sender` in the Merkle tree. | +| `to` | `address` | The address receiving the ERC-20 tokens on behalf of `msg.sender`. | +| `amount` | `uint128` | The amount of ERC-20 tokens allocated to the `msg.sender`. | +| `merkleProof` | `bytes32[]` | The proof of inclusion in the Merkle tree. | + +### claimViaSig + +Claim airdrop on behalf of eligible recipient using an EIP-712 or EIP-1271 signature, and transfer the tokens to the +`to` address. + +\*It emits a +[ClaimInstant](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleInstant.md#claiminstant) event. +Requirements: + +- If `recipient` is an EOA, it must match the recovered signer. +- If `recipient` is a contract, it must implement the IERC-1271 interface. +- The `to` must not be the zero address. +- The `validFrom` must be less than or equal to the current block timestamp. +- Refer to the requirements in {claim}. Below is the example of typed data to be signed by the airdrop recipient, + referenced from https://docs.metamask.io/wallet/how-to/sign-data/#example. + +```json +types: { +EIP712Domain: [ +{ name: "name", type: "string" }, +{ name: "chainId", type: "uint256" }, +{ name: "verifyingContract", type: "address" }, +], +Claim: [ +{ name: "index", type: "uint256" }, +{ name: "recipient", type: "address" }, +{ name: "to", type: "address" }, +{ name: "amount", type: "uint128" }, +{ name: "validFrom", type: "uint40" }, +], +}, +domain: { +name: "Sablier Airdrops Protocol", +chainId: 1, // Chain on which the contract is deployed +verifyingContract: "0xTheAddressOfThisContract", // The address of this contract +}, +primaryType: "Claim", +message: { +index: 2, // The index of the signer in the Merkle tree +recipient: "0xTheAddressOfTheRecipient", // The address of the airdrop recipient +to: "0xTheAddressReceivingTheTokens", // The address where recipient wants to transfer the tokens +amount: "1000000000000000000000", // The amount of tokens allocated to the recipient +validFrom: 1752425637 // The timestamp from which the claim signature is valid +}, +``` + +```solidity +function claimViaSig( + uint256 index, + address recipient, + address to, + uint128 amount, + uint40 validFrom, + bytes32[] calldata merkleProof, + bytes calldata signature +) + external + payable; +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | ----------- | -------------------------------------------------------------------- | +| `index` | `uint256` | The index of the recipient in the Merkle tree. | +| `recipient` | `address` | The address of the airdrop recipient who is providing the signature. | +| `to` | `address` | The address receiving the ERC-20 tokens on behalf of the recipient. | +| `amount` | `uint128` | The amount of ERC-20 tokens allocated to the recipient. | +| `validFrom` | `uint40` | The timestamp from which the claim signature is valid. | +| `merkleProof` | `bytes32[]` | The proof of inclusion in the Merkle tree. | +| `signature` | `bytes` | The EIP-712 or EIP-1271 signature from the airdrop recipient. | ## Events -### Claim +### ClaimInstant -Emitted when a recipient claims an instant airdrop. +Emitted when an airdrop is claimed on behalf of an eligible recipient. ```solidity -event Claim(uint256 index, address indexed recipient, uint128 amount); +event ClaimInstant(uint256 index, address indexed recipient, uint128 amount, address to, bool viaSig); ``` + +**Parameters** + +| Name | Type | Description | +| ----------- | --------- | -------------------------------------------------------------------------- | +| `index` | `uint256` | The index of the airdrop recipient in the Merkle tree. | +| `recipient` | `address` | The address of the airdrop recipient. | +| `amount` | `uint128` | The amount of ERC-20 tokens claimed. | +| `to` | `address` | The address receiving the claim amount on behalf of the airdrop recipient. | +| `viaSig` | `bool` | Bool indicating whether the claim is made via a signature. | diff --git a/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleLL.md b/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleLL.md index f534e3fc..dc311274 100644 --- a/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleLL.md +++ b/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleLL.md @@ -1,58 +1,220 @@ # ISablierMerkleLL -[Git Source](https://github.com/sablier-labs/airdrops/blob/f9a358c0a5bccfec77601d4490ef9117e0488068/src/interfaces/ISablierMerkleLL.sol) +[Git Source](https://github.com/sablier-labs/airdrops/blob/077c6b9766ef7693ba9e82a9e001dc0097709c01/src/interfaces/ISablierMerkleLL.sol) -**Inherits:** [ISablierMerkleBase](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleBase.md) +**Inherits:** [ISablierMerkleLockup](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleLockup.md) -Merkle Lockup enables airdrops with a vesting period powered by the Lockup Linear distribution model. +MerkleLL enables an airdrop model with a vesting period powered by the Lockup Linear model. ## Functions -### LOCKUP +### VESTING_CLIFF_DURATION -The address of the [SablierLockup](/reference/lockup/contracts/contract.SablierLockup.md) contract. +Retrieves the cliff duration of the vesting stream, in seconds. ```solidity -function LOCKUP() external view returns (ISablierLockup); +function VESTING_CLIFF_DURATION() external view returns (uint40); ``` -### STREAM_CANCELABLE +### VESTING_CLIFF_UNLOCK_PERCENTAGE -A flag indicating whether the streams can be canceled. +Retrieves the percentage of the claim amount due to be unlocked at the vesting cliff time, as a fixed-point number where +1e18 is 100%. -_This is an immutable state variable._ +```solidity +function VESTING_CLIFF_UNLOCK_PERCENTAGE() external view returns (UD60x18); +``` + +### VESTING_START_TIME + +Retrieves the start time of the vesting stream, as a Unix timestamp. Zero is a sentinel value for `block.timestamp`. ```solidity -function STREAM_CANCELABLE() external returns (bool); +function VESTING_START_TIME() external view returns (uint40); ``` -### STREAM_TRANSFERABLE +### VESTING_START_UNLOCK_PERCENTAGE -A flag indicating whether the stream NFTs are transferable. +Retrieves the percentage of the claim amount due to be unlocked at the vesting start time, as a fixed-point number where +1e18 is 100%. -_This is an immutable state variable._ +```solidity +function VESTING_START_UNLOCK_PERCENTAGE() external view returns (UD60x18); +``` + +### VESTING_TOTAL_DURATION + +Retrieves the total duration of the vesting stream, in seconds. ```solidity -function STREAM_TRANSFERABLE() external returns (bool); +function VESTING_TOTAL_DURATION() external view returns (uint40); ``` -### getSchedule +### claim + +Claim airdrop on behalf of eligible recipient. If the vesting end time is in the future, it creates a Lockup Linear +stream, otherwise it transfers the tokens directly to the recipient address. + +\*It emits either +[ClaimLLWithTransfer](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleLL.md#claimllwithtransfer) +or {ClaimLLWithVesting} event. Requirements: + +- The current time must be greater than or equal to the campaign start time. +- The campaign must not have expired. +- `msg.value` must not be less than the value returned by {COMPTROLLER.calculateMinFeeWei}. +- The `index` must not be claimed already. +- The Merkle proof must be valid. +- All requirements from {ISablierLockupLinear.createWithTimestampsLL} must be met.\* + +```solidity +function claim(uint256 index, address recipient, uint128 amount, bytes32[] calldata merkleProof) external payable; +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | ----------- | ------------------------------------------------------- | +| `index` | `uint256` | The index of the recipient in the Merkle tree. | +| `recipient` | `address` | The address of the airdrop recipient. | +| `amount` | `uint128` | The amount of ERC-20 tokens allocated to the recipient. | +| `merkleProof` | `bytes32[]` | The proof of inclusion in the Merkle tree. | + +### claimTo -A tuple containing the start time, start unlock percentage, cliff duration, cliff unlock percentage, and end duration. -These values are used to calculate the vesting schedule in `Lockup.CreateWithTimestampsLL`. +Claim airdrop. If the vesting end time is in the future, it creates a Lockup Linear stream with `to` address as the +stream recipient, otherwise it transfers the tokens directly to the `to` address. -_A start time value of zero will be considered as `block.timestamp`._ +\*It emits either +[ClaimLLWithTransfer](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleLL.md#claimllwithtransfer) +or {ClaimLLWithVesting} event. Requirements: + +- `msg.sender` must be the airdrop recipient. +- The `to` must not be the zero address. +- Refer to the requirements in {claim}.\* ```solidity -function getSchedule() external view returns (MerkleLL.Schedule memory); +function claimTo(uint256 index, address to, uint128 amount, bytes32[] calldata merkleProof) external payable; +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | ----------- | ------------------------------------------------------------------------------------------- | +| `index` | `uint256` | The index of the `msg.sender` in the Merkle tree. | +| `to` | `address` | The address to which Lockup stream or ERC-20 tokens will be sent on behalf of `msg.sender`. | +| `amount` | `uint128` | The amount of ERC-20 tokens allocated to the `msg.sender`. | +| `merkleProof` | `bytes32[]` | The proof of inclusion in the Merkle tree. | + +### claimViaSig + +Claim airdrop on behalf of eligible recipient using an EIP-712 or EIP-1271 signature. If the vesting end time is in the +future, it creates a Lockup Linear stream with `to` address as the stream recipient, otherwise it transfers the tokens +directly to the `to` address. + +\*It emits either +[ClaimLLWithTransfer](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleLL.md#claimllwithtransfer) +or {ClaimLLWithVesting} event. Requirements: + +- If `recipient` is an EOA, it must match the recovered signer. +- If `recipient` is a contract, it must implement the IERC-1271 interface. +- The `to` must not be the zero address. +- The `validFrom` must be less than or equal to the current block timestamp. +- Refer to the requirements in {claim}. Below is the example of typed data to be signed by the airdrop recipient, + referenced from https://docs.metamask.io/wallet/how-to/sign-data/#example. + +```json +types: { +EIP712Domain: [ +{ name: "name", type: "string" }, +{ name: "chainId", type: "uint256" }, +{ name: "verifyingContract", type: "address" }, +], +Claim: [ +{ name: "index", type: "uint256" }, +{ name: "recipient", type: "address" }, +{ name: "to", type: "address" }, +{ name: "amount", type: "uint128" }, +{ name: "validFrom", type: "uint40" }, +], +}, +domain: { +name: "Sablier Airdrops Protocol", +chainId: 1, // Chain on which the contract is deployed +verifyingContract: "0xTheAddressOfThisContract", // The address of this contract +}, +primaryType: "Claim", +message: { +index: 2, // The index of the signer in the Merkle tree +recipient: "0xTheAddressOfTheRecipient", // The address of the airdrop recipient +to: "0xTheAddressReceivingTheTokens", // The address where recipient wants to transfer the tokens +amount: "1000000000000000000000", // The amount of tokens allocated to the recipient +validFrom: 1752425637 // The timestamp from which the claim signature is valid +}, ``` +```solidity +function claimViaSig( + uint256 index, + address recipient, + address to, + uint128 amount, + uint40 validFrom, + bytes32[] calldata merkleProof, + bytes calldata signature +) + external + payable; +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | ----------- | -------------------------------------------------------------------------------------------- | +| `index` | `uint256` | The index of the recipient in the Merkle tree. | +| `recipient` | `address` | The address of the airdrop recipient who is providing the signature. | +| `to` | `address` | The address to which Lockup stream or ERC-20 tokens will be sent on behalf of the recipient. | +| `amount` | `uint128` | The amount of ERC-20 tokens allocated to the recipient. | +| `validFrom` | `uint40` | The timestamp from which the claim signature is valid. | +| `merkleProof` | `bytes32[]` | The proof of inclusion in the Merkle tree. | +| `signature` | `bytes` | The EIP-712 or EIP-1271 signature from the airdrop recipient. | + ## Events -### Claim +### ClaimLLWithTransfer -Emitted when a recipient claims a stream. +Emitted when an airdrop is claimed using direct transfer on behalf of an eligible recipient. ```solidity -event Claim(uint256 index, address indexed recipient, uint128 amount, uint256 indexed streamId); +event ClaimLLWithTransfer(uint256 index, address indexed recipient, uint128 amount, address to, bool viaSig); ``` + +**Parameters** + +| Name | Type | Description | +| ----------- | --------- | -------------------------------------------------------------------------- | +| `index` | `uint256` | The index of the airdrop recipient in the Merkle tree. | +| `recipient` | `address` | The address of the airdrop recipient. | +| `amount` | `uint128` | The amount of ERC-20 tokens claimed using direct transfer. | +| `to` | `address` | The address receiving the claim amount on behalf of the airdrop recipient. | +| `viaSig` | `bool` | Bool indicating whether the claim is made via a signature. | + +### ClaimLLWithVesting + +Emitted when an airdrop is claimed using Lockup Linear stream on behalf of an eligible recipient. + +```solidity +event ClaimLLWithVesting( + uint256 index, address indexed recipient, uint128 amount, uint256 indexed streamId, address to, bool viaSig +); +``` + +**Parameters** + +| Name | Type | Description | +| ----------- | --------- | --------------------------------------------------------------------------- | +| `index` | `uint256` | The index of the airdrop recipient in the Merkle tree. | +| `recipient` | `address` | The address of the airdrop recipient. | +| `amount` | `uint128` | The amount of ERC-20 tokens claimed using Lockup Linear stream. | +| `streamId` | `uint256` | The ID of the Lockup stream. | +| `to` | `address` | The address receiving the Lockup stream on behalf of the airdrop recipient. | +| `viaSig` | `bool` | Bool indicating whether the claim is made via a signature. | diff --git a/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleLT.md b/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleLT.md index 7faee62a..0c363be1 100644 --- a/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleLT.md +++ b/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleLT.md @@ -1,73 +1,194 @@ # ISablierMerkleLT -[Git Source](https://github.com/sablier-labs/airdrops/blob/f9a358c0a5bccfec77601d4490ef9117e0488068/src/interfaces/ISablierMerkleLT.sol) +[Git Source](https://github.com/sablier-labs/airdrops/blob/077c6b9766ef7693ba9e82a9e001dc0097709c01/src/interfaces/ISablierMerkleLT.sol) -**Inherits:** [ISablierMerkleBase](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleBase.md) +**Inherits:** [ISablierMerkleLockup](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleLockup.md) -Merkle Lockup enables airdrops with a vesting period powered by the Lockup Tranched distribution model. +MerkleLT enables an airdrop model with a vesting period powered by the Lockup Tranched model. ## Functions -### LOCKUP +### VESTING_START_TIME -The address of the [SablierLockup](/reference/lockup/contracts/contract.SablierLockup.md) contract. +Retrieves the start time of the vesting stream, as a Unix timestamp. Zero is a sentinel value for `block.timestamp`. ```solidity -function LOCKUP() external view returns (ISablierLockup); +function VESTING_START_TIME() external view returns (uint40); ``` -### STREAM_CANCELABLE +### tranchesWithPercentages -A flag indicating whether the streams can be canceled. - -_This is an immutable state variable._ +Retrieves the tranches with their respective unlock percentages and durations. ```solidity -function STREAM_CANCELABLE() external returns (bool); +function tranchesWithPercentages() external view returns (MerkleLT.TrancheWithPercentage[] memory); ``` -### STREAM_START_TIME +### claim + +Claim airdrop on behalf of eligible recipient. If the vesting end time is in the future, it creates a Lockup Tranched +stream, otherwise it transfers the tokens directly to the recipient address. -The start time of the streams created through {SablierMerkleBase.claim} function. +\*It emits either +[ClaimLTWithTransfer](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleLT.md#claimltwithtransfer) +or {ClaimLTWithVesting} event. Requirements: -_A start time value of zero will be treated as `block.timestamp`._ +- The current time must be greater than or equal to the campaign start time. +- The campaign must not have expired. +- `msg.value` must not be less than the value returned by {COMPTROLLER.calculateMinFeeWei}. +- The `index` must not be claimed already. +- The Merkle proof must be valid. +- All requirements from {ISablierLockupTranched.createWithTimestampsLT} must be met.\* ```solidity -function STREAM_START_TIME() external returns (uint40); +function claim(uint256 index, address recipient, uint128 amount, bytes32[] calldata merkleProof) external payable; ``` -### STREAM_TRANSFERABLE +**Parameters** + +| Name | Type | Description | +| ------------- | ----------- | ------------------------------------------------------- | +| `index` | `uint256` | The index of the recipient in the Merkle tree. | +| `recipient` | `address` | The address of the airdrop recipient. | +| `amount` | `uint128` | The amount of ERC-20 tokens allocated to the recipient. | +| `merkleProof` | `bytes32[]` | The proof of inclusion in the Merkle tree. | + +### claimTo -A flag indicating whether the stream NFTs are transferable. +Claim airdrop. If the vesting end time is in the future, it creates a Lockup Tranched stream with `to` address as the +stream recipient, otherwise it transfers the tokens directly to the `to` address. -_This is an immutable state variable._ +\*It emits either +[ClaimLTWithTransfer](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleLT.md#claimltwithtransfer) +or {ClaimLTWithVesting} event. Requirements: + +- `msg.sender` must be the airdrop recipient. +- The `to` must not be the zero address. +- Refer to the requirements in {claim}.\* ```solidity -function STREAM_TRANSFERABLE() external returns (bool); +function claimTo(uint256 index, address to, uint128 amount, bytes32[] calldata merkleProof) external payable; ``` -### TOTAL_PERCENTAGE - -The total percentage of the tranches. +**Parameters** + +| Name | Type | Description | +| ------------- | ----------- | ------------------------------------------------------------------------------------------- | +| `index` | `uint256` | The index of the `msg.sender` in the Merkle tree. | +| `to` | `address` | The address to which Lockup stream or ERC-20 tokens will be sent on behalf of `msg.sender`. | +| `amount` | `uint128` | The amount of ERC-20 tokens allocated to the `msg.sender`. | +| `merkleProof` | `bytes32[]` | The proof of inclusion in the Merkle tree. | + +### claimViaSig + +Claim airdrop on behalf of eligible recipient using an EIP-712 or EIP-1271 signature. If the vesting end time is in the +future, it creates a Lockup Tranched stream with `to` address as the stream recipient, otherwise it transfers the tokens +directly to the `to` address. + +\*It emits either +[ClaimLTWithTransfer](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleLT.md#claimltwithtransfer) +or {ClaimLTWithVesting} event. Requirements: + +- If `recipient` is an EOA, it must match the recovered signer. +- If `recipient` is a contract, it must implement the IERC-1271 interface. +- The `to` must not be the zero address. +- The `validFrom` must be less than or equal to the current block timestamp. +- Refer to the requirements in {claim}. Below is the example of typed data to be signed by the airdrop recipient, + referenced from https://docs.metamask.io/wallet/how-to/sign-data/#example. + +```json +types: { +EIP712Domain: [ +{ name: "name", type: "string" }, +{ name: "chainId", type: "uint256" }, +{ name: "verifyingContract", type: "address" }, +], +Claim: [ +{ name: "index", type: "uint256" }, +{ name: "recipient", type: "address" }, +{ name: "to", type: "address" }, +{ name: "amount", type: "uint128" }, +{ name: "validFrom", type: "uint40" }, +], +}, +domain: { +name: "Sablier Airdrops Protocol", +chainId: 1, // Chain on which the contract is deployed +verifyingContract: "0xTheAddressOfThisContract", // The address of this contract +}, +primaryType: "Claim", +message: { +index: 2, // The index of the signer in the Merkle tree +recipient: "0xTheAddressOfTheRecipient", // The address of the airdrop recipient +to: "0xTheAddressReceivingTheTokens", // The address where recipient wants to transfer the tokens +amount: "1000000000000000000000", // The amount of tokens allocated to the recipient +validFrom: 1752425637 // The timestamp from which the claim signature is valid +}, +``` ```solidity -function TOTAL_PERCENTAGE() external view returns (uint64); +function claimViaSig( + uint256 index, + address recipient, + address to, + uint128 amount, + uint40 validFrom, + bytes32[] calldata merkleProof, + bytes calldata signature +) + external + payable; ``` -### getTranchesWithPercentages +**Parameters** -Retrieves the tranches with their respective unlock percentages and durations. +| Name | Type | Description | +| ------------- | ----------- | -------------------------------------------------------------------------------------------- | +| `index` | `uint256` | The index of the recipient in the Merkle tree. | +| `recipient` | `address` | The address of the airdrop recipient who is providing the signature. | +| `to` | `address` | The address to which Lockup stream or ERC-20 tokens will be sent on behalf of the recipient. | +| `amount` | `uint128` | The amount of ERC-20 tokens allocated to the recipient. | +| `validFrom` | `uint40` | The timestamp from which the claim signature is valid. | +| `merkleProof` | `bytes32[]` | The proof of inclusion in the Merkle tree. | +| `signature` | `bytes` | The EIP-712 or EIP-1271 signature from the airdrop recipient. | + +## Events + +### ClaimLTWithTransfer + +Emitted when an airdrop is claimed using direct transfer on behalf of an eligible recipient. ```solidity -function getTranchesWithPercentages() external view returns (MerkleLT.TrancheWithPercentage[] memory); +event ClaimLTWithTransfer(uint256 index, address indexed recipient, uint128 amount, address to, bool viaSig); ``` -## Events +**Parameters** + +| Name | Type | Description | +| ----------- | --------- | -------------------------------------------------------------------------- | +| `index` | `uint256` | The index of the airdrop recipient in the Merkle tree. | +| `recipient` | `address` | The address of the airdrop recipient. | +| `amount` | `uint128` | The amount of ERC-20 tokens claimed using direct transfer. | +| `to` | `address` | The address receiving the claim amount on behalf of the airdrop recipient. | +| `viaSig` | `bool` | Bool indicating whether the claim is made via a signature. | -### Claim +### ClaimLTWithVesting -Emitted when a recipient claims a stream. +Emitted when an airdrop is claimed using Lockup Tranched stream on behalf of an eligible recipient. ```solidity -event Claim(uint256 index, address indexed recipient, uint128 amount, uint256 indexed streamId); +event ClaimLTWithVesting( + uint256 index, address indexed recipient, uint128 amount, uint256 indexed streamId, address to, bool viaSig +); ``` + +**Parameters** + +| Name | Type | Description | +| ----------- | --------- | --------------------------------------------------------------------------- | +| `index` | `uint256` | The index of the airdrop recipient in the Merkle tree. | +| `recipient` | `address` | The address of the airdrop recipient. | +| `amount` | `uint128` | The amount of ERC-20 tokens claimed using Lockup Tranched stream. | +| `streamId` | `uint256` | The ID of the Lockup stream. | +| `to` | `address` | The address receiving the Lockup stream on behalf of the airdrop recipient. | +| `viaSig` | `bool` | Bool indicating whether the claim is made via a signature. | diff --git a/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleLockup.md b/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleLockup.md new file mode 100644 index 00000000..b52c5f6f --- /dev/null +++ b/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleLockup.md @@ -0,0 +1,57 @@ +# ISablierMerkleLockup + +[Git Source](https://github.com/sablier-labs/airdrops/blob/077c6b9766ef7693ba9e82a9e001dc0097709c01/src/interfaces/ISablierMerkleLockup.sol) + +**Inherits:** [ISablierMerkleBase](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleBase.md) + +MerkleLockup enables Airstreams (a portmanteau of "airdrop" and "stream"), an airdrop model where the tokens are vested +over time, as opposed to being unlocked at once. The vesting is provided by Sablier Lockup. + +_Common interface between MerkleLL and MerkleLT._ + +## Functions + +### SABLIER_LOCKUP + +The address of the [SablierLockup](/reference/lockup/contracts/contract.SablierLockup.md) contract. + +```solidity +function SABLIER_LOCKUP() external view returns (ISablierLockup); +``` + +### STREAM_CANCELABLE + +A flag indicating whether the streams can be canceled. + +_This is an immutable state variable._ + +```solidity +function STREAM_CANCELABLE() external view returns (bool); +``` + +### STREAM_TRANSFERABLE + +A flag indicating whether the stream NFTs are transferable. + +_This is an immutable state variable._ + +```solidity +function STREAM_TRANSFERABLE() external view returns (bool); +``` + +### claimedStreams + +Retrieves the stream IDs associated with the airdrops claimed by the provided recipient. In practice, most campaigns +will only have one stream per recipient. + +```solidity +function claimedStreams(address recipient) external view returns (uint256[] memory); +``` + +### streamShape + +Retrieves the shape of the Lockup stream created upon claiming. + +```solidity +function streamShape() external view returns (string memory); +``` diff --git a/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleVCA.md b/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleVCA.md new file mode 100644 index 00000000..57cb8cf2 --- /dev/null +++ b/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleVCA.md @@ -0,0 +1,216 @@ +# ISablierMerkleVCA + +[Git Source](https://github.com/sablier-labs/airdrops/blob/077c6b9766ef7693ba9e82a9e001dc0097709c01/src/interfaces/ISablierMerkleVCA.sol) + +**Inherits:** [ISablierMerkleBase](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleBase.md) + +VCA stands for Variable Claim Amount, and is an airdrop model where the claim amount increases linearly until the +airdrop period ends. Claiming early results in forgoing the remaining amount, whereas claiming after the period grants +the full amount that was allocated. + +## Functions + +### UNLOCK_PERCENTAGE + +Retrieves the percentage of the full amount that will unlock immediately at the start time. The value is denominated as +a fixed-point number where 1e18 is 100%. + +```solidity +function UNLOCK_PERCENTAGE() external view returns (UD60x18); +``` + +### VESTING_END_TIME + +Retrieves the time when the VCA airdrop is fully vested, as a Unix timestamp. + +```solidity +function VESTING_END_TIME() external view returns (uint40); +``` + +### VESTING_START_TIME + +Retrieves the time when the VCA airdrop begins to unlock, as a Unix timestamp. + +```solidity +function VESTING_START_TIME() external view returns (uint40); +``` + +### calculateClaimAmount + +Calculates the amount that would be claimed if the claim were made at `claimTime`. + +_This is for informational purposes only. To actually claim the airdrop, a Merkle proof is required._ + +```solidity +function calculateClaimAmount(uint128 fullAmount, uint40 claimTime) external view returns (uint128); +``` + +**Parameters** + +| Name | Type | Description | +| ------------ | --------- | ----------------------------------------------------------------------------------------------- | +| `fullAmount` | `uint128` | The amount of tokens allocated to a user, denominated in the token's decimals. | +| `claimTime` | `uint40` | A hypothetical time at which to make the claim. Zero is a sentinel value for `block.timestamp`. | + +**Returns** + +| Name | Type | Description | +| -------- | --------- | ---------------------------------------------------------------------- | +| `` | `uint128` | The amount that would be claimed, denominated in the token's decimals. | + +### calculateForgoneAmount + +Calculates the amount that would be forgone if the claim were made at `claimTime`. + +_This is for informational purposes only. Reverts if the claim time is less than the vesting start time, since the claim +cannot be made, no amount can be forgone._ + +```solidity +function calculateForgoneAmount(uint128 fullAmount, uint40 claimTime) external view returns (uint128); +``` + +**Parameters** + +| Name | Type | Description | +| ------------ | --------- | ----------------------------------------------------------------------------------------------- | +| `fullAmount` | `uint128` | The amount of tokens allocated to a user, denominated in the token's decimals. | +| `claimTime` | `uint40` | A hypothetical time at which to make the claim. Zero is a sentinel value for `block.timestamp`. | + +**Returns** + +| Name | Type | Description | +| -------- | --------- | ---------------------------------------------------------------------- | +| `` | `uint128` | The amount that would be forgone, denominated in the token's decimals. | + +### totalForgoneAmount + +Retrieves the total amount of tokens forgone by early claimers. + +```solidity +function totalForgoneAmount() external view returns (uint256); +``` + +### claimTo + +Claim airdrop. If the vesting end time is in the future, it calculates the claim amount to transfer to the `to` address, +otherwise it transfers the full amount. + +\*It emits a [ClaimVCA](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleVCA.md#claimvca) event. +Requirements: + +- The current time must be greater than or equal to the campaign start time. +- The campaign must not have expired. +- `msg.value` must not be less than the value returned by {COMPTROLLER.calculateMinFeeWei}. +- The `index` must not be claimed already. +- The Merkle proof must be valid. +- The claim amount must be greater than zero. +- `msg.sender` must be the airdrop recipient. +- The `to` must not be the zero address.\* + +```solidity +function claimTo(uint256 index, address to, uint128 fullAmount, bytes32[] calldata merkleProof) external payable; +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | ----------- | ------------------------------------------------------------------ | +| `index` | `uint256` | The index of the `msg.sender` in the Merkle tree. | +| `to` | `address` | The address receiving the ERC-20 tokens on behalf of `msg.sender`. | +| `fullAmount` | `uint128` | The total amount of ERC-20 tokens allocated to the recipient. | +| `merkleProof` | `bytes32[]` | The proof of inclusion in the Merkle tree. | + +### claimViaSig + +Claim airdrop on behalf of eligible recipient using an EIP-712 or EIP-1271 signature. If the vesting end time is in the +future, it calculates the claim amount to transfer to the `to` address, otherwise it transfers the full amount. + +\*It emits a [ClaimVCA](/docs/reference/airdrops/contracts/interfaces/interface.ISablierMerkleVCA.md#claimvca) event. +Requirements: + +- If `recipient` is an EOA, it must match the recovered signer. +- If `recipient` is a contract, it must implement the IERC-1271 interface. +- The `to` must not be the zero address. +- The `validFrom` must be less than or equal to the current block timestamp. +- Refer to the requirements in {claimTo} except that there are no restrictions on `msg.sender`. Below is the example of + typed data to be signed by the airdrop recipient, referenced from + https://docs.metamask.io/wallet/how-to/sign-data/#example. + +```json +types: { +EIP712Domain: [ +{ name: "name", type: "string" }, +{ name: "chainId", type: "uint256" }, +{ name: "verifyingContract", type: "address" }, +], +Claim: [ +{ name: "index", type: "uint256" }, +{ name: "recipient", type: "address" }, +{ name: "to", type: "address" }, +{ name: "amount", type: "uint128" }, +{ name: "validFrom", type: "uint40" }, +], +}, +domain: { +name: "Sablier Airdrops Protocol", +chainId: 1, // Chain on which the contract is deployed +verifyingContract: "0xTheAddressOfThisContract", // The address of this contract +}, +primaryType: "Claim", +message: { +index: 2, // The index of the signer in the Merkle tree +recipient: "0xTheAddressOfTheRecipient", // The address of the airdrop recipient +to: "0xTheAddressReceivingTheTokens", // The address where recipient wants to transfer the tokens +amount: "1000000000000000000000", // The amount of tokens allocated to the recipient +validFrom: 1752425637 // The timestamp from which the claim signature is valid +}, +``` + +```solidity +function claimViaSig( + uint256 index, + address recipient, + address to, + uint128 fullAmount, + uint40 validFrom, + bytes32[] calldata merkleProof, + bytes calldata signature +) + external + payable; +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | ----------- | -------------------------------------------------------------------- | +| `index` | `uint256` | The index of the recipient in the Merkle tree. | +| `recipient` | `address` | The address of the airdrop recipient who is providing the signature. | +| `to` | `address` | The address receiving the ERC-20 tokens on behalf of the recipient. | +| `fullAmount` | `uint128` | The total amount of ERC-20 tokens allocated to the recipient. | +| `validFrom` | `uint40` | The timestamp from which the claim signature is valid. | +| `merkleProof` | `bytes32[]` | The proof of inclusion in the Merkle tree. | +| `signature` | `bytes` | The EIP-712 or EIP-1271 signature from the airdrop recipient. | + +## Events + +### ClaimVCA + +Emitted when an airdrop is claimed on behalf of an eligible recipient. + +```solidity +event ClaimVCA( + uint256 index, address indexed recipient, uint128 claimAmount, uint128 forgoneAmount, address to, bool viaSig +); +``` + +**Parameters** + +| Name | Type | Description | +| --------------- | --------- | -------------------------------------------------------------------------- | +| `index` | `uint256` | The index of the airdrop recipient in the Merkle tree. | +| `recipient` | `address` | The address of the airdrop recipient. | +| `claimAmount` | `uint128` | The amount of ERC-20 tokens claimed. | +| `forgoneAmount` | `uint128` | The amount of ERC-20 tokens forgone. | +| `to` | `address` | The address receiving the claim amount on behalf of the airdrop recipient. | +| `viaSig` | `bool` | Bool indicating whether the claim is made via a signature. | diff --git a/docs/reference/airdrops/contracts/libraries/library.Errors.md b/docs/reference/airdrops/contracts/libraries/library.Errors.md index 575a11fe..fca6b080 100644 --- a/docs/reference/airdrops/contracts/libraries/library.Errors.md +++ b/docs/reference/airdrops/contracts/libraries/library.Errors.md @@ -1,23 +1,91 @@ # Errors -[Git Source](https://github.com/sablier-labs/airdrops/blob/f9a358c0a5bccfec77601d4490ef9117e0488068/src/libraries/Errors.sol) +[Git Source](https://github.com/sablier-labs/airdrops/blob/077c6b9766ef7693ba9e82a9e001dc0097709c01/src/libraries/Errors.sol) Library containing all custom errors the protocol may revert with. ## Errors -### CallerNotAdmin +### SablierFactoryMerkleBase_ForbidNativeToken + +Thrown when trying to create a campaign with native token. + +```solidity +error SablierFactoryMerkleBase_ForbidNativeToken(address nativeToken); +``` + +### SablierFactoryMerkleBase_NativeTokenAlreadySet + +Thrown when trying to set the native token address when it is already set. + +```solidity +error SablierFactoryMerkleBase_NativeTokenAlreadySet(address nativeToken); +``` + +### SablierFactoryMerkleBase_NativeTokenZeroAddress + +Thrown when trying to set zero address as native token. + +```solidity +error SablierFactoryMerkleBase_NativeTokenZeroAddress(); +``` + +### SablierFactoryMerkleLT_TotalPercentageNotOneHundred + +Thrown when trying to create an LT campaign with tranches' unlock percentages not adding up to 100%. + +```solidity +error SablierFactoryMerkleLT_TotalPercentageNotOneHundred(uint64 totalPercentage); +``` + +### SablierFactoryMerkleVCA_ExpirationTooEarly + +Thrown if expiration time is within 1 week from the vesting end time. + +```solidity +error SablierFactoryMerkleVCA_ExpirationTooEarly(uint40 vestingEndTime, uint40 expiration); +``` + +### SablierFactoryMerkleVCA_ExpirationTimeZero + +Thrown if expiration time is zero. + +```solidity +error SablierFactoryMerkleVCA_ExpirationTimeZero(); +``` + +### SablierFactoryMerkleVCA_VestingEndTimeNotGreaterThanVestingStartTime + +Thrown if vesting end time is not greater than the vesting start time. + +```solidity +error SablierFactoryMerkleVCA_VestingEndTimeNotGreaterThanVestingStartTime( + uint40 vestingStartTime, uint40 vestingEndTime +); +``` + +### SablierFactoryMerkleVCA_StartTimeZero + +Thrown if the start time is zero. ```solidity -error CallerNotAdmin(address admin, address caller); +error SablierFactoryMerkleVCA_StartTimeZero(); ``` -### SablierMerkleBase_CallerNotFactory +### SablierFactoryMerkleVCA_UnlockPercentageTooHigh -Thrown when caller is not the factory contract. +Thrown if the unlock percentage is greater than 100%. ```solidity -error SablierMerkleBase_CallerNotFactory(address factory, address caller); +error SablierFactoryMerkleVCA_UnlockPercentageTooHigh(UD60x18 unlockPercentage); +``` + +### SablierMerkleBase_CallerNotComptroller + +Thrown when caller is not the comptroller. + +```solidity +error SablierMerkleBase_CallerNotComptroller(address comptroller, address caller); ``` ### SablierMerkleBase_CampaignExpired @@ -28,6 +96,14 @@ Thrown when trying to claim after the campaign has expired. error SablierMerkleBase_CampaignExpired(uint256 blockTimestamp, uint40 expiration); ``` +### SablierMerkleBase_CampaignNotStarted + +Thrown when trying to claim before the campaign start time. + +```solidity +error SablierMerkleBase_CampaignNotStarted(uint256 blockTimestamp, uint40 campaignStartTime); +``` + ### SablierMerkleBase_ClawbackNotAllowed Thrown when trying to clawback when the current timestamp is over the grace period and the campaign has not expired. @@ -36,20 +112,28 @@ Thrown when trying to clawback when the current timestamp is over the grace peri error SablierMerkleBase_ClawbackNotAllowed(uint256 blockTimestamp, uint40 expiration, uint40 firstClaimTime); ``` -### SablierMerkleBase_FeeTransferFail +### SablierMerkleBase_FeeTransferFailed -Thrown if the fees withdrawal failed. +Thrown if fee transfer fails. ```solidity -error SablierMerkleBase_FeeTransferFail(address factoryAdmin, uint256 feeAmount); +error SablierMerkleBase_FeeTransferFailed(address feeRecipient, uint256 feeAmount); +``` + +### SablierMerkleBase_IndexClaimed + +Thrown when trying to claim the same index more than once. + +```solidity +error SablierMerkleBase_IndexClaimed(uint256 index); ``` ### SablierMerkleBase_InsufficientFeePayment -Thrown when trying to claim with an insufficient fee payment. +Thrown when trying to claim without paying the min fee. ```solidity -error SablierMerkleBase_InsufficientFeePayment(uint256 feePaid, uint256 fee); +error SablierMerkleBase_InsufficientFeePayment(uint256 feePaid, uint256 minFeeWei); ``` ### SablierMerkleBase_InvalidProof @@ -60,18 +144,50 @@ Thrown when trying to claim with an invalid Merkle proof. error SablierMerkleBase_InvalidProof(); ``` -### SablierMerkleBase_StreamClaimed +### SablierMerkleBase_InvalidSignature + +Thrown when claiming with an invalid EIP-712 or EIP-1271 signature. + +```solidity +error SablierMerkleBase_InvalidSignature(); +``` + +### SablierMerkleBase_NewMinFeeUSDNotLower + +Thrown when trying to set a new min USD fee that is higher than the current fee. + +```solidity +error SablierMerkleBase_NewMinFeeUSDNotLower(uint256 currentMinFeeUSD, uint256 newMinFeeUSD); +``` + +### SablierMerkleBase_SignatureNotYetValid + +Thrown when trying to claim with a signature that is not yet valid. + +```solidity +error SablierMerkleBase_SignatureNotYetValid(uint40 validFrom, uint40 blockTimestamp); +``` + +### SablierMerkleBase_ToZeroAddress + +Thrown when trying to claim to the zero address. + +```solidity +error SablierMerkleBase_ToZeroAddress(); +``` + +### SablierMerkleVCA_VestingNotStarted -Thrown when trying to claim the same stream more than once. +Thrown when calculating the forgone amount with claim time less than the vesting start time. ```solidity -error SablierMerkleBase_StreamClaimed(uint256 index); +error SablierMerkleVCA_VestingNotStarted(uint40 claimTime, uint40 vestingStartTime); ``` -### SablierMerkleLT_TotalPercentageNotOneHundred +### SablierMerkleVCA_ClaimAmountZero -Thrown when trying to claim from an LT campaign with tranches' unlock percentages not adding up to 100%. +Thrown when the claim amount is zero. ```solidity -error SablierMerkleLT_TotalPercentageNotOneHundred(uint64 totalPercentage); +error SablierMerkleVCA_ClaimAmountZero(address recipient); ``` diff --git a/docs/reference/airdrops/contracts/libraries/library.SignatureHash.md b/docs/reference/airdrops/contracts/libraries/library.SignatureHash.md new file mode 100644 index 00000000..09e8d134 --- /dev/null +++ b/docs/reference/airdrops/contracts/libraries/library.SignatureHash.md @@ -0,0 +1,33 @@ +# SignatureHash + +[Git Source](https://github.com/sablier-labs/airdrops/blob/077c6b9766ef7693ba9e82a9e001dc0097709c01/src/libraries/SignatureHash.sol) + +Library containing the hashes for the EIP-712 and EIP-1271 signatures. + +## State Variables + +### CLAIM_TYPEHASH + +_The struct type hash for computing the domain separator for EIP-712 and EIP-1271 signatures._ + +```solidity +bytes32 public constant CLAIM_TYPEHASH = + keccak256("Claim(uint256 index,address recipient,address to,uint128 amount,uint40 validFrom)"); +``` + +### DOMAIN_TYPEHASH + +The domain type hash for computing the domain separator. + +```solidity +bytes32 public constant DOMAIN_TYPEHASH = + keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)"); +``` + +### PROTOCOL_NAME + +The protocol name for the EIP-712 and EIP-1271 signatures. + +```solidity +bytes32 public constant PROTOCOL_NAME = keccak256("Sablier Airdrops Protocol"); +``` diff --git a/docs/reference/airdrops/contracts/types/library.MerkleBase.md b/docs/reference/airdrops/contracts/types/library.MerkleBase.md deleted file mode 100644 index f38422e5..00000000 --- a/docs/reference/airdrops/contracts/types/library.MerkleBase.md +++ /dev/null @@ -1,33 +0,0 @@ -# MerkleBase - -[Git Source](https://github.com/sablier-labs/airdrops/blob/f9a358c0a5bccfec77601d4490ef9117e0488068/src/types/DataTypes.sol) - -## Structs - -### ConstructorParams - -Struct encapsulating the base constructor parameters of a Merkle campaign. - -```solidity -struct ConstructorParams { - IERC20 token; - uint40 expiration; - address initialAdmin; - string ipfsCID; - bytes32 merkleRoot; - string campaignName; - string shape; -} -``` - -**Properties** - -| Name | Type | Description | -| -------------- | --------- | ------------------------------------------------------------------------------------------------------------------------ | -| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | -| `expiration` | `uint40` | The expiration of the campaign, as a Unix timestamp. A value of zero means the campaign does not expire. | -| `initialAdmin` | `address` | The initial admin of the campaign. | -| `ipfsCID` | `string` | The content identifier for indexing the contract on IPFS. | -| `merkleRoot` | `bytes32` | The Merkle root of the claim data. | -| `campaignName` | `string` | The name of the campaign. It is truncated if exceeding 32 bytes | -| `shape` | `string` | The shape of Lockup stream is used for differentiating between streams in the UI. It is truncated if exceeding 32 bytes. | diff --git a/docs/reference/airdrops/contracts/types/library.MerkleFactory.md b/docs/reference/airdrops/contracts/types/library.MerkleFactory.md deleted file mode 100644 index 8192c6a8..00000000 --- a/docs/reference/airdrops/contracts/types/library.MerkleFactory.md +++ /dev/null @@ -1,23 +0,0 @@ -# MerkleFactory - -[Git Source](https://github.com/sablier-labs/airdrops/blob/f9a358c0a5bccfec77601d4490ef9117e0488068/src/types/DataTypes.sol) - -## Structs - -### CustomFee - -Struct encapsulating the custom fee details for a given campaign creator. - -```solidity -struct CustomFee { - bool enabled; - uint256 fee; -} -``` - -**Properties** - -| Name | Type | Description | -| --------- | --------- | ----------------------------------------------------------------------------------------------------------------- | -| `enabled` | `bool` | Whether the fee is enabled. If false, the default fee will be applied for campaigns created by the given creator. | -| `fee` | `uint256` | The fee amount. | diff --git a/docs/reference/airdrops/contracts/types/library.MerkleInstant.md b/docs/reference/airdrops/contracts/types/library.MerkleInstant.md new file mode 100644 index 00000000..36e74818 --- /dev/null +++ b/docs/reference/airdrops/contracts/types/library.MerkleInstant.md @@ -0,0 +1,35 @@ +# MerkleInstant + +[Git Source](https://github.com/sablier-labs/airdrops/blob/077c6b9766ef7693ba9e82a9e001dc0097709c01/src/types/DataTypes.sol) + +## Structs + +### ConstructorParams + +Struct encapsulating the constructor parameters of Merkle Instant campaigns. + +_The fields are arranged alphabetically._ + +```solidity +struct ConstructorParams { + string campaignName; + uint40 campaignStartTime; + uint40 expiration; + address initialAdmin; + string ipfsCID; + bytes32 merkleRoot; + IERC20 token; +} +``` + +**Properties** + +| Name | Type | Description | +| ------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------- | +| `campaignName` | `string` | The name of the campaign. | +| `campaignStartTime` | `uint40` | The start time of the campaign, as a Unix timestamp. | +| `expiration` | `uint40` | The expiration of the campaign, as a Unix timestamp. A value of zero means the campaign does not expire. | +| `initialAdmin` | `address` | The initial admin of the campaign. | +| `ipfsCID` | `string` | The content identifier for indexing the contract on IPFS. An empty value may break certain UI features that depend upon the IPFS CID. | +| `merkleRoot` | `bytes32` | The Merkle root of the claim data. | +| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | diff --git a/docs/reference/airdrops/contracts/types/library.MerkleLL.md b/docs/reference/airdrops/contracts/types/library.MerkleLL.md index ffc6dbd0..cbfeb8ac 100644 --- a/docs/reference/airdrops/contracts/types/library.MerkleLL.md +++ b/docs/reference/airdrops/contracts/types/library.MerkleLL.md @@ -1,32 +1,53 @@ # MerkleLL -[Git Source](https://github.com/sablier-labs/airdrops/blob/f9a358c0a5bccfec77601d4490ef9117e0488068/src/types/DataTypes.sol) +[Git Source](https://github.com/sablier-labs/airdrops/blob/077c6b9766ef7693ba9e82a9e001dc0097709c01/src/types/DataTypes.sol) ## Structs -### Schedule +### ConstructorParams -Struct encapsulating the start time, cliff duration and the end duration used to construct the time variables in -`Lockup.CreateWithTimestampsLL`. +Struct encapsulating the constructor parameters of Merkle Lockup Linear campaigns. -_A start time value of zero will be considered as `block.timestamp`._ +_The fields are arranged alphabetically._ ```solidity -struct Schedule { - uint40 startTime; - UD2x18 startPercentage; +struct ConstructorParams { + string campaignName; + uint40 campaignStartTime; + bool cancelable; uint40 cliffDuration; - UD2x18 cliffPercentage; + UD60x18 cliffUnlockPercentage; + uint40 expiration; + address initialAdmin; + string ipfsCID; + ISablierLockup lockup; + bytes32 merkleRoot; + string shape; + UD60x18 startUnlockPercentage; + IERC20 token; uint40 totalDuration; + bool transferable; + uint40 vestingStartTime; } ``` **Properties** -| Name | Type | Description | -| ----------------- | -------- | ------------------------------------------------ | -| `startTime` | `uint40` | The start time of the stream. | -| `startPercentage` | `UD2x18` | The percentage to be unlocked at the start time. | -| `cliffDuration` | `uint40` | The duration of the cliff. | -| `cliffPercentage` | `UD2x18` | The percentage to be unlocked at the cliff time. | -| `totalDuration` | `uint40` | The total duration of the stream. | +| Name | Type | Description | +| ----------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------- | +| `campaignName` | `string` | The name of the campaign. | +| `campaignStartTime` | `uint40` | The start time of the campaign, as a Unix timestamp. | +| `cancelable` | `bool` | Indicates if the Lockup stream will be cancelable after claiming. | +| `cliffDuration` | `uint40` | The cliff duration of the vesting stream, in seconds. | +| `cliffUnlockPercentage` | `UD60x18` | The percentage of the claim amount due to be unlocked at the vesting cliff time, as a fixed-point number where 1e18 is 100% | +| `expiration` | `uint40` | The expiration of the campaign, as a Unix timestamp. A value of zero means the campaign does not expire. | +| `initialAdmin` | `address` | The initial admin of the campaign. | +| `ipfsCID` | `string` | The content identifier for indexing the contract on IPFS. An empty value may break certain UI features that depend upon the IPFS CID. | +| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/reference/lockup/contracts/contract.SablierLockup.md) contract. | +| `merkleRoot` | `bytes32` | The Merkle root of the claim data. | +| `shape` | `string` | The shape of the vesting stream, used for differentiating between streams in the UI. | +| `startUnlockPercentage` | `UD60x18` | The percentage of the claim amount due to be unlocked at the vesting start time, as a fixed-point number where 1e18 is 100%. | +| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | +| `totalDuration` | `uint40` | The total duration of the vesting stream, in seconds. | +| `transferable` | `bool` | Indicates if the Lockup stream will be transferable after claiming. | +| `vestingStartTime` | `uint40` | The start time of the vesting stream, as a Unix timestamp. Zero is a sentinel value for `block.timestamp`. | diff --git a/docs/reference/airdrops/contracts/types/library.MerkleLT.md b/docs/reference/airdrops/contracts/types/library.MerkleLT.md index abcba85e..e4c64e14 100644 --- a/docs/reference/airdrops/contracts/types/library.MerkleLT.md +++ b/docs/reference/airdrops/contracts/types/library.MerkleLT.md @@ -1,9 +1,51 @@ # MerkleLT -[Git Source](https://github.com/sablier-labs/airdrops/blob/f9a358c0a5bccfec77601d4490ef9117e0488068/src/types/DataTypes.sol) +[Git Source](https://github.com/sablier-labs/airdrops/blob/077c6b9766ef7693ba9e82a9e001dc0097709c01/src/types/DataTypes.sol) ## Structs +### ConstructorParams + +Struct encapsulating the constructor parameters of Merkle Lockup Tranched campaigns. + +_The fields are arranged alphabetically._ + +```solidity +struct ConstructorParams { + string campaignName; + uint40 campaignStartTime; + bool cancelable; + uint40 expiration; + address initialAdmin; + string ipfsCID; + ISablierLockup lockup; + bytes32 merkleRoot; + string shape; + IERC20 token; + MerkleLT.TrancheWithPercentage[] tranchesWithPercentages; + bool transferable; + uint40 vestingStartTime; +} +``` + +**Properties** + +| Name | Type | Description | +| ------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | +| `campaignName` | `string` | The name of the campaign. | +| `campaignStartTime` | `uint40` | The start time of the campaign, as a Unix timestamp. | +| `cancelable` | `bool` | Indicates if the Lockup stream will be cancelable after claiming. | +| `expiration` | `uint40` | The expiration of the campaign, as a Unix timestamp. A value of zero means the campaign does not expire. | +| `initialAdmin` | `address` | The initial admin of the campaign. | +| `ipfsCID` | `string` | The content identifier for indexing the contract on IPFS. An empty value may break certain UI features that depend upon the IPFS CID. | +| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/reference/lockup/contracts/contract.SablierLockup.md) contract. | +| `merkleRoot` | `bytes32` | The Merkle root of the claim data. | +| `shape` | `string` | The shape of Lockup stream, used for differentiating between streams in the UI. | +| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | +| `tranchesWithPercentages` | `MerkleLT.TrancheWithPercentage[]` | The tranches with their respective unlock percentages, which are documented in {MerkleLT.TrancheWithPercentage}. | +| `transferable` | `bool` | Indicates if the Lockup stream will be transferable after claiming. | +| `vestingStartTime` | `uint40` | The start time of the vesting stream, as a Unix timestamp. Zero is a sentinel value for `block.timestamp`. | + ### TrancheWithPercentage Struct encapsulating the unlock percentage and duration of a tranche. diff --git a/docs/reference/airdrops/contracts/types/library.MerkleVCA.md b/docs/reference/airdrops/contracts/types/library.MerkleVCA.md new file mode 100644 index 00000000..da024e9b --- /dev/null +++ b/docs/reference/airdrops/contracts/types/library.MerkleVCA.md @@ -0,0 +1,41 @@ +# MerkleVCA + +[Git Source](https://github.com/sablier-labs/airdrops/blob/077c6b9766ef7693ba9e82a9e001dc0097709c01/src/types/DataTypes.sol) + +## Structs + +### ConstructorParams + +Struct encapsulating the constructor parameters of Merkle VCA campaigns. + +_The fields are arranged alphabetically._ + +```solidity +struct ConstructorParams { + string campaignName; + uint40 campaignStartTime; + uint40 expiration; + address initialAdmin; + string ipfsCID; + bytes32 merkleRoot; + IERC20 token; + UD60x18 unlockPercentage; + uint40 vestingEndTime; + uint40 vestingStartTime; +} +``` + +**Properties** + +| Name | Type | Description | +| ------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------- | +| `campaignName` | `string` | The name of the campaign. | +| `campaignStartTime` | `uint40` | The start time of the campaign, as a Unix timestamp. | +| `expiration` | `uint40` | The expiration of the campaign, as a Unix timestamp. | +| `initialAdmin` | `address` | The initial admin of the campaign. | +| `ipfsCID` | `string` | The content identifier for indexing the contract on IPFS. An empty value may break certain UI features that depend upon the IPFS CID. | +| `merkleRoot` | `bytes32` | The Merkle root of the claim data. | +| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | +| `unlockPercentage` | `UD60x18` | The percentage of the full amount that will unlock immediately at the start time, denominated as fixed-point number where 1e18 is 100%. | +| `vestingEndTime` | `uint40` | Vesting end time, as a Unix timestamp. | +| `vestingStartTime` | `uint40` | Vesting start time, as a Unix timestamp. | diff --git a/docs/reference/flow/contracts/abstracts/abstract.Adminable.md b/docs/reference/flow/contracts/abstracts/abstract.Adminable.md deleted file mode 100644 index 2d3e1d02..00000000 --- a/docs/reference/flow/contracts/abstracts/abstract.Adminable.md +++ /dev/null @@ -1,48 +0,0 @@ -# Adminable - -[Git Source](https://github.com/sablier-labs/flow/blob/a0fa33d2843af0817e34970cdc05822ead31daaa/src/abstracts/Adminable.sol) - -**Inherits:** [IAdminable](/docs/reference/flow/contracts/interfaces/interface.IAdminable.md) - -See the documentation in [IAdminable](/docs/reference/flow/contracts/interfaces/interface.IAdminable.md). - -## State Variables - -### admin - -The address of the admin account or contract. - -```solidity -address public override admin; -``` - -## Functions - -### onlyAdmin - -Reverts if called by any account other than the admin. - -```solidity -modifier onlyAdmin(); -``` - -### transferAdmin - -Transfers the contract admin to a new address. - -Notes: - -- Does not revert if the admin is the same. -- This function can potentially leave the contract without an admin, thereby removing any functionality that is only - available to the admin. Requirements: -- `msg.sender` must be the contract admin. - -```solidity -function transferAdmin(address newAdmin) public virtual override onlyAdmin; -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ----------------------------- | -| `newAdmin` | `address` | The address of the new admin. | diff --git a/docs/reference/flow/contracts/abstracts/abstract.Batch.md b/docs/reference/flow/contracts/abstracts/abstract.Batch.md index 14e331e5..3bf6b7ee 100644 --- a/docs/reference/flow/contracts/abstracts/abstract.Batch.md +++ b/docs/reference/flow/contracts/abstracts/abstract.Batch.md @@ -1,10 +1,10 @@ # Batch -[Git Source](https://github.com/sablier-labs/flow/blob/a0fa33d2843af0817e34970cdc05822ead31daaa/src/abstracts/Batch.sol) +[Git Source](https://github.com/sablier-labs/evm-utils/blob/d7d6c051a39cbacadef672e92ed9d57628c80dc4/src/Batch.sol) -**Inherits:** [IBatch](/docs/reference/flow/contracts/interfaces/interface.IBatch.md) +**Inherits:** IBatch -See the documentation in [IBatch](/docs/reference/flow/contracts/interfaces/interface.IBatch.md). +See the documentation in {IBatch}. ## Functions @@ -16,7 +16,7 @@ _Since `msg.value` can be reused across calls, be VERY CAREFUL when using it. Re https://paradigm.xyz/2021/08/two-rights-might-make-a-wrong for more information._ ```solidity -function batch(bytes[] calldata calls) external payable override returns (bytes[] memory results); +function batch(bytes[] calldata calls) external payable virtual override returns (bytes[] memory results); ``` **Parameters** diff --git a/docs/reference/flow/contracts/abstracts/abstract.Comptrollerable.md b/docs/reference/flow/contracts/abstracts/abstract.Comptrollerable.md new file mode 100644 index 00000000..6335e17b --- /dev/null +++ b/docs/reference/flow/contracts/abstracts/abstract.Comptrollerable.md @@ -0,0 +1,95 @@ +# Comptrollerable + +[Git Source](https://github.com/sablier-labs/evm-utils/blob/d7d6c051a39cbacadef672e92ed9d57628c80dc4/src/Comptrollerable.sol) + +**Inherits:** IComptrollerable + +See the documentation in {IComptrollerable}. + +## State Variables + +### comptroller + +Retrieves the address of the comptroller contract. + +```solidity +ISablierComptroller public override comptroller; +``` + +## Functions + +### onlyComptroller + +Reverts if called by any account other than the comptroller. + +```solidity +modifier onlyComptroller(); +``` + +### constructor + +```solidity +constructor(address initialComptroller); +``` + +**Parameters** + +| Name | Type | Description | +| -------------------- | --------- | ------------------------------------------------ | +| `initialComptroller` | `address` | The address of the initial comptroller contract. | + +### setComptroller + +Sets the comptroller to a new address. + +\*Emits a {SetComptroller} event. Requirements: + +- `msg.sender` must be the current comptroller. +- The new comptroller must return `true` from {supportsInterface} with the comptroller's minimal interface ID which is + defined as the XOR of the following function selectors: + +1. {calculateMinFeeWeiFor} +2. {convertUSDFeeToWei} +3. {execute} +4. {getMinFeeUSDFor}\* + +```solidity +function setComptroller(ISablierComptroller newComptroller) external override onlyComptroller; +``` + +**Parameters** + +| Name | Type | Description | +| ---------------- | --------------------- | -------------------------------------------- | +| `newComptroller` | `ISablierComptroller` | The address of the new comptroller contract. | + +### transferFeesToComptroller + +Transfers the fees to the comptroller contract. + +_Emits a {TransferFeesToComptroller} event._ + +```solidity +function transferFeesToComptroller() external override; +``` + +### \_checkComptroller + +_See the documentation for the user-facing functions that call this private function._ + +```solidity +function _checkComptroller() private view; +``` + +### \_setComptroller + +_See the documentation for the user-facing functions that call this private function._ + +```solidity +function _setComptroller( + ISablierComptroller previousComptroller, + ISablierComptroller newComptroller, + bytes4 minimalInterfaceId +) + private; +``` diff --git a/docs/reference/flow/contracts/abstracts/abstract.NoDelegateCall.md b/docs/reference/flow/contracts/abstracts/abstract.NoDelegateCall.md index c2dfe6fd..90d0ec52 100644 --- a/docs/reference/flow/contracts/abstracts/abstract.NoDelegateCall.md +++ b/docs/reference/flow/contracts/abstracts/abstract.NoDelegateCall.md @@ -1,6 +1,6 @@ # NoDelegateCall -[Git Source](https://github.com/sablier-labs/flow/blob/a0fa33d2843af0817e34970cdc05822ead31daaa/src/abstracts/NoDelegateCall.sol) +[Git Source](https://github.com/sablier-labs/evm-utils/blob/d7d6c051a39cbacadef672e92ed9d57628c80dc4/src/NoDelegateCall.sol) This contract implements logic to prevent delegate calls. @@ -16,30 +16,30 @@ address private immutable ORIGINAL; ## Functions -### constructor +### noDelegateCall -_Sets the original contract address._ +Prevents delegate calls. ```solidity -constructor(); +modifier noDelegateCall(); ``` -### noDelegateCall +### constructor -Prevents delegate calls. +_Sets the original contract address._ ```solidity -modifier noDelegateCall(); +constructor(); ``` ### \_preventDelegateCall -This function checks whether the current call is a delegate call, and reverts if it is. +\*This function checks whether the current call is a delegate call, and reverts if it is. - A private function is used instead of inlining this logic in a modifier because Solidity copies modifiers into every function that uses them. The `ORIGINAL` address would get copied in every place the modifier is used, which would increase the contract size. By using a function instead, we can avoid this duplication of code and reduce the overall - size of the contract. + size of the contract.\* ```solidity function _preventDelegateCall() private view; diff --git a/docs/reference/flow/contracts/abstracts/abstract.SablierFlowBase.md b/docs/reference/flow/contracts/abstracts/abstract.SablierFlowBase.md deleted file mode 100644 index ac8da2b2..00000000 --- a/docs/reference/flow/contracts/abstracts/abstract.SablierFlowBase.md +++ /dev/null @@ -1,498 +0,0 @@ -# SablierFlowBase - -[Git Source](https://github.com/sablier-labs/flow/blob/a0fa33d2843af0817e34970cdc05822ead31daaa/src/abstracts/SablierFlowBase.sol) - -**Inherits:** [Adminable](/docs/reference/flow/contracts/abstracts/abstract.Adminable.md), -[ISablierFlowBase](/docs/reference/flow/contracts/interfaces/interface.ISablierFlowBase.md), ERC721 - -See the documentation in [ISablierFlowBase](/docs/reference/flow/contracts/interfaces/interface.ISablierFlowBase.md). - -## State Variables - -### MAX_FEE - -Retrieves the maximum fee that can be charged by the broker and the protocol, denoted as a fixed-point percentage where -1e18 is 100%. - -_This value is hard coded as a constant._ - -```solidity -UD60x18 public constant override MAX_FEE = UD60x18.wrap(0.1e18); -``` - -### aggregateBalance - -Retrieves the sum of balances of all streams. - -```solidity -mapping(IERC20 token => uint256 amount) public override aggregateBalance; -``` - -### nextStreamId - -Counter for stream ids. - -```solidity -uint256 public override nextStreamId; -``` - -### nftDescriptor - -Contract that generates the non-fungible token URI. - -```solidity -IFlowNFTDescriptor public override nftDescriptor; -``` - -### protocolFee - -Protocol fee for the provided ERC-20 token, denoted as a fixed-point percentage where 1e18 is 100%. - -```solidity -mapping(IERC20 token => UD60x18 fee) public override protocolFee; -``` - -### protocolRevenue - -Protocol revenue accrued for the provided ERC-20 token, denoted in token's decimals. - -```solidity -mapping(IERC20 token => uint128 revenue) public override protocolRevenue; -``` - -### \_streams - -_Sablier Flow streams mapped by unsigned integers._ - -```solidity -mapping(uint256 id => Flow.Stream stream) internal _streams; -``` - -## Functions - -### constructor - -_Emits {TransferAdmin} event._ - -```solidity -constructor(address initialAdmin, IFlowNFTDescriptor initialNFTDescriptor); -``` - -**Parameters** - -| Name | Type | Description | -| ---------------------- | -------------------- | ------------------------------------------ | -| `initialAdmin` | `address` | The address of the initial contract admin. | -| `initialNFTDescriptor` | `IFlowNFTDescriptor` | The address of the initial NFT descriptor. | - -### notNull - -_Checks that `streamId` does not reference a null stream._ - -```solidity -modifier notNull(uint256 streamId); -``` - -### notPaused - -_Checks that `streamId` does not reference a paused stream._ - -```solidity -modifier notPaused(uint256 streamId); -``` - -### notVoided - -_Checks that `streamId` does not reference a voided stream._ - -```solidity -modifier notVoided(uint256 streamId); -``` - -### onlySender - -_Checks the `msg.sender` is the stream's sender._ - -```solidity -modifier onlySender(uint256 streamId); -``` - -### updateMetadata - -_Emits an ERC-4906 event to trigger an update of the NFT metadata._ - -```solidity -modifier updateMetadata(uint256 streamId); -``` - -### getBalance - -Retrieves the balance of the stream, i.e. the total deposited amounts subtracted by the total withdrawn amounts, denoted -in token's decimals. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getBalance(uint256 streamId) external view override notNull(streamId) returns (uint128 balance); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### getRatePerSecond - -Retrieves the rate per second of the stream, denoted as a fixed-point number where 1e18 is 1 token per second. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getRatePerSecond(uint256 streamId) external view override notNull(streamId) returns (UD21x18 ratePerSecond); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ------------------------------------------- | -| `streamId` | `uint256` | The ID of the stream to make the query for. | - -### getRecipient - -Retrieves the stream's recipient. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getRecipient(uint256 streamId) external view override notNull(streamId) returns (address recipient); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### getSender - -Retrieves the stream's sender. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getSender(uint256 streamId) external view override notNull(streamId) returns (address sender); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### getSnapshotDebtScaled - -Retrieves the snapshot debt of the stream, denoted as a fixed-point number where 1e18 is 1 token. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getSnapshotDebtScaled(uint256 streamId) - external - view - override - notNull(streamId) - returns (uint256 snapshotDebtScaled); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### getSnapshotTime - -Retrieves the snapshot time of the stream, which is a Unix timestamp. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getSnapshotTime(uint256 streamId) external view override notNull(streamId) returns (uint40 snapshotTime); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ------------------------------------------- | -| `streamId` | `uint256` | The ID of the stream to make the query for. | - -### getStream - -Retrieves the stream entity. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getStream(uint256 streamId) external view override notNull(streamId) returns (Flow.Stream memory stream); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### getToken - -Retrieves the token of the stream. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getToken(uint256 streamId) external view override notNull(streamId) returns (IERC20 token); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ------------------------------------------- | -| `streamId` | `uint256` | The ID of the stream to make the query for. | - -### getTokenDecimals - -Retrieves the token decimals of the stream. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getTokenDecimals(uint256 streamId) external view override notNull(streamId) returns (uint8 tokenDecimals); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ------------------------------------------- | -| `streamId` | `uint256` | The ID of the stream to make the query for. | - -### isPaused - -Returns whether a stream is paused. - -_Reverts if `streamId` references a null stream._ - -```solidity -function isPaused(uint256 streamId) external view override notNull(streamId) returns (bool result); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### isStream - -Retrieves a flag indicating whether the stream exists. - -_Does not revert if `streamId` references a null stream._ - -```solidity -function isStream(uint256 streamId) external view override returns (bool result); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### isTransferable - -Retrieves a flag indicating whether the stream NFT is transferable. - -_Reverts if `streamId` references a null stream._ - -```solidity -function isTransferable(uint256 streamId) external view override notNull(streamId) returns (bool result); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### isVoided - -Retrieves a flag indicating whether the stream is voided. - -_Reverts if `streamId` references a null stream._ - -```solidity -function isVoided(uint256 streamId) external view override notNull(streamId) returns (bool result); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### tokenURI - -_See {IERC721Metadata-tokenURI}._ - -```solidity -function tokenURI(uint256 streamId) public view override(IERC721Metadata, ERC721) returns (string memory uri); -``` - -### collectFees - -Collects the accrued fees by transferring them to the contract admin. - -Emits a {CollectFees} event. Notes: - -- If the admin is a contract, it must be able to receive native token payments, e.g., ETH for Ethereum Mainnet. - -```solidity -function collectFees() external override; -``` - -### collectProtocolRevenue - -Collect the protocol revenue accrued for the provided ERC-20 token. - -Emits a {CollectProtocolRevenue} event. Requirements: - -- `msg.sender` must be the contract admin. -- The accrued protocol revenue must be greater than zero. - -```solidity -function collectProtocolRevenue(IERC20 token, address to) external override onlyAdmin; -``` - -**Parameters** - -| Name | Type | Description | -| ------- | --------- | ----------------------------------------------------------------------------- | -| `token` | `IERC20` | The contract address of the ERC-20 token for which to claim protocol revenue. | -| `to` | `address` | The address to send the protocol revenue. | - -### recover - -Recover the surplus amount of tokens. - -Emits a {Recover} event. Notes: - -- The surplus amount is defined as the difference between the total balance of the contract for the provided ERC-20 - token and the sum of balances of all streams created using the same ERC-20 token. Requirements: -- `msg.sender` must be the contract admin. -- The surplus amount must be greater than zero. - -```solidity -function recover(IERC20 token, address to) external override onlyAdmin; -``` - -**Parameters** - -| Name | Type | Description | -| ------- | --------- | -------------------------------------------------------- | -| `token` | `IERC20` | The contract address of the ERC-20 token to recover for. | -| `to` | `address` | The address to send the surplus amount. | - -### setNFTDescriptor - -Sets a new NFT descriptor contract, which produces the URI describing the Sablier stream NFTs. - -Emits a {SetNFTDescriptor} and {BatchMetadataUpdate} event. Notes: - -- Does not revert if the NFT descriptor is the same. Requirements: -- `msg.sender` must be the contract admin. - -```solidity -function setNFTDescriptor(IFlowNFTDescriptor newNFTDescriptor) external override onlyAdmin; -``` - -**Parameters** - -| Name | Type | Description | -| ------------------ | -------------------- | ----------------------------------------------- | -| `newNFTDescriptor` | `IFlowNFTDescriptor` | The address of the new NFT descriptor contract. | - -### setProtocolFee - -Sets a new protocol fee that will be charged on all the withdrawals from streams created with the provided ERC-20 token. - -Emits a {SetProtocolFee} and {BatchMetadataUpdate} event. Notes: - -- Does not revert if the fee is the same. -- It can be zero. Requirements: -- `msg.sender` must be the contract admin. -- `newProtocolFee` must not be greater than `MAX_FEE`. - -```solidity -function setProtocolFee(IERC20 token, UD60x18 newProtocolFee) external override onlyAdmin; -``` - -**Parameters** - -| Name | Type | Description | -| ---------------- | --------- | ----------------------------------------------------------------------------- | -| `token` | `IERC20` | The contract address of the ERC-20 token to update the fee for. | -| `newProtocolFee` | `UD60x18` | The new protocol fee, denoted as a fixed-point percentage where 1e18 is 100%. | - -### supportsInterface - -_See {IERC165-supportsInterface}._ - -```solidity -function supportsInterface(bytes4 interfaceId) public view override(IERC165, ERC721) returns (bool); -``` - -### \_isCallerStreamRecipientOrApproved - -Checks whether `msg.sender` is the stream's recipient or an approved third party. - -```solidity -function _isCallerStreamRecipientOrApproved(uint256 streamId) internal view returns (bool); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### \_update - -Overrides the {ERC-721.\_update} function to check that the stream is transferable. - -_The transferable flag is ignored if the current owner is 0, as the update in this case is a mint and is allowed. -Transfers to the zero address are not allowed, preventing accidental burns._ - -```solidity -function _update( - address to, - uint256 streamId, - address auth -) - internal - override - updateMetadata(streamId) - returns (address); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `to` | `address` | The address of the new recipient of the stream. | -| `streamId` | `uint256` | ID of the stream to update. | -| `auth` | `address` | Optional parameter. If the value is not zero, the overridden implementation will check that `auth` is either the recipient of the stream, or an approved third party. | - -**Returns** - -| Name | Type | Description | -| -------- | --------- | ----------------------------------------------------------- | -| `` | `address` | The original recipient of the `streamId` before the update. | diff --git a/docs/reference/flow/contracts/abstracts/abstract.SablierFlowState.md b/docs/reference/flow/contracts/abstracts/abstract.SablierFlowState.md new file mode 100644 index 00000000..f6499e1e --- /dev/null +++ b/docs/reference/flow/contracts/abstracts/abstract.SablierFlowState.md @@ -0,0 +1,296 @@ +# SablierFlowState + +[Git Source](https://github.com/sablier-labs/flow/blob/a4143de45478f508bca8305fec2bd81b7ad25fe9/src/abstracts/SablierFlowState.sol) + +**Inherits:** [ISablierFlowState](/docs/reference/flow/contracts/interfaces/interface.ISablierFlowState.md) + +See the documentation in [ISablierFlowState](/docs/reference/flow/contracts/interfaces/interface.ISablierFlowState.md). + +## State Variables + +### aggregateAmount + +Retrieves the aggregate amount across all streams, denoted in units of the token's decimals. + +_If tokens are directly transferred to the contract without using the stream creation functions, the ERC-20 balance may +be greater than the aggregate amount._ + +```solidity +mapping(IERC20 token => uint256 amount) public override aggregateAmount; +``` + +### nativeToken + +Retrieves the address of the ERC-20 interface of the native token, if it exists. + +_The native tokens on some chains have a dual interface as ERC-20. For example, on Polygon the $POL token is the native +token and has an ERC-20 version at 0x0000000000000000000000000000000000001010. This means that `address(this).balance` +returns the same value as `balanceOf(address(this))`. To avoid any unintended behavior, these tokens cannot be used in +Sablier. As an alternative, users can use the Wrapped version of the token, i.e. WMATIC, which is a standard ERC-20 +token._ + +```solidity +address public override nativeToken; +``` + +### nextStreamId + +Counter for stream ids. + +```solidity +uint256 public override nextStreamId; +``` + +### nftDescriptor + +Contract that generates the non-fungible token URI. + +```solidity +IFlowNFTDescriptor public override nftDescriptor; +``` + +### \_streams + +_Sablier Flow streams mapped by unsigned integers._ + +```solidity +mapping(uint256 id => Flow.Stream stream) internal _streams; +``` + +## Functions + +### constructor + +```solidity +constructor(address initialNFTDescriptor); +``` + +**Parameters** + +| Name | Type | Description | +| ---------------------- | --------- | ------------------------------------------ | +| `initialNFTDescriptor` | `address` | The address of the initial NFT descriptor. | + +### notNull + +_Checks that `streamId` does not reference a null stream._ + +```solidity +modifier notNull(uint256 streamId); +``` + +### notPaused + +_Checks that `streamId` does not reference a paused stream. Note that this implicitly checks that the stream is not +voided either._ + +```solidity +modifier notPaused(uint256 streamId); +``` + +### notVoided + +_Checks that `streamId` does not reference a voided stream._ + +```solidity +modifier notVoided(uint256 streamId); +``` + +### onlySender + +_Checks the `msg.sender` is the stream's sender._ + +```solidity +modifier onlySender(uint256 streamId); +``` + +### getBalance + +Retrieves the balance of the stream, i.e. the total deposited amounts subtracted by the total withdrawn amounts, denoted +in token's decimals. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getBalance(uint256 streamId) external view override notNull(streamId) returns (uint128 balance); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getRatePerSecond + +Retrieves the rate per second of the stream, denoted as a fixed-point number where 1e18 is 1 token per second. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getRatePerSecond(uint256 streamId) external view override notNull(streamId) returns (UD21x18 ratePerSecond); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to make the query for. | + +### getSender + +Retrieves the stream's sender. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getSender(uint256 streamId) external view override notNull(streamId) returns (address sender); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getSnapshotDebtScaled + +Retrieves the snapshot debt of the stream, denoted as a fixed-point number where 1e18 is 1 token. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getSnapshotDebtScaled(uint256 streamId) + external + view + override + notNull(streamId) + returns (uint256 snapshotDebtScaled); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getSnapshotTime + +Retrieves the snapshot time of the stream, which is a Unix timestamp. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getSnapshotTime(uint256 streamId) external view override notNull(streamId) returns (uint40 snapshotTime); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to make the query for. | + +### getStream + +Retrieves the stream entity. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getStream(uint256 streamId) external view override notNull(streamId) returns (Flow.Stream memory stream); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getToken + +Retrieves the token of the stream. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getToken(uint256 streamId) external view override notNull(streamId) returns (IERC20 token); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to make the query for. | + +### getTokenDecimals + +Retrieves the token decimals of the stream. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getTokenDecimals(uint256 streamId) external view override notNull(streamId) returns (uint8 tokenDecimals); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to make the query for. | + +### isStream + +Retrieves a flag indicating whether the stream exists. + +_Does not revert if `streamId` references a null stream._ + +```solidity +function isStream(uint256 streamId) external view override returns (bool result); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### isTransferable + +Retrieves a flag indicating whether the stream NFT is transferable. + +_Reverts if `streamId` references a null stream._ + +```solidity +function isTransferable(uint256 streamId) external view override notNull(streamId) returns (bool result); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### isVoided + +Retrieves a flag indicating whether the stream is voided. + +_Reverts if `streamId` references a null stream._ + +```solidity +function isVoided(uint256 streamId) external view override notNull(streamId) returns (bool result); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### \_notNull + +_A private function is used instead of inlining this logic in a modifier because Solidity copies modifiers into every +function that uses them._ + +```solidity +function _notNull(uint256 streamId) private view; +``` diff --git a/docs/reference/flow/contracts/contract.FlowNFTDescriptor.md b/docs/reference/flow/contracts/contract.FlowNFTDescriptor.md index 0e510a7c..80ddfe8f 100644 --- a/docs/reference/flow/contracts/contract.FlowNFTDescriptor.md +++ b/docs/reference/flow/contracts/contract.FlowNFTDescriptor.md @@ -4,7 +4,7 @@ sidebar_position: 2 # FlowNFTDescriptor -[Git Source](https://github.com/sablier-labs/flow/blob/a0fa33d2843af0817e34970cdc05822ead31daaa/src/FlowNFTDescriptor.sol) +[Git Source](https://github.com/sablier-labs/flow/blob/a4143de45478f508bca8305fec2bd81b7ad25fe9/src/FlowNFTDescriptor.sol) **Inherits:** [IFlowNFTDescriptor](/docs/reference/flow/contracts/interfaces/interface.IFlowNFTDescriptor.md) diff --git a/docs/reference/flow/contracts/contract.SablierFlow.md b/docs/reference/flow/contracts/contract.SablierFlow.md index e8971536..c256c197 100644 --- a/docs/reference/flow/contracts/contract.SablierFlow.md +++ b/docs/reference/flow/contracts/contract.SablierFlow.md @@ -4,12 +4,13 @@ sidebar_position: 1 # SablierFlow -[Git Source](https://github.com/sablier-labs/flow/blob/a0fa33d2843af0817e34970cdc05822ead31daaa/src/SablierFlow.sol) +[Git Source](https://github.com/sablier-labs/flow/blob/a4143de45478f508bca8305fec2bd81b7ad25fe9/src/SablierFlow.sol) **Inherits:** [Batch](/docs/reference/flow/contracts/abstracts/abstract.Batch.md), -[NoDelegateCall](/docs/reference/flow/contracts/abstracts/abstract.NoDelegateCall.md), +[Comptrollerable](/docs/reference/flow/contracts/abstracts/abstract.Comptrollerable.md), ERC721, [ISablierFlow](/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md), -[SablierFlowBase](/docs/reference/flow/contracts/abstracts/abstract.SablierFlowBase.md) +[NoDelegateCall](/docs/reference/flow/contracts/abstracts/abstract.NoDelegateCall.md), +[SablierFlowState](/docs/reference/flow/contracts/abstracts/abstract.SablierFlowState.md) See the documentation in [ISablierFlow](/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md). @@ -17,23 +18,46 @@ See the documentation in [ISablierFlow](/docs/reference/flow/contracts/interface ### constructor -_Emits {TransferAdmin} event._ - ```solidity constructor( - address initialAdmin, - IFlowNFTDescriptor initialNFTDescriptor + address initialComptroller, + address initialNFTDescriptor ) + [Comptrollerable](/docs/reference/flow/contracts/abstracts/abstract.Comptrollerable.md)(initialComptroller) ERC721("Sablier Flow NFT", "SAB-FLOW") - SablierFlowBase(initialAdmin, initialNFTDescriptor); + SablierFlowState(initialNFTDescriptor); ``` **Parameters** -| Name | Type | Description | -| ---------------------- | -------------------- | ------------------------------------------ | -| `initialAdmin` | `address` | The address of the initial contract admin. | -| `initialNFTDescriptor` | `IFlowNFTDescriptor` | The address of the initial NFT descriptor. | +| Name | Type | Description | +| ---------------------- | --------- | ------------------------------------------------ | +| `initialComptroller` | `address` | The address of the initial comptroller contract. | +| `initialNFTDescriptor` | `address` | The address of the initial NFT descriptor. | + +### updateMetadata + +_Emits an ERC-4906 event to trigger an update of the NFT metadata._ + +```solidity +modifier updateMetadata(uint256 streamId); +``` + +### calculateMinFeeWei + +Calculates the minimum fee in wei required to withdraw from the given stream ID. + +_Reverts if `streamId` references a null stream._ + +```solidity +function calculateMinFeeWei(uint256 streamId) external view override notNull(streamId) returns (uint256 minFeeWei); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | ### coveredDebtOf @@ -53,13 +77,13 @@ function coveredDebtOf(uint256 streamId) external view override notNull(streamId ### depletionTimeOf -Returns the time at which the total debt exceeds stream balance. If the total debt is less than or equal to stream -balance, it returns 0. +Returns the time at which the total debt exceeds stream balance. If the total debt exceeds the stream balance, it +returns 0. -Reverts on the following conditions: +\*Reverts on the following conditions: - If `streamId` references a paused or a null stream. -- If stream balance is zero. +- If stream balance is zero.\* ```solidity function depletionTimeOf(uint256 streamId) @@ -77,10 +101,26 @@ function depletionTimeOf(uint256 streamId) | ---------- | --------- | ---------------------------- | | `streamId` | `uint256` | The stream ID for the query. | +### getRecipient + +Retrieves the stream's recipient. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getRecipient(uint256 streamId) external view override notNull(streamId) returns (address recipient); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + ### ongoingDebtScaledOf Returns the amount of debt accrued since the snapshot time until now, denoted as a fixed-point number where 1e18 is 1 -token. +token. If the stream is pending, it returns zero. _Reverts if `streamId` references a null stream._ @@ -201,13 +241,13 @@ function withdrawableAmountOf(uint256 streamId) Changes the stream's rate per second. -Emits a {AdjustFlowStream} and {MetadataUpdate} event. Notes: +\*Emits a {AdjustFlowStream} and {MetadataUpdate} event. Notes: -- It updates snapshot debt and snapshot time. Requirements: +- If the snapshot time is not in the future, it updates both the snapshot time and snapshot debt. Requirements: - Must not be delegate called. -- `streamId` must not reference a null or a paused stream. +- `streamId` must not reference a null, paused, or voided stream. - `msg.sender` must be the stream's sender. -- `newRatePerSecond` must not equal to the current rate per second. +- `newRatePerSecond` must be greater than zero and must be different from the current rate per second.\* ```solidity function adjustRatePerSecond( @@ -233,21 +273,24 @@ function adjustRatePerSecond( ### create -Creates a new Flow stream by setting the snapshot time to `block.timestamp` and leaving the balance to zero. The stream -is wrapped in an ERC-721 NFT. +Creates a new Flow stream by setting the snapshot time to `startTime` and leaving the balance to zero. The stream is +wrapped in an ERC-721 NFT. -Emits {CreateFlowStream} event. Requirements: +\*Emits a {CreateFlowStream} and {MetadataUpdate} event. Requirements: - Must not be delegate called. - `sender` must not be the zero address. - `recipient` must not be the zero address. -- The `token`'s decimals must be less than or equal to 18. +- If `startTime` is in the future, the `ratePerSecond` must be greater than zero. +- The `token` must not be the native token. +- The `token`'s decimals must be less than or equal to 18.\* ```solidity function create( address sender, address recipient, UD21x18 ratePerSecond, + uint40 startTime, IERC20 token, bool transferable ) @@ -260,13 +303,14 @@ function create( **Parameters** -| Name | Type | Description | -| --------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------- | -| `sender` | `address` | The address streaming the tokens, which is able to adjust and pause the stream. It doesn't have to be the same as `msg.sender`. | -| `recipient` | `address` | The address receiving the tokens. | -| `ratePerSecond` | `UD21x18` | The amount by which the debt is increasing every second, denoted as a fixed-point number where 1e18 is 1 token per second. | -| `token` | `IERC20` | The contract address of the ERC-20 token to be streamed. | -| `transferable` | `bool` | Boolean indicating if the stream NFT is transferable. | +| Name | Type | Description | +| --------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------- | +| `sender` | `address` | The address streaming the tokens, which is able to adjust and pause the stream. It doesn't have to be the same as `msg.sender`. | +| `recipient` | `address` | The address receiving the tokens. | +| `ratePerSecond` | `UD21x18` | The amount by which the debt is increasing every second, denoted as a fixed-point number where 1e18 is 1 token per second. | +| `startTime` | `uint40` | The timestamp when the stream starts. A sentinel value of zero means the stream will be created with the snapshot time as `block.timestamp`. | +| `token` | `IERC20` | The contract address of the ERC-20 token to be streamed. | +| `transferable` | `bool` | Boolean indicating if the stream NFT is transferable. | **Returns** @@ -276,19 +320,20 @@ function create( ### createAndDeposit -Creates a new Flow stream by setting the snapshot time to `block.timestamp` and the balance to `amount`. The stream is -wrapped in an ERC-721 NFT. +Creates a new Flow stream by setting the snapshot time to `startTime` and the balance to `amount`. The stream is wrapped +in an ERC-721 NFT. -Emits a {Transfer}, {CreateFlowStream}, and {DepositFlowStream} event. Notes: +\*Emits a {Transfer}, {CreateFlowStream}, {DepositFlowStream} and {MetadataUpdate} event. Notes: -- Refer to the notes in {deposit}. Requirements: -- Refer to the requirements in {create} and {deposit}. +- Refer to the notes in {create} and {deposit}. Requirements: +- Refer to the requirements in {create} and {deposit}.\* ```solidity function createAndDeposit( address sender, address recipient, UD21x18 ratePerSecond, + uint40 startTime, IERC20 token, bool transferable, uint128 amount @@ -302,14 +347,15 @@ function createAndDeposit( **Parameters** -| Name | Type | Description | -| --------------- | --------- | -------------------------------------------------------------------------------------------------------------------------- | -| `sender` | `address` | The address streaming the tokens. It doesn't have to be the same as `msg.sender`. | -| `recipient` | `address` | The address receiving the tokens. | -| `ratePerSecond` | `UD21x18` | The amount by which the debt is increasing every second, denoted as a fixed-point number where 1e18 is 1 token per second. | -| `token` | `IERC20` | The contract address of the ERC-20 token to be streamed. | -| `transferable` | `bool` | Boolean indicating if the stream NFT is transferable. | -| `amount` | `uint128` | The deposit amount, denoted in token's decimals. | +| Name | Type | Description | +| --------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------- | +| `sender` | `address` | The address streaming the tokens. It doesn't have to be the same as `msg.sender`. | +| `recipient` | `address` | The address receiving the tokens. | +| `ratePerSecond` | `UD21x18` | The amount by which the debt is increasing every second, denoted as a fixed-point number where 1e18 is 1 token per second. | +| `startTime` | `uint40` | The timestamp when the stream starts. A sentinel value of zero means the stream will be created with the snapshot time as `block.timestamp`. | +| `token` | `IERC20` | The contract address of the ERC-20 token to be streamed. | +| `transferable` | `bool` | Boolean indicating if the stream NFT is transferable. | +| `amount` | `uint128` | The deposit amount, denoted in token's decimals. | **Returns** @@ -321,12 +367,12 @@ function createAndDeposit( Makes a deposit in a stream. -Emits a {Transfer} and {DepositFlowStream} event. Requirements: +\*Emits a {Transfer}, {DepositFlowStream} and {MetadataUpdate} event. Requirements: - Must not be delegate called. - `streamId` must not reference a null or a voided stream. - `amount` must be greater than zero. -- `sender` and `recipient` must match the stream's sender and recipient addresses. +- `sender` and `recipient` must match the stream's sender and recipient addresses.\* ```solidity function deposit( @@ -357,10 +403,10 @@ function deposit( Deposits tokens in a stream and pauses it. -Emits a {Transfer}, {DepositFlowStream} and {PauseFlowStream} event. Notes: +\*Emits a {Transfer}, {DepositFlowStream}, {PauseFlowStream} and {MetadataUpdate} event. Notes: - Refer to the notes in {deposit} and {pause}. Requirements: -- Refer to the requirements in {deposit} and {pause}. +- Refer to the requirements in {deposit} and {pause}.\* ```solidity function depositAndPause( @@ -384,57 +430,17 @@ function depositAndPause( | `streamId` | `uint256` | The ID of the stream to deposit to, and then pause. | | `amount` | `uint128` | The deposit amount, denoted in token's decimals. | -### depositViaBroker - -Deposits tokens in a stream. - -Emits a {Transfer} and {DepositFlowStream} event. Notes: - -- Refer to the notes in {deposit}. Requirements: -- Must not be delegate called. -- `streamId` must not reference a null stream. -- `totalAmount` must be greater than zero. Otherwise it will revert inside {deposit}. -- `broker.account` must not be 0 address. -- `broker.fee` must not be greater than `MAX_FEE`. It can be zero. - -```solidity -function depositViaBroker( - uint256 streamId, - uint128 totalAmount, - address sender, - address recipient, - Broker calldata broker -) - external - payable - override - noDelegateCall - notNull(streamId) - notVoided(streamId) - updateMetadata(streamId); -``` - -**Parameters** - -| Name | Type | Description | -| ------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `streamId` | `uint256` | The ID of the stream to deposit on. | -| `totalAmount` | `uint128` | The total amount, including the deposit and any broker fee, denoted in token's decimals. | -| `sender` | `address` | The stream's sender address. | -| `recipient` | `address` | The stream's recipient address. | -| `broker` | `Broker` | Struct encapsulating (i) the address of the broker assisting in creating the stream, and (ii) the percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point percentage. | - ### pause Pauses the stream. -Emits {PauseFlowStream} event. Notes: +\*Emits a {PauseFlowStream} and {MetadataUpdate} event. Notes: - It updates snapshot debt and snapshot time. - It sets the rate per second to zero. Requirements: - Must not be delegate called. -- `streamId` must not reference a null or an already paused stream. -- `msg.sender` must be the stream's sender. +- `streamId` must not reference a null, pending or paused stream. +- `msg.sender` must be the stream's sender.\* ```solidity function pause(uint256 streamId) @@ -454,16 +460,38 @@ function pause(uint256 streamId) | ---------- | --------- | ------------------------------ | | `streamId` | `uint256` | The ID of the stream to pause. | +### recover + +Recover the surplus amount of tokens. + +\*Emits a {Recover} event. Notes: + +- The surplus amount is defined as the difference between the total balance of the contract for the provided ERC-20 + token and the sum of balances of all streams created using the same ERC-20 token. Requirements: +- `msg.sender` must be the comptroller contract. +- The surplus amount must be greater than zero.\* + +```solidity +function recover(IERC20 token, address to) external override onlyComptroller; +``` + +**Parameters** + +| Name | Type | Description | +| ------- | --------- | -------------------------------------------------------- | +| `token` | `IERC20` | The contract address of the ERC-20 token to recover for. | +| `to` | `address` | The address to send the surplus amount. | + ### refund Refunds the provided amount of tokens from the stream to the sender's address. -Emits a {Transfer} and {RefundFromFlowStream} event. Requirements: +\*Emits a {Transfer}, {RefundFromFlowStream} and {MetadataUpdate} event. Requirements: - Must not be delegate called. - `streamId` must not reference a null stream. - `msg.sender` must be the sender. -- `amount` must be greater than zero and must not exceed the refundable amount. +- `amount` must be greater than zero and must not exceed the refundable amount.\* ```solidity function refund( @@ -490,10 +518,10 @@ function refund( Refunds the provided amount of tokens from the stream to the sender's address. -Emits a {Transfer}, {RefundFromFlowStream} and {PauseFlowStream} event. Notes: +\*Emits a {Transfer}, {RefundFromFlowStream}, {PauseFlowStream} and {MetadataUpdate} event. Notes: - Refer to the notes in {pause}. Requirements: -- Refer to the requirements in {refund} and {pause}. +- Refer to the requirements in {refund} and {pause}.\* ```solidity function refundAndPause( @@ -521,9 +549,9 @@ function refundAndPause( Refunds the entire refundable amount of tokens from the stream to the sender's address. -Emits a {Transfer} and {RefundFromFlowStream} event. Requirements: +\*Emits a {Transfer}, {RefundFromFlowStream} and {MetadataUpdate} event. Requirements: -- Refer to the requirements in {refund}. +- Refer to the requirements in {refund}.\* ```solidity function refundMax(uint256 streamId) @@ -533,7 +561,8 @@ function refundMax(uint256 streamId) noDelegateCall notNull(streamId) onlySender(streamId) - updateMetadata(streamId); + updateMetadata(streamId) + returns (uint128 refundedAmount); ``` **Parameters** @@ -542,17 +571,23 @@ function refundMax(uint256 streamId) | ---------- | --------- | ------------------------------------ | | `streamId` | `uint256` | The ID of the stream to refund from. | +**Returns** + +| Name | Type | Description | +| ---------------- | --------- | ---------------------------------------------------------------------- | +| `refundedAmount` | `uint128` | The amount refunded to the stream sender, denoted in token's decimals. | + ### restart Restarts the stream with the provided rate per second. -Emits {RestartFlowStream} event. Notes: +\*Emits a {RestartFlowStream} and {MetadataUpdate} event. Notes: - It updates snapshot debt and snapshot time. Requirements: - Must not be delegate called. -- `streamId` must not reference a null, or a voided stream. +- `streamId` must not reference a null stream, must be paused, and must not be voided. - `msg.sender` must be the stream's sender. -- `ratePerSecond` must be greater than zero. +- `ratePerSecond` must be greater than zero.\* ```solidity function restart( @@ -580,11 +615,11 @@ function restart( Restarts the stream with the provided rate per second, and makes a deposit. -Emits a {RestartFlowStream}, {Transfer}, and {DepositFlowStream} event. Notes: +\*Emits a {RestartFlowStream}, {Transfer}, {DepositFlowStream} and {MetadataUpdate} event. Notes: - Refer to the notes in {restart} and {deposit}. Requirements: - `amount` must be greater than zero. -- Refer to the requirements in {restart}. +- Refer to the requirements in {restart}.\* ```solidity function restartAndDeposit( @@ -610,20 +645,95 @@ function restartAndDeposit( | `ratePerSecond` | `UD21x18` | The amount by which the debt is increasing every second, denoted as a fixed-point number where 1e18 is 1 token per second. | | `amount` | `uint128` | The deposit amount, denoted in token's decimals. | +### setNativeToken + +Sets the native token address. Once set, it cannot be changed. + +\*For more information, see the documentation for {nativeToken}. Emits a {SetNativeToken} event. Requirements: + +- `msg.sender` must be the comptroller contract. +- `newNativeToken` must not be zero address. +- The native token must not be already set.\* + +```solidity +function setNativeToken(address newNativeToken) external override onlyComptroller; +``` + +**Parameters** + +| Name | Type | Description | +| ---------------- | --------- | -------------------------------- | +| `newNativeToken` | `address` | The address of the native token. | + +### setNFTDescriptor + +Sets a new NFT descriptor contract, which produces the URI describing the Sablier stream NFTs. + +\*Emits a {SetNFTDescriptor} and {BatchMetadataUpdate} event. Notes: + +- Does not revert if the NFT descriptor is the same. Requirements: +- `msg.sender` must be the comptroller contract.\* + +```solidity +function setNFTDescriptor(IFlowNFTDescriptor newNFTDescriptor) external override onlyComptroller; +``` + +**Parameters** + +| Name | Type | Description | +| ------------------ | -------------------- | ----------------------------------------------- | +| `newNFTDescriptor` | `IFlowNFTDescriptor` | The address of the new NFT descriptor contract. | + +### supportsInterface + +_See {IERC165-supportsInterface}._ + +```solidity +function supportsInterface(bytes4 interfaceId) public view override(IERC165, ERC721) returns (bool); +``` + +### tokenURI + +_See {IERC721Metadata-tokenURI}._ + +```solidity +function tokenURI(uint256 streamId) public view override(IERC721Metadata, ERC721) returns (string memory uri); +``` + +### transferTokens + +A helper to transfer ERC-20 tokens from the caller to the provided address. Useful for paying one-time bonuses. + +\*Emits a {Transfer} event. Requirements: + +- `msg.sender` must have approved this contract to spend at least `amount` tokens.\* + +```solidity +function transferTokens(IERC20 token, address to, uint128 amount) external payable; +``` + +**Parameters** + +| Name | Type | Description | +| -------- | --------- | -------------------------------------------------------------- | +| `token` | `IERC20` | The contract address of the ERC-20 token to be transferred. | +| `to` | `address` | The address receiving the tokens. | +| `amount` | `uint128` | The amount of tokens to transfer, denoted in token's decimals. | + ### void Voids a stream. -Emits {VoidFlowStream} event. Notes: +\*Emits a {VoidFlowStream} and {MetadataUpdate} event. Notes: -- It sets snapshot time to the `block.timestamp` +- It sets snapshot time to the `block.timestamp`. - Voiding an insolvent stream sets the snapshot debt to the stream's balance making the uncovered debt to become zero. - Voiding a solvent stream updates the snapshot debt by adding up ongoing debt. - It sets the rate per second to zero. - A voided stream cannot be restarted. Requirements: - Must not be delegate called. - `streamId` must not reference a null or a voided stream. -- `msg.sender` must either be the stream's sender, recipient or an approved third party. +- `msg.sender` must either be the stream's sender, recipient or an approved third party.\* ```solidity function void(uint256 streamId) @@ -644,18 +754,16 @@ function void(uint256 streamId) ### withdraw -Withdraws the provided `amount` minus the protocol fee to the provided `to` address. +Withdraws the provided `amount` to the provided `to` address. -Emits a {Transfer} and {WithdrawFromFlowStream} event. Notes: +\*Emits a {Transfer}, {WithdrawFromFlowStream} and {MetadataUpdate} event. Notes: -- It sets the snapshot time to the `block.timestamp` if `amount` is greater than snapshot debt. -- A protocol fee may be charged on the withdrawn amount if the protocol fee is enabled for the streaming token. - Requirements: +- It sets the snapshot time to the `block.timestamp` if `amount` is greater than snapshot debt. Requirements: - Must not be delegate called. - `streamId` must not reference a null stream. - `to` must not be the zero address. -- `to` must be the recipient if `msg.sender` is not the stream's recipient. -- `amount` must be greater than zero and must not exceed the withdrawable amount. +- `to` must be the recipient if `msg.sender` is not the stream's recipient or an approved third party. +- `amount` must be greater than zero and must not exceed the withdrawable amount.\* ```solidity function withdraw( @@ -668,8 +776,7 @@ function withdraw( override noDelegateCall notNull(streamId) - updateMetadata(streamId) - returns (uint128 withdrawnAmount, uint128 protocolFeeAmount); + updateMetadata(streamId); ``` **Parameters** @@ -680,21 +787,14 @@ function withdraw( | `to` | `address` | The address receiving the withdrawn tokens. | | `amount` | `uint128` | The amount to withdraw, denoted in token's decimals. | -**Returns** - -| Name | Type | Description | -| ------------------- | --------- | ---------------------------------------------------------------------------------------------------------------- | -| `withdrawnAmount` | `uint128` | The amount withdrawn to the recipient, denoted in token's decimals. This is input amount minus the protocol fee. | -| `protocolFeeAmount` | `uint128` | The protocol fee amount, denoted in the token's decimals. | - ### withdrawMax -Withdraws the entire withdrawable amount minus the protocol fee to the provided `to` address. +Withdraws the entire withdrawable amount to the provided `to` address. -Emits a {Transfer} and {WithdrawFromFlowStream} event. Notes: +\*Emits a {Transfer}, {WithdrawFromFlowStream} and {MetadataUpdate} event. Notes: - Refer to the notes in {withdraw}. Requirements: -- Refer to the requirements in {withdraw}. +- Refer to the requirements in {withdraw}.\* ```solidity function withdrawMax( @@ -707,7 +807,7 @@ function withdrawMax( noDelegateCall notNull(streamId) updateMetadata(streamId) - returns (uint128 withdrawnAmount, uint128 protocolFeeAmount); + returns (uint128 withdrawnAmount); ``` **Parameters** @@ -719,26 +819,73 @@ function withdrawMax( **Returns** -| Name | Type | Description | -| ------------------- | --------- | ------------------------------------------------------------------- | -| `withdrawnAmount` | `uint128` | The amount withdrawn to the recipient, denoted in token's decimals. | -| `protocolFeeAmount` | `uint128` | The protocol fee amount, denoted in the token's decimals. | +| Name | Type | Description | +| ----------------- | --------- | ------------------------------------------------------------------- | +| `withdrawnAmount` | `uint128` | The amount withdrawn to the recipient, denoted in token's decimals. | + +### \_update + +Overrides the {ERC-721.\_update} function to check that the stream is transferable. + +_The transferable flag is ignored if the current owner is 0, as the update in this case is a mint and is allowed. +Transfers to the zero address are not allowed, preventing accidental burns._ + +```solidity +function _update( + address to, + uint256 streamId, + address auth +) + internal + override + updateMetadata(streamId) + returns (address); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `to` | `address` | The address of the new recipient of the stream. | +| `streamId` | `uint256` | ID of the stream to update. | +| `auth` | `address` | Optional parameter. If the value is not zero, the overridden implementation will check that `auth` is either the recipient of the stream, or an approved third party. | + +**Returns** + +| Name | Type | Description | +| -------- | --------- | ----------------------------------------------------------- | +| `` | `address` | The original recipient of the `streamId` before the update. | ### \_coveredDebtOf _Calculates the amount of covered debt by the stream balance._ ```solidity -function _coveredDebtOf(uint256 streamId) internal view returns (uint128); +function _coveredDebtOf(uint256 streamId) private view returns (uint128); +``` + +### \_isCallerStreamRecipientOrApproved + +Checks whether `msg.sender` is the stream's recipient or an approved third party. + +```solidity +function _isCallerStreamRecipientOrApproved(uint256 streamId, address recipient) private view returns (bool); ``` +**Parameters** + +| Name | Type | Description | +| ----------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | +| `recipient` | `address` | | + ### \_ongoingDebtScaledOf _Calculates the ongoing debt, as a 18-decimals fixed point number, accrued since last snapshot. Return 0 if the stream is paused or `block.timestamp` is less than or equal to snapshot time._ ```solidity -function _ongoingDebtScaledOf(uint256 streamId) internal view returns (uint256); +function _ongoingDebtScaledOf(uint256 streamId) private view returns (uint256); ``` ### \_refundableAmountOf @@ -746,7 +893,7 @@ function _ongoingDebtScaledOf(uint256 streamId) internal view returns (uint256); _Calculates the refundable amount._ ```solidity -function _refundableAmountOf(uint256 streamId) internal view returns (uint128); +function _refundableAmountOf(uint256 streamId) private view returns (uint128); ``` ### \_totalDebtOf @@ -755,7 +902,7 @@ _The total debt is the sum of the snapshot debt and the ongoing debt descaled to independent of the stream's balance._ ```solidity -function _totalDebtOf(uint256 streamId) internal view returns (uint256); +function _totalDebtOf(uint256 streamId) private view returns (uint256); ``` ### \_uncoveredDebtOf @@ -763,7 +910,7 @@ function _totalDebtOf(uint256 streamId) internal view returns (uint256); _Calculates the uncovered debt._ ```solidity -function _uncoveredDebtOf(uint256 streamId) internal view returns (uint256); +function _uncoveredDebtOf(uint256 streamId) private view returns (uint256); ``` ### \_verifyStreamSenderRecipient @@ -771,91 +918,78 @@ function _uncoveredDebtOf(uint256 streamId) internal view returns (uint256); _Checks whether the provided addresses matches stream's sender and recipient._ ```solidity -function _verifyStreamSenderRecipient(uint256 streamId, address sender, address recipient) internal view; +function _verifyStreamSenderRecipient(uint256 streamId, address sender, address recipient) private view; ``` ### \_adjustRatePerSecond -_See the documentation for the user-facing functions that call this internal function._ +_See the documentation for the user-facing functions that call this private function._ ```solidity -function _adjustRatePerSecond(uint256 streamId, UD21x18 newRatePerSecond) internal; +function _adjustRatePerSecond(uint256 streamId, UD21x18 newRatePerSecond) private; ``` ### \_create -_See the documentation for the user-facing functions that call this internal function._ +_See the documentation for the user-facing functions that call this private function._ ```solidity function _create( address sender, address recipient, UD21x18 ratePerSecond, + uint40 startTime, IERC20 token, bool transferable ) - internal + private returns (uint256 streamId); ``` ### \_deposit -_See the documentation for the user-facing functions that call this internal function._ +_See the documentation for the user-facing functions that call this private function._ ```solidity -function _deposit(uint256 streamId, uint128 amount) internal; -``` - -### \_depositViaBroker - -_See the documentation for the user-facing functions that call this internal function._ - -```solidity -function _depositViaBroker(uint256 streamId, uint128 totalAmount, Broker memory broker) internal; +function _deposit(uint256 streamId, uint128 amount) private; ``` ### \_pause -_See the documentation for the user-facing functions that call this internal function._ +_See the documentation for the user-facing functions that call this private function._ ```solidity -function _pause(uint256 streamId) internal; +function _pause(uint256 streamId) private; ``` ### \_refund -_See the documentation for the user-facing functions that call this internal function._ +_See the documentation for the user-facing functions that call this private function._ ```solidity -function _refund(uint256 streamId, uint128 amount) internal; +function _refund(uint256 streamId, uint128 amount) private; ``` ### \_restart -_See the documentation for the user-facing functions that call this internal function._ +_See the documentation for the user-facing functions that call this private function._ ```solidity -function _restart(uint256 streamId, UD21x18 ratePerSecond) internal; +function _restart(uint256 streamId, UD21x18 ratePerSecond) private; ``` ### \_void -_See the documentation for the user-facing functions that call this internal function._ +_See the documentation for the user-facing functions that call this private function._ ```solidity -function _void(uint256 streamId) internal; +function _void(uint256 streamId) private; ``` ### \_withdraw -_See the documentation for the user-facing functions that call this internal function._ +_See the documentation for the user-facing functions that call this private function._ ```solidity -function _withdraw( - uint256 streamId, - address to, - uint128 amount -) - internal - returns (uint128 withdrawnAmount, uint128 protocolFeeAmount); +function _withdraw(uint256 streamId, address to, uint128 amount) private; ``` diff --git a/docs/reference/flow/contracts/interfaces/interface.IAdminable.md b/docs/reference/flow/contracts/interfaces/interface.IAdminable.md deleted file mode 100644 index 1446ec32..00000000 --- a/docs/reference/flow/contracts/interfaces/interface.IAdminable.md +++ /dev/null @@ -1,54 +0,0 @@ -# IAdminable - -[Git Source](https://github.com/sablier-labs/flow/blob/a0fa33d2843af0817e34970cdc05822ead31daaa/src/interfaces/IAdminable.sol) - -Contract module that provides a basic access control mechanism, with an admin that can be granted exclusive access to -specific functions. The inheriting contract must set the initial admin in the constructor. - -## Functions - -### admin - -The address of the admin account or contract. - -```solidity -function admin() external view returns (address); -``` - -### transferAdmin - -Transfers the contract admin to a new address. - -Notes: - -- Does not revert if the admin is the same. -- This function can potentially leave the contract without an admin, thereby removing any functionality that is only - available to the admin. Requirements: -- `msg.sender` must be the contract admin. - -```solidity -function transferAdmin(address newAdmin) external; -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ----------------------------- | -| `newAdmin` | `address` | The address of the new admin. | - -## Events - -### TransferAdmin - -Emitted when the admin is transferred. - -```solidity -event TransferAdmin(address indexed oldAdmin, address indexed newAdmin); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ----------------------------- | -| `oldAdmin` | `address` | The address of the old admin. | -| `newAdmin` | `address` | The address of the new admin. | diff --git a/docs/reference/flow/contracts/interfaces/interface.IBatch.md b/docs/reference/flow/contracts/interfaces/interface.IBatch.md deleted file mode 100644 index 7aa9aaab..00000000 --- a/docs/reference/flow/contracts/interfaces/interface.IBatch.md +++ /dev/null @@ -1,30 +0,0 @@ -# IBatch - -[Git Source](https://github.com/sablier-labs/flow/blob/a0fa33d2843af0817e34970cdc05822ead31daaa/src/interfaces/IBatch.sol) - -This contract implements logic to batch call any function. - -## Functions - -### batch - -Allows batched calls to self, i.e., `this` contract. - -_Since `msg.value` can be reused across calls, be VERY CAREFUL when using it. Refer to -https://paradigm.xyz/2021/08/two-rights-might-make-a-wrong for more information._ - -```solidity -function batch(bytes[] calldata calls) external payable returns (bytes[] memory results); -``` - -**Parameters** - -| Name | Type | Description | -| ------- | --------- | --------------------------------- | -| `calls` | `bytes[]` | An array of inputs for each call. | - -**Returns** - -| Name | Type | Description | -| --------- | --------- | -------------------------------------------------------------------------------- | -| `results` | `bytes[]` | An array of results from each call. Empty when the calls do not return anything. | diff --git a/docs/reference/flow/contracts/interfaces/interface.IFlowNFTDescriptor.md b/docs/reference/flow/contracts/interfaces/interface.IFlowNFTDescriptor.md index fc8d52bd..e51f1883 100644 --- a/docs/reference/flow/contracts/interfaces/interface.IFlowNFTDescriptor.md +++ b/docs/reference/flow/contracts/interfaces/interface.IFlowNFTDescriptor.md @@ -1,6 +1,6 @@ # IFlowNFTDescriptor -[Git Source](https://github.com/sablier-labs/flow/blob/a0fa33d2843af0817e34970cdc05822ead31daaa/src/interfaces/IFlowNFTDescriptor.sol) +[Git Source](https://github.com/sablier-labs/flow/blob/a4143de45478f508bca8305fec2bd81b7ad25fe9/src/interfaces/IFlowNFTDescriptor.sol) This contract generates the URI describing the Sablier Flow stream NFTs. diff --git a/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md b/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md index 7e2148db..0a2e92f9 100644 --- a/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md +++ b/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md @@ -1,14 +1,30 @@ # ISablierFlow -[Git Source](https://github.com/sablier-labs/flow/blob/a0fa33d2843af0817e34970cdc05822ead31daaa/src/interfaces/ISablierFlow.sol) +[Git Source](https://github.com/sablier-labs/flow/blob/a4143de45478f508bca8305fec2bd81b7ad25fe9/src/interfaces/ISablierFlow.sol) -**Inherits:** [IBatch](/docs/reference/flow/contracts/interfaces/interface.IBatch.md), -[ISablierFlowBase](/docs/reference/flow/contracts/interfaces/interface.ISablierFlowBase.md) +**Inherits:** IBatch, IComptrollerable, IERC4906, IERC721Metadata, +[ISablierFlowState](/docs/reference/flow/contracts/interfaces/interface.ISablierFlowState.md) Creates and manages Flow streams with linear streaming functions. ## Functions +### calculateMinFeeWei + +Calculates the minimum fee in wei required to withdraw from the given stream ID. + +_Reverts if `streamId` references a null stream._ + +```solidity +function calculateMinFeeWei(uint256 streamId) external view returns (uint256 minFeeWei); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + ### coveredDebtOf Returns the amount of debt covered by the stream balance, denoted in token's decimals. @@ -27,13 +43,13 @@ function coveredDebtOf(uint256 streamId) external view returns (uint128 coveredD ### depletionTimeOf -Returns the time at which the total debt exceeds stream balance. If the total debt is less than or equal to stream -balance, it returns 0. +Returns the time at which the total debt exceeds stream balance. If the total debt exceeds the stream balance, it +returns 0. -Reverts on the following conditions: +\*Reverts on the following conditions: - If `streamId` references a paused or a null stream. -- If stream balance is zero. +- If stream balance is zero.\* ```solidity function depletionTimeOf(uint256 streamId) external view returns (uint256 depletionTime); @@ -45,10 +61,26 @@ function depletionTimeOf(uint256 streamId) external view returns (uint256 deplet | ---------- | --------- | ---------------------------- | | `streamId` | `uint256` | The stream ID for the query. | +### getRecipient + +Retrieves the stream's recipient. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getRecipient(uint256 streamId) external view returns (address recipient); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + ### ongoingDebtScaledOf Returns the amount of debt accrued since the snapshot time until now, denoted as a fixed-point number where 1e18 is 1 -token. +token. If the stream is pending, it returns zero. _Reverts if `streamId` references a null stream._ @@ -154,14 +186,14 @@ function withdrawableAmountOf(uint256 streamId) external view returns (uint128 w Changes the stream's rate per second. -Emits a [AdjustFlowStream](/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md#adjustflowstream) and +\*Emits a [AdjustFlowStream](/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md#adjustflowstream) and {MetadataUpdate} event. Notes: -- It updates snapshot debt and snapshot time. Requirements: +- If the snapshot time is not in the future, it updates both the snapshot time and snapshot debt. Requirements: - Must not be delegate called. -- `streamId` must not reference a null or a paused stream. +- `streamId` must not reference a null, paused, or voided stream. - `msg.sender` must be the stream's sender. -- `newRatePerSecond` must not equal to the current rate per second. +- `newRatePerSecond` must be greater than zero and must be different from the current rate per second.\* ```solidity function adjustRatePerSecond(uint256 streamId, UD21x18 newRatePerSecond) external payable; @@ -176,22 +208,25 @@ function adjustRatePerSecond(uint256 streamId, UD21x18 newRatePerSecond) externa ### create -Creates a new Flow stream by setting the snapshot time to `block.timestamp` and leaving the balance to zero. The stream -is wrapped in an ERC-721 NFT. +Creates a new Flow stream by setting the snapshot time to `startTime` and leaving the balance to zero. The stream is +wrapped in an ERC-721 NFT. -Emits [CreateFlowStream](/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md#createflowstream) event. -Requirements: +\*Emits a [CreateFlowStream](/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md#createflowstream) and +{MetadataUpdate} event. Requirements: - Must not be delegate called. - `sender` must not be the zero address. - `recipient` must not be the zero address. -- The `token`'s decimals must be less than or equal to 18. +- If `startTime` is in the future, the `ratePerSecond` must be greater than zero. +- The `token` must not be the native token. +- The `token`'s decimals must be less than or equal to 18.\* ```solidity function create( address sender, address recipient, UD21x18 ratePerSecond, + uint40 startTime, IERC20 token, bool transferable ) @@ -202,13 +237,14 @@ function create( **Parameters** -| Name | Type | Description | -| --------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------- | -| `sender` | `address` | The address streaming the tokens, which is able to adjust and pause the stream. It doesn't have to be the same as `msg.sender`. | -| `recipient` | `address` | The address receiving the tokens. | -| `ratePerSecond` | `UD21x18` | The amount by which the debt is increasing every second, denoted as a fixed-point number where 1e18 is 1 token per second. | -| `token` | `IERC20` | The contract address of the ERC-20 token to be streamed. | -| `transferable` | `bool` | Boolean indicating if the stream NFT is transferable. | +| Name | Type | Description | +| --------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------- | +| `sender` | `address` | The address streaming the tokens, which is able to adjust and pause the stream. It doesn't have to be the same as `msg.sender`. | +| `recipient` | `address` | The address receiving the tokens. | +| `ratePerSecond` | `UD21x18` | The amount by which the debt is increasing every second, denoted as a fixed-point number where 1e18 is 1 token per second. | +| `startTime` | `uint40` | The timestamp when the stream starts. A sentinel value of zero means the stream will be created with the snapshot time as `block.timestamp`. | +| `token` | `IERC20` | The contract address of the ERC-20 token to be streamed. | +| `transferable` | `bool` | Boolean indicating if the stream NFT is transferable. | **Returns** @@ -218,19 +254,20 @@ function create( ### createAndDeposit -Creates a new Flow stream by setting the snapshot time to `block.timestamp` and the balance to `amount`. The stream is -wrapped in an ERC-721 NFT. +Creates a new Flow stream by setting the snapshot time to `startTime` and the balance to `amount`. The stream is wrapped +in an ERC-721 NFT. -Emits a {Transfer}, {CreateFlowStream}, and {DepositFlowStream} event. Notes: +\*Emits a {Transfer}, {CreateFlowStream}, {DepositFlowStream} and {MetadataUpdate} event. Notes: -- Refer to the notes in {deposit}. Requirements: -- Refer to the requirements in {create} and {deposit}. +- Refer to the notes in {create} and {deposit}. Requirements: +- Refer to the requirements in {create} and {deposit}.\* ```solidity function createAndDeposit( address sender, address recipient, UD21x18 ratePerSecond, + uint40 startTime, IERC20 token, bool transferable, uint128 amount @@ -242,14 +279,15 @@ function createAndDeposit( **Parameters** -| Name | Type | Description | -| --------------- | --------- | -------------------------------------------------------------------------------------------------------------------------- | -| `sender` | `address` | The address streaming the tokens. It doesn't have to be the same as `msg.sender`. | -| `recipient` | `address` | The address receiving the tokens. | -| `ratePerSecond` | `UD21x18` | The amount by which the debt is increasing every second, denoted as a fixed-point number where 1e18 is 1 token per second. | -| `token` | `IERC20` | The contract address of the ERC-20 token to be streamed. | -| `transferable` | `bool` | Boolean indicating if the stream NFT is transferable. | -| `amount` | `uint128` | The deposit amount, denoted in token's decimals. | +| Name | Type | Description | +| --------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------- | +| `sender` | `address` | The address streaming the tokens. It doesn't have to be the same as `msg.sender`. | +| `recipient` | `address` | The address receiving the tokens. | +| `ratePerSecond` | `UD21x18` | The amount by which the debt is increasing every second, denoted as a fixed-point number where 1e18 is 1 token per second. | +| `startTime` | `uint40` | The timestamp when the stream starts. A sentinel value of zero means the stream will be created with the snapshot time as `block.timestamp`. | +| `token` | `IERC20` | The contract address of the ERC-20 token to be streamed. | +| `transferable` | `bool` | Boolean indicating if the stream NFT is transferable. | +| `amount` | `uint128` | The deposit amount, denoted in token's decimals. | **Returns** @@ -261,12 +299,12 @@ function createAndDeposit( Makes a deposit in a stream. -Emits a {Transfer} and {DepositFlowStream} event. Requirements: +\*Emits a {Transfer}, {DepositFlowStream} and {MetadataUpdate} event. Requirements: - Must not be delegate called. - `streamId` must not reference a null or a voided stream. - `amount` must be greater than zero. -- `sender` and `recipient` must match the stream's sender and recipient addresses. +- `sender` and `recipient` must match the stream's sender and recipient addresses.\* ```solidity function deposit(uint256 streamId, uint128 amount, address sender, address recipient) external payable; @@ -285,10 +323,10 @@ function deposit(uint256 streamId, uint128 amount, address sender, address recip Deposits tokens in a stream and pauses it. -Emits a {Transfer}, {DepositFlowStream} and {PauseFlowStream} event. Notes: +\*Emits a {Transfer}, {DepositFlowStream}, {PauseFlowStream} and {MetadataUpdate} event. Notes: - Refer to the notes in {deposit} and {pause}. Requirements: -- Refer to the requirements in {deposit} and {pause}. +- Refer to the requirements in {deposit} and {pause}.\* ```solidity function depositAndPause(uint256 streamId, uint128 amount) external payable; @@ -301,74 +339,61 @@ function depositAndPause(uint256 streamId, uint128 amount) external payable; | `streamId` | `uint256` | The ID of the stream to deposit to, and then pause. | | `amount` | `uint128` | The deposit amount, denoted in token's decimals. | -### depositViaBroker +### pause -Deposits tokens in a stream. +Pauses the stream. -Emits a {Transfer} and {DepositFlowStream} event. Notes: +\*Emits a [PauseFlowStream](/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md#pauseflowstream) and +{MetadataUpdate} event. Notes: -- Refer to the notes in {deposit}. Requirements: +- It updates snapshot debt and snapshot time. +- It sets the rate per second to zero. Requirements: - Must not be delegate called. -- `streamId` must not reference a null stream. -- `totalAmount` must be greater than zero. Otherwise it will revert inside {deposit}. -- `broker.account` must not be 0 address. -- `broker.fee` must not be greater than `MAX_FEE`. It can be zero. +- `streamId` must not reference a null, pending or paused stream. +- `msg.sender` must be the stream's sender.\* ```solidity -function depositViaBroker( - uint256 streamId, - uint128 totalAmount, - address sender, - address recipient, - Broker calldata broker -) - external - payable; +function pause(uint256 streamId) external payable; ``` **Parameters** -| Name | Type | Description | -| ------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `streamId` | `uint256` | The ID of the stream to deposit on. | -| `totalAmount` | `uint128` | The total amount, including the deposit and any broker fee, denoted in token's decimals. | -| `sender` | `address` | The stream's sender address. | -| `recipient` | `address` | The stream's recipient address. | -| `broker` | `Broker` | Struct encapsulating (i) the address of the broker assisting in creating the stream, and (ii) the percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point percentage. | +| Name | Type | Description | +| ---------- | --------- | ------------------------------ | +| `streamId` | `uint256` | The ID of the stream to pause. | -### pause +### recover -Pauses the stream. +Recover the surplus amount of tokens. -Emits [PauseFlowStream](/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md#pauseflowstream) event. -Notes: +\*Emits a [Recover](/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md#recover) event. Notes: -- It updates snapshot debt and snapshot time. -- It sets the rate per second to zero. Requirements: -- Must not be delegate called. -- `streamId` must not reference a null or an already paused stream. -- `msg.sender` must be the stream's sender. +- The surplus amount is defined as the difference between the total balance of the contract for the provided ERC-20 + token and the sum of balances of all streams created using the same ERC-20 token. Requirements: +- `msg.sender` must be the comptroller contract. +- The surplus amount must be greater than zero.\* ```solidity -function pause(uint256 streamId) external payable; +function recover(IERC20 token, address to) external; ``` **Parameters** -| Name | Type | Description | -| ---------- | --------- | ------------------------------ | -| `streamId` | `uint256` | The ID of the stream to pause. | +| Name | Type | Description | +| ------- | --------- | -------------------------------------------------------- | +| `token` | `IERC20` | The contract address of the ERC-20 token to recover for. | +| `to` | `address` | The address to send the surplus amount. | ### refund Refunds the provided amount of tokens from the stream to the sender's address. -Emits a {Transfer} and {RefundFromFlowStream} event. Requirements: +\*Emits a {Transfer}, {RefundFromFlowStream} and {MetadataUpdate} event. Requirements: - Must not be delegate called. - `streamId` must not reference a null stream. - `msg.sender` must be the sender. -- `amount` must be greater than zero and must not exceed the refundable amount. +- `amount` must be greater than zero and must not exceed the refundable amount.\* ```solidity function refund(uint256 streamId, uint128 amount) external payable; @@ -385,10 +410,10 @@ function refund(uint256 streamId, uint128 amount) external payable; Refunds the provided amount of tokens from the stream to the sender's address. -Emits a {Transfer}, {RefundFromFlowStream} and {PauseFlowStream} event. Notes: +\*Emits a {Transfer}, {RefundFromFlowStream}, {PauseFlowStream} and {MetadataUpdate} event. Notes: - Refer to the notes in {pause}. Requirements: -- Refer to the requirements in {refund} and {pause}. +- Refer to the requirements in {refund} and {pause}.\* ```solidity function refundAndPause(uint256 streamId, uint128 amount) external payable; @@ -405,12 +430,12 @@ function refundAndPause(uint256 streamId, uint128 amount) external payable; Refunds the entire refundable amount of tokens from the stream to the sender's address. -Emits a {Transfer} and {RefundFromFlowStream} event. Requirements: +\*Emits a {Transfer}, {RefundFromFlowStream} and {MetadataUpdate} event. Requirements: -- Refer to the requirements in {refund}. +- Refer to the requirements in {refund}.\* ```solidity -function refundMax(uint256 streamId) external payable; +function refundMax(uint256 streamId) external payable returns (uint128 refundedAmount); ``` **Parameters** @@ -419,18 +444,24 @@ function refundMax(uint256 streamId) external payable; | ---------- | --------- | ------------------------------------ | | `streamId` | `uint256` | The ID of the stream to refund from. | +**Returns** + +| Name | Type | Description | +| ---------------- | --------- | ---------------------------------------------------------------------- | +| `refundedAmount` | `uint128` | The amount refunded to the stream sender, denoted in token's decimals. | + ### restart Restarts the stream with the provided rate per second. -Emits [RestartFlowStream](/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md#restartflowstream) event. -Notes: +\*Emits a [RestartFlowStream](/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md#restartflowstream) and +{MetadataUpdate} event. Notes: - It updates snapshot debt and snapshot time. Requirements: - Must not be delegate called. -- `streamId` must not reference a null, or a voided stream. +- `streamId` must not reference a null stream, must be paused, and must not be voided. - `msg.sender` must be the stream's sender. -- `ratePerSecond` must be greater than zero. +- `ratePerSecond` must be greater than zero.\* ```solidity function restart(uint256 streamId, UD21x18 ratePerSecond) external payable; @@ -447,12 +478,12 @@ function restart(uint256 streamId, UD21x18 ratePerSecond) external payable; Restarts the stream with the provided rate per second, and makes a deposit. -Emits a [RestartFlowStream](/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md#restartflowstream), -{Transfer}, and {DepositFlowStream} event. Notes: +\*Emits a [RestartFlowStream](/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md#restartflowstream), +{Transfer}, {DepositFlowStream} and {MetadataUpdate} event. Notes: - Refer to the notes in {restart} and {deposit}. Requirements: - `amount` must be greater than zero. -- Refer to the requirements in {restart}. +- Refer to the requirements in {restart}.\* ```solidity function restartAndDeposit(uint256 streamId, UD21x18 ratePerSecond, uint128 amount) external payable; @@ -466,20 +497,81 @@ function restartAndDeposit(uint256 streamId, UD21x18 ratePerSecond, uint128 amou | `ratePerSecond` | `UD21x18` | The amount by which the debt is increasing every second, denoted as a fixed-point number where 1e18 is 1 token per second. | | `amount` | `uint128` | The deposit amount, denoted in token's decimals. | +### setNativeToken + +Sets the native token address. Once set, it cannot be changed. + +\*For more information, see the documentation for {nativeToken}. Emits a {SetNativeToken} event. Requirements: + +- `msg.sender` must be the comptroller contract. +- `newNativeToken` must not be zero address. +- The native token must not be already set.\* + +```solidity +function setNativeToken(address newNativeToken) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---------------- | --------- | -------------------------------- | +| `newNativeToken` | `address` | The address of the native token. | + +### setNFTDescriptor + +Sets a new NFT descriptor contract, which produces the URI describing the Sablier stream NFTs. + +\*Emits a [SetNFTDescriptor](/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md#setnftdescriptor) and +{BatchMetadataUpdate} event. Notes: + +- Does not revert if the NFT descriptor is the same. Requirements: +- `msg.sender` must be the comptroller contract.\* + +```solidity +function setNFTDescriptor(IFlowNFTDescriptor newNFTDescriptor) external; +``` + +**Parameters** + +| Name | Type | Description | +| ------------------ | -------------------- | ----------------------------------------------- | +| `newNFTDescriptor` | `IFlowNFTDescriptor` | The address of the new NFT descriptor contract. | + +### transferTokens + +A helper to transfer ERC-20 tokens from the caller to the provided address. Useful for paying one-time bonuses. + +\*Emits a {Transfer} event. Requirements: + +- `msg.sender` must have approved this contract to spend at least `amount` tokens.\* + +```solidity +function transferTokens(IERC20 token, address to, uint128 amount) external payable; +``` + +**Parameters** + +| Name | Type | Description | +| -------- | --------- | -------------------------------------------------------------- | +| `token` | `IERC20` | The contract address of the ERC-20 token to be transferred. | +| `to` | `address` | The address receiving the tokens. | +| `amount` | `uint128` | The amount of tokens to transfer, denoted in token's decimals. | + ### void Voids a stream. -Emits [VoidFlowStream](/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md#voidflowstream) event. Notes: +\*Emits a [VoidFlowStream](/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md#voidflowstream) and +{MetadataUpdate} event. Notes: -- It sets snapshot time to the `block.timestamp` +- It sets snapshot time to the `block.timestamp`. - Voiding an insolvent stream sets the snapshot debt to the stream's balance making the uncovered debt to become zero. - Voiding a solvent stream updates the snapshot debt by adding up ongoing debt. - It sets the rate per second to zero. - A voided stream cannot be restarted. Requirements: - Must not be delegate called. - `streamId` must not reference a null or a voided stream. -- `msg.sender` must either be the stream's sender, recipient or an approved third party. +- `msg.sender` must either be the stream's sender, recipient or an approved third party.\* ```solidity function void(uint256 streamId) external payable; @@ -493,28 +585,19 @@ function void(uint256 streamId) external payable; ### withdraw -Withdraws the provided `amount` minus the protocol fee to the provided `to` address. +Withdraws the provided `amount` to the provided `to` address. -Emits a {Transfer} and {WithdrawFromFlowStream} event. Notes: +\*Emits a {Transfer}, {WithdrawFromFlowStream} and {MetadataUpdate} event. Notes: -- It sets the snapshot time to the `block.timestamp` if `amount` is greater than snapshot debt. -- A protocol fee may be charged on the withdrawn amount if the protocol fee is enabled for the streaming token. - Requirements: +- It sets the snapshot time to the `block.timestamp` if `amount` is greater than snapshot debt. Requirements: - Must not be delegate called. - `streamId` must not reference a null stream. - `to` must not be the zero address. -- `to` must be the recipient if `msg.sender` is not the stream's recipient. -- `amount` must be greater than zero and must not exceed the withdrawable amount. +- `to` must be the recipient if `msg.sender` is not the stream's recipient or an approved third party. +- `amount` must be greater than zero and must not exceed the withdrawable amount.\* ```solidity -function withdraw( - uint256 streamId, - address to, - uint128 amount -) - external - payable - returns (uint128 withdrawnAmount, uint128 protocolFeeAmount); +function withdraw(uint256 streamId, address to, uint128 amount) external payable; ``` **Parameters** @@ -525,30 +608,17 @@ function withdraw( | `to` | `address` | The address receiving the withdrawn tokens. | | `amount` | `uint128` | The amount to withdraw, denoted in token's decimals. | -**Returns** - -| Name | Type | Description | -| ------------------- | --------- | ---------------------------------------------------------------------------------------------------------------- | -| `withdrawnAmount` | `uint128` | The amount withdrawn to the recipient, denoted in token's decimals. This is input amount minus the protocol fee. | -| `protocolFeeAmount` | `uint128` | The protocol fee amount, denoted in the token's decimals. | - ### withdrawMax -Withdraws the entire withdrawable amount minus the protocol fee to the provided `to` address. +Withdraws the entire withdrawable amount to the provided `to` address. -Emits a {Transfer} and {WithdrawFromFlowStream} event. Notes: +\*Emits a {Transfer}, {WithdrawFromFlowStream} and {MetadataUpdate} event. Notes: - Refer to the notes in {withdraw}. Requirements: -- Refer to the requirements in {withdraw}. +- Refer to the requirements in {withdraw}.\* ```solidity -function withdrawMax( - uint256 streamId, - address to -) - external - payable - returns (uint128 withdrawnAmount, uint128 protocolFeeAmount); +function withdrawMax(uint256 streamId, address to) external payable returns (uint128 withdrawnAmount); ``` **Parameters** @@ -560,10 +630,9 @@ function withdrawMax( **Returns** -| Name | Type | Description | -| ------------------- | --------- | ------------------------------------------------------------------- | -| `withdrawnAmount` | `uint128` | The amount withdrawn to the recipient, denoted in token's decimals. | -| `protocolFeeAmount` | `uint128` | The protocol fee amount, denoted in the token's decimals. | +| Name | Type | Description | +| ----------------- | --------- | ------------------------------------------------------------------- | +| `withdrawnAmount` | `uint128` | The amount withdrawn to the recipient, denoted in token's decimals. | ## Events @@ -591,9 +660,11 @@ Emitted when a Flow stream is created. ```solidity event CreateFlowStream( uint256 streamId, + address creator, address indexed sender, address indexed recipient, UD21x18 ratePerSecond, + uint40 snapshotTime, IERC20 indexed token, bool transferable ); @@ -604,9 +675,11 @@ event CreateFlowStream( | Name | Type | Description | | --------------- | --------- | -------------------------------------------------------------------------------------------------------------------------- | | `streamId` | `uint256` | The ID of the newly created stream. | +| `creator` | `address` | The address creating the stream. | | `sender` | `address` | The address streaming the tokens, which is able to adjust and pause the stream. | | `recipient` | `address` | The address receiving the tokens, as well as the NFT owner. | | `ratePerSecond` | `UD21x18` | The amount by which the debt is increasing every second, denoted as a fixed-point number where 1e18 is 1 token per second. | +| `snapshotTime` | `uint40` | The timestamp when the stream begins accumulating debt. | | `token` | `IERC20` | The contract address of the ERC-20 token to be streamed. | | `transferable` | `bool` | Boolean indicating whether the stream NFT is transferable or not. | @@ -643,6 +716,23 @@ event PauseFlowStream(uint256 indexed streamId, address indexed sender, address | `recipient` | `address` | The stream's recipient address. | | `totalDebt` | `uint256` | The amount of tokens owed by the sender to the recipient, denoted in token's decimals. | +### Recover + +Emitted when the comptroller recovers the surplus amount of token. + +```solidity +event Recover(ISablierComptroller indexed comptroller, IERC20 indexed token, address to, uint256 surplus); +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | --------------------- | -------------------------------------------------------------------------- | +| `comptroller` | `ISablierComptroller` | The address of the current comptroller. | +| `token` | `IERC20` | The address of the ERC-20 token the surplus amount has been recovered for. | +| `to` | `address` | The address the surplus amount has been sent to. | +| `surplus` | `uint256` | The amount of surplus tokens recovered. | + ### RefundFromFlowStream Emitted when a sender is refunded from a stream. @@ -675,6 +765,32 @@ event RestartFlowStream(uint256 indexed streamId, address indexed sender, UD21x1 | `sender` | `address` | The stream's sender address. | | `ratePerSecond` | `UD21x18` | The amount by which the debt is increasing every second, denoted as a fixed-point number where 1e18 is 1 token per second. | +### SetNativeToken + +Emitted when the native token address is set by the comptroller. + +```solidity +event SetNativeToken(ISablierComptroller indexed comptroller, address nativeToken); +``` + +### SetNFTDescriptor + +Emitted when the comptroller sets a new NFT descriptor contract. + +```solidity +event SetNFTDescriptor( + ISablierComptroller indexed comptroller, IFlowNFTDescriptor oldNFTDescriptor, IFlowNFTDescriptor newNFTDescriptor +); +``` + +**Parameters** + +| Name | Type | Description | +| ------------------ | --------------------- | ----------------------------------------------- | +| `comptroller` | `ISablierComptroller` | The address of the current comptroller. | +| `oldNFTDescriptor` | `IFlowNFTDescriptor` | The address of the old NFT descriptor contract. | +| `newNFTDescriptor` | `IFlowNFTDescriptor` | The address of the new NFT descriptor contract. | + ### VoidFlowStream Emitted when a stream is voided by the sender, recipient or an approved operator. @@ -707,22 +823,16 @@ Emitted when tokens are withdrawn from a stream by a recipient or an approved op ```solidity event WithdrawFromFlowStream( - uint256 indexed streamId, - address indexed to, - IERC20 indexed token, - address caller, - uint128 withdrawAmount, - uint128 protocolFeeAmount + uint256 indexed streamId, address indexed to, IERC20 indexed token, address caller, uint128 withdrawAmount ); ``` **Parameters** -| Name | Type | Description | -| ------------------- | --------- | ------------------------------------------------------------------------------------------------------ | -| `streamId` | `uint256` | The ID of the stream. | -| `to` | `address` | The address that received the withdrawn tokens. | -| `token` | `IERC20` | The contract address of the ERC-20 token that was withdrawn. | -| `caller` | `address` | The address that performed the withdrawal, which can be the recipient or an approved operator. | -| `withdrawAmount` | `uint128` | The amount withdrawn to the recipient after subtracting the protocol fee, denoted in token's decimals. | -| `protocolFeeAmount` | `uint128` | The amount of protocol fee deducted from the withdrawn amount, denoted in token's decimals. | +| Name | Type | Description | +| ---------------- | --------- | ---------------------------------------------------------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream. | +| `to` | `address` | The address that received the withdrawn tokens. | +| `token` | `IERC20` | The contract address of the ERC-20 token that was withdrawn. | +| `caller` | `address` | The address that performed the withdrawal, which can be the recipient or an approved operator. | +| `withdrawAmount` | `uint128` | The amount withdrawn to the recipient, denoted in token's decimals. | diff --git a/docs/reference/flow/contracts/interfaces/interface.ISablierFlowBase.md b/docs/reference/flow/contracts/interfaces/interface.ISablierFlowBase.md deleted file mode 100644 index 126ee472..00000000 --- a/docs/reference/flow/contracts/interfaces/interface.ISablierFlowBase.md +++ /dev/null @@ -1,468 +0,0 @@ -# ISablierFlowBase - -[Git Source](https://github.com/sablier-labs/flow/blob/a0fa33d2843af0817e34970cdc05822ead31daaa/src/interfaces/ISablierFlowBase.sol) - -**Inherits:** IERC4906, IERC721Metadata, [IAdminable](/docs/reference/flow/contracts/interfaces/interface.IAdminable.md) - -Base contract that includes state variables (storage and constants) for the -[SablierFlow](/docs/reference/flow/contracts/contract.SablierFlow.md) contract, their respective getters, helpful -modifiers, and helper functions. - -_This contract also includes admin control functions._ - -## Functions - -### MAX_FEE - -Retrieves the maximum fee that can be charged by the broker and the protocol, denoted as a fixed-point percentage where -1e18 is 100%. - -_This value is hard coded as a constant._ - -```solidity -function MAX_FEE() external view returns (UD60x18 fee); -``` - -### aggregateBalance - -Retrieves the sum of balances of all streams. - -```solidity -function aggregateBalance(IERC20 token) external view returns (uint256); -``` - -**Parameters** - -| Name | Type | Description | -| ------- | -------- | ------------------------------- | -| `token` | `IERC20` | The ERC-20 token for the query. | - -### getBalance - -Retrieves the balance of the stream, i.e. the total deposited amounts subtracted by the total withdrawn amounts, denoted -in token's decimals. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getBalance(uint256 streamId) external view returns (uint128 balance); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### getRatePerSecond - -Retrieves the rate per second of the stream, denoted as a fixed-point number where 1e18 is 1 token per second. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getRatePerSecond(uint256 streamId) external view returns (UD21x18 ratePerSecond); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ------------------------------------------- | -| `streamId` | `uint256` | The ID of the stream to make the query for. | - -### getRecipient - -Retrieves the stream's recipient. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getRecipient(uint256 streamId) external view returns (address recipient); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### getSender - -Retrieves the stream's sender. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getSender(uint256 streamId) external view returns (address sender); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### getSnapshotDebtScaled - -Retrieves the snapshot debt of the stream, denoted as a fixed-point number where 1e18 is 1 token. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getSnapshotDebtScaled(uint256 streamId) external view returns (uint256 snapshotDebtScaled); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### getSnapshotTime - -Retrieves the snapshot time of the stream, which is a Unix timestamp. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getSnapshotTime(uint256 streamId) external view returns (uint40 snapshotTime); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ------------------------------------------- | -| `streamId` | `uint256` | The ID of the stream to make the query for. | - -### getStream - -Retrieves the stream entity. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getStream(uint256 streamId) external view returns (Flow.Stream memory stream); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### getToken - -Retrieves the token of the stream. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getToken(uint256 streamId) external view returns (IERC20 token); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ------------------------------------------- | -| `streamId` | `uint256` | The ID of the stream to make the query for. | - -### getTokenDecimals - -Retrieves the token decimals of the stream. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getTokenDecimals(uint256 streamId) external view returns (uint8 tokenDecimals); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ------------------------------------------- | -| `streamId` | `uint256` | The ID of the stream to make the query for. | - -### isPaused - -Returns whether a stream is paused. - -_Reverts if `streamId` references a null stream._ - -```solidity -function isPaused(uint256 streamId) external view returns (bool result); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### isStream - -Retrieves a flag indicating whether the stream exists. - -_Does not revert if `streamId` references a null stream._ - -```solidity -function isStream(uint256 streamId) external view returns (bool result); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### isTransferable - -Retrieves a flag indicating whether the stream NFT is transferable. - -_Reverts if `streamId` references a null stream._ - -```solidity -function isTransferable(uint256 streamId) external view returns (bool result); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### isVoided - -Retrieves a flag indicating whether the stream is voided. - -_Reverts if `streamId` references a null stream._ - -```solidity -function isVoided(uint256 streamId) external view returns (bool result); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### nextStreamId - -Counter for stream ids. - -```solidity -function nextStreamId() external view returns (uint256); -``` - -**Returns** - -| Name | Type | Description | -| -------- | --------- | ------------------- | -| `` | `uint256` | The next stream ID. | - -### nftDescriptor - -Contract that generates the non-fungible token URI. - -```solidity -function nftDescriptor() external view returns (IFlowNFTDescriptor); -``` - -### protocolFee - -Protocol fee for the provided ERC-20 token, denoted as a fixed-point percentage where 1e18 is 100%. - -```solidity -function protocolFee(IERC20 token) external view returns (UD60x18); -``` - -### protocolRevenue - -Protocol revenue accrued for the provided ERC-20 token, denoted in token's decimals. - -```solidity -function protocolRevenue(IERC20 token) external view returns (uint128); -``` - -### collectFees - -Collects the accrued fees by transferring them to the contract admin. - -Emits a [CollectFees](/docs/reference/flow/contracts/interfaces/interface.ISablierFlowBase.md#collectfees) event. Notes: - -- If the admin is a contract, it must be able to receive native token payments, e.g., ETH for Ethereum Mainnet. - -```solidity -function collectFees() external; -``` - -### collectProtocolRevenue - -Collect the protocol revenue accrued for the provided ERC-20 token. - -Emits a -[CollectProtocolRevenue](/docs/reference/flow/contracts/interfaces/interface.ISablierFlowBase.md#collectprotocolrevenue) -event. Requirements: - -- `msg.sender` must be the contract admin. -- The accrued protocol revenue must be greater than zero. - -```solidity -function collectProtocolRevenue(IERC20 token, address to) external; -``` - -**Parameters** - -| Name | Type | Description | -| ------- | --------- | ----------------------------------------------------------------------------- | -| `token` | `IERC20` | The contract address of the ERC-20 token for which to claim protocol revenue. | -| `to` | `address` | The address to send the protocol revenue. | - -### recover - -Recover the surplus amount of tokens. - -Emits a [Recover](/docs/reference/flow/contracts/interfaces/interface.ISablierFlowBase.md#recover) event. Notes: - -- The surplus amount is defined as the difference between the total balance of the contract for the provided ERC-20 - token and the sum of balances of all streams created using the same ERC-20 token. Requirements: -- `msg.sender` must be the contract admin. -- The surplus amount must be greater than zero. - -```solidity -function recover(IERC20 token, address to) external; -``` - -**Parameters** - -| Name | Type | Description | -| ------- | --------- | -------------------------------------------------------- | -| `token` | `IERC20` | The contract address of the ERC-20 token to recover for. | -| `to` | `address` | The address to send the surplus amount. | - -### setNFTDescriptor - -Sets a new NFT descriptor contract, which produces the URI describing the Sablier stream NFTs. - -Emits a [SetNFTDescriptor](/docs/reference/flow/contracts/interfaces/interface.ISablierFlowBase.md#setnftdescriptor) and -{BatchMetadataUpdate} event. Notes: - -- Does not revert if the NFT descriptor is the same. Requirements: -- `msg.sender` must be the contract admin. - -```solidity -function setNFTDescriptor(IFlowNFTDescriptor newNFTDescriptor) external; -``` - -**Parameters** - -| Name | Type | Description | -| ------------------ | -------------------- | ----------------------------------------------- | -| `newNFTDescriptor` | `IFlowNFTDescriptor` | The address of the new NFT descriptor contract. | - -### setProtocolFee - -Sets a new protocol fee that will be charged on all the withdrawals from streams created with the provided ERC-20 token. - -Emits a [SetProtocolFee](/docs/reference/flow/contracts/interfaces/interface.ISablierFlowBase.md#setprotocolfee) and -{BatchMetadataUpdate} event. Notes: - -- Does not revert if the fee is the same. -- It can be zero. Requirements: -- `msg.sender` must be the contract admin. -- `newProtocolFee` must not be greater than `MAX_FEE`. - -```solidity -function setProtocolFee(IERC20 token, UD60x18 newProtocolFee) external; -``` - -**Parameters** - -| Name | Type | Description | -| ---------------- | --------- | ----------------------------------------------------------------------------- | -| `token` | `IERC20` | The contract address of the ERC-20 token to update the fee for. | -| `newProtocolFee` | `UD60x18` | The new protocol fee, denoted as a fixed-point percentage where 1e18 is 100%. | - -## Events - -### CollectFees - -Emitted when the accrued fees are collected. - -```solidity -event CollectFees(address indexed admin, uint256 indexed feeAmount); -``` - -**Parameters** - -| Name | Type | Description | -| ----------- | --------- | ----------------------------------------------------------------------- | -| `admin` | `address` | The address of the current contract admin, which has received the fees. | -| `feeAmount` | `uint256` | The amount of collected fees. | - -### CollectProtocolRevenue - -Emitted when the contract admin collects protocol revenue accrued. - -```solidity -event CollectProtocolRevenue(address indexed admin, IERC20 indexed token, address to, uint128 revenue); -``` - -**Parameters** - -| Name | Type | Description | -| --------- | --------- | ---------------------------------------------------------------------------- | -| `admin` | `address` | The address of the contract admin. | -| `token` | `IERC20` | The address of the ERC-20 token the protocol revenue has been collected for. | -| `to` | `address` | The address the protocol revenue has been sent to. | -| `revenue` | `uint128` | The amount of protocol revenue collected. | - -### Recover - -Emitted when the contract admin recovers the surplus amount of token. - -```solidity -event Recover(address indexed admin, IERC20 indexed token, address to, uint256 surplus); -``` - -**Parameters** - -| Name | Type | Description | -| --------- | --------- | -------------------------------------------------------------------------- | -| `admin` | `address` | The address of the contract admin. | -| `token` | `IERC20` | The address of the ERC-20 token the surplus amount has been recovered for. | -| `to` | `address` | The address the surplus amount has been sent to. | -| `surplus` | `uint256` | The amount of surplus tokens recovered. | - -### SetNFTDescriptor - -Emitted when the contract admin sets a new NFT descriptor contract. - -```solidity -event SetNFTDescriptor(address indexed admin, IFlowNFTDescriptor oldNFTDescriptor, IFlowNFTDescriptor newNFTDescriptor); -``` - -**Parameters** - -| Name | Type | Description | -| ------------------ | -------------------- | ----------------------------------------------- | -| `admin` | `address` | The address of the contract admin. | -| `oldNFTDescriptor` | `IFlowNFTDescriptor` | The address of the old NFT descriptor contract. | -| `newNFTDescriptor` | `IFlowNFTDescriptor` | The address of the new NFT descriptor contract. | - -### SetProtocolFee - -Emitted when the contract admin sets a new protocol fee for the provided ERC-20 token. - -```solidity -event SetProtocolFee(address indexed admin, IERC20 indexed token, UD60x18 oldProtocolFee, UD60x18 newProtocolFee); -``` - -**Parameters** - -| Name | Type | Description | -| ---------------- | --------- | ---------------------------------------------------------------------- | -| `admin` | `address` | The address of the contract admin. | -| `token` | `IERC20` | The address of the ERC-20 token the new protocol fee has been set for. | -| `oldProtocolFee` | `UD60x18` | The old protocol fee, denoted as a fixed-point percentage. | -| `newProtocolFee` | `UD60x18` | The new protocol fee, denoted as a fixed-point percentage. | diff --git a/docs/reference/flow/contracts/interfaces/interface.ISablierFlowState.md b/docs/reference/flow/contracts/interfaces/interface.ISablierFlowState.md new file mode 100644 index 00000000..a39221c8 --- /dev/null +++ b/docs/reference/flow/contracts/interfaces/interface.ISablierFlowState.md @@ -0,0 +1,239 @@ +# ISablierFlowState + +[Git Source](https://github.com/sablier-labs/flow/blob/a4143de45478f508bca8305fec2bd81b7ad25fe9/src/interfaces/ISablierFlowState.sol) + +Contract with state variables (storage and constants) for the +[SablierFlow](/docs/reference/flow/contracts/contract.SablierFlow.md) contract, their respective getters and helpful +modifiers. + +## Functions + +### aggregateAmount + +Retrieves the aggregate amount across all streams, denoted in units of the token's decimals. + +_If tokens are directly transferred to the contract without using the stream creation functions, the ERC-20 balance may +be greater than the aggregate amount._ + +```solidity +function aggregateAmount(IERC20 token) external view returns (uint256); +``` + +**Parameters** + +| Name | Type | Description | +| ------- | -------- | ------------------------------- | +| `token` | `IERC20` | The ERC-20 token for the query. | + +### getBalance + +Retrieves the balance of the stream, i.e. the total deposited amounts subtracted by the total withdrawn amounts, denoted +in token's decimals. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getBalance(uint256 streamId) external view returns (uint128 balance); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getRatePerSecond + +Retrieves the rate per second of the stream, denoted as a fixed-point number where 1e18 is 1 token per second. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getRatePerSecond(uint256 streamId) external view returns (UD21x18 ratePerSecond); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to make the query for. | + +### getSender + +Retrieves the stream's sender. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getSender(uint256 streamId) external view returns (address sender); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getSnapshotDebtScaled + +Retrieves the snapshot debt of the stream, denoted as a fixed-point number where 1e18 is 1 token. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getSnapshotDebtScaled(uint256 streamId) external view returns (uint256 snapshotDebtScaled); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getSnapshotTime + +Retrieves the snapshot time of the stream, which is a Unix timestamp. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getSnapshotTime(uint256 streamId) external view returns (uint40 snapshotTime); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to make the query for. | + +### getStream + +Retrieves the stream entity. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getStream(uint256 streamId) external view returns (Flow.Stream memory stream); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getToken + +Retrieves the token of the stream. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getToken(uint256 streamId) external view returns (IERC20 token); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to make the query for. | + +### getTokenDecimals + +Retrieves the token decimals of the stream. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getTokenDecimals(uint256 streamId) external view returns (uint8 tokenDecimals); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to make the query for. | + +### isStream + +Retrieves a flag indicating whether the stream exists. + +_Does not revert if `streamId` references a null stream._ + +```solidity +function isStream(uint256 streamId) external view returns (bool result); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### isTransferable + +Retrieves a flag indicating whether the stream NFT is transferable. + +_Reverts if `streamId` references a null stream._ + +```solidity +function isTransferable(uint256 streamId) external view returns (bool result); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### isVoided + +Retrieves a flag indicating whether the stream is voided. + +_Reverts if `streamId` references a null stream._ + +```solidity +function isVoided(uint256 streamId) external view returns (bool result); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### nativeToken + +Retrieves the address of the ERC-20 interface of the native token, if it exists. + +_The native tokens on some chains have a dual interface as ERC-20. For example, on Polygon the $POL token is the native +token and has an ERC-20 version at 0x0000000000000000000000000000000000001010. This means that `address(this).balance` +returns the same value as `balanceOf(address(this))`. To avoid any unintended behavior, these tokens cannot be used in +Sablier. As an alternative, users can use the Wrapped version of the token, i.e. WMATIC, which is a standard ERC-20 +token._ + +```solidity +function nativeToken() external view returns (address); +``` + +### nextStreamId + +Counter for stream ids. + +```solidity +function nextStreamId() external view returns (uint256); +``` + +**Returns** + +| Name | Type | Description | +| -------- | --------- | ------------------- | +| `` | `uint256` | The next stream ID. | + +### nftDescriptor + +Contract that generates the non-fungible token URI. + +```solidity +function nftDescriptor() external view returns (IFlowNFTDescriptor); +``` diff --git a/docs/reference/flow/contracts/libraries/library.Errors.md b/docs/reference/flow/contracts/libraries/library.Errors.md index 012d6b25..ef3b3b1a 100644 --- a/docs/reference/flow/contracts/libraries/library.Errors.md +++ b/docs/reference/flow/contracts/libraries/library.Errors.md @@ -1,73 +1,81 @@ # Errors -[Git Source](https://github.com/sablier-labs/flow/blob/a0fa33d2843af0817e34970cdc05822ead31daaa/src/libraries/Errors.sol) +[Git Source](https://github.com/sablier-labs/flow/blob/a4143de45478f508bca8305fec2bd81b7ad25fe9/src/libraries/Errors.sol) Library with custom errors used across the Flow contract. ## Errors -### BatchError +### SablierFlow_CreateNativeToken -Thrown when an unexpected error occurs during a batch call. +Thrown when trying to create a stream with the native token. ```solidity -error BatchError(bytes errorData); +error SablierFlow_CreateNativeToken(address nativeToken); ``` -### CallerNotAdmin +### SablierFlow_CreateRatePerSecondZero -Thrown when `msg.sender` is not the admin. +Thrown when trying to create a pending stream with zero rate per second. ```solidity -error CallerNotAdmin(address admin, address caller); +error SablierFlow_CreateRatePerSecondZero(); ``` -### DelegateCall +### SablierFlow_DepositAmountZero -Thrown when trying to delegate call to a function that disallows delegate calls. +Thrown when trying to create a stream with a zero deposit amount. ```solidity -error DelegateCall(); +error SablierFlow_DepositAmountZero(uint256 streamId); ``` -### SablierFlow_BrokerAddressZero +### SablierFlow_InsufficientFeePayment -Thrown when trying to create a stream with a broker recipient address as zero. +Thrown when trying to withdraw with a fee amount less than the minimum fee. ```solidity -error SablierFlow_BrokerAddressZero(); +error SablierFlow_InsufficientFeePayment(uint256 feePaid, uint256 minFeeWei); ``` -### SablierFlow_BrokerFeeTooHigh +### SablierFlow_InvalidCalculation -Thrown when trying to create a stream with a broker fee more than the allowed. +Thrown when an unexpected error occurs during the calculation of an amount. ```solidity -error SablierFlow_BrokerFeeTooHigh(UD60x18 brokerFee, UD60x18 maxFee); +error SablierFlow_InvalidCalculation(uint256 streamId, uint128 availableAmount, uint128 amount); ``` -### SablierFlow_DepositAmountZero +### SablierFlow_InvalidTokenDecimals -Thrown when trying to create a stream with a zero deposit amount. +Thrown when trying to create a stream with a token with decimals greater than 18. ```solidity -error SablierFlow_DepositAmountZero(uint256 streamId); +error SablierFlow_InvalidTokenDecimals(address token); ``` -### SablierFlow_InvalidCalculation +### SablierFlow_NativeTokenAlreadySet -Thrown when an unexpected error occurs during the calculation of an amount. +Thrown when trying to set the native token address when it is already set. ```solidity -error SablierFlow_InvalidCalculation(uint256 streamId, uint128 availableAmount, uint128 amount); +error SablierFlow_NativeTokenAlreadySet(address nativeToken); ``` -### SablierFlow_InvalidTokenDecimals +### SablierFlow_NativeTokenZeroAddress -Thrown when trying to create a stream with an token with no decimals. +Thrown when trying to set zero address as native token. ```solidity -error SablierFlow_InvalidTokenDecimals(address token); +error SablierFlow_NativeTokenZeroAddress(); +``` + +### SablierFlow_NewRatePerSecondZero + +Thrown when trying to adjust the rate per second to zero. + +```solidity +error SablierFlow_NewRatePerSecondZero(uint256 streamId); ``` ### SablierFlow_NotStreamRecipient @@ -86,12 +94,12 @@ Thrown when the sender address does not match the stream's sender. error SablierFlow_NotStreamSender(address sender, address streamSender); ``` -### SablierFlow_Null +### SablierFlow_NotTransferable -Thrown when the ID references a null stream. +Thrown when trying to transfer Stream NFT when transferability is disabled. ```solidity -error SablierFlow_Null(uint256 streamId); +error SablierFlow_NotTransferable(uint256 streamId); ``` ### SablierFlow_Overdraw @@ -142,28 +150,28 @@ Thrown when trying to get depletion time of a stream with zero balance. error SablierFlow_StreamBalanceZero(uint256 streamId); ``` -### SablierFlow_StreamPaused +### SablierFlow_StreamNotPaused -Thrown when trying to perform an action with a paused stream. +Thrown when trying to perform a disallowed action on a non-paused stream. ```solidity -error SablierFlow_StreamPaused(uint256 streamId); +error SablierFlow_StreamNotPaused(uint256 streamId); ``` -### SablierFlow_StreamNotPaused +### SablierFlow_StreamPending -Thrown when trying to restart a stream that is not paused. +Thrown when trying to perform a disallowed action on a pending stream. ```solidity -error SablierFlow_StreamNotPaused(uint256 streamId); +error SablierFlow_StreamPending(uint256 streamId, uint40 snapshotTime); ``` -### SablierFlow_StreamVoided +### SablierFlow_SurplusZero -Thrown when trying to perform an action with a voided stream. +Thrown when trying to recover for a token with zero surplus. ```solidity -error SablierFlow_StreamVoided(uint256 streamId); +error SablierFlow_SurplusZero(address token); ``` ### SablierFlow_Unauthorized @@ -198,42 +206,34 @@ Thrown when trying to withdraw to the zero address. error SablierFlow_WithdrawToZeroAddress(uint256 streamId); ``` -### SablierFlowBase_FeeTransferFail +### SablierFlowState_Null -Thrown when the fee transfer fails. - -```solidity -error SablierFlowBase_FeeTransferFail(address admin, uint256 feeAmount); -``` - -### SablierFlowBase_NoProtocolRevenue - -Thrown when trying to claim protocol revenue when the accrued amount is zero. +Thrown when the ID references a null stream. ```solidity -error SablierFlowBase_NoProtocolRevenue(address token); +error SablierFlowState_Null(uint256 streamId); ``` -### SablierFlowBase_NotTransferable +### SablierFlowState_StreamPaused -Thrown when trying to transfer Stream NFT when transferability is disabled. +Thrown when trying to perform a disallowed action on a paused stream. ```solidity -error SablierFlowBase_NotTransferable(uint256 streamId); +error SablierFlowState_StreamPaused(uint256 streamId); ``` -### SablierFlowBase_ProtocolFeeTooHigh +### SablierFlowState_StreamVoided -Thrown when trying to set protocol fee more than the allowed. +Thrown when trying to perform a disallowed action on a voided stream. ```solidity -error SablierFlowBase_ProtocolFeeTooHigh(UD60x18 newProtocolFee, UD60x18 maxFee); +error SablierFlowState_StreamVoided(uint256 streamId); ``` -### SablierFlowBase_SurplusZero +### SablierFlowState_Unauthorized -Thrown when trying to recover for a token with zero surplus. +Thrown when `msg.sender` lacks authorization to perform an action. ```solidity -error SablierFlowBase_SurplusZero(address token); +error SablierFlowState_Unauthorized(uint256 streamId, address caller); ``` diff --git a/docs/reference/flow/contracts/libraries/library.Helpers.md b/docs/reference/flow/contracts/libraries/library.Helpers.md index 1cf7b8cd..582b2648 100644 --- a/docs/reference/flow/contracts/libraries/library.Helpers.md +++ b/docs/reference/flow/contracts/libraries/library.Helpers.md @@ -1,43 +1,16 @@ # Helpers -[Git Source](https://github.com/sablier-labs/flow/blob/a0fa33d2843af0817e34970cdc05822ead31daaa/src/libraries/Helpers.sol) +[Git Source](https://github.com/sablier-labs/flow/blob/a4143de45478f508bca8305fec2bd81b7ad25fe9/src/libraries/Helpers.sol) Library with helper functions in [SablierFlow](/docs/reference/flow/contracts/contract.SablierFlow.md) contract. ## Functions -### calculateAmountsFromFee - -_Calculate the fee amount and the net amount after subtracting the fee, based on the `fee` percentage._ - -```solidity -function calculateAmountsFromFee( - uint128 totalAmount, - UD60x18 fee -) - internal - pure - returns (uint128 feeAmount, uint128 netAmount); -``` - -### checkAndCalculateBrokerFee - -_Checks the `Broker` parameter, and then calculates the broker fee amount and the deposit amount from the total amount._ - -```solidity -function checkAndCalculateBrokerFee( - uint128 totalAmount, - Broker memory broker, - UD60x18 maxFee -) - internal - pure - returns (uint128 brokerFeeAmount, uint128 depositAmount); -``` - ### descaleAmount -_Descales the provided `amount` from 18 decimals fixed-point number to token's decimals number._ +Descales the provided `amount` from 18 decimals fixed-point number to token's decimals number. + +_If `decimals` exceeds 18, it will cause an underflow._ ```solidity function descaleAmount(uint256 amount, uint8 decimals) internal pure returns (uint256); @@ -45,7 +18,10 @@ function descaleAmount(uint256 amount, uint8 decimals) internal pure returns (ui ### scaleAmount -_Scales the provided `amount` from token's decimals number to 18 decimals fixed-point number._ +Scales the provided `amount` from token's decimals number to 18 decimals fixed-point number. + +_If `decimals` exceeds 18, it will cause an underflow. If `amount` exceeds max value of `uint128`, the result may +overflow `uint256`._ ```solidity function scaleAmount(uint256 amount, uint8 decimals) internal pure returns (uint256); diff --git a/docs/reference/flow/contracts/types/library.Flow.md b/docs/reference/flow/contracts/types/library.Flow.md index 380cf1b3..d7c451a9 100644 --- a/docs/reference/flow/contracts/types/library.Flow.md +++ b/docs/reference/flow/contracts/types/library.Flow.md @@ -1,6 +1,6 @@ # Flow -[Git Source](https://github.com/sablier-labs/flow/blob/a0fa33d2843af0817e34970cdc05822ead31daaa/src/types/DataTypes.sol) +[Git Source](https://github.com/sablier-labs/flow/blob/a4143de45478f508bca8305fec2bd81b7ad25fe9/src/types/DataTypes.sol) ## Structs @@ -29,8 +29,8 @@ struct Stream { | Name | Type | Description | | -------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `balance` | `uint128` | The amount of tokens that are currently available in the stream, denoted in token's decimals. This is the sum of deposited amounts minus the sum of withdrawn amounts. | -| `ratePerSecond` | `UD21x18` | The payment rate per second, denoted as a fixed-point number where 1e18 is 1 token per second. For example, to stream 1000 tokens per week, this parameter would have the value $(1000 * 10^{18}) / (7 days in seconds)$. | +| `balance` | `uint128` | The amount of tokens that are currently available in the stream, denoted in the token's decimals. This is the sum of deposited amounts minus the sum of withdrawn amounts. | +| `ratePerSecond` | `UD21x18` | The payment rate per second, denoted as a fixed-point number where 1e18 is 1 token per second. For example, to stream 1000 tokens per week, this parameter would have the value $(1000 * 10^18) / (7 days in seconds)$. | | `sender` | `address` | The address streaming the tokens, with the ability to pause the stream. | | `snapshotTime` | `uint40` | The Unix timestamp used for the ongoing debt calculation. | | `isStream` | `bool` | Boolean indicating if the struct entity exists. | @@ -46,25 +46,23 @@ struct Stream { Enum representing the different statuses of a stream. -Explanations for the two types of streams: - -1. Streaming: when the total debt is increasing. -2. Paused: when the total debt is not increasing. - **Notes:** -- value0: STREAMING_SOLVENT Streaming stream when there is no uncovered debt. +- value0: PENDING Stream scheduled to start in the future. + +- value1: STREAMING_SOLVENT Streaming stream with no uncovered debt. -- value1: STREAMING_INSOLVENT Streaming stream when there is uncovered debt. +- value2: STREAMING_INSOLVENT Streaming stream with uncovered debt. -- value2: PAUSED_SOLVENT Paused stream when there is no uncovered debt. +- value3: PAUSED_SOLVENT Paused stream with no uncovered debt. -- value3: PAUSED_INSOLVENT Paused stream when there is uncovered debt. +- value4: PAUSED_INSOLVENT Paused stream with uncovered debt. -- value4: VOIDED Paused stream with no uncovered debt and it cannot be restarted. +- value5: VOIDED Paused stream with no uncovered debt, which cannot be restarted. ```solidity enum Status { + PENDING, STREAMING_SOLVENT, STREAMING_INSOLVENT, PAUSED_SOLVENT, diff --git a/docs/reference/flow/contracts/types/struct.Broker.md b/docs/reference/flow/contracts/types/struct.Broker.md deleted file mode 100644 index c96b9383..00000000 --- a/docs/reference/flow/contracts/types/struct.Broker.md +++ /dev/null @@ -1,19 +0,0 @@ -# Broker - -[Git Source](https://github.com/sablier-labs/flow/blob/a0fa33d2843af0817e34970cdc05822ead31daaa/src/types/DataTypes.sol) - -Struct encapsulating the broker parameters. - -```solidity -struct Broker { - address account; - UD60x18 fee; -} -``` - -**Properties** - -| Name | Type | Description | -| --------- | --------- | -------------------------------------------------------------------------------------------------------------------- | -| `account` | `address` | The address receiving the broker's fee. | -| `fee` | `UD60x18` | The broker's percentage fee charged from the deposit amount, denoted as a fixed-point percentage where 1e18 is 100%. | diff --git a/docs/reference/lockup/contracts/abstracts/abstract.Batch.md b/docs/reference/lockup/contracts/abstracts/abstract.Batch.md index 843f7b11..3bf6b7ee 100644 --- a/docs/reference/lockup/contracts/abstracts/abstract.Batch.md +++ b/docs/reference/lockup/contracts/abstracts/abstract.Batch.md @@ -1,10 +1,10 @@ # Batch -[Git Source](https://github.com/sablier-labs/lockup/blob/463278dbb461b1733d6424cf0aeee3b8d6bc036a/src/abstracts/Batch.sol) +[Git Source](https://github.com/sablier-labs/evm-utils/blob/d7d6c051a39cbacadef672e92ed9d57628c80dc4/src/Batch.sol) -**Inherits:** [IBatch](/docs/reference/lockup/contracts/interfaces/interface.IBatch.md) +**Inherits:** IBatch -See the documentation in [IBatch](/docs/reference/lockup/contracts/interfaces/interface.IBatch.md). +See the documentation in {IBatch}. ## Functions @@ -16,7 +16,7 @@ _Since `msg.value` can be reused across calls, be VERY CAREFUL when using it. Re https://paradigm.xyz/2021/08/two-rights-might-make-a-wrong for more information._ ```solidity -function batch(bytes[] calldata calls) external payable override returns (bytes[] memory results); +function batch(bytes[] calldata calls) external payable virtual override returns (bytes[] memory results); ``` **Parameters** diff --git a/docs/reference/lockup/contracts/abstracts/abstract.Comptrollerable.md b/docs/reference/lockup/contracts/abstracts/abstract.Comptrollerable.md new file mode 100644 index 00000000..6335e17b --- /dev/null +++ b/docs/reference/lockup/contracts/abstracts/abstract.Comptrollerable.md @@ -0,0 +1,95 @@ +# Comptrollerable + +[Git Source](https://github.com/sablier-labs/evm-utils/blob/d7d6c051a39cbacadef672e92ed9d57628c80dc4/src/Comptrollerable.sol) + +**Inherits:** IComptrollerable + +See the documentation in {IComptrollerable}. + +## State Variables + +### comptroller + +Retrieves the address of the comptroller contract. + +```solidity +ISablierComptroller public override comptroller; +``` + +## Functions + +### onlyComptroller + +Reverts if called by any account other than the comptroller. + +```solidity +modifier onlyComptroller(); +``` + +### constructor + +```solidity +constructor(address initialComptroller); +``` + +**Parameters** + +| Name | Type | Description | +| -------------------- | --------- | ------------------------------------------------ | +| `initialComptroller` | `address` | The address of the initial comptroller contract. | + +### setComptroller + +Sets the comptroller to a new address. + +\*Emits a {SetComptroller} event. Requirements: + +- `msg.sender` must be the current comptroller. +- The new comptroller must return `true` from {supportsInterface} with the comptroller's minimal interface ID which is + defined as the XOR of the following function selectors: + +1. {calculateMinFeeWeiFor} +2. {convertUSDFeeToWei} +3. {execute} +4. {getMinFeeUSDFor}\* + +```solidity +function setComptroller(ISablierComptroller newComptroller) external override onlyComptroller; +``` + +**Parameters** + +| Name | Type | Description | +| ---------------- | --------------------- | -------------------------------------------- | +| `newComptroller` | `ISablierComptroller` | The address of the new comptroller contract. | + +### transferFeesToComptroller + +Transfers the fees to the comptroller contract. + +_Emits a {TransferFeesToComptroller} event._ + +```solidity +function transferFeesToComptroller() external override; +``` + +### \_checkComptroller + +_See the documentation for the user-facing functions that call this private function._ + +```solidity +function _checkComptroller() private view; +``` + +### \_setComptroller + +_See the documentation for the user-facing functions that call this private function._ + +```solidity +function _setComptroller( + ISablierComptroller previousComptroller, + ISablierComptroller newComptroller, + bytes4 minimalInterfaceId +) + private; +``` diff --git a/docs/reference/lockup/contracts/abstracts/abstract.NoDelegateCall.md b/docs/reference/lockup/contracts/abstracts/abstract.NoDelegateCall.md index 8f798581..90d0ec52 100644 --- a/docs/reference/lockup/contracts/abstracts/abstract.NoDelegateCall.md +++ b/docs/reference/lockup/contracts/abstracts/abstract.NoDelegateCall.md @@ -1,6 +1,6 @@ # NoDelegateCall -[Git Source](https://github.com/sablier-labs/lockup/blob/463278dbb461b1733d6424cf0aeee3b8d6bc036a/src/abstracts/NoDelegateCall.sol) +[Git Source](https://github.com/sablier-labs/evm-utils/blob/d7d6c051a39cbacadef672e92ed9d57628c80dc4/src/NoDelegateCall.sol) This contract implements logic to prevent delegate calls. @@ -16,30 +16,30 @@ address private immutable ORIGINAL; ## Functions -### constructor +### noDelegateCall -_Sets the original contract address._ +Prevents delegate calls. ```solidity -constructor(); +modifier noDelegateCall(); ``` -### noDelegateCall +### constructor -Prevents delegate calls. +_Sets the original contract address._ ```solidity -modifier noDelegateCall(); +constructor(); ``` ### \_preventDelegateCall -This function checks whether the current call is a delegate call, and reverts if it is. +\*This function checks whether the current call is a delegate call, and reverts if it is. - A private function is used instead of inlining this logic in a modifier because Solidity copies modifiers into every function that uses them. The `ORIGINAL` address would get copied in every place the modifier is used, which would increase the contract size. By using a function instead, we can avoid this duplication of code and reduce the overall - size of the contract. + size of the contract.\* ```solidity function _preventDelegateCall() private view; diff --git a/docs/reference/lockup/contracts/abstracts/abstract.SablierLockupBase.md b/docs/reference/lockup/contracts/abstracts/abstract.SablierLockupBase.md deleted file mode 100644 index b9c63268..00000000 --- a/docs/reference/lockup/contracts/abstracts/abstract.SablierLockupBase.md +++ /dev/null @@ -1,865 +0,0 @@ -# SablierLockupBase - -[Git Source](https://github.com/sablier-labs/lockup/blob/463278dbb461b1733d6424cf0aeee3b8d6bc036a/src/abstracts/SablierLockupBase.sol) - -**Inherits:** [Batch](/docs/reference/lockup/contracts/abstracts/abstract.Batch.md), -[NoDelegateCall](/docs/reference/lockup/contracts/abstracts/abstract.NoDelegateCall.md), -[Adminable](/docs/reference/lockup/contracts/abstracts/abstract.Adminable.md), -[ISablierLockupBase](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupBase.md), ERC721 - -See the documentation in -[ISablierLockupBase](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupBase.md). - -## State Variables - -### MAX_BROKER_FEE - -Retrieves the maximum broker fee that can be charged by the broker, denoted as a fixed-point number where 1e18 is 100%. - -_This value is hard coded as a constant._ - -```solidity -UD60x18 public constant override MAX_BROKER_FEE = UD60x18.wrap(0.1e18); -``` - -### nextStreamId - -Counter for stream IDs, used in the create functions. - -```solidity -uint256 public override nextStreamId; -``` - -### nftDescriptor - -Contract that generates the non-fungible token URI. - -```solidity -ILockupNFTDescriptor public override nftDescriptor; -``` - -### \_allowedToHook - -_Mapping of contracts allowed to hook to Sablier when a stream is canceled or when tokens are withdrawn._ - -```solidity -mapping(address recipient => bool allowed) internal _allowedToHook; -``` - -### \_streams - -_Lockup streams mapped by unsigned integers._ - -```solidity -mapping(uint256 id => Lockup.Stream stream) internal _streams; -``` - -## Functions - -### constructor - -```solidity -constructor(address initialAdmin, ILockupNFTDescriptor initialNFTDescriptor) Adminable(initialAdmin); -``` - -**Parameters** - -| Name | Type | Description | -| ---------------------- | ---------------------- | ------------------------------------------ | -| `initialAdmin` | `address` | The address of the initial contract admin. | -| `initialNFTDescriptor` | `ILockupNFTDescriptor` | The address of the initial NFT descriptor. | - -### notNull - -_Checks that `streamId` does not reference a null stream._ - -```solidity -modifier notNull(uint256 streamId); -``` - -### getDepositedAmount - -Retrieves the amount deposited in the stream, denoted in units of the token's decimals. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getDepositedAmount(uint256 streamId) - external - view - override - notNull(streamId) - returns (uint128 depositedAmount); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### getEndTime - -Retrieves the stream's end time, which is a Unix timestamp. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getEndTime(uint256 streamId) external view override notNull(streamId) returns (uint40 endTime); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### getLockupModel - -Retrieves the distribution models used to create the stream. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getLockupModel(uint256 streamId) external view override notNull(streamId) returns (Lockup.Model lockupModel); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### getRecipient - -Retrieves the stream's recipient. - -_Reverts if the NFT has been burned._ - -```solidity -function getRecipient(uint256 streamId) external view override returns (address recipient); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### getRefundedAmount - -Retrieves the amount refunded to the sender after a cancellation, denoted in units of the token's decimals. This amount -is always zero unless the stream was canceled. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getRefundedAmount(uint256 streamId) - external - view - override - notNull(streamId) - returns (uint128 refundedAmount); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### getSender - -Retrieves the stream's sender. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getSender(uint256 streamId) external view override notNull(streamId) returns (address sender); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### getStartTime - -Retrieves the stream's start time, which is a Unix timestamp. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getStartTime(uint256 streamId) external view override notNull(streamId) returns (uint40 startTime); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### getUnderlyingToken - -Retrieves the address of the underlying ERC-20 token being distributed. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getUnderlyingToken(uint256 streamId) external view override notNull(streamId) returns (IERC20 token); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### getWithdrawnAmount - -Retrieves the amount withdrawn from the stream, denoted in units of the token's decimals. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getWithdrawnAmount(uint256 streamId) - external - view - override - notNull(streamId) - returns (uint128 withdrawnAmount); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### isAllowedToHook - -Retrieves a flag indicating whether the provided address is a contract allowed to hook to Sablier when a stream is -canceled or when tokens are withdrawn. - -_See [ISablierLockupRecipient](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupRecipient.md) for -more information._ - -```solidity -function isAllowedToHook(address recipient) external view returns (bool result); -``` - -### isCancelable - -Retrieves a flag indicating whether the stream can be canceled. When the stream is cold, this flag is always `false`. - -_Reverts if `streamId` references a null stream._ - -```solidity -function isCancelable(uint256 streamId) external view override notNull(streamId) returns (bool result); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### isCold - -Retrieves a flag indicating whether the stream is cold, i.e. settled, canceled, or depleted. - -_Reverts if `streamId` references a null stream._ - -```solidity -function isCold(uint256 streamId) external view override notNull(streamId) returns (bool result); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### isDepleted - -Retrieves a flag indicating whether the stream is depleted. - -_Reverts if `streamId` references a null stream._ - -```solidity -function isDepleted(uint256 streamId) external view override notNull(streamId) returns (bool result); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### isStream - -Retrieves a flag indicating whether the stream exists. - -_Does not revert if `streamId` references a null stream._ - -```solidity -function isStream(uint256 streamId) external view override returns (bool result); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### isTransferable - -Retrieves a flag indicating whether the stream NFT can be transferred. - -_Reverts if `streamId` references a null stream._ - -```solidity -function isTransferable(uint256 streamId) external view override notNull(streamId) returns (bool result); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### isWarm - -Retrieves a flag indicating whether the stream is warm, i.e. either pending or streaming. - -_Reverts if `streamId` references a null stream._ - -```solidity -function isWarm(uint256 streamId) external view override notNull(streamId) returns (bool result); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### refundableAmountOf - -Calculates the amount that the sender would be refunded if the stream were canceled, denoted in units of the token's -decimals. - -_Reverts if `streamId` references a null stream._ - -```solidity -function refundableAmountOf(uint256 streamId) - external - view - override - notNull(streamId) - returns (uint128 refundableAmount); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### statusOf - -Retrieves the stream's status. - -_Reverts if `streamId` references a null stream._ - -```solidity -function statusOf(uint256 streamId) external view override notNull(streamId) returns (Lockup.Status status); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### streamedAmountOf - -Calculates the amount streamed to the recipient, denoted in units of the token's decimals. - -Reverts if `streamId` references a null stream. Notes: - -- Upon cancellation of the stream, the amount streamed is calculated as the difference between the deposited amount and - the refunded amount. Ultimately, when the stream becomes depleted, the streamed amount is equivalent to the total - amount withdrawn. - -```solidity -function streamedAmountOf(uint256 streamId) external view override notNull(streamId) returns (uint128 streamedAmount); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### supportsInterface - -_See {IERC165-supportsInterface}._ - -```solidity -function supportsInterface(bytes4 interfaceId) public view override(IERC165, ERC721) returns (bool); -``` - -### tokenURI - -_See {IERC721Metadata-tokenURI}._ - -```solidity -function tokenURI(uint256 streamId) public view override(IERC721Metadata, ERC721) returns (string memory uri); -``` - -### wasCanceled - -Retrieves a flag indicating whether the stream was canceled. - -_Reverts if `streamId` references a null stream._ - -```solidity -function wasCanceled(uint256 streamId) external view override notNull(streamId) returns (bool result); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### withdrawableAmountOf - -Calculates the amount that the recipient can withdraw from the stream, denoted in units of the token's decimals. - -_Reverts if `streamId` references a null stream._ - -```solidity -function withdrawableAmountOf(uint256 streamId) - external - view - override - notNull(streamId) - returns (uint128 withdrawableAmount); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### allowToHook - -Allows a recipient contract to hook to Sablier when a stream is canceled or when tokens are withdrawn. Useful for -implementing contracts that hold streams on behalf of users, such as vaults or staking contracts. - -Emits an {AllowToHook} event. Notes: - -- Does not revert if the contract is already on the allowlist. -- This is an irreversible operation. The contract cannot be removed from the allowlist. Requirements: -- `msg.sender` must be the contract admin. -- `recipient` must have a non-zero code size. -- `recipient` must implement - [ISablierLockupRecipient](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupRecipient.md). - -```solidity -function allowToHook(address recipient) external override onlyAdmin; -``` - -**Parameters** - -| Name | Type | Description | -| ----------- | --------- | ----------------------------------------------- | -| `recipient` | `address` | The address of the contract to allow for hooks. | - -### burn - -Burns the NFT associated with the stream. - -Emits a {Transfer} and {MetadataUpdate} event. Requirements: - -- Must not be delegate called. -- `streamId` must reference a depleted stream. -- The NFT must exist. -- `msg.sender` must be either the NFT owner or an approved third party. - -```solidity -function burn(uint256 streamId) external payable override noDelegateCall notNull(streamId); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | --------------------------------- | -| `streamId` | `uint256` | The ID of the stream NFT to burn. | - -### cancel - -Cancels the stream and refunds any remaining tokens to the sender. - -Emits a {Transfer}, {CancelLockupStream} and {MetadataUpdate} event. Notes: - -- If there any tokens left for the recipient to withdraw, the stream is marked as canceled. Otherwise, the stream is - marked as depleted. -- If the address is on the allowlist, this function will invoke a hook on the recipient. Requirements: -- Must not be delegate called. -- The stream must be warm and cancelable. -- `msg.sender` must be the stream's sender. - -```solidity -function cancel(uint256 streamId) public payable override noDelegateCall notNull(streamId); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ------------------------------- | -| `streamId` | `uint256` | The ID of the stream to cancel. | - -### cancelMultiple - -Cancels multiple streams and refunds any remaining tokens to the sender. - -Emits multiple {Transfer}, {CancelLockupStream} and {MetadataUpdate} events. Notes: - -- Refer to the notes in {cancel}. Requirements: -- All requirements from {cancel} must be met for each stream. - -```solidity -function cancelMultiple(uint256[] calldata streamIds) external payable override noDelegateCall; -``` - -**Parameters** - -| Name | Type | Description | -| ----------- | ----------- | --------------------------------- | -| `streamIds` | `uint256[]` | The IDs of the streams to cancel. | - -### collectFees - -Collects the accrued fees by transferring them to the contract admin. - -Emits a {CollectFees} event. Notes: - -- If the admin is a contract, it must be able to receive native token payments, e.g., ETH for Ethereum Mainnet. - -```solidity -function collectFees() external override; -``` - -### renounce - -Removes the right of the stream's sender to cancel the stream. - -Emits a {RenounceLockupStream} event. Notes: - -- This is an irreversible operation. Requirements: -- Must not be delegate called. -- `streamId` must reference a warm stream. -- `msg.sender` must be the stream's sender. -- The stream must be cancelable. - -```solidity -function renounce(uint256 streamId) public payable override noDelegateCall notNull(streamId); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | --------------------------------- | -| `streamId` | `uint256` | The ID of the stream to renounce. | - -### renounceMultiple - -Renounces multiple streams. - -Emits multiple {RenounceLockupStream} events. Notes: - -- Refer to the notes in {renounce}. Requirements: -- All requirements from {renounce} must be met for each stream. - -```solidity -function renounceMultiple(uint256[] calldata streamIds) external payable override noDelegateCall; -``` - -**Parameters** - -| Name | Type | Description | -| ----------- | ----------- | ----------------------------------- | -| `streamIds` | `uint256[]` | An array of stream IDs to renounce. | - -### setNFTDescriptor - -Sets a new NFT descriptor contract, which produces the URI describing the Sablier stream NFTs. - -Emits a {SetNFTDescriptor} and {BatchMetadataUpdate} event. Notes: - -- Does not revert if the NFT descriptor is the same. Requirements: -- `msg.sender` must be the contract admin. - -```solidity -function setNFTDescriptor(ILockupNFTDescriptor newNFTDescriptor) external override onlyAdmin; -``` - -**Parameters** - -| Name | Type | Description | -| ------------------ | ---------------------- | ----------------------------------------------- | -| `newNFTDescriptor` | `ILockupNFTDescriptor` | The address of the new NFT descriptor contract. | - -### withdraw - -Withdraws the provided amount of tokens from the stream to the `to` address. - -Emits a {Transfer}, {WithdrawFromLockupStream} and {MetadataUpdate} event. Notes: - -- If `msg.sender` is not the recipient and the address is on the allowlist, this function will invoke a hook on the - recipient. Requirements: -- Must not be delegate called. -- `streamId` must not reference a null or depleted stream. -- `to` must not be the zero address. -- `amount` must be greater than zero and must not exceed the withdrawable amount. -- `to` must be the recipient if `msg.sender` is not the stream's recipient or an approved third party. - -```solidity -function withdraw( - uint256 streamId, - address to, - uint128 amount -) - public - payable - override - noDelegateCall - notNull(streamId); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ----------------------------------------------------------------- | -| `streamId` | `uint256` | The ID of the stream to withdraw from. | -| `to` | `address` | The address receiving the withdrawn tokens. | -| `amount` | `uint128` | The amount to withdraw, denoted in units of the token's decimals. | - -### withdrawMax - -Withdraws the maximum withdrawable amount from the stream to the provided address `to`. - -Emits a {Transfer}, {WithdrawFromLockupStream} and {MetadataUpdate} event. Notes: - -- Refer to the notes in {withdraw}. Requirements: -- Refer to the requirements in {withdraw}. - -```solidity -function withdrawMax(uint256 streamId, address to) external payable override returns (uint128 withdrawnAmount); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ------------------------------------------- | -| `streamId` | `uint256` | The ID of the stream to withdraw from. | -| `to` | `address` | The address receiving the withdrawn tokens. | - -**Returns** - -| Name | Type | Description | -| ----------------- | --------- | --------------------------------------------------------------- | -| `withdrawnAmount` | `uint128` | The amount withdrawn, denoted in units of the token's decimals. | - -### withdrawMaxAndTransfer - -Withdraws the maximum withdrawable amount from the stream to the current recipient, and transfers the NFT to -`newRecipient`. - -Emits a {WithdrawFromLockupStream}, {Transfer} and {MetadataUpdate} event. Notes: - -- If the withdrawable amount is zero, the withdrawal is skipped. -- Refer to the notes in {withdraw}. Requirements: -- `msg.sender` must be either the NFT owner or an approved third party. -- Refer to the requirements in {withdraw}. -- Refer to the requirements in {IERC721.transferFrom}. - -```solidity -function withdrawMaxAndTransfer( - uint256 streamId, - address newRecipient -) - external - payable - override - noDelegateCall - notNull(streamId) - returns (uint128 withdrawnAmount); -``` - -**Parameters** - -| Name | Type | Description | -| -------------- | --------- | ----------------------------------------------- | -| `streamId` | `uint256` | The ID of the stream NFT to transfer. | -| `newRecipient` | `address` | The address of the new owner of the stream NFT. | - -**Returns** - -| Name | Type | Description | -| ----------------- | --------- | --------------------------------------------------------------- | -| `withdrawnAmount` | `uint128` | The amount withdrawn, denoted in units of the token's decimals. | - -### withdrawMultiple - -Withdraws tokens from streams to the recipient of each stream. - -Emits multiple {Transfer}, {WithdrawFromLockupStream} and {MetadataUpdate} events. For each stream that reverted the -withdrawal, it emits an -[InvalidWithdrawalInWithdrawMultiple](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupBase.md#invalidwithdrawalinwithdrawmultiple) -event. Notes: - -- This function attempts to call a hook on the recipient of each stream, unless `msg.sender` is the recipient. - Requirements: -- Must not be delegate called. -- There must be an equal number of `streamIds` and `amounts`. -- Each stream ID in the array must not reference a null or depleted stream. -- Each amount in the array must be greater than zero and must not exceed the withdrawable amount. - -```solidity -function withdrawMultiple( - uint256[] calldata streamIds, - uint128[] calldata amounts -) - external - payable - override - noDelegateCall; -``` - -**Parameters** - -| Name | Type | Description | -| ----------- | ----------- | ------------------------------------------------------------------ | -| `streamIds` | `uint256[]` | The IDs of the streams to withdraw from. | -| `amounts` | `uint128[]` | The amounts to withdraw, denoted in units of the token's decimals. | - -### \_calculateStreamedAmount - -Calculates the streamed amount of the stream without looking up the stream's status. - -_This function is implemented by child contracts, so the logic varies depending on the model._ - -```solidity -function _calculateStreamedAmount(uint256 streamId) internal view virtual returns (uint128); -``` - -### \_isCallerStreamRecipientOrApproved - -Checks whether `msg.sender` is the stream's recipient or an approved third party, when the `recipient` is known in -advance. - -```solidity -function _isCallerStreamRecipientOrApproved(uint256 streamId, address recipient) internal view returns (bool); -``` - -**Parameters** - -| Name | Type | Description | -| ----------- | --------- | -------------------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | -| `recipient` | `address` | The address of the stream's recipient. | - -### \_isCallerStreamSender - -Checks whether `msg.sender` is the stream's sender. - -```solidity -function _isCallerStreamSender(uint256 streamId) internal view returns (bool); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### \_statusOf - -_Retrieves the stream's status without performing a null check._ - -```solidity -function _statusOf(uint256 streamId) internal view returns (Lockup.Status); -``` - -### \_streamedAmountOf - -_See the documentation for the user-facing functions that call this internal function._ - -```solidity -function _streamedAmountOf(uint256 streamId) internal view returns (uint128); -``` - -### \_withdrawableAmountOf - -_See the documentation for the user-facing functions that call this internal function._ - -```solidity -function _withdrawableAmountOf(uint256 streamId) internal view returns (uint128); -``` - -### \_cancel - -_See the documentation for the user-facing functions that call this internal function._ - -```solidity -function _cancel(uint256 streamId) internal; -``` - -### \_renounce - -_See the documentation for the user-facing functions that call this internal function._ - -```solidity -function _renounce(uint256 streamId) internal; -``` - -### \_update - -Overrides the {ERC-721.\_update} function to check that the stream is transferable, and emits an ERC-4906 event. - -There are two cases when the transferable flag is ignored: - -- If the current owner is 0, then the update is a mint and is allowed. -- If `to` is 0, then the update is a burn and is also allowed. - -```solidity -function _update(address to, uint256 streamId, address auth) internal override returns (address); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `to` | `address` | The address of the new recipient of the stream. | -| `streamId` | `uint256` | ID of the stream to update. | -| `auth` | `address` | Optional parameter. If the value is not zero, the overridden implementation will check that `auth` is either the recipient of the stream, or an approved third party. | - -**Returns** - -| Name | Type | Description | -| -------- | --------- | ----------------------------------------------------------- | -| `` | `address` | The original recipient of the `streamId` before the update. | - -### \_withdraw - -_See the documentation for the user-facing functions that call this internal function._ - -```solidity -function _withdraw(uint256 streamId, address to, uint128 amount) internal; -``` diff --git a/docs/reference/lockup/contracts/abstracts/abstract.SablierLockupDynamic.md b/docs/reference/lockup/contracts/abstracts/abstract.SablierLockupDynamic.md new file mode 100644 index 00000000..cc948e8c --- /dev/null +++ b/docs/reference/lockup/contracts/abstracts/abstract.SablierLockupDynamic.md @@ -0,0 +1,114 @@ +# SablierLockupDynamic + +[Git Source](https://github.com/sablier-labs/lockup/blob/58eaac45c20c57a93b73d887c714e68f061ec3e6/src/abstracts/SablierLockupDynamic.sol) + +**Inherits:** [ISablierLockupDynamic](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupDynamic.md), +[NoDelegateCall](/docs/reference/lockup/contracts/abstracts/abstract.NoDelegateCall.md), +[SablierLockupState](/docs/reference/lockup/contracts/abstracts/abstract.SablierLockupState.md) + +See the documentation in +[ISablierLockupDynamic](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupDynamic.md). + +## Functions + +### createWithDurationsLD + +Creates a stream by setting the start time to `block.timestamp`, and the end time to the sum of `block.timestamp` and +all specified time durations. The segment timestamps are derived from these durations. The stream is funded by +`msg.sender` and is wrapped in an ERC-721 NFT. + +\*Emits a {Transfer}, {CreateLockupDynamicStream} and {MetadataUpdate} event. Requirements: + +- All requirements in {createWithTimestampsLD} must be met for the calculated parameters.\* + +```solidity +function createWithDurationsLD( + Lockup.CreateWithDurations calldata params, + LockupDynamic.SegmentWithDuration[] calldata segmentsWithDuration +) + external + payable + override + noDelegateCall + returns (uint256 streamId); +``` + +**Parameters** + +| Name | Type | Description | +| ---------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `params` | `Lockup.CreateWithDurations` | Struct encapsulating the function parameters, which are documented in {Lockup} type. | +| `segmentsWithDuration` | `LockupDynamic.SegmentWithDuration[]` | Segments with durations used to compose the dynamic distribution function. Timestamps are calculated by starting from `block.timestamp` and adding each duration to the previous timestamp. | + +**Returns** + +| Name | Type | Description | +| ---------- | --------- | ----------------------------------- | +| `streamId` | `uint256` | The ID of the newly created stream. | + +### createWithTimestampsLD + +Creates a stream with the provided segment timestamps, implying the end time from the last timestamp. The stream is +funded by `msg.sender` and is wrapped in an ERC-721 NFT. + +\*Emits a {Transfer}, {CreateLockupDynamicStream} and {MetadataUpdate} event. Notes: + +- As long as the segment timestamps are arranged in ascending order, it is not an error for some of them to be in the + past. Requirements: +- Must not be delegate called. +- `params.depositAmount` must be greater than zero. +- `params.timestamps.start` must be greater than zero and less than the first segment's timestamp. +- `segments` must have at least one segment. +- The segment timestamps must be arranged in ascending order. +- `params.timestamps.end` must be equal to the last segment's timestamp. +- The sum of the segment amounts must equal the deposit amount. +- `params.recipient` must not be the zero address. +- `params.sender` must not be the zero address. +- `msg.sender` must have allowed this contract to spend at least `params.depositAmount` tokens. +- `params.token` must not be the native token. +- `params.shape.length` must not be greater than 32 characters.\* + +```solidity +function createWithTimestampsLD( + Lockup.CreateWithTimestamps calldata params, + LockupDynamic.Segment[] calldata segments +) + external + payable + override + noDelegateCall + returns (uint256 streamId); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | ----------------------------- | ------------------------------------------------------------------------------------ | +| `params` | `Lockup.CreateWithTimestamps` | Struct encapsulating the function parameters, which are documented in {Lockup} type. | +| `segments` | `LockupDynamic.Segment[]` | Segments used to compose the dynamic distribution function. | + +**Returns** + +| Name | Type | Description | +| ---------- | --------- | ----------------------------------- | +| `streamId` | `uint256` | The ID of the newly created stream. | + +### \_createLD + +_See the documentation for the user-facing functions that call this private function._ + +```solidity +function _createLD( + bool cancelable, + uint128 depositAmount, + address recipient, + LockupDynamic.Segment[] memory segments, + address sender, + string memory shape, + Lockup.Timestamps memory timestamps, + IERC20 token, + bool transferable +) + private + returns (uint256 streamId); +``` diff --git a/docs/reference/lockup/contracts/abstracts/abstract.SablierLockupLinear.md b/docs/reference/lockup/contracts/abstracts/abstract.SablierLockupLinear.md new file mode 100644 index 00000000..8a89acc6 --- /dev/null +++ b/docs/reference/lockup/contracts/abstracts/abstract.SablierLockupLinear.md @@ -0,0 +1,117 @@ +# SablierLockupLinear + +[Git Source](https://github.com/sablier-labs/lockup/blob/58eaac45c20c57a93b73d887c714e68f061ec3e6/src/abstracts/SablierLockupLinear.sol) + +**Inherits:** [ISablierLockupLinear](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupLinear.md), +[NoDelegateCall](/docs/reference/lockup/contracts/abstracts/abstract.NoDelegateCall.md), +[SablierLockupState](/docs/reference/lockup/contracts/abstracts/abstract.SablierLockupState.md) + +See the documentation in +[ISablierLockupLinear](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupLinear.md). + +## Functions + +### createWithDurationsLL + +Creates a stream by setting the start time to `block.timestamp`, and the end time to the sum of `block.timestamp` and +`durations.total`. The stream is funded by `msg.sender` and is wrapped in an ERC-721 NFT. + +\*Emits a {Transfer}, {CreateLockupLinearStream} and {MetadataUpdate} event. Requirements: + +- All requirements in {createWithTimestampsLL} must be met for the calculated parameters.\* + +```solidity +function createWithDurationsLL( + Lockup.CreateWithDurations calldata params, + LockupLinear.UnlockAmounts calldata unlockAmounts, + LockupLinear.Durations calldata durations +) + external + payable + override + noDelegateCall + returns (uint256 streamId); +``` + +**Parameters** + +| Name | Type | Description | +| --------------- | ---------------------------- | ---------------------------------------------------------------------------------------------------------------- | +| `params` | `Lockup.CreateWithDurations` | Struct encapsulating the function parameters, which are documented in {Lockup} type. | +| `unlockAmounts` | `LockupLinear.UnlockAmounts` | Struct encapsulating (i) the amount to unlock at the start time and (ii) the amount to unlock at the cliff time. | +| `durations` | `LockupLinear.Durations` | Struct encapsulating (i) cliff period duration and (ii) total stream duration, both in seconds. | + +**Returns** + +| Name | Type | Description | +| ---------- | --------- | ----------------------------------- | +| `streamId` | `uint256` | The ID of the newly created stream. | + +### createWithTimestampsLL + +Creates a stream with the provided start time and end time. The stream is funded by `msg.sender` and is wrapped in an +ERC-721 NFT. + +\*Emits a {Transfer}, {CreateLockupLinearStream} and {MetadataUpdate} event. Notes: + +- A cliff time of zero means there is no cliff. +- As long as the times are ordered, it is not an error for the start or the cliff time to be in the past. Requirements: +- Must not be delegate called. +- `params.depositAmount` must be greater than zero. +- `params.timestamps.start` must be greater than zero and less than `params.timestamps.end`. +- If set, `cliffTime` must be greater than `params.timestamps.start` and less than `params.timestamps.end`. +- `params.recipient` must not be the zero address. +- `params.sender` must not be the zero address. +- The sum of `params.unlockAmounts.start` and `params.unlockAmounts.cliff` must be less than or equal to deposit amount. +- If `params.timestamps.cliff` not set, the `params.unlockAmounts.cliff` must be zero. +- `msg.sender` must have allowed this contract to spend at least `params.depositAmount` tokens. +- `params.token` must not be the native token. +- `params.shape.length` must not be greater than 32 characters.\* + +```solidity +function createWithTimestampsLL( + Lockup.CreateWithTimestamps calldata params, + LockupLinear.UnlockAmounts calldata unlockAmounts, + uint40 cliffTime +) + external + payable + override + noDelegateCall + returns (uint256 streamId); +``` + +**Parameters** + +| Name | Type | Description | +| --------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------- | +| `params` | `Lockup.CreateWithTimestamps` | Struct encapsulating the function parameters, which are documented in {Lockup} type. | +| `unlockAmounts` | `LockupLinear.UnlockAmounts` | Struct encapsulating (i) the amount to unlock at the start time and (ii) the amount to unlock at the cliff time. | +| `cliffTime` | `uint40` | The Unix timestamp for the cliff period's end. A value of zero means there is no cliff. | + +**Returns** + +| Name | Type | Description | +| ---------- | --------- | ----------------------------------- | +| `streamId` | `uint256` | The ID of the newly created stream. | + +### \_createLL + +_See the documentation for the user-facing functions that call this private function._ + +```solidity +function _createLL( + bool cancelable, + uint40 cliffTime, + uint128 depositAmount, + address recipient, + address sender, + string memory shape, + Lockup.Timestamps memory timestamps, + IERC20 token, + bool transferable, + LockupLinear.UnlockAmounts memory unlockAmounts +) + private + returns (uint256 streamId); +``` diff --git a/docs/reference/lockup/contracts/abstracts/abstract.SablierLockupState.md b/docs/reference/lockup/contracts/abstracts/abstract.SablierLockupState.md new file mode 100644 index 00000000..af6a6861 --- /dev/null +++ b/docs/reference/lockup/contracts/abstracts/abstract.SablierLockupState.md @@ -0,0 +1,507 @@ +# SablierLockupState + +[Git Source](https://github.com/sablier-labs/lockup/blob/58eaac45c20c57a93b73d887c714e68f061ec3e6/src/abstracts/SablierLockupState.sol) + +**Inherits:** [ISablierLockupState](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupState.md) + +See the documentation in +[ISablierLockupState](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupState.md). + +## State Variables + +### aggregateAmount + +Retrieves the aggregate amount across all streams, denoted in units of the token's decimals. + +_If tokens are directly transferred to the contract without using the stream creation functions, the ERC-20 balance may +be greater than the aggregate amount._ + +```solidity +mapping(IERC20 token => uint256 amount) public override aggregateAmount; +``` + +### nativeToken + +Retrieves the address of the ERC-20 interface of the native token, if it exists. + +_The native tokens on some chains have a dual interface as ERC-20. For example, on Polygon the $POL token is the native +token and has an ERC-20 version at 0x0000000000000000000000000000000000001010. This means that `address(this).balance` +returns the same value as `balanceOf(address(this))`. To avoid any unintended behavior, these tokens cannot be used in +Sablier. As an alternative, users can use the Wrapped version of the token, i.e. WMATIC, which is a standard ERC-20 +token._ + +```solidity +address public override nativeToken; +``` + +### nextStreamId + +Counter for stream IDs, used in the create functions. + +```solidity +uint256 public override nextStreamId; +``` + +### nftDescriptor + +Contract that generates the non-fungible token URI. + +```solidity +ILockupNFTDescriptor public override nftDescriptor; +``` + +### \_allowedToHook + +_Mapping of contracts allowed to hook to Sablier when a stream is canceled or when tokens are withdrawn._ + +```solidity +mapping(address recipient => bool allowed) internal _allowedToHook; +``` + +### \_cliffs + +_Cliff timestamp mapped by stream IDs, used in LL streams._ + +```solidity +mapping(uint256 streamId => uint40 cliffTime) internal _cliffs; +``` + +### \_segments + +_Stream segments mapped by stream IDs, used in LD streams._ + +```solidity +mapping(uint256 streamId => LockupDynamic.Segment[] segments) internal _segments; +``` + +### \_streams + +_Lockup streams mapped by unsigned integers._ + +```solidity +mapping(uint256 id => Lockup.Stream stream) internal _streams; +``` + +### \_tranches + +_Stream tranches mapped by stream IDs, used in LT streams._ + +```solidity +mapping(uint256 streamId => LockupTranched.Tranche[] tranches) internal _tranches; +``` + +### \_unlockAmounts + +_Unlock amounts mapped by stream IDs, used in LL streams._ + +```solidity +mapping(uint256 streamId => LockupLinear.UnlockAmounts unlockAmounts) internal _unlockAmounts; +``` + +## Functions + +### notNull + +_Checks that `streamId` does not reference a null stream._ + +```solidity +modifier notNull(uint256 streamId); +``` + +### constructor + +```solidity +constructor(address initialNFTDescriptor); +``` + +**Parameters** + +| Name | Type | Description | +| ---------------------- | --------- | ------------------------------------------ | +| `initialNFTDescriptor` | `address` | The address of the initial NFT descriptor. | + +### getCliffTime + +Retrieves the stream's cliff time, which is a Unix timestamp. A value of zero means there is no cliff. + +_Reverts if `streamId` references either a null stream or a non-LL stream._ + +```solidity +function getCliffTime(uint256 streamId) external view override notNull(streamId) returns (uint40 cliffTime); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getDepositedAmount + +Retrieves the amount deposited in the stream, denoted in units of the token's decimals. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getDepositedAmount(uint256 streamId) + external + view + override + notNull(streamId) + returns (uint128 depositedAmount); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getEndTime + +Retrieves the stream's end time, which is a Unix timestamp. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getEndTime(uint256 streamId) external view override notNull(streamId) returns (uint40 endTime); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getLockupModel + +Retrieves the distribution models used to create the stream. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getLockupModel(uint256 streamId) external view override notNull(streamId) returns (Lockup.Model lockupModel); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getRefundedAmount + +Retrieves the amount refunded to the sender after a cancellation, denoted in units of the token's decimals. This amount +is always zero unless the stream was canceled. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getRefundedAmount(uint256 streamId) + external + view + override + notNull(streamId) + returns (uint128 refundedAmount); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getSegments + +Retrieves the segments used to compose the dynamic distribution function. + +_Reverts if `streamId` references either a null stream or a non-LD stream._ + +```solidity +function getSegments(uint256 streamId) + external + view + override + notNull(streamId) + returns (LockupDynamic.Segment[] memory segments); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +**Returns** + +| Name | Type | Description | +| ---------- | ------------------------- | ---------------------------------------------- | +| `segments` | `LockupDynamic.Segment[]` | See the documentation in {LockupDynamic} type. | + +### getSender + +Retrieves the stream's sender. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getSender(uint256 streamId) external view override notNull(streamId) returns (address sender); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getStartTime + +Retrieves the stream's start time, which is a Unix timestamp. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getStartTime(uint256 streamId) external view override notNull(streamId) returns (uint40 startTime); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getTranches + +Retrieves the tranches used to compose the tranched distribution function. + +_Reverts if `streamId` references either a null stream or a non-LT stream._ + +```solidity +function getTranches(uint256 streamId) + external + view + override + notNull(streamId) + returns (LockupTranched.Tranche[] memory tranches); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +**Returns** + +| Name | Type | Description | +| ---------- | -------------------------- | ----------------------------------------------- | +| `tranches` | `LockupTranched.Tranche[]` | See the documentation in {LockupTranched} type. | + +### getUnderlyingToken + +Retrieves the address of the underlying ERC-20 token being distributed. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getUnderlyingToken(uint256 streamId) external view override notNull(streamId) returns (IERC20 token); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getUnlockAmounts + +Retrieves the unlock amounts used to compose the linear distribution function. + +_Reverts if `streamId` references either a null stream or a non-LL stream._ + +```solidity +function getUnlockAmounts(uint256 streamId) + external + view + override + notNull(streamId) + returns (LockupLinear.UnlockAmounts memory unlockAmounts); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +**Returns** + +| Name | Type | Description | +| --------------- | ---------------------------- | --------------------------------------------- | +| `unlockAmounts` | `LockupLinear.UnlockAmounts` | See the documentation in {LockupLinear} type. | + +### getWithdrawnAmount + +Retrieves the amount withdrawn from the stream, denoted in units of the token's decimals. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getWithdrawnAmount(uint256 streamId) + external + view + override + notNull(streamId) + returns (uint128 withdrawnAmount); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### isAllowedToHook + +Retrieves a flag indicating whether the provided address is a contract allowed to hook to Sablier when a stream is +canceled or when tokens are withdrawn. + +_See [ISablierLockupRecipient](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupRecipient.md) for +more information._ + +```solidity +function isAllowedToHook(address recipient) external view returns (bool result); +``` + +### isCancelable + +Retrieves a flag indicating whether the stream can be canceled. When the stream is cold, this flag is always `false`. + +_Reverts if `streamId` references a null stream._ + +```solidity +function isCancelable(uint256 streamId) external view override notNull(streamId) returns (bool result); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### isDepleted + +Retrieves a flag indicating whether the stream is depleted. + +_Reverts if `streamId` references a null stream._ + +```solidity +function isDepleted(uint256 streamId) external view override notNull(streamId) returns (bool result); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### isStream + +Retrieves a flag indicating whether the stream exists. + +_Does not revert if `streamId` references a null stream._ + +```solidity +function isStream(uint256 streamId) external view override returns (bool result); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### isTransferable + +Retrieves a flag indicating whether the stream NFT can be transferred. + +_Reverts if `streamId` references a null stream._ + +```solidity +function isTransferable(uint256 streamId) external view override notNull(streamId) returns (bool result); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### wasCanceled + +Retrieves a flag indicating whether the stream was canceled. + +_Reverts if `streamId` references a null stream._ + +```solidity +function wasCanceled(uint256 streamId) external view override notNull(streamId) returns (bool result); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### \_statusOf + +_Retrieves the stream's status without performing a null check._ + +```solidity +function _statusOf(uint256 streamId) internal view returns (Lockup.Status); +``` + +### \_streamedAmountOf + +Calculates the streamed amount of the stream. + +_This function is implemented by child contract. The logic varies according to the distribution model._ + +```solidity +function _streamedAmountOf(uint256 streamId) internal view virtual returns (uint128); +``` + +### \_create + +This function is implemented by [SablierLockup](/docs/reference/lockup/contracts/contract.SablierLockup.md) and is used +in the [SablierLockupDynamic](docs/reference/lockup/contracts/abstracts/abstract.SablierLockupDynamic.md), +[SablierLockupLinear](docs/reference/lockup/contracts/abstracts/abstract.SablierLockupLinear.md) and +[SablierLockupTranched](docs/reference/lockup/contracts/abstracts/abstract.SablierLockupTranched.md) contracts. + +_It updates state variables based on the stream parameters, mints an NFT to the recipient, bumps stream ID, and +transfers the deposit amount._ + +```solidity +function _create( + bool cancelable, + uint128 depositAmount, + Lockup.Model lockupModel, + address recipient, + address sender, + uint256 streamId, + Lockup.Timestamps memory timestamps, + IERC20 token, + bool transferable +) + internal + virtual; +``` + +### \_notNull + +_A private function is used instead of inlining this logic in a modifier because Solidity copies modifiers into every +function that uses them._ + +```solidity +function _notNull(uint256 streamId) private view; +``` diff --git a/docs/reference/lockup/contracts/abstracts/abstract.SablierLockupTranched.md b/docs/reference/lockup/contracts/abstracts/abstract.SablierLockupTranched.md new file mode 100644 index 00000000..00b17795 --- /dev/null +++ b/docs/reference/lockup/contracts/abstracts/abstract.SablierLockupTranched.md @@ -0,0 +1,114 @@ +# SablierLockupTranched + +[Git Source](https://github.com/sablier-labs/lockup/blob/58eaac45c20c57a93b73d887c714e68f061ec3e6/src/abstracts/SablierLockupTranched.sol) + +**Inherits:** [ISablierLockupTranched](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupTranched.md), +[NoDelegateCall](/docs/reference/lockup/contracts/abstracts/abstract.NoDelegateCall.md), +[SablierLockupState](/docs/reference/lockup/contracts/abstracts/abstract.SablierLockupState.md) + +See the documentation in +[ISablierLockupTranched](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupTranched.md). + +## Functions + +### createWithDurationsLT + +Creates a stream by setting the start time to `block.timestamp`, and the end time to the sum of `block.timestamp` and +all specified time durations. The tranche timestamps are derived from these durations. The stream is funded by +`msg.sender` and is wrapped in an ERC-721 NFT. + +\*Emits a {Transfer}, {CreateLockupTrancheStream} and {MetadataUpdate} event. Requirements: + +- All requirements in {createWithTimestampsLT} must be met for the calculated parameters.\* + +```solidity +function createWithDurationsLT( + Lockup.CreateWithDurations calldata params, + LockupTranched.TrancheWithDuration[] calldata tranchesWithDuration +) + external + payable + override + noDelegateCall + returns (uint256 streamId); +``` + +**Parameters** + +| Name | Type | Description | +| ---------------------- | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `params` | `Lockup.CreateWithDurations` | Struct encapsulating the function parameters, which are documented in {Lockup} type. | +| `tranchesWithDuration` | `LockupTranched.TrancheWithDuration[]` | Tranches with durations used to compose the tranched distribution function. Timestamps are calculated by starting from `block.timestamp` and adding each duration to the previous timestamp. | + +**Returns** + +| Name | Type | Description | +| ---------- | --------- | ----------------------------------- | +| `streamId` | `uint256` | The ID of the newly created stream. | + +### createWithTimestampsLT + +Creates a stream with the provided tranche timestamps, implying the end time from the last timestamp. The stream is +funded by `msg.sender` and is wrapped in an ERC-721 NFT. + +\*Emits a {Transfer}, {CreateLockupTrancheStream} and {MetadataUpdate} event. Notes: + +- As long as the tranche timestamps are arranged in ascending order, it is not an error for some of them to be in the + past. Requirements: +- Must not be delegate called. +- `params.depositAmount` must be greater than zero. +- `params.timestamps.start` must be greater than zero and less than the first tranche's timestamp. +- `tranches` must have at least one tranche. +- The tranche timestamps must be arranged in ascending order. +- `params.timestamps.end` must be equal to the last tranche's timestamp. +- The sum of the tranche amounts must equal the deposit amount. +- `params.recipient` must not be the zero address. +- `params.sender` must not be the zero address. +- `msg.sender` must have allowed this contract to spend at least `params.depositAmount` tokens. +- `params.token` must not be the native token. +- `params.shape.length` must not be greater than 32 characters.\* + +```solidity +function createWithTimestampsLT( + Lockup.CreateWithTimestamps calldata params, + LockupTranched.Tranche[] calldata tranches +) + external + payable + override + noDelegateCall + returns (uint256 streamId); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | ----------------------------- | ------------------------------------------------------------------------------------ | +| `params` | `Lockup.CreateWithTimestamps` | Struct encapsulating the function parameters, which are documented in {Lockup} type. | +| `tranches` | `LockupTranched.Tranche[]` | Tranches used to compose the tranched distribution function. | + +**Returns** + +| Name | Type | Description | +| ---------- | --------- | ----------------------------------- | +| `streamId` | `uint256` | The ID of the newly created stream. | + +### \_createLT + +_See the documentation for the user-facing functions that call this private function._ + +```solidity +function _createLT( + bool cancelable, + uint128 depositAmount, + address recipient, + address sender, + string memory shape, + Lockup.Timestamps memory timestamps, + IERC20 token, + bool transferable, + LockupTranched.Tranche[] memory tranches +) + private + returns (uint256 streamId); +``` diff --git a/docs/reference/lockup/contracts/contract.LockupNFTDescriptor.md b/docs/reference/lockup/contracts/contract.LockupNFTDescriptor.md index 2f517f48..cfdf09ef 100644 --- a/docs/reference/lockup/contracts/contract.LockupNFTDescriptor.md +++ b/docs/reference/lockup/contracts/contract.LockupNFTDescriptor.md @@ -4,7 +4,7 @@ sidebar_position: 3 # LockupNFTDescriptor -[Git Source](https://github.com/sablier-labs/lockup/blob/463278dbb461b1733d6424cf0aeee3b8d6bc036a/src/LockupNFTDescriptor.sol) +[Git Source](https://github.com/sablier-labs/lockup/blob/58eaac45c20c57a93b73d887c714e68f061ec3e6/src/LockupNFTDescriptor.sol) **Inherits:** [ILockupNFTDescriptor](/docs/reference/lockup/contracts/interfaces/interface.ILockupNFTDescriptor.md) @@ -40,12 +40,12 @@ function tokenURI(IERC721Metadata lockup, uint256 streamId) external view overri Creates an abbreviated representation of the provided amount, rounded down and prefixed with ">= ". -The abbreviation uses these suffixes: +\*The abbreviation uses these suffixes: - "K" for thousands - "M" for millions - "B" for billions -- "T" for trillions For example, if the input is 1,234,567, the output is ">= 1.23M". +- "T" for trillions For example, if the input is 1,234,567, the output is ">= 1.23M".\* ```solidity function abbreviateAmount(uint256 amount, uint256 decimals) internal pure returns (string memory); diff --git a/docs/reference/lockup/contracts/contract.SablierBatchLockup.md b/docs/reference/lockup/contracts/contract.SablierBatchLockup.md index 41265944..b3be3d43 100644 --- a/docs/reference/lockup/contracts/contract.SablierBatchLockup.md +++ b/docs/reference/lockup/contracts/contract.SablierBatchLockup.md @@ -4,7 +4,7 @@ sidebar_position: 1 # SablierBatchLockup -[Git Source](https://github.com/sablier-labs/lockup/blob/463278dbb461b1733d6424cf0aeee3b8d6bc036a/src/SablierBatchLockup.sol) +[Git Source](https://github.com/sablier-labs/lockup/blob/58eaac45c20c57a93b73d887c714e68f061ec3e6/src/SablierBatchLockup.sol) **Inherits:** [ISablierBatchLockup](/docs/reference/lockup/contracts/interfaces/interface.ISablierBatchLockup.md) @@ -15,12 +15,12 @@ See the documentation in ### createWithDurationsLD -Creates a batch of Lockup Dynamic streams using `createWithDurationsLD`. +Creates a batch of LD streams using `createWithDurationsLD`. -Requirements: +\*Requirements: - There must be at least one element in `batch`. -- All requirements from {ISablierLockup.createWithDurationsLD} must be met for each stream. +- All requirements from {ISablierLockupDynamic.createWithDurationsLD} must be met for each stream.\* ```solidity function createWithDurationsLD( @@ -35,11 +35,11 @@ function createWithDurationsLD( **Parameters** -| Name | Type | Description | -| -------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------ | -| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/docs/reference/lockup/contracts/contract.SablierLockup.md) contract. | -| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | -| `batch` | `BatchLockup.CreateWithDurationsLD[]` | An array of structs, each encapsulating a subset of the parameters of {SablierLockup.createWithDurationsLD}. | +| Name | Type | Description | +| -------- | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | +| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/docs/reference/lockup/contracts/contract.SablierLockup.md) contract. | +| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | +| `batch` | `BatchLockup.CreateWithDurationsLD[]` | An array of structs, each encapsulating a subset of the parameters of {ISablierLockupDynamic.createWithDurationsLD}. | **Returns** @@ -49,12 +49,12 @@ function createWithDurationsLD( ### createWithTimestampsLD -Creates a batch of Lockup Dynamic streams using `createWithTimestampsLD`. +Creates a batch of LD streams using `createWithTimestampsLD`. -Requirements: +\*Requirements: - There must be at least one element in `batch`. -- All requirements from {ISablierLockup.createWithTimestampsLD} must be met for each stream. +- All requirements from {ISablierLockupDynamic.createWithTimestampsLD} must be met for each stream.\* ```solidity function createWithTimestampsLD( @@ -69,11 +69,11 @@ function createWithTimestampsLD( **Parameters** -| Name | Type | Description | -| -------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------- | -| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/docs/reference/lockup/contracts/contract.SablierLockup.md) contract. | -| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | -| `batch` | `BatchLockup.CreateWithTimestampsLD[]` | An array of structs, each encapsulating a subset of the parameters of {SablierLockup.createWithTimestampsLD}. | +| Name | Type | Description | +| -------- | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | +| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/docs/reference/lockup/contracts/contract.SablierLockup.md) contract. | +| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | +| `batch` | `BatchLockup.CreateWithTimestampsLD[]` | An array of structs, each encapsulating a subset of the parameters of {ISablierLockupDynamic.createWithTimestampsLD}. | **Returns** @@ -83,12 +83,12 @@ function createWithTimestampsLD( ### createWithDurationsLL -Creates a batch of Lockup Linear streams using `createWithDurationsLL`. +Creates a batch of LL streams using `createWithDurationsLL`. -Requirements: +\*Requirements: - There must be at least one element in `batch`. -- All requirements from {ISablierLockup.createWithDurationsLL} must be met for each stream. +- All requirements from {ISablierLockupLinear.createWithDurationsLL} must be met for each stream.\* ```solidity function createWithDurationsLL( @@ -103,11 +103,11 @@ function createWithDurationsLL( **Parameters** -| Name | Type | Description | -| -------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------ | -| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/docs/reference/lockup/contracts/contract.SablierLockup.md) contract. | -| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | -| `batch` | `BatchLockup.CreateWithDurationsLL[]` | An array of structs, each encapsulating a subset of the parameters of {SablierLockup.createWithDurationsLL}. | +| Name | Type | Description | +| -------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | +| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/docs/reference/lockup/contracts/contract.SablierLockup.md) contract. | +| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | +| `batch` | `BatchLockup.CreateWithDurationsLL[]` | An array of structs, each encapsulating a subset of the parameters of {ISablierLockupLinear.createWithDurationsLL}. | **Returns** @@ -117,12 +117,12 @@ function createWithDurationsLL( ### createWithTimestampsLL -Creates a batch of Lockup Linear streams using `createWithTimestampsLL`. +Creates a batch of LL streams using `createWithTimestampsLL`. -Requirements: +\*Requirements: - There must be at least one element in `batch`. -- All requirements from {ISablierLockup.createWithTimestampsLL} must be met for each stream. +- All requirements from {ISablierLockupLinear.createWithTimestampsLL} must be met for each stream.\* ```solidity function createWithTimestampsLL( @@ -137,11 +137,11 @@ function createWithTimestampsLL( **Parameters** -| Name | Type | Description | -| -------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------- | -| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/docs/reference/lockup/contracts/contract.SablierLockup.md) contract. | -| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | -| `batch` | `BatchLockup.CreateWithTimestampsLL[]` | An array of structs, each encapsulating a subset of the parameters of {SablierLockup.createWithTimestampsLL}. | +| Name | Type | Description | +| -------- | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | +| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/docs/reference/lockup/contracts/contract.SablierLockup.md) contract. | +| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | +| `batch` | `BatchLockup.CreateWithTimestampsLL[]` | An array of structs, each encapsulating a subset of the parameters of {ISablierLockupLinear.createWithTimestampsLL}. | **Returns** @@ -151,12 +151,12 @@ function createWithTimestampsLL( ### createWithDurationsLT -Creates a batch of Lockup Tranched streams using `createWithDurationsLT`. +Creates a batch of LT streams using `createWithDurationsLT`. -Requirements: +\*Requirements: - There must be at least one element in `batch`. -- All requirements from {ISablierLockup.createWithDurationsLT} must be met for each stream. +- All requirements from {ISablierLockupTranched.createWithDurationsLT} must be met for each stream.\* ```solidity function createWithDurationsLT( @@ -171,11 +171,11 @@ function createWithDurationsLT( **Parameters** -| Name | Type | Description | -| -------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------ | -| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/docs/reference/lockup/contracts/contract.SablierLockup.md) contract. | -| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | -| `batch` | `BatchLockup.CreateWithDurationsLT[]` | An array of structs, each encapsulating a subset of the parameters of {SablierLockup.createWithDurationsLT}. | +| Name | Type | Description | +| -------- | ------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | +| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/docs/reference/lockup/contracts/contract.SablierLockup.md) contract. | +| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | +| `batch` | `BatchLockup.CreateWithDurationsLT[]` | An array of structs, each encapsulating a subset of the parameters of {ISablierLockupTranched.createWithDurationsLT}. | **Returns** @@ -185,12 +185,12 @@ function createWithDurationsLT( ### createWithTimestampsLT -Creates a batch of Lockup Tranched streams using `createWithTimestampsLT`. +Creates a batch of LT streams using `createWithTimestampsLT`. -Requirements: +\*Requirements: - There must be at least one element in `batch`. -- All requirements from {ISablierLockup.createWithTimestampsLT} must be met for each stream. +- All requirements from {ISablierLockupTranched.createWithTimestampsLT} must be met for each stream.\* ```solidity function createWithTimestampsLT( @@ -205,11 +205,11 @@ function createWithTimestampsLT( **Parameters** -| Name | Type | Description | -| -------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------- | -| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/docs/reference/lockup/contracts/contract.SablierLockup.md) contract. | -| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | -| `batch` | `BatchLockup.CreateWithTimestampsLT[]` | An array of structs, each encapsulating a subset of the parameters of {SablierLockup.createWithTimestampsLT}. | +| Name | Type | Description | +| -------- | -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | +| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/docs/reference/lockup/contracts/contract.SablierLockup.md) contract. | +| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | +| `batch` | `BatchLockup.CreateWithTimestampsLT[]` | An array of structs, each encapsulating a subset of the parameters of {ISablierLockupTranched.createWithTimestampsLT}. | **Returns** diff --git a/docs/reference/lockup/contracts/contract.SablierLockup.md b/docs/reference/lockup/contracts/contract.SablierLockup.md index 95e8c8c3..b1bfc625 100644 --- a/docs/reference/lockup/contracts/contract.SablierLockup.md +++ b/docs/reference/lockup/contracts/contract.SablierLockup.md @@ -4,87 +4,94 @@ sidebar_position: 1 # SablierLockup -[Git Source](https://github.com/sablier-labs/lockup/blob/463278dbb461b1733d6424cf0aeee3b8d6bc036a/src/SablierLockup.sol) +[Git Source](https://github.com/sablier-labs/lockup/blob/58eaac45c20c57a93b73d887c714e68f061ec3e6/src/SablierLockup.sol) -**Inherits:** [ISablierLockup](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockup.md), -[SablierLockupBase](/docs/reference/lockup/contracts/abstracts/abstract.SablierLockupBase.md) +**Inherits:** [Batch](/docs/reference/lockup/contracts/abstracts/abstract.Batch.md), +[Comptrollerable](/docs/reference/lockup/contracts/abstracts/abstract.Comptrollerable.md), ERC721, +[ISablierLockup](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockup.md), +[SablierLockupDynamic](/docs/reference/lockup/contracts/abstracts/abstract.SablierLockupDynamic.md), +[SablierLockupLinear](/docs/reference/lockup/contracts/abstracts/abstract.SablierLockupLinear.md), +[SablierLockupTranched](/docs/reference/lockup/contracts/abstracts/abstract.SablierLockupTranched.md) See the documentation in [ISablierLockup](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockup.md). -## State Variables - -### MAX_COUNT - -The maximum number of segments and tranches allowed in Dynamic and Tranched streams respectively. +## Functions -_This is initialized at construction time and cannot be changed later._ +### constructor ```solidity -uint256 public immutable override MAX_COUNT; +constructor( + address initialComptroller, + address initialNFTDescriptor +) + [Comptrollerable](/docs/reference/lockup/contracts/abstracts/abstract.Comptrollerable.md)(initialComptroller) + ERC721("Sablier Lockup NFT", "SAB-LOCKUP") + SablierLockupState(initialNFTDescriptor); ``` -### \_cliffs +**Parameters** -_Cliff timestamp mapped by stream IDs. This is used in Lockup Linear models._ +| Name | Type | Description | +| ---------------------- | --------- | ------------------------------------------------ | +| `initialComptroller` | `address` | The address of the initial comptroller contract. | +| `initialNFTDescriptor` | `address` | The address of the NFT descriptor contract. | -```solidity -mapping(uint256 streamId => uint40 cliffTime) internal _cliffs; -``` +### calculateMinFeeWei -### \_segments +Calculates the minimum fee in wei required to withdraw from the given stream ID. -_Stream segments mapped by stream IDs. This is used in Lockup Dynamic models._ +_Reverts if `streamId` references a null stream._ ```solidity -mapping(uint256 streamId => LockupDynamic.Segment[] segments) internal _segments; +function calculateMinFeeWei(uint256 streamId) external view override notNull(streamId) returns (uint256 minFeeWei); ``` -### \_tranches +**Parameters** -_Stream tranches mapped by stream IDs. This is used in Lockup Tranched models._ +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | -```solidity -mapping(uint256 streamId => LockupTranched.Tranche[] tranches) internal _tranches; -``` +### getRecipient -### \_unlockAmounts +Retrieves the stream's recipient. -_Unlock amounts mapped by stream IDs. This is used in Lockup Linear models._ +_Reverts if the NFT has been burned._ ```solidity -mapping(uint256 streamId => LockupLinear.UnlockAmounts unlockAmounts) internal _unlockAmounts; +function getRecipient(uint256 streamId) external view override returns (address recipient); ``` -## Functions +**Parameters** -### constructor +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### isCold + +Retrieves a flag indicating whether the stream is cold, i.e. settled, canceled, or depleted. + +_Reverts if `streamId` references a null stream._ ```solidity -constructor( - address initialAdmin, - ILockupNFTDescriptor initialNFTDescriptor, - uint256 maxCount -) - ERC721("Sablier Lockup NFT", "SAB-LOCKUP") - SablierLockupBase(initialAdmin, initialNFTDescriptor); +function isCold(uint256 streamId) external view override notNull(streamId) returns (bool result); ``` **Parameters** -| Name | Type | Description | -| ---------------------- | ---------------------- | --------------------------------------------------------------------------------------------------------------- | -| `initialAdmin` | `address` | The address of the initial contract admin. | -| `initialNFTDescriptor` | `ILockupNFTDescriptor` | The address of the NFT descriptor contract. | -| `maxCount` | `uint256` | The maximum number of segments and tranched allowed in Lockup Dynamic and Lockup Tranched models, respectively. | +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | -### getCliffTime +### isWarm -Retrieves the stream's cliff time, which is a Unix timestamp. A value of zero means there is no cliff. +Retrieves a flag indicating whether the stream is warm, i.e. either pending or streaming. -_Reverts if `streamId` references a null stream or a non Lockup Linear stream._ +_Reverts if `streamId` references a null stream._ ```solidity -function getCliffTime(uint256 streamId) external view override notNull(streamId) returns (uint40 cliffTime); +function isWarm(uint256 streamId) external view override notNull(streamId) returns (bool result); ``` **Parameters** @@ -93,19 +100,20 @@ function getCliffTime(uint256 streamId) external view override notNull(streamId) | ---------- | --------- | ---------------------------- | | `streamId` | `uint256` | The stream ID for the query. | -### getSegments +### refundableAmountOf -Retrieves the segments used to compose the dynamic distribution function. +Calculates the amount that the sender would be refunded if the stream were canceled, denoted in units of the token's +decimals. -_Reverts if `streamId` references a null stream or a non Lockup Dynamic stream._ +_Reverts if `streamId` references a null stream._ ```solidity -function getSegments(uint256 streamId) +function refundableAmountOf(uint256 streamId) external view override notNull(streamId) - returns (LockupDynamic.Segment[] memory segments); + returns (uint128 refundableAmount); ``` **Parameters** @@ -114,25 +122,34 @@ function getSegments(uint256 streamId) | ---------- | --------- | ---------------------------- | | `streamId` | `uint256` | The stream ID for the query. | -**Returns** +### statusOf + +Retrieves the stream's status. + +_Reverts if `streamId` references a null stream._ + +```solidity +function statusOf(uint256 streamId) external view override notNull(streamId) returns (Lockup.Status status); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | -| Name | Type | Description | -| ---------- | ------------------------- | ------------------------------------- | -| `segments` | `LockupDynamic.Segment[]` | See the documentation in {DataTypes}. | +### streamedAmountOf -### getTranches +Calculates the amount streamed to the recipient, denoted in units of the token's decimals. -Retrieves the tranches used to compose the tranched distribution function. +\*Reverts if `streamId` references a null stream. Notes: -_Reverts if `streamId` references a null stream or a non Lockup Tranched stream._ +- Upon cancellation of the stream, the amount streamed is calculated as the difference between the deposited amount and + the refunded amount. Ultimately, when the stream becomes depleted, the streamed amount is equivalent to the total + amount withdrawn.\* ```solidity -function getTranches(uint256 streamId) - external - view - override - notNull(streamId) - returns (LockupTranched.Tranche[] memory tranches); +function streamedAmountOf(uint256 streamId) external view override notNull(streamId) returns (uint128 streamedAmount); ``` **Parameters** @@ -141,25 +158,35 @@ function getTranches(uint256 streamId) | ---------- | --------- | ---------------------------- | | `streamId` | `uint256` | The stream ID for the query. | -**Returns** +### supportsInterface + +_See {IERC165-supportsInterface}._ + +```solidity +function supportsInterface(bytes4 interfaceId) public view override(IERC165, ERC721) returns (bool); +``` + +### tokenURI -| Name | Type | Description | -| ---------- | -------------------------- | ------------------------------------- | -| `tranches` | `LockupTranched.Tranche[]` | See the documentation in {DataTypes}. | +_See {IERC721Metadata-tokenURI}._ + +```solidity +function tokenURI(uint256 streamId) public view override(IERC721Metadata, ERC721) returns (string memory uri); +``` -### getUnlockAmounts +### withdrawableAmountOf -Retrieves the unlock amounts used to compose the linear distribution function. +Calculates the amount that the recipient can withdraw from the stream, denoted in units of the token's decimals. -_Reverts if `streamId` references a null stream or a non Lockup Linear stream._ +_Reverts if `streamId` references a null stream._ ```solidity -function getUnlockAmounts(uint256 streamId) +function withdrawableAmountOf(uint256 streamId) external view override notNull(streamId) - returns (LockupLinear.UnlockAmounts memory unlockAmounts); + returns (uint128 withdrawableAmount); ``` **Parameters** @@ -168,327 +195,436 @@ function getUnlockAmounts(uint256 streamId) | ---------- | --------- | ---------------------------- | | `streamId` | `uint256` | The stream ID for the query. | -**Returns** +### allowToHook + +Allows a recipient contract to hook to Sablier when a stream is canceled or when tokens are withdrawn. Useful for +implementing contracts that hold streams on behalf of users, such as vaults or staking contracts. + +\*Emits an {AllowToHook} event. Notes: + +- Does not revert if the contract is already on the allowlist. +- This is an irreversible operation. The contract cannot be removed from the allowlist. Requirements: +- `msg.sender` must be the comptroller contract. +- `recipient` must implement + [ISablierLockupRecipient](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupRecipient.md).\* -| Name | Type | Description | -| --------------- | ---------------------------- | ------------------------------------- | -| `unlockAmounts` | `LockupLinear.UnlockAmounts` | See the documentation in {DataTypes}. | +```solidity +function allowToHook(address recipient) external override onlyComptroller; +``` + +**Parameters** + +| Name | Type | Description | +| ----------- | --------- | ----------------------------------------------- | +| `recipient` | `address` | The address of the contract to allow for hooks. | -### createWithDurationsLD +### burn -Creates a stream by setting the start time to `block.timestamp`, and the end time to the sum of `block.timestamp` and -all specified time durations. The segment timestamps are derived from these durations. The stream is funded by -`msg.sender` and is wrapped in an ERC-721 NFT. +Burns the NFT associated with the stream. -Emits a {Transfer}, {CreateLockupDynamicStream} and {MetadataUpdate} event. Requirements: +\*Emits a {Transfer} and {MetadataUpdate} event. Requirements: -- All requirements in {createWithTimestampsLD} must be met for the calculated parameters. +- Must not be delegate called. +- `streamId` must reference a depleted stream. +- The NFT must exist. +- `msg.sender` must be either the NFT owner or an approved third party.\* ```solidity -function createWithDurationsLD( - Lockup.CreateWithDurations calldata params, - LockupDynamic.SegmentWithDuration[] calldata segmentsWithDuration -) - external +function burn(uint256 streamId) external payable override noDelegateCall notNull(streamId); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | --------------------------------- | +| `streamId` | `uint256` | The ID of the stream NFT to burn. | + +### cancel + +Cancels the stream and refunds any remaining tokens to the sender. + +\*Emits a {Transfer}, {CancelLockupStream} and {MetadataUpdate} event. Notes: + +- If there any tokens left for the recipient to withdraw, the stream is marked as canceled. Otherwise, the stream is + marked as depleted. +- If the address is on the allowlist, this function will invoke a hook on the recipient. Requirements: +- Must not be delegate called. +- The stream must be warm and cancelable. +- `msg.sender` must be the stream's sender.\* + +```solidity +function cancel(uint256 streamId) + public payable override noDelegateCall - returns (uint256 streamId); + notNull(streamId) + returns (uint128 refundedAmount); ``` **Parameters** -| Name | Type | Description | -| ---------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `params` | `Lockup.CreateWithDurations` | Struct encapsulating the function parameters, which are documented in {DataTypes}. | -| `segmentsWithDuration` | `LockupDynamic.SegmentWithDuration[]` | Segments with durations used to compose the dynamic distribution function. Timestamps are calculated by starting from `block.timestamp` and adding each duration to the previous timestamp. | +| Name | Type | Description | +| ---------- | --------- | ------------------------------- | +| `streamId` | `uint256` | The ID of the stream to cancel. | **Returns** -| Name | Type | Description | -| ---------- | --------- | ----------------------------------- | -| `streamId` | `uint256` | The ID of the newly created stream. | +| Name | Type | Description | +| ---------------- | --------- | ---------------------------------------------------------------------------- | +| `refundedAmount` | `uint128` | The amount refunded to the sender, denoted in units of the token's decimals. | -### createWithDurationsLL +### cancelMultiple -Creates a stream by setting the start time to `block.timestamp`, and the end time to the sum of `block.timestamp` and -`durations.total`. The stream is funded by `msg.sender` and is wrapped in an ERC-721 NFT. +Cancels multiple streams and refunds any remaining tokens to the sender. -Emits a {Transfer}, {CreateLockupLinearStream} and {MetadataUpdate} event. Requirements: +\*Emits multiple {Transfer}, {CancelLockupStream} and {MetadataUpdate} events. For each reverted cancellation, it emits +an +[InvalidStreamInCancelMultiple](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockup.md#invalidstreamincancelmultiple) +event. Notes: -- All requirements in {createWithTimestampsLL} must be met for the calculated parameters. +- This function as a whole will not revert if one or more cancellations revert. A zero amount is returned for reverted + streams. +- Refer to the notes and requirements from {cancel}.\* ```solidity -function createWithDurationsLL( - Lockup.CreateWithDurations calldata params, - LockupLinear.UnlockAmounts calldata unlockAmounts, - LockupLinear.Durations calldata durations -) +function cancelMultiple(uint256[] calldata streamIds) external payable override noDelegateCall - returns (uint256 streamId); + returns (uint128[] memory refundedAmounts); ``` **Parameters** -| Name | Type | Description | -| --------------- | ---------------------------- | ---------------------------------------------------------------------------------------------------------------- | -| `params` | `Lockup.CreateWithDurations` | Struct encapsulating the function parameters, which are documented in {DataTypes}. | -| `unlockAmounts` | `LockupLinear.UnlockAmounts` | Struct encapsulating (i) the amount to unlock at the start time and (ii) the amount to unlock at the cliff time. | -| `durations` | `LockupLinear.Durations` | Struct encapsulating (i) cliff period duration and (ii) total stream duration, both in seconds. | +| Name | Type | Description | +| ----------- | ----------- | --------------------------------- | +| `streamIds` | `uint256[]` | The IDs of the streams to cancel. | **Returns** -| Name | Type | Description | -| ---------- | --------- | ----------------------------------- | -| `streamId` | `uint256` | The ID of the newly created stream. | +| Name | Type | Description | +| ----------------- | ----------- | ----------------------------------------------------------------------------- | +| `refundedAmounts` | `uint128[]` | The amounts refunded to the sender, denoted in units of the token's decimals. | -### createWithDurationsLT +### recover -Creates a stream by setting the start time to `block.timestamp`, and the end time to the sum of `block.timestamp` and -all specified time durations. The tranche timestamps are derived from these durations. The stream is funded by -`msg.sender` and is wrapped in an ERC-721 NFT. +Recover the surplus amount of tokens. -Emits a {Transfer}, {CreateLockupTrancheStream} and {MetadataUpdate} event. Requirements: +\*Notes: -- All requirements in {createWithTimestampsLT} must be met for the calculated parameters. +- The surplus amount is defined as the difference between the total balance of the contract for the provided ERC-20 + token and the sum of balances of all streams created using the same ERC-20 token. Requirements: +- `msg.sender` must be the comptroller contract. +- The surplus amount must be greater than zero.\* ```solidity -function createWithDurationsLT( - Lockup.CreateWithDurations calldata params, - LockupTranched.TrancheWithDuration[] calldata tranchesWithDuration -) - external - payable - override - noDelegateCall - returns (uint256 streamId); +function recover(IERC20 token, address to) external override onlyComptroller; ``` **Parameters** -| Name | Type | Description | -| ---------------------- | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `params` | `Lockup.CreateWithDurations` | Struct encapsulating the function parameters, which are documented in {DataTypes}. | -| `tranchesWithDuration` | `LockupTranched.TrancheWithDuration[]` | Tranches with durations used to compose the tranched distribution function. Timestamps are calculated by starting from `block.timestamp` and adding each duration to the previous timestamp. | +| Name | Type | Description | +| ------- | --------- | -------------------------------------------------------- | +| `token` | `IERC20` | The contract address of the ERC-20 token to recover for. | +| `to` | `address` | The address to send the surplus amount. | -**Returns** +### renounce + +Removes the right of the stream's sender to cancel the stream. + +\*Emits a {RenounceLockupStream} event. Notes: + +- This is an irreversible operation. Requirements: +- Must not be delegate called. +- `streamId` must reference a warm stream. +- `msg.sender` must be the stream's sender. +- The stream must be cancelable.\* + +```solidity +function renounce(uint256 streamId) public payable override noDelegateCall notNull(streamId); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | --------------------------------- | +| `streamId` | `uint256` | The ID of the stream to renounce. | + +### setNativeToken + +Sets the native token address. Once set, it cannot be changed. + +\*For more information, see the documentation for {nativeToken}. Notes: -| Name | Type | Description | -| ---------- | --------- | ----------------------------------- | -| `streamId` | `uint256` | The ID of the newly created stream. | +- If `newNativeToken` is zero address, the function does not revert. Requirements: +- `msg.sender` must be the comptroller contract. +- The current native token must be zero address.\* -### createWithTimestampsLD +```solidity +function setNativeToken(address newNativeToken) external override onlyComptroller; +``` + +**Parameters** + +| Name | Type | Description | +| ---------------- | --------- | -------------------------------- | +| `newNativeToken` | `address` | The address of the native token. | + +### setNFTDescriptor + +Sets a new NFT descriptor contract, which produces the URI describing the Sablier stream NFTs. + +\*Emits a {SetNFTDescriptor} and {BatchMetadataUpdate} event. Notes: + +- Does not revert if the NFT descriptor is the same. Requirements: +- `msg.sender` must be the comptroller contract.\* + +```solidity +function setNFTDescriptor(ILockupNFTDescriptor newNFTDescriptor) external override onlyComptroller; +``` + +**Parameters** + +| Name | Type | Description | +| ------------------ | ---------------------- | ----------------------------------------------- | +| `newNFTDescriptor` | `ILockupNFTDescriptor` | The address of the new NFT descriptor contract. | -Creates a stream with the provided segment timestamps, implying the end time from the last timestamp. The stream is -funded by `msg.sender` and is wrapped in an ERC-721 NFT. +### withdraw -Emits a {Transfer}, {CreateLockupDynamicStream} and {MetadataUpdate} event. Notes: +Withdraws the provided amount of tokens from the stream to the `to` address. -- As long as the segment timestamps are arranged in ascending order, it is not an error for some of them to be in the - past. Requirements: +\*Emits a {Transfer}, {WithdrawFromLockupStream} and {MetadataUpdate} event. Notes: + +- If `msg.sender` is not the recipient and the address is on the allowlist, this function will invoke a hook on the + recipient. +- The minimum fee in wei is calculated for the stream's sender using the **SablierComptroller** contract. Requirements: - Must not be delegate called. -- `params.totalAmount` must be greater than zero. -- If set, `params.broker.fee` must not be greater than `MAX_BROKER_FEE`. -- `params.timestamps.start` must be greater than zero and less than the first segment's timestamp. -- `segments` must have at least one segment, but not more than `MAX_COUNT`. -- The segment timestamps must be arranged in ascending order. -- `params.timestamps.end` must be equal to the last segment's timestamp. -- The sum of the segment amounts must equal the deposit amount. -- `params.recipient` must not be the zero address. -- `params.sender` must not be the zero address. -- `msg.sender` must have allowed this contract to spend at least `params.totalAmount` tokens. -- `params.shape.length` must not be greater than 32 characters. +- `streamId` must not reference a null or depleted stream. +- `to` must not be the zero address. +- `amount` must be greater than zero and must not exceed the withdrawable amount. +- `to` must be the recipient if `msg.sender` is not the stream's recipient or an approved third party. +- `msg.value` must be greater than or equal to the minimum fee in wei for the stream's sender.\* ```solidity -function createWithTimestampsLD( - Lockup.CreateWithTimestamps calldata params, - LockupDynamic.Segment[] calldata segments +function withdraw( + uint256 streamId, + address to, + uint128 amount ) - external + public payable override noDelegateCall - returns (uint256 streamId); + notNull(streamId); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ----------------------------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to withdraw from. | +| `to` | `address` | The address receiving the withdrawn tokens. | +| `amount` | `uint128` | The amount to withdraw, denoted in units of the token's decimals. | + +### withdrawMax + +Withdraws the maximum withdrawable amount from the stream to the provided address `to`. + +\*Emits a {Transfer}, {WithdrawFromLockupStream} and {MetadataUpdate} event. Notes: + +- Refer to the notes in {withdraw}. Requirements: +- Refer to the requirements in {withdraw}.\* + +```solidity +function withdrawMax(uint256 streamId, address to) external payable override returns (uint128 withdrawnAmount); ``` **Parameters** -| Name | Type | Description | -| ---------- | ----------------------------- | ---------------------------------------------------------------------------------- | -| `params` | `Lockup.CreateWithTimestamps` | Struct encapsulating the function parameters, which are documented in {DataTypes}. | -| `segments` | `LockupDynamic.Segment[]` | Segments used to compose the dynamic distribution function. | +| Name | Type | Description | +| ---------- | --------- | ------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to withdraw from. | +| `to` | `address` | The address receiving the withdrawn tokens. | **Returns** -| Name | Type | Description | -| ---------- | --------- | ----------------------------------- | -| `streamId` | `uint256` | The ID of the newly created stream. | +| Name | Type | Description | +| ----------------- | --------- | --------------------------------------------------------------- | +| `withdrawnAmount` | `uint128` | The amount withdrawn, denoted in units of the token's decimals. | -### createWithTimestampsLL +### withdrawMaxAndTransfer -Creates a stream with the provided start time and end time. The stream is funded by `msg.sender` and is wrapped in an -ERC-721 NFT. +Withdraws the maximum withdrawable amount from the stream to the current recipient, and transfers the NFT to +`newRecipient`. -Emits a {Transfer}, {CreateLockupLinearStream} and {MetadataUpdate} event. Notes: +\*Emits a {WithdrawFromLockupStream}, {Transfer} and {MetadataUpdate} event. Notes: -- A cliff time of zero means there is no cliff. -- As long as the times are ordered, it is not an error for the start or the cliff time to be in the past. Requirements: -- Must not be delegate called. -- `params.totalAmount` must be greater than zero. -- If set, `params.broker.fee` must not be greater than `MAX_BROKER_FEE`. -- `params.timestamps.start` must be greater than zero and less than `params.timestamps.end`. -- If set, `cliffTime` must be greater than `params.timestamps.start` and less than `params.timestamps.end`. -- `params.recipient` must not be the zero address. -- `params.sender` must not be the zero address. -- The sum of `params.unlockAmounts.start` and `params.unlockAmounts.cliff` must be less than or equal to deposit amount. -- If `params.timestamps.cliff` not set, the `params.unlockAmounts.cliff` must be zero. -- `msg.sender` must have allowed this contract to spend at least `params.totalAmount` tokens. -- `params.shape.length` must not be greater than 32 characters. +- If the withdrawable amount is zero, the withdrawal is skipped. +- Refer to the notes in {withdraw}. Requirements: +- `msg.sender` must be either the NFT owner or an approved third party. +- Refer to the requirements in {withdraw}. +- Refer to the requirements in {IERC721.transferFrom}.\* ```solidity -function createWithTimestampsLL( - Lockup.CreateWithTimestamps calldata params, - LockupLinear.UnlockAmounts calldata unlockAmounts, - uint40 cliffTime +function withdrawMaxAndTransfer( + uint256 streamId, + address newRecipient ) external payable override noDelegateCall - returns (uint256 streamId); + notNull(streamId) + returns (uint128 withdrawnAmount); ``` **Parameters** -| Name | Type | Description | -| --------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------- | -| `params` | `Lockup.CreateWithTimestamps` | Struct encapsulating the function parameters, which are documented in {DataTypes}. | -| `unlockAmounts` | `LockupLinear.UnlockAmounts` | Struct encapsulating (i) the amount to unlock at the start time and (ii) the amount to unlock at the cliff time. | -| `cliffTime` | `uint40` | The Unix timestamp for the cliff period's end. A value of zero means there is no cliff. | +| Name | Type | Description | +| -------------- | --------- | ----------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream NFT to transfer. | +| `newRecipient` | `address` | The address of the new owner of the stream NFT. | **Returns** -| Name | Type | Description | -| ---------- | --------- | ----------------------------------- | -| `streamId` | `uint256` | The ID of the newly created stream. | +| Name | Type | Description | +| ----------------- | --------- | --------------------------------------------------------------- | +| `withdrawnAmount` | `uint128` | The amount withdrawn, denoted in units of the token's decimals. | -### createWithTimestampsLT +### withdrawMultiple -Creates a stream with the provided tranche timestamps, implying the end time from the last timestamp. The stream is -funded by `msg.sender` and is wrapped in an ERC-721 NFT. +Withdraws tokens from streams to the recipient of each stream. -Emits a {Transfer}, {CreateLockupTrancheStream} and {MetadataUpdate} event. Notes: +\*Emits multiple {Transfer}, {WithdrawFromLockupStream} and {MetadataUpdate} events. For each reverting withdrawal, it +emits an +[InvalidWithdrawalInWithdrawMultiple](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockup.md#invalidwithdrawalinwithdrawmultiple) +event. Notes: -- As long as the tranche timestamps are arranged in ascending order, it is not an error for some of them to be in the - past. Requirements: +- This function as a whole will not revert if one or more withdrawals revert. +- This function attempts to call a hook on the recipient of each stream, unless `msg.sender` is the recipient. +- Refer to the notes and requirements from {withdraw}. Requirements: - Must not be delegate called. -- `params.totalAmount` must be greater than zero. -- If set, `params.broker.fee` must not be greater than `MAX_BROKER_FEE`. -- `params.timestamps.start` must be greater than zero and less than the first tranche's timestamp. -- `tranches` must have at least one tranche, but not more than `MAX_COUNT`. -- The tranche timestamps must be arranged in ascending order. -- `params.timestamps.end` must be equal to the last tranche's timestamp. -- The sum of the tranche amounts must equal the deposit amount. -- `params.recipient` must not be the zero address. -- `params.sender` must not be the zero address. -- `msg.sender` must have allowed this contract to spend at least `params.totalAmount` tokens. -- `params.shape.length` must not be greater than 32 characters. +- There must be an equal number of `streamIds` and `amounts`.\* ```solidity -function createWithTimestampsLT( - Lockup.CreateWithTimestamps calldata params, - LockupTranched.Tranche[] calldata tranches +function withdrawMultiple( + uint256[] calldata streamIds, + uint128[] calldata amounts ) external payable override - noDelegateCall - returns (uint256 streamId); + noDelegateCall; ``` **Parameters** -| Name | Type | Description | -| ---------- | ----------------------------- | ---------------------------------------------------------------------------------- | -| `params` | `Lockup.CreateWithTimestamps` | Struct encapsulating the function parameters, which are documented in {DataTypes}. | -| `tranches` | `LockupTranched.Tranche[]` | Tranches used to compose the tranched distribution function. | - -**Returns** - -| Name | Type | Description | -| ---------- | --------- | ----------------------------------- | -| `streamId` | `uint256` | The ID of the newly created stream. | +| Name | Type | Description | +| ----------- | ----------- | ------------------------------------------------------------------ | +| `streamIds` | `uint256[]` | The IDs of the streams to withdraw from. | +| `amounts` | `uint128[]` | The amounts to withdraw, denoted in units of the token's decimals. | -### \_calculateStreamedAmount +### \_streamedAmountOf -Calculates the streamed amount of the stream without looking up the stream's status. +Calculates the streamed amount of the stream. -_This function is implemented by child contracts, so the logic varies depending on the model._ +_This function is implemented by child contract. The logic varies according to the distribution model._ ```solidity -function _calculateStreamedAmount(uint256 streamId) internal view override returns (uint128); +function _streamedAmountOf(uint256 streamId) internal view override returns (uint128 streamedAmount); ``` ### \_create -_Common logic for creating a stream._ +This function is implemented by [SablierLockup](/docs/reference/lockup/contracts/contract.SablierLockup.md) and is used +in the [SablierLockupDynamic](docs/reference/lockup/contracts/abstracts/abstract.SablierLockupDynamic.md), +[SablierLockupLinear](docs/reference/lockup/contracts/abstracts/abstract.SablierLockupLinear.md) and +[SablierLockupTranched](docs/reference/lockup/contracts/abstracts/abstract.SablierLockupTranched.md) contracts. + +_It updates state variables based on the stream parameters, mints an NFT to the recipient, bumps stream ID, and +transfers the deposit amount._ ```solidity function _create( + bool cancelable, + uint128 depositAmount, + Lockup.Model lockupModel, + address recipient, + address sender, uint256 streamId, - Lockup.CreateWithTimestamps memory params, - Lockup.CreateAmounts memory createAmounts, - Lockup.Model lockupModel + Lockup.Timestamps memory timestamps, + IERC20 token, + bool transferable ) internal - returns (Lockup.CreateEventCommon memory); + override; +``` + +### \_update + +Overrides the {ERC-721.\_update} function to check that the stream is transferable, and emits an ERC-4906 event. + +\*There are two cases when the transferable flag is ignored: + +- If the current owner is 0, then the update is a mint and is allowed. +- If `to` is 0, then the update is a burn and is also allowed.\* + +```solidity +function _update(address to, uint256 streamId, address auth) internal override returns (address); ``` +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `to` | `address` | The address of the new recipient of the stream. | +| `streamId` | `uint256` | ID of the stream to update. | +| `auth` | `address` | Optional parameter. If the value is not zero, the overridden implementation will check that `auth` is either the recipient of the stream, or an approved third party. | + **Returns** -| Name | Type | Description | -| -------- | -------------------------- | ---------------------------------------------------------------------------- | -| `` | `Lockup.CreateEventCommon` | The common parameters emitted in the create event between all Lockup models. | +| Name | Type | Description | +| -------- | --------- | ----------------------------------------------------------- | +| `` | `address` | The original recipient of the `streamId` before the update. | -### \_createLD +### \_isCallerStreamRecipientOrApproved -_See the documentation for the user-facing functions that call this internal function._ +Checks whether `msg.sender` is the stream's recipient or an approved third party, when the `recipient` is known in +advance. ```solidity -function _createLD( - Lockup.CreateWithTimestamps memory params, - LockupDynamic.Segment[] memory segments -) - internal - returns (uint256 streamId); +function _isCallerStreamRecipientOrApproved(uint256 streamId, address recipient) private view returns (bool); +``` + +**Parameters** + +| Name | Type | Description | +| ----------- | --------- | -------------------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | +| `recipient` | `address` | The address of the stream's recipient. | + +### \_withdrawableAmountOf + +_See the documentation for the user-facing functions that call this private function._ + +```solidity +function _withdrawableAmountOf(uint256 streamId) private view returns (uint128); ``` -### \_createLL +### \_cancel -_See the documentation for the user-facing functions that call this internal function._ +_See the documentation for the user-facing functions that call this private function._ ```solidity -function _createLL( - Lockup.CreateWithTimestamps memory params, - LockupLinear.UnlockAmounts memory unlockAmounts, - uint40 cliffTime -) - internal - returns (uint256 streamId); +function _cancel(uint256 streamId) private returns (uint128 senderAmount); ``` -### \_createLT +### \_withdraw -_See the documentation for the user-facing functions that call this internal function._ +_See the documentation for the user-facing functions that call this private function._ ```solidity -function _createLT( - Lockup.CreateWithTimestamps memory params, - LockupTranched.Tranche[] memory tranches -) - internal - returns (uint256 streamId); +function _withdraw(uint256 streamId, address to, uint128 amount) private; ``` diff --git a/docs/reference/lockup/contracts/interfaces/interface.IAdminable.md b/docs/reference/lockup/contracts/interfaces/interface.IAdminable.md deleted file mode 100644 index f37624af..00000000 --- a/docs/reference/lockup/contracts/interfaces/interface.IAdminable.md +++ /dev/null @@ -1,54 +0,0 @@ -# IAdminable - -[Git Source](https://github.com/sablier-labs/lockup/blob/463278dbb461b1733d6424cf0aeee3b8d6bc036a/src/interfaces/IAdminable.sol) - -Contract module that provides a basic access control mechanism, with an admin that can be granted exclusive access to -specific functions. The inheriting contract must set the initial admin in the constructor. - -## Functions - -### admin - -The address of the admin account or contract. - -```solidity -function admin() external view returns (address); -``` - -### transferAdmin - -Transfers the contract admin to a new address. - -Notes: - -- Does not revert if the admin is the same. -- This function can potentially leave the contract without an admin, thereby removing any functionality that is only - available to the admin. Requirements: -- `msg.sender` must be the contract admin. - -```solidity -function transferAdmin(address newAdmin) external; -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ----------------------------- | -| `newAdmin` | `address` | The address of the new admin. | - -## Events - -### TransferAdmin - -Emitted when the admin is transferred. - -```solidity -event TransferAdmin(address indexed oldAdmin, address indexed newAdmin); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ----------------------------- | -| `oldAdmin` | `address` | The address of the old admin. | -| `newAdmin` | `address` | The address of the new admin. | diff --git a/docs/reference/lockup/contracts/interfaces/interface.IBatch.md b/docs/reference/lockup/contracts/interfaces/interface.IBatch.md deleted file mode 100644 index 272cfc20..00000000 --- a/docs/reference/lockup/contracts/interfaces/interface.IBatch.md +++ /dev/null @@ -1,30 +0,0 @@ -# IBatch - -[Git Source](https://github.com/sablier-labs/lockup/blob/463278dbb461b1733d6424cf0aeee3b8d6bc036a/src/interfaces/IBatch.sol) - -This contract implements logic to batch call any function. - -## Functions - -### batch - -Allows batched calls to self, i.e., `this` contract. - -_Since `msg.value` can be reused across calls, be VERY CAREFUL when using it. Refer to -https://paradigm.xyz/2021/08/two-rights-might-make-a-wrong for more information._ - -```solidity -function batch(bytes[] calldata calls) external payable returns (bytes[] memory results); -``` - -**Parameters** - -| Name | Type | Description | -| ------- | --------- | --------------------------------- | -| `calls` | `bytes[]` | An array of inputs for each call. | - -**Returns** - -| Name | Type | Description | -| --------- | --------- | -------------------------------------------------------------------------------- | -| `results` | `bytes[]` | An array of results from each call. Empty when the calls do not return anything. | diff --git a/docs/reference/lockup/contracts/interfaces/interface.ILockupNFTDescriptor.md b/docs/reference/lockup/contracts/interfaces/interface.ILockupNFTDescriptor.md index eb90b487..a6b90d68 100644 --- a/docs/reference/lockup/contracts/interfaces/interface.ILockupNFTDescriptor.md +++ b/docs/reference/lockup/contracts/interfaces/interface.ILockupNFTDescriptor.md @@ -1,6 +1,6 @@ # ILockupNFTDescriptor -[Git Source](https://github.com/sablier-labs/lockup/blob/463278dbb461b1733d6424cf0aeee3b8d6bc036a/src/interfaces/ILockupNFTDescriptor.sol) +[Git Source](https://github.com/sablier-labs/lockup/blob/58eaac45c20c57a93b73d887c714e68f061ec3e6/src/interfaces/ILockupNFTDescriptor.sol) This contract generates the URI describing the Sablier stream NFTs. diff --git a/docs/reference/lockup/contracts/interfaces/interface.ISablierBatchLockup.md b/docs/reference/lockup/contracts/interfaces/interface.ISablierBatchLockup.md index c71bea3a..07351f2a 100644 --- a/docs/reference/lockup/contracts/interfaces/interface.ISablierBatchLockup.md +++ b/docs/reference/lockup/contracts/interfaces/interface.ISablierBatchLockup.md @@ -1,6 +1,6 @@ # ISablierBatchLockup -[Git Source](https://github.com/sablier-labs/lockup/blob/463278dbb461b1733d6424cf0aeee3b8d6bc036a/src/interfaces/ISablierBatchLockup.sol) +[Git Source](https://github.com/sablier-labs/lockup/blob/58eaac45c20c57a93b73d887c714e68f061ec3e6/src/interfaces/ISablierBatchLockup.sol) Helper to batch create Lockup streams. @@ -8,12 +8,12 @@ Helper to batch create Lockup streams. ### createWithDurationsLD -Creates a batch of Lockup Dynamic streams using `createWithDurationsLD`. +Creates a batch of LD streams using `createWithDurationsLD`. -Requirements: +\*Requirements: - There must be at least one element in `batch`. -- All requirements from {ISablierLockup.createWithDurationsLD} must be met for each stream. +- All requirements from {ISablierLockupDynamic.createWithDurationsLD} must be met for each stream.\* ```solidity function createWithDurationsLD( @@ -27,11 +27,11 @@ function createWithDurationsLD( **Parameters** -| Name | Type | Description | -| -------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------ | -| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/docs/reference/lockup/contracts/contract.SablierLockup.md) contract. | -| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | -| `batch` | `BatchLockup.CreateWithDurationsLD[]` | An array of structs, each encapsulating a subset of the parameters of {SablierLockup.createWithDurationsLD}. | +| Name | Type | Description | +| -------- | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | +| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/docs/reference/lockup/contracts/contract.SablierLockup.md) contract. | +| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | +| `batch` | `BatchLockup.CreateWithDurationsLD[]` | An array of structs, each encapsulating a subset of the parameters of {ISablierLockupDynamic.createWithDurationsLD}. | **Returns** @@ -41,12 +41,12 @@ function createWithDurationsLD( ### createWithTimestampsLD -Creates a batch of Lockup Dynamic streams using `createWithTimestampsLD`. +Creates a batch of LD streams using `createWithTimestampsLD`. -Requirements: +\*Requirements: - There must be at least one element in `batch`. -- All requirements from {ISablierLockup.createWithTimestampsLD} must be met for each stream. +- All requirements from {ISablierLockupDynamic.createWithTimestampsLD} must be met for each stream.\* ```solidity function createWithTimestampsLD( @@ -60,11 +60,11 @@ function createWithTimestampsLD( **Parameters** -| Name | Type | Description | -| -------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------- | -| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/docs/reference/lockup/contracts/contract.SablierLockup.md) contract. | -| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | -| `batch` | `BatchLockup.CreateWithTimestampsLD[]` | An array of structs, each encapsulating a subset of the parameters of {SablierLockup.createWithTimestampsLD}. | +| Name | Type | Description | +| -------- | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | +| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/docs/reference/lockup/contracts/contract.SablierLockup.md) contract. | +| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | +| `batch` | `BatchLockup.CreateWithTimestampsLD[]` | An array of structs, each encapsulating a subset of the parameters of {ISablierLockupDynamic.createWithTimestampsLD}. | **Returns** @@ -74,12 +74,12 @@ function createWithTimestampsLD( ### createWithDurationsLL -Creates a batch of Lockup Linear streams using `createWithDurationsLL`. +Creates a batch of LL streams using `createWithDurationsLL`. -Requirements: +\*Requirements: - There must be at least one element in `batch`. -- All requirements from {ISablierLockup.createWithDurationsLL} must be met for each stream. +- All requirements from {ISablierLockupLinear.createWithDurationsLL} must be met for each stream.\* ```solidity function createWithDurationsLL( @@ -93,11 +93,11 @@ function createWithDurationsLL( **Parameters** -| Name | Type | Description | -| -------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------ | -| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/docs/reference/lockup/contracts/contract.SablierLockup.md) contract. | -| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | -| `batch` | `BatchLockup.CreateWithDurationsLL[]` | An array of structs, each encapsulating a subset of the parameters of {SablierLockup.createWithDurationsLL}. | +| Name | Type | Description | +| -------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | +| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/docs/reference/lockup/contracts/contract.SablierLockup.md) contract. | +| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | +| `batch` | `BatchLockup.CreateWithDurationsLL[]` | An array of structs, each encapsulating a subset of the parameters of {ISablierLockupLinear.createWithDurationsLL}. | **Returns** @@ -107,12 +107,12 @@ function createWithDurationsLL( ### createWithTimestampsLL -Creates a batch of Lockup Linear streams using `createWithTimestampsLL`. +Creates a batch of LL streams using `createWithTimestampsLL`. -Requirements: +\*Requirements: - There must be at least one element in `batch`. -- All requirements from {ISablierLockup.createWithTimestampsLL} must be met for each stream. +- All requirements from {ISablierLockupLinear.createWithTimestampsLL} must be met for each stream.\* ```solidity function createWithTimestampsLL( @@ -126,11 +126,11 @@ function createWithTimestampsLL( **Parameters** -| Name | Type | Description | -| -------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------- | -| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/docs/reference/lockup/contracts/contract.SablierLockup.md) contract. | -| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | -| `batch` | `BatchLockup.CreateWithTimestampsLL[]` | An array of structs, each encapsulating a subset of the parameters of {SablierLockup.createWithTimestampsLL}. | +| Name | Type | Description | +| -------- | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | +| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/docs/reference/lockup/contracts/contract.SablierLockup.md) contract. | +| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | +| `batch` | `BatchLockup.CreateWithTimestampsLL[]` | An array of structs, each encapsulating a subset of the parameters of {ISablierLockupLinear.createWithTimestampsLL}. | **Returns** @@ -140,12 +140,12 @@ function createWithTimestampsLL( ### createWithDurationsLT -Creates a batch of Lockup Tranched streams using `createWithDurationsLT`. +Creates a batch of LT streams using `createWithDurationsLT`. -Requirements: +\*Requirements: - There must be at least one element in `batch`. -- All requirements from {ISablierLockup.createWithDurationsLT} must be met for each stream. +- All requirements from {ISablierLockupTranched.createWithDurationsLT} must be met for each stream.\* ```solidity function createWithDurationsLT( @@ -159,11 +159,11 @@ function createWithDurationsLT( **Parameters** -| Name | Type | Description | -| -------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------ | -| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/docs/reference/lockup/contracts/contract.SablierLockup.md) contract. | -| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | -| `batch` | `BatchLockup.CreateWithDurationsLT[]` | An array of structs, each encapsulating a subset of the parameters of {SablierLockup.createWithDurationsLT}. | +| Name | Type | Description | +| -------- | ------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | +| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/docs/reference/lockup/contracts/contract.SablierLockup.md) contract. | +| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | +| `batch` | `BatchLockup.CreateWithDurationsLT[]` | An array of structs, each encapsulating a subset of the parameters of {ISablierLockupTranched.createWithDurationsLT}. | **Returns** @@ -173,12 +173,12 @@ function createWithDurationsLT( ### createWithTimestampsLT -Creates a batch of Lockup Tranched streams using `createWithTimestampsLT`. +Creates a batch of LT streams using `createWithTimestampsLT`. -Requirements: +\*Requirements: - There must be at least one element in `batch`. -- All requirements from {ISablierLockup.createWithTimestampsLT} must be met for each stream. +- All requirements from {ISablierLockupTranched.createWithTimestampsLT} must be met for each stream.\* ```solidity function createWithTimestampsLT( @@ -192,14 +192,32 @@ function createWithTimestampsLT( **Parameters** -| Name | Type | Description | -| -------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------- | -| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/docs/reference/lockup/contracts/contract.SablierLockup.md) contract. | -| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | -| `batch` | `BatchLockup.CreateWithTimestampsLT[]` | An array of structs, each encapsulating a subset of the parameters of {SablierLockup.createWithTimestampsLT}. | +| Name | Type | Description | +| -------- | -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | +| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/docs/reference/lockup/contracts/contract.SablierLockup.md) contract. | +| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | +| `batch` | `BatchLockup.CreateWithTimestampsLT[]` | An array of structs, each encapsulating a subset of the parameters of {ISablierLockupTranched.createWithTimestampsLT}. | **Returns** | Name | Type | Description | | ----------- | ----------- | ------------------------------------- | | `streamIds` | `uint256[]` | The ids of the newly created streams. | + +## Events + +### CreateLockupBatch + +Emitted when a batch of Lockup streams are created. + +```solidity +event CreateLockupBatch(address indexed funder, ISablierLockup indexed lockup, uint256[] streamIds); +``` + +**Parameters** + +| Name | Type | Description | +| ----------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| `funder` | `address` | The address funding the streams. | +| `lockup` | `ISablierLockup` | The address of the [SablierLockup](/docs/reference/lockup/contracts/contract.SablierLockup.md) contract used to create the streams. | +| `streamIds` | `uint256[]` | The ids of the newly created streams, the ones that were successfully created. | diff --git a/docs/reference/lockup/contracts/interfaces/interface.ISablierLockup.md b/docs/reference/lockup/contracts/interfaces/interface.ISablierLockup.md index cef7c991..92e7f3fa 100644 --- a/docs/reference/lockup/contracts/interfaces/interface.ISablierLockup.md +++ b/docs/reference/lockup/contracts/interfaces/interface.ISablierLockup.md @@ -1,31 +1,40 @@ # ISablierLockup -[Git Source](https://github.com/sablier-labs/lockup/blob/463278dbb461b1733d6424cf0aeee3b8d6bc036a/src/interfaces/ISablierLockup.sol) +[Git Source](https://github.com/sablier-labs/lockup/blob/58eaac45c20c57a93b73d887c714e68f061ec3e6/src/interfaces/ISablierLockup.sol) -**Inherits:** [ISablierLockupBase](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupBase.md) +**Inherits:** IBatch, IComptrollerable, IERC4906, IERC721Metadata, +[ISablierLockupDynamic](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupDynamic.md), +[ISablierLockupLinear](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupLinear.md), +[ISablierLockupTranched](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupTranched.md) -Creates and manages Lockup streams with various distribution models. +Interface to manage Lockup streams with various distribution models. ## Functions -### MAX_COUNT +### calculateMinFeeWei -The maximum number of segments and tranches allowed in Dynamic and Tranched streams respectively. +Calculates the minimum fee in wei required to withdraw from the given stream ID. -_This is initialized at construction time and cannot be changed later._ +_Reverts if `streamId` references a null stream._ ```solidity -function MAX_COUNT() external view returns (uint256); +function calculateMinFeeWei(uint256 streamId) external view returns (uint256 minFeeWei); ``` -### getCliffTime +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | -Retrieves the stream's cliff time, which is a Unix timestamp. A value of zero means there is no cliff. +### getRecipient -_Reverts if `streamId` references a null stream or a non Lockup Linear stream._ +Retrieves the stream's recipient. + +_Reverts if the NFT has been burned._ ```solidity -function getCliffTime(uint256 streamId) external view returns (uint40 cliffTime); +function getRecipient(uint256 streamId) external view returns (address recipient); ``` **Parameters** @@ -34,14 +43,14 @@ function getCliffTime(uint256 streamId) external view returns (uint40 cliffTime) | ---------- | --------- | ---------------------------- | | `streamId` | `uint256` | The stream ID for the query. | -### getSegments +### isCold -Retrieves the segments used to compose the dynamic distribution function. +Retrieves a flag indicating whether the stream is cold, i.e. settled, canceled, or depleted. -_Reverts if `streamId` references a null stream or a non Lockup Dynamic stream._ +_Reverts if `streamId` references a null stream._ ```solidity -function getSegments(uint256 streamId) external view returns (LockupDynamic.Segment[] memory segments); +function isCold(uint256 streamId) external view returns (bool result); ``` **Parameters** @@ -50,20 +59,31 @@ function getSegments(uint256 streamId) external view returns (LockupDynamic.Segm | ---------- | --------- | ---------------------------- | | `streamId` | `uint256` | The stream ID for the query. | -**Returns** +### isWarm -| Name | Type | Description | -| ---------- | ------------------------- | ------------------------------------- | -| `segments` | `LockupDynamic.Segment[]` | See the documentation in {DataTypes}. | +Retrieves a flag indicating whether the stream is warm, i.e. either pending or streaming. -### getTranches +_Reverts if `streamId` references a null stream._ -Retrieves the tranches used to compose the tranched distribution function. +```solidity +function isWarm(uint256 streamId) external view returns (bool result); +``` -_Reverts if `streamId` references a null stream or a non Lockup Tranched stream._ +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### refundableAmountOf + +Calculates the amount that the sender would be refunded if the stream were canceled, denoted in units of the token's +decimals. + +_Reverts if `streamId` references a null stream._ ```solidity -function getTranches(uint256 streamId) external view returns (LockupTranched.Tranche[] memory tranches); +function refundableAmountOf(uint256 streamId) external view returns (uint128 refundableAmount); ``` **Parameters** @@ -72,20 +92,34 @@ function getTranches(uint256 streamId) external view returns (LockupTranched.Tra | ---------- | --------- | ---------------------------- | | `streamId` | `uint256` | The stream ID for the query. | -**Returns** +### statusOf + +Retrieves the stream's status. -| Name | Type | Description | -| ---------- | -------------------------- | ------------------------------------- | -| `tranches` | `LockupTranched.Tranche[]` | See the documentation in {DataTypes}. | +_Reverts if `streamId` references a null stream._ -### getUnlockAmounts +```solidity +function statusOf(uint256 streamId) external view returns (Lockup.Status status); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### streamedAmountOf + +Calculates the amount streamed to the recipient, denoted in units of the token's decimals. -Retrieves the unlock amounts used to compose the linear distribution function. +\*Reverts if `streamId` references a null stream. Notes: -_Reverts if `streamId` references a null stream or a non Lockup Linear stream._ +- Upon cancellation of the stream, the amount streamed is calculated as the difference between the deposited amount and + the refunded amount. Ultimately, when the stream becomes depleted, the streamed amount is equivalent to the total + amount withdrawn.\* ```solidity -function getUnlockAmounts(uint256 streamId) external view returns (LockupLinear.UnlockAmounts memory unlockAmounts); +function streamedAmountOf(uint256 streamId) external view returns (uint128 streamedAmount); ``` **Parameters** @@ -94,304 +128,449 @@ function getUnlockAmounts(uint256 streamId) external view returns (LockupLinear. | ---------- | --------- | ---------------------------- | | `streamId` | `uint256` | The stream ID for the query. | -**Returns** +### withdrawableAmountOf -| Name | Type | Description | -| --------------- | ---------------------------- | ------------------------------------- | -| `unlockAmounts` | `LockupLinear.UnlockAmounts` | See the documentation in {DataTypes}. | +Calculates the amount that the recipient can withdraw from the stream, denoted in units of the token's decimals. -### createWithDurationsLD +_Reverts if `streamId` references a null stream._ -Creates a stream by setting the start time to `block.timestamp`, and the end time to the sum of `block.timestamp` and -all specified time durations. The segment timestamps are derived from these durations. The stream is funded by -`msg.sender` and is wrapped in an ERC-721 NFT. +```solidity +function withdrawableAmountOf(uint256 streamId) external view returns (uint128 withdrawableAmount); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | -Emits a {Transfer}, {CreateLockupDynamicStream} and {MetadataUpdate} event. Requirements: +### allowToHook -- All requirements in {createWithTimestampsLD} must be met for the calculated parameters. +Allows a recipient contract to hook to Sablier when a stream is canceled or when tokens are withdrawn. Useful for +implementing contracts that hold streams on behalf of users, such as vaults or staking contracts. + +\*Emits an [AllowToHook](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockup.md#allowtohook) event. +Notes: + +- Does not revert if the contract is already on the allowlist. +- This is an irreversible operation. The contract cannot be removed from the allowlist. Requirements: +- `msg.sender` must be the comptroller contract. +- `recipient` must implement + [ISablierLockupRecipient](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupRecipient.md).\* ```solidity -function createWithDurationsLD( - Lockup.CreateWithDurations calldata params, - LockupDynamic.SegmentWithDuration[] calldata segmentsWithDuration -) - external - payable - returns (uint256 streamId); +function allowToHook(address recipient) external; ``` **Parameters** -| Name | Type | Description | -| ---------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `params` | `Lockup.CreateWithDurations` | Struct encapsulating the function parameters, which are documented in {DataTypes}. | -| `segmentsWithDuration` | `LockupDynamic.SegmentWithDuration[]` | Segments with durations used to compose the dynamic distribution function. Timestamps are calculated by starting from `block.timestamp` and adding each duration to the previous timestamp. | +| Name | Type | Description | +| ----------- | --------- | ----------------------------------------------- | +| `recipient` | `address` | The address of the contract to allow for hooks. | -**Returns** +### burn -| Name | Type | Description | -| ---------- | --------- | ----------------------------------- | -| `streamId` | `uint256` | The ID of the newly created stream. | +Burns the NFT associated with the stream. -### createWithDurationsLL +\*Emits a {Transfer} and {MetadataUpdate} event. Requirements: -Creates a stream by setting the start time to `block.timestamp`, and the end time to the sum of `block.timestamp` and -`durations.total`. The stream is funded by `msg.sender` and is wrapped in an ERC-721 NFT. +- Must not be delegate called. +- `streamId` must reference a depleted stream. +- The NFT must exist. +- `msg.sender` must be either the NFT owner or an approved third party.\* -Emits a {Transfer}, {CreateLockupLinearStream} and {MetadataUpdate} event. Requirements: +```solidity +function burn(uint256 streamId) external payable; +``` -- All requirements in {createWithTimestampsLL} must be met for the calculated parameters. +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | --------------------------------- | +| `streamId` | `uint256` | The ID of the stream NFT to burn. | + +### cancel + +Cancels the stream and refunds any remaining tokens to the sender. + +\*Emits a {Transfer}, {CancelLockupStream} and {MetadataUpdate} event. Notes: + +- If there any tokens left for the recipient to withdraw, the stream is marked as canceled. Otherwise, the stream is + marked as depleted. +- If the address is on the allowlist, this function will invoke a hook on the recipient. Requirements: +- Must not be delegate called. +- The stream must be warm and cancelable. +- `msg.sender` must be the stream's sender.\* ```solidity -function createWithDurationsLL( - Lockup.CreateWithDurations calldata params, - LockupLinear.UnlockAmounts calldata unlockAmounts, - LockupLinear.Durations calldata durations -) - external - payable - returns (uint256 streamId); +function cancel(uint256 streamId) external payable returns (uint128 refundedAmount); ``` **Parameters** -| Name | Type | Description | -| --------------- | ---------------------------- | ---------------------------------------------------------------------------------------------------------------- | -| `params` | `Lockup.CreateWithDurations` | Struct encapsulating the function parameters, which are documented in {DataTypes}. | -| `unlockAmounts` | `LockupLinear.UnlockAmounts` | Struct encapsulating (i) the amount to unlock at the start time and (ii) the amount to unlock at the cliff time. | -| `durations` | `LockupLinear.Durations` | Struct encapsulating (i) cliff period duration and (ii) total stream duration, both in seconds. | +| Name | Type | Description | +| ---------- | --------- | ------------------------------- | +| `streamId` | `uint256` | The ID of the stream to cancel. | **Returns** -| Name | Type | Description | -| ---------- | --------- | ----------------------------------- | -| `streamId` | `uint256` | The ID of the newly created stream. | +| Name | Type | Description | +| ---------------- | --------- | ---------------------------------------------------------------------------- | +| `refundedAmount` | `uint128` | The amount refunded to the sender, denoted in units of the token's decimals. | -### createWithDurationsLT +### cancelMultiple -Creates a stream by setting the start time to `block.timestamp`, and the end time to the sum of `block.timestamp` and -all specified time durations. The tranche timestamps are derived from these durations. The stream is funded by -`msg.sender` and is wrapped in an ERC-721 NFT. +Cancels multiple streams and refunds any remaining tokens to the sender. -Emits a {Transfer}, {CreateLockupTrancheStream} and {MetadataUpdate} event. Requirements: +\*Emits multiple {Transfer}, {CancelLockupStream} and {MetadataUpdate} events. For each reverted cancellation, it emits +an +[InvalidStreamInCancelMultiple](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockup.md#invalidstreamincancelmultiple) +event. Notes: -- All requirements in {createWithTimestampsLT} must be met for the calculated parameters. +- This function as a whole will not revert if one or more cancellations revert. A zero amount is returned for reverted + streams. +- Refer to the notes and requirements from {cancel}.\* ```solidity -function createWithDurationsLT( - Lockup.CreateWithDurations calldata params, - LockupTranched.TrancheWithDuration[] calldata tranchesWithDuration -) - external - payable - returns (uint256 streamId); +function cancelMultiple(uint256[] calldata streamIds) external payable returns (uint128[] memory refundedAmounts); ``` **Parameters** -| Name | Type | Description | -| ---------------------- | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `params` | `Lockup.CreateWithDurations` | Struct encapsulating the function parameters, which are documented in {DataTypes}. | -| `tranchesWithDuration` | `LockupTranched.TrancheWithDuration[]` | Tranches with durations used to compose the tranched distribution function. Timestamps are calculated by starting from `block.timestamp` and adding each duration to the previous timestamp. | +| Name | Type | Description | +| ----------- | ----------- | --------------------------------- | +| `streamIds` | `uint256[]` | The IDs of the streams to cancel. | **Returns** -| Name | Type | Description | -| ---------- | --------- | ----------------------------------- | -| `streamId` | `uint256` | The ID of the newly created stream. | +| Name | Type | Description | +| ----------------- | ----------- | ----------------------------------------------------------------------------- | +| `refundedAmounts` | `uint128[]` | The amounts refunded to the sender, denoted in units of the token's decimals. | + +### recover + +Recover the surplus amount of tokens. + +\*Notes: + +- The surplus amount is defined as the difference between the total balance of the contract for the provided ERC-20 + token and the sum of balances of all streams created using the same ERC-20 token. Requirements: +- `msg.sender` must be the comptroller contract. +- The surplus amount must be greater than zero.\* + +```solidity +function recover(IERC20 token, address to) external; +``` + +**Parameters** -### createWithTimestampsLD +| Name | Type | Description | +| ------- | --------- | -------------------------------------------------------- | +| `token` | `IERC20` | The contract address of the ERC-20 token to recover for. | +| `to` | `address` | The address to send the surplus amount. | -Creates a stream with the provided segment timestamps, implying the end time from the last timestamp. The stream is -funded by `msg.sender` and is wrapped in an ERC-721 NFT. +### renounce -Emits a {Transfer}, {CreateLockupDynamicStream} and {MetadataUpdate} event. Notes: +Removes the right of the stream's sender to cancel the stream. -- As long as the segment timestamps are arranged in ascending order, it is not an error for some of them to be in the - past. Requirements: +\*Emits a +[RenounceLockupStream](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockup.md#renouncelockupstream) +event. Notes: + +- This is an irreversible operation. Requirements: - Must not be delegate called. -- `params.totalAmount` must be greater than zero. -- If set, `params.broker.fee` must not be greater than `MAX_BROKER_FEE`. -- `params.timestamps.start` must be greater than zero and less than the first segment's timestamp. -- `segments` must have at least one segment, but not more than `MAX_COUNT`. -- The segment timestamps must be arranged in ascending order. -- `params.timestamps.end` must be equal to the last segment's timestamp. -- The sum of the segment amounts must equal the deposit amount. -- `params.recipient` must not be the zero address. -- `params.sender` must not be the zero address. -- `msg.sender` must have allowed this contract to spend at least `params.totalAmount` tokens. -- `params.shape.length` must not be greater than 32 characters. +- `streamId` must reference a warm stream. +- `msg.sender` must be the stream's sender. +- The stream must be cancelable.\* ```solidity -function createWithTimestampsLD( - Lockup.CreateWithTimestamps calldata params, - LockupDynamic.Segment[] calldata segments -) - external - payable - returns (uint256 streamId); +function renounce(uint256 streamId) external payable; ``` **Parameters** -| Name | Type | Description | -| ---------- | ----------------------------- | ---------------------------------------------------------------------------------- | -| `params` | `Lockup.CreateWithTimestamps` | Struct encapsulating the function parameters, which are documented in {DataTypes}. | -| `segments` | `LockupDynamic.Segment[]` | Segments used to compose the dynamic distribution function. | +| Name | Type | Description | +| ---------- | --------- | --------------------------------- | +| `streamId` | `uint256` | The ID of the stream to renounce. | -**Returns** +### setNativeToken + +Sets the native token address. Once set, it cannot be changed. -| Name | Type | Description | -| ---------- | --------- | ----------------------------------- | -| `streamId` | `uint256` | The ID of the newly created stream. | +\*For more information, see the documentation for {nativeToken}. Notes: -### createWithTimestampsLL +- If `newNativeToken` is zero address, the function does not revert. Requirements: +- `msg.sender` must be the comptroller contract. +- The current native token must be zero address.\* -Creates a stream with the provided start time and end time. The stream is funded by `msg.sender` and is wrapped in an -ERC-721 NFT. +```solidity +function setNativeToken(address newNativeToken) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---------------- | --------- | -------------------------------- | +| `newNativeToken` | `address` | The address of the native token. | -Emits a {Transfer}, {CreateLockupLinearStream} and {MetadataUpdate} event. Notes: +### setNFTDescriptor -- A cliff time of zero means there is no cliff. -- As long as the times are ordered, it is not an error for the start or the cliff time to be in the past. Requirements: +Sets a new NFT descriptor contract, which produces the URI describing the Sablier stream NFTs. + +\*Emits a [SetNFTDescriptor](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockup.md#setnftdescriptor) +and {BatchMetadataUpdate} event. Notes: + +- Does not revert if the NFT descriptor is the same. Requirements: +- `msg.sender` must be the comptroller contract.\* + +```solidity +function setNFTDescriptor(ILockupNFTDescriptor newNFTDescriptor) external; +``` + +**Parameters** + +| Name | Type | Description | +| ------------------ | ---------------------- | ----------------------------------------------- | +| `newNFTDescriptor` | `ILockupNFTDescriptor` | The address of the new NFT descriptor contract. | + +### withdraw + +Withdraws the provided amount of tokens from the stream to the `to` address. + +\*Emits a {Transfer}, {WithdrawFromLockupStream} and {MetadataUpdate} event. Notes: + +- If `msg.sender` is not the recipient and the address is on the allowlist, this function will invoke a hook on the + recipient. +- The minimum fee in wei is calculated for the stream's sender using the **SablierComptroller** contract. Requirements: - Must not be delegate called. -- `params.totalAmount` must be greater than zero. -- If set, `params.broker.fee` must not be greater than `MAX_BROKER_FEE`. -- `params.timestamps.start` must be greater than zero and less than `params.timestamps.end`. -- If set, `cliffTime` must be greater than `params.timestamps.start` and less than `params.timestamps.end`. -- `params.recipient` must not be the zero address. -- `params.sender` must not be the zero address. -- The sum of `params.unlockAmounts.start` and `params.unlockAmounts.cliff` must be less than or equal to deposit amount. -- If `params.timestamps.cliff` not set, the `params.unlockAmounts.cliff` must be zero. -- `msg.sender` must have allowed this contract to spend at least `params.totalAmount` tokens. -- `params.shape.length` must not be greater than 32 characters. +- `streamId` must not reference a null or depleted stream. +- `to` must not be the zero address. +- `amount` must be greater than zero and must not exceed the withdrawable amount. +- `to` must be the recipient if `msg.sender` is not the stream's recipient or an approved third party. +- `msg.value` must be greater than or equal to the minimum fee in wei for the stream's sender.\* ```solidity -function createWithTimestampsLL( - Lockup.CreateWithTimestamps calldata params, - LockupLinear.UnlockAmounts calldata unlockAmounts, - uint40 cliffTime -) - external - payable - returns (uint256 streamId); +function withdraw(uint256 streamId, address to, uint128 amount) external payable; ``` **Parameters** -| Name | Type | Description | -| --------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------- | -| `params` | `Lockup.CreateWithTimestamps` | Struct encapsulating the function parameters, which are documented in {DataTypes}. | -| `unlockAmounts` | `LockupLinear.UnlockAmounts` | Struct encapsulating (i) the amount to unlock at the start time and (ii) the amount to unlock at the cliff time. | -| `cliffTime` | `uint40` | The Unix timestamp for the cliff period's end. A value of zero means there is no cliff. | +| Name | Type | Description | +| ---------- | --------- | ----------------------------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to withdraw from. | +| `to` | `address` | The address receiving the withdrawn tokens. | +| `amount` | `uint128` | The amount to withdraw, denoted in units of the token's decimals. | + +### withdrawMax + +Withdraws the maximum withdrawable amount from the stream to the provided address `to`. + +\*Emits a {Transfer}, {WithdrawFromLockupStream} and {MetadataUpdate} event. Notes: + +- Refer to the notes in {withdraw}. Requirements: +- Refer to the requirements in {withdraw}.\* + +```solidity +function withdrawMax(uint256 streamId, address to) external payable returns (uint128 withdrawnAmount); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to withdraw from. | +| `to` | `address` | The address receiving the withdrawn tokens. | **Returns** -| Name | Type | Description | -| ---------- | --------- | ----------------------------------- | -| `streamId` | `uint256` | The ID of the newly created stream. | +| Name | Type | Description | +| ----------------- | --------- | --------------------------------------------------------------- | +| `withdrawnAmount` | `uint128` | The amount withdrawn, denoted in units of the token's decimals. | -### createWithTimestampsLT +### withdrawMaxAndTransfer -Creates a stream with the provided tranche timestamps, implying the end time from the last timestamp. The stream is -funded by `msg.sender` and is wrapped in an ERC-721 NFT. +Withdraws the maximum withdrawable amount from the stream to the current recipient, and transfers the NFT to +`newRecipient`. -Emits a {Transfer}, {CreateLockupTrancheStream} and {MetadataUpdate} event. Notes: +\*Emits a +[WithdrawFromLockupStream](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockup.md#withdrawfromlockupstream), +{Transfer} and {MetadataUpdate} event. Notes: -- As long as the tranche timestamps are arranged in ascending order, it is not an error for some of them to be in the - past. Requirements: -- Must not be delegate called. -- `params.totalAmount` must be greater than zero. -- If set, `params.broker.fee` must not be greater than `MAX_BROKER_FEE`. -- `params.timestamps.start` must be greater than zero and less than the first tranche's timestamp. -- `tranches` must have at least one tranche, but not more than `MAX_COUNT`. -- The tranche timestamps must be arranged in ascending order. -- `params.timestamps.end` must be equal to the last tranche's timestamp. -- The sum of the tranche amounts must equal the deposit amount. -- `params.recipient` must not be the zero address. -- `params.sender` must not be the zero address. -- `msg.sender` must have allowed this contract to spend at least `params.totalAmount` tokens. -- `params.shape.length` must not be greater than 32 characters. +- If the withdrawable amount is zero, the withdrawal is skipped. +- Refer to the notes in {withdraw}. Requirements: +- `msg.sender` must be either the NFT owner or an approved third party. +- Refer to the requirements in {withdraw}. +- Refer to the requirements in {IERC721.transferFrom}.\* ```solidity -function createWithTimestampsLT( - Lockup.CreateWithTimestamps calldata params, - LockupTranched.Tranche[] calldata tranches +function withdrawMaxAndTransfer( + uint256 streamId, + address newRecipient ) external payable - returns (uint256 streamId); + returns (uint128 withdrawnAmount); ``` **Parameters** -| Name | Type | Description | -| ---------- | ----------------------------- | ---------------------------------------------------------------------------------- | -| `params` | `Lockup.CreateWithTimestamps` | Struct encapsulating the function parameters, which are documented in {DataTypes}. | -| `tranches` | `LockupTranched.Tranche[]` | Tranches used to compose the tranched distribution function. | +| Name | Type | Description | +| -------------- | --------- | ----------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream NFT to transfer. | +| `newRecipient` | `address` | The address of the new owner of the stream NFT. | **Returns** -| Name | Type | Description | -| ---------- | --------- | ----------------------------------- | -| `streamId` | `uint256` | The ID of the newly created stream. | +| Name | Type | Description | +| ----------------- | --------- | --------------------------------------------------------------- | +| `withdrawnAmount` | `uint128` | The amount withdrawn, denoted in units of the token's decimals. | + +### withdrawMultiple + +Withdraws tokens from streams to the recipient of each stream. + +\*Emits multiple {Transfer}, {WithdrawFromLockupStream} and {MetadataUpdate} events. For each reverting withdrawal, it +emits an +[InvalidWithdrawalInWithdrawMultiple](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockup.md#invalidwithdrawalinwithdrawmultiple) +event. Notes: + +- This function as a whole will not revert if one or more withdrawals revert. +- This function attempts to call a hook on the recipient of each stream, unless `msg.sender` is the recipient. +- Refer to the notes and requirements from {withdraw}. Requirements: +- Must not be delegate called. +- There must be an equal number of `streamIds` and `amounts`.\* + +```solidity +function withdrawMultiple(uint256[] calldata streamIds, uint128[] calldata amounts) external payable; +``` + +**Parameters** + +| Name | Type | Description | +| ----------- | ----------- | ------------------------------------------------------------------ | +| `streamIds` | `uint256[]` | The IDs of the streams to withdraw from. | +| `amounts` | `uint128[]` | The amounts to withdraw, denoted in units of the token's decimals. | ## Events -### CreateLockupDynamicStream +### AllowToHook -Emitted when a stream is created using Lockup dynamic model. +Emitted when the comptroller allows a new recipient contract to hook to Sablier. ```solidity -event CreateLockupDynamicStream( - uint256 indexed streamId, Lockup.CreateEventCommon commonParams, LockupDynamic.Segment[] segments -); +event AllowToHook(ISablierComptroller indexed comptroller, address indexed recipient); ``` **Parameters** -| Name | Type | Description | -| -------------- | -------------------------- | ---------------------------------------------------------------------------- | -| `streamId` | `uint256` | The ID of the newly created stream. | -| `commonParams` | `Lockup.CreateEventCommon` | Common parameters emitted in Create events across all Lockup models. | -| `segments` | `LockupDynamic.Segment[]` | The segments the protocol uses to compose the dynamic distribution function. | +| Name | Type | Description | +| ------------- | --------------------- | ----------------------------------------------------------- | +| `comptroller` | `ISablierComptroller` | The address of the current comptroller. | +| `recipient` | `address` | The address of the recipient contract put on the allowlist. | -### CreateLockupLinearStream +### CancelLockupStream -Emitted when a stream is created using Lockup linear model. +Emitted when a stream is canceled. ```solidity -event CreateLockupLinearStream( - uint256 indexed streamId, - Lockup.CreateEventCommon commonParams, - uint40 cliffTime, - LockupLinear.UnlockAmounts unlockAmounts +event CancelLockupStream( + uint256 streamId, + address indexed sender, + address indexed recipient, + IERC20 indexed token, + uint128 senderAmount, + uint128 recipientAmount ); ``` **Parameters** -| Name | Type | Description | -| --------------- | ---------------------------- | ---------------------------------------------------------------------------------------------------------------- | -| `streamId` | `uint256` | The ID of the newly created stream. | -| `commonParams` | `Lockup.CreateEventCommon` | Common parameters emitted in Create events across all Lockup models. | -| `cliffTime` | `uint40` | The Unix timestamp for the cliff period's end. A value of zero means there is no cliff. | -| `unlockAmounts` | `LockupLinear.UnlockAmounts` | Struct encapsulating (i) the amount to unlock at the start time and (ii) the amount to unlock at the cliff time. | +| Name | Type | Description | +| ----------------- | --------- | ----------------------------------------------------------------------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream. | +| `sender` | `address` | The address of the stream's sender. | +| `recipient` | `address` | The address of the stream's recipient. | +| `token` | `IERC20` | The contract address of the ERC-20 token that has been distributed. | +| `senderAmount` | `uint128` | The amount of tokens refunded to the stream's sender, denoted in units of the token's decimals. | +| `recipientAmount` | `uint128` | The amount of tokens left for the stream's recipient to withdraw, denoted in units of the token's decimals. | -### CreateLockupTranchedStream +### InvalidStreamInCancelMultiple -Emitted when a stream is created using Lockup tranched model. +Emitted when canceling multiple streams and one particular cancellation reverts. ```solidity -event CreateLockupTranchedStream( - uint256 indexed streamId, Lockup.CreateEventCommon commonParams, LockupTranched.Tranche[] tranches +event InvalidStreamInCancelMultiple(uint256 indexed streamId, bytes revertData); +``` + +**Parameters** + +| Name | Type | Description | +| ------------ | --------- | ---------------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream that reverted the cancellation. | +| `revertData` | `bytes` | The error data returned by the reverted cancel. | + +### InvalidWithdrawalInWithdrawMultiple + +Emitted when withdrawing from multiple streams and one particular withdrawal reverts. + +```solidity +event InvalidWithdrawalInWithdrawMultiple(uint256 indexed streamId, bytes revertData); +``` + +**Parameters** + +| Name | Type | Description | +| ------------ | --------- | -------------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream that reverted the withdrawal. | +| `revertData` | `bytes` | The error data returned by the reverted withdraw. | + +### RenounceLockupStream + +Emitted when a sender gives up the right to cancel a stream. + +```solidity +event RenounceLockupStream(uint256 indexed streamId); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | --------------------- | +| `streamId` | `uint256` | The ID of the stream. | + +### SetNFTDescriptor + +Emitted when the comptroller sets a new NFT descriptor contract. + +```solidity +event SetNFTDescriptor( + ISablierComptroller indexed comptroller, + ILockupNFTDescriptor indexed oldNFTDescriptor, + ILockupNFTDescriptor indexed newNFTDescriptor ); ``` **Parameters** -| Name | Type | Description | -| -------------- | -------------------------- | ----------------------------------------------------------------------------- | -| `streamId` | `uint256` | The ID of the newly created stream. | -| `commonParams` | `Lockup.CreateEventCommon` | Common parameters emitted in Create events across all Lockup models. | -| `tranches` | `LockupTranched.Tranche[]` | The tranches the protocol uses to compose the tranched distribution function. | +| Name | Type | Description | +| ------------------ | ---------------------- | ----------------------------------------------- | +| `comptroller` | `ISablierComptroller` | The address of the current comptroller. | +| `oldNFTDescriptor` | `ILockupNFTDescriptor` | The address of the old NFT descriptor contract. | +| `newNFTDescriptor` | `ILockupNFTDescriptor` | The address of the new NFT descriptor contract. | + +### WithdrawFromLockupStream + +Emitted when tokens are withdrawn from a stream. + +```solidity +event WithdrawFromLockupStream(uint256 indexed streamId, address indexed to, IERC20 indexed token, uint128 amount); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ------------------------------------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream. | +| `to` | `address` | The address that has received the withdrawn tokens. | +| `token` | `IERC20` | The contract address of the ERC-20 token that has been withdrawn. | +| `amount` | `uint128` | The amount of tokens withdrawn, denoted in units of the token's decimals. | diff --git a/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupBase.md b/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupBase.md deleted file mode 100644 index 60243306..00000000 --- a/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupBase.md +++ /dev/null @@ -1,779 +0,0 @@ -# ISablierLockupBase - -[Git Source](https://github.com/sablier-labs/lockup/blob/463278dbb461b1733d6424cf0aeee3b8d6bc036a/src/interfaces/ISablierLockupBase.sol) - -**Inherits:** [IAdminable](/docs/reference/lockup/contracts/interfaces/interface.IAdminable.md), -[IBatch](/docs/reference/lockup/contracts/interfaces/interface.IBatch.md), IERC4906, IERC721Metadata - -Common logic between all Sablier Lockup contracts. - -## Functions - -### MAX_BROKER_FEE - -Retrieves the maximum broker fee that can be charged by the broker, denoted as a fixed-point number where 1e18 is 100%. - -_This value is hard coded as a constant._ - -```solidity -function MAX_BROKER_FEE() external view returns (UD60x18); -``` - -### getDepositedAmount - -Retrieves the amount deposited in the stream, denoted in units of the token's decimals. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getDepositedAmount(uint256 streamId) external view returns (uint128 depositedAmount); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### getEndTime - -Retrieves the stream's end time, which is a Unix timestamp. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getEndTime(uint256 streamId) external view returns (uint40 endTime); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### getLockupModel - -Retrieves the distribution models used to create the stream. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getLockupModel(uint256 streamId) external view returns (Lockup.Model lockupModel); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### getRecipient - -Retrieves the stream's recipient. - -_Reverts if the NFT has been burned._ - -```solidity -function getRecipient(uint256 streamId) external view returns (address recipient); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### getRefundedAmount - -Retrieves the amount refunded to the sender after a cancellation, denoted in units of the token's decimals. This amount -is always zero unless the stream was canceled. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getRefundedAmount(uint256 streamId) external view returns (uint128 refundedAmount); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### getSender - -Retrieves the stream's sender. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getSender(uint256 streamId) external view returns (address sender); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### getStartTime - -Retrieves the stream's start time, which is a Unix timestamp. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getStartTime(uint256 streamId) external view returns (uint40 startTime); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### getUnderlyingToken - -Retrieves the address of the underlying ERC-20 token being distributed. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getUnderlyingToken(uint256 streamId) external view returns (IERC20 token); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### getWithdrawnAmount - -Retrieves the amount withdrawn from the stream, denoted in units of the token's decimals. - -_Reverts if `streamId` references a null stream._ - -```solidity -function getWithdrawnAmount(uint256 streamId) external view returns (uint128 withdrawnAmount); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### isAllowedToHook - -Retrieves a flag indicating whether the provided address is a contract allowed to hook to Sablier when a stream is -canceled or when tokens are withdrawn. - -_See [ISablierLockupRecipient](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupRecipient.md) for -more information._ - -```solidity -function isAllowedToHook(address recipient) external view returns (bool result); -``` - -### isCancelable - -Retrieves a flag indicating whether the stream can be canceled. When the stream is cold, this flag is always `false`. - -_Reverts if `streamId` references a null stream._ - -```solidity -function isCancelable(uint256 streamId) external view returns (bool result); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### isCold - -Retrieves a flag indicating whether the stream is cold, i.e. settled, canceled, or depleted. - -_Reverts if `streamId` references a null stream._ - -```solidity -function isCold(uint256 streamId) external view returns (bool result); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### isDepleted - -Retrieves a flag indicating whether the stream is depleted. - -_Reverts if `streamId` references a null stream._ - -```solidity -function isDepleted(uint256 streamId) external view returns (bool result); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### isStream - -Retrieves a flag indicating whether the stream exists. - -_Does not revert if `streamId` references a null stream._ - -```solidity -function isStream(uint256 streamId) external view returns (bool result); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### isTransferable - -Retrieves a flag indicating whether the stream NFT can be transferred. - -_Reverts if `streamId` references a null stream._ - -```solidity -function isTransferable(uint256 streamId) external view returns (bool result); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### isWarm - -Retrieves a flag indicating whether the stream is warm, i.e. either pending or streaming. - -_Reverts if `streamId` references a null stream._ - -```solidity -function isWarm(uint256 streamId) external view returns (bool result); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### nextStreamId - -Counter for stream IDs, used in the create functions. - -```solidity -function nextStreamId() external view returns (uint256); -``` - -### nftDescriptor - -Contract that generates the non-fungible token URI. - -```solidity -function nftDescriptor() external view returns (ILockupNFTDescriptor); -``` - -### refundableAmountOf - -Calculates the amount that the sender would be refunded if the stream were canceled, denoted in units of the token's -decimals. - -_Reverts if `streamId` references a null stream._ - -```solidity -function refundableAmountOf(uint256 streamId) external view returns (uint128 refundableAmount); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### statusOf - -Retrieves the stream's status. - -_Reverts if `streamId` references a null stream._ - -```solidity -function statusOf(uint256 streamId) external view returns (Lockup.Status status); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### streamedAmountOf - -Calculates the amount streamed to the recipient, denoted in units of the token's decimals. - -Reverts if `streamId` references a null stream. Notes: - -- Upon cancellation of the stream, the amount streamed is calculated as the difference between the deposited amount and - the refunded amount. Ultimately, when the stream becomes depleted, the streamed amount is equivalent to the total - amount withdrawn. - -```solidity -function streamedAmountOf(uint256 streamId) external view returns (uint128 streamedAmount); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### wasCanceled - -Retrieves a flag indicating whether the stream was canceled. - -_Reverts if `streamId` references a null stream._ - -```solidity -function wasCanceled(uint256 streamId) external view returns (bool result); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### withdrawableAmountOf - -Calculates the amount that the recipient can withdraw from the stream, denoted in units of the token's decimals. - -_Reverts if `streamId` references a null stream._ - -```solidity -function withdrawableAmountOf(uint256 streamId) external view returns (uint128 withdrawableAmount); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ---------------------------- | -| `streamId` | `uint256` | The stream ID for the query. | - -### allowToHook - -Allows a recipient contract to hook to Sablier when a stream is canceled or when tokens are withdrawn. Useful for -implementing contracts that hold streams on behalf of users, such as vaults or staking contracts. - -Emits an [AllowToHook](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupBase.md#allowtohook) event. -Notes: - -- Does not revert if the contract is already on the allowlist. -- This is an irreversible operation. The contract cannot be removed from the allowlist. Requirements: -- `msg.sender` must be the contract admin. -- `recipient` must have a non-zero code size. -- `recipient` must implement - [ISablierLockupRecipient](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupRecipient.md). - -```solidity -function allowToHook(address recipient) external; -``` - -**Parameters** - -| Name | Type | Description | -| ----------- | --------- | ----------------------------------------------- | -| `recipient` | `address` | The address of the contract to allow for hooks. | - -### burn - -Burns the NFT associated with the stream. - -Emits a {Transfer} and {MetadataUpdate} event. Requirements: - -- Must not be delegate called. -- `streamId` must reference a depleted stream. -- The NFT must exist. -- `msg.sender` must be either the NFT owner or an approved third party. - -```solidity -function burn(uint256 streamId) external payable; -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | --------------------------------- | -| `streamId` | `uint256` | The ID of the stream NFT to burn. | - -### cancel - -Cancels the stream and refunds any remaining tokens to the sender. - -Emits a {Transfer}, {CancelLockupStream} and {MetadataUpdate} event. Notes: - -- If there any tokens left for the recipient to withdraw, the stream is marked as canceled. Otherwise, the stream is - marked as depleted. -- If the address is on the allowlist, this function will invoke a hook on the recipient. Requirements: -- Must not be delegate called. -- The stream must be warm and cancelable. -- `msg.sender` must be the stream's sender. - -```solidity -function cancel(uint256 streamId) external payable; -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ------------------------------- | -| `streamId` | `uint256` | The ID of the stream to cancel. | - -### cancelMultiple - -Cancels multiple streams and refunds any remaining tokens to the sender. - -Emits multiple {Transfer}, {CancelLockupStream} and {MetadataUpdate} events. Notes: - -- Refer to the notes in {cancel}. Requirements: -- All requirements from {cancel} must be met for each stream. - -```solidity -function cancelMultiple(uint256[] calldata streamIds) external payable; -``` - -**Parameters** - -| Name | Type | Description | -| ----------- | ----------- | --------------------------------- | -| `streamIds` | `uint256[]` | The IDs of the streams to cancel. | - -### collectFees - -Collects the accrued fees by transferring them to the contract admin. - -Emits a [CollectFees](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupBase.md#collectfees) event. -Notes: - -- If the admin is a contract, it must be able to receive native token payments, e.g., ETH for Ethereum Mainnet. - -```solidity -function collectFees() external; -``` - -### renounce - -Removes the right of the stream's sender to cancel the stream. - -Emits a -[RenounceLockupStream](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupBase.md#renouncelockupstream) -event. Notes: - -- This is an irreversible operation. Requirements: -- Must not be delegate called. -- `streamId` must reference a warm stream. -- `msg.sender` must be the stream's sender. -- The stream must be cancelable. - -```solidity -function renounce(uint256 streamId) external payable; -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | --------------------------------- | -| `streamId` | `uint256` | The ID of the stream to renounce. | - -### renounceMultiple - -Renounces multiple streams. - -Emits multiple -[RenounceLockupStream](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupBase.md#renouncelockupstream) -events. Notes: - -- Refer to the notes in {renounce}. Requirements: -- All requirements from {renounce} must be met for each stream. - -```solidity -function renounceMultiple(uint256[] calldata streamIds) external payable; -``` - -**Parameters** - -| Name | Type | Description | -| ----------- | ----------- | ----------------------------------- | -| `streamIds` | `uint256[]` | An array of stream IDs to renounce. | - -### setNFTDescriptor - -Sets a new NFT descriptor contract, which produces the URI describing the Sablier stream NFTs. - -Emits a [SetNFTDescriptor](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupBase.md#setnftdescriptor) -and {BatchMetadataUpdate} event. Notes: - -- Does not revert if the NFT descriptor is the same. Requirements: -- `msg.sender` must be the contract admin. - -```solidity -function setNFTDescriptor(ILockupNFTDescriptor newNFTDescriptor) external; -``` - -**Parameters** - -| Name | Type | Description | -| ------------------ | ---------------------- | ----------------------------------------------- | -| `newNFTDescriptor` | `ILockupNFTDescriptor` | The address of the new NFT descriptor contract. | - -### withdraw - -Withdraws the provided amount of tokens from the stream to the `to` address. - -Emits a {Transfer}, {WithdrawFromLockupStream} and {MetadataUpdate} event. Notes: - -- If `msg.sender` is not the recipient and the address is on the allowlist, this function will invoke a hook on the - recipient. Requirements: -- Must not be delegate called. -- `streamId` must not reference a null or depleted stream. -- `to` must not be the zero address. -- `amount` must be greater than zero and must not exceed the withdrawable amount. -- `to` must be the recipient if `msg.sender` is not the stream's recipient or an approved third party. - -```solidity -function withdraw(uint256 streamId, address to, uint128 amount) external payable; -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ----------------------------------------------------------------- | -| `streamId` | `uint256` | The ID of the stream to withdraw from. | -| `to` | `address` | The address receiving the withdrawn tokens. | -| `amount` | `uint128` | The amount to withdraw, denoted in units of the token's decimals. | - -### withdrawMax - -Withdraws the maximum withdrawable amount from the stream to the provided address `to`. - -Emits a {Transfer}, {WithdrawFromLockupStream} and {MetadataUpdate} event. Notes: - -- Refer to the notes in {withdraw}. Requirements: -- Refer to the requirements in {withdraw}. - -```solidity -function withdrawMax(uint256 streamId, address to) external payable returns (uint128 withdrawnAmount); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ------------------------------------------- | -| `streamId` | `uint256` | The ID of the stream to withdraw from. | -| `to` | `address` | The address receiving the withdrawn tokens. | - -**Returns** - -| Name | Type | Description | -| ----------------- | --------- | --------------------------------------------------------------- | -| `withdrawnAmount` | `uint128` | The amount withdrawn, denoted in units of the token's decimals. | - -### withdrawMaxAndTransfer - -Withdraws the maximum withdrawable amount from the stream to the current recipient, and transfers the NFT to -`newRecipient`. - -Emits a -[WithdrawFromLockupStream](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupBase.md#withdrawfromlockupstream), -{Transfer} and {MetadataUpdate} event. Notes: - -- If the withdrawable amount is zero, the withdrawal is skipped. -- Refer to the notes in {withdraw}. Requirements: -- `msg.sender` must be either the NFT owner or an approved third party. -- Refer to the requirements in {withdraw}. -- Refer to the requirements in {IERC721.transferFrom}. - -```solidity -function withdrawMaxAndTransfer( - uint256 streamId, - address newRecipient -) - external - payable - returns (uint128 withdrawnAmount); -``` - -**Parameters** - -| Name | Type | Description | -| -------------- | --------- | ----------------------------------------------- | -| `streamId` | `uint256` | The ID of the stream NFT to transfer. | -| `newRecipient` | `address` | The address of the new owner of the stream NFT. | - -**Returns** - -| Name | Type | Description | -| ----------------- | --------- | --------------------------------------------------------------- | -| `withdrawnAmount` | `uint128` | The amount withdrawn, denoted in units of the token's decimals. | - -### withdrawMultiple - -Withdraws tokens from streams to the recipient of each stream. - -Emits multiple {Transfer}, {WithdrawFromLockupStream} and {MetadataUpdate} events. For each stream that reverted the -withdrawal, it emits an -[InvalidWithdrawalInWithdrawMultiple](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupBase.md#invalidwithdrawalinwithdrawmultiple) -event. Notes: - -- This function attempts to call a hook on the recipient of each stream, unless `msg.sender` is the recipient. - Requirements: -- Must not be delegate called. -- There must be an equal number of `streamIds` and `amounts`. -- Each stream ID in the array must not reference a null or depleted stream. -- Each amount in the array must be greater than zero and must not exceed the withdrawable amount. - -```solidity -function withdrawMultiple(uint256[] calldata streamIds, uint128[] calldata amounts) external payable; -``` - -**Parameters** - -| Name | Type | Description | -| ----------- | ----------- | ------------------------------------------------------------------ | -| `streamIds` | `uint256[]` | The IDs of the streams to withdraw from. | -| `amounts` | `uint128[]` | The amounts to withdraw, denoted in units of the token's decimals. | - -## Events - -### AllowToHook - -Emitted when the admin allows a new recipient contract to hook to Sablier. - -```solidity -event AllowToHook(address indexed admin, address recipient); -``` - -**Parameters** - -| Name | Type | Description | -| ----------- | --------- | ----------------------------------------------------------- | -| `admin` | `address` | The address of the current contract admin. | -| `recipient` | `address` | The address of the recipient contract put on the allowlist. | - -### CancelLockupStream - -Emitted when a stream is canceled. - -```solidity -event CancelLockupStream( - uint256 streamId, - address indexed sender, - address indexed recipient, - IERC20 indexed token, - uint128 senderAmount, - uint128 recipientAmount -); -``` - -**Parameters** - -| Name | Type | Description | -| ----------------- | --------- | ----------------------------------------------------------------------------------------------------------- | -| `streamId` | `uint256` | The ID of the stream. | -| `sender` | `address` | The address of the stream's sender. | -| `recipient` | `address` | The address of the stream's recipient. | -| `token` | `IERC20` | The contract address of the ERC-20 token that has been distributed. | -| `senderAmount` | `uint128` | The amount of tokens refunded to the stream's sender, denoted in units of the token's decimals. | -| `recipientAmount` | `uint128` | The amount of tokens left for the stream's recipient to withdraw, denoted in units of the token's decimals. | - -### CollectFees - -Emitted when the accrued fees are collected. - -```solidity -event CollectFees(address indexed admin, uint256 indexed feeAmount); -``` - -**Parameters** - -| Name | Type | Description | -| ----------- | --------- | ----------------------------------------------------------------------- | -| `admin` | `address` | The address of the current contract admin, which has received the fees. | -| `feeAmount` | `uint256` | The amount of collected fees. | - -### InvalidWithdrawalInWithdrawMultiple - -Emitted when withdrawing from multiple streams and one particular withdrawal reverts. - -```solidity -event InvalidWithdrawalInWithdrawMultiple(uint256 streamId, bytes revertData); -``` - -**Parameters** - -| Name | Type | Description | -| ------------ | --------- | ------------------------------------------------- | -| `streamId` | `uint256` | The stream ID that reverted during withdraw. | -| `revertData` | `bytes` | The error data returned by the reverted withdraw. | - -### RenounceLockupStream - -Emitted when a sender gives up the right to cancel a stream. - -```solidity -event RenounceLockupStream(uint256 indexed streamId); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | --------------------- | -| `streamId` | `uint256` | The ID of the stream. | - -### SetNFTDescriptor - -Emitted when the admin sets a new NFT descriptor contract. - -```solidity -event SetNFTDescriptor( - address indexed admin, ILockupNFTDescriptor oldNFTDescriptor, ILockupNFTDescriptor newNFTDescriptor -); -``` - -**Parameters** - -| Name | Type | Description | -| ------------------ | ---------------------- | ----------------------------------------------- | -| `admin` | `address` | The address of the current contract admin. | -| `oldNFTDescriptor` | `ILockupNFTDescriptor` | The address of the old NFT descriptor contract. | -| `newNFTDescriptor` | `ILockupNFTDescriptor` | The address of the new NFT descriptor contract. | - -### WithdrawFromLockupStream - -Emitted when tokens are withdrawn from a stream. - -```solidity -event WithdrawFromLockupStream(uint256 indexed streamId, address indexed to, IERC20 indexed token, uint128 amount); -``` - -**Parameters** - -| Name | Type | Description | -| ---------- | --------- | ------------------------------------------------------------------------- | -| `streamId` | `uint256` | The ID of the stream. | -| `to` | `address` | The address that has received the withdrawn tokens. | -| `token` | `IERC20` | The contract address of the ERC-20 token that has been withdrawn. | -| `amount` | `uint128` | The amount of tokens withdrawn, denoted in units of the token's decimals. | diff --git a/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupDynamic.md b/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupDynamic.md new file mode 100644 index 00000000..2014e4e3 --- /dev/null +++ b/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupDynamic.md @@ -0,0 +1,107 @@ +# ISablierLockupDynamic + +[Git Source](https://github.com/sablier-labs/lockup/blob/58eaac45c20c57a93b73d887c714e68f061ec3e6/src/interfaces/ISablierLockupDynamic.sol) + +**Inherits:** [ISablierLockupState](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupState.md) + +Creates Lockup streams with dynamic distribution model. + +## Functions + +### createWithDurationsLD + +Creates a stream by setting the start time to `block.timestamp`, and the end time to the sum of `block.timestamp` and +all specified time durations. The segment timestamps are derived from these durations. The stream is funded by +`msg.sender` and is wrapped in an ERC-721 NFT. + +\*Emits a {Transfer}, {CreateLockupDynamicStream} and {MetadataUpdate} event. Requirements: + +- All requirements in {createWithTimestampsLD} must be met for the calculated parameters.\* + +```solidity +function createWithDurationsLD( + Lockup.CreateWithDurations calldata params, + LockupDynamic.SegmentWithDuration[] calldata segmentsWithDuration +) + external + payable + returns (uint256 streamId); +``` + +**Parameters** + +| Name | Type | Description | +| ---------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `params` | `Lockup.CreateWithDurations` | Struct encapsulating the function parameters, which are documented in {Lockup} type. | +| `segmentsWithDuration` | `LockupDynamic.SegmentWithDuration[]` | Segments with durations used to compose the dynamic distribution function. Timestamps are calculated by starting from `block.timestamp` and adding each duration to the previous timestamp. | + +**Returns** + +| Name | Type | Description | +| ---------- | --------- | ----------------------------------- | +| `streamId` | `uint256` | The ID of the newly created stream. | + +### createWithTimestampsLD + +Creates a stream with the provided segment timestamps, implying the end time from the last timestamp. The stream is +funded by `msg.sender` and is wrapped in an ERC-721 NFT. + +\*Emits a {Transfer}, {CreateLockupDynamicStream} and {MetadataUpdate} event. Notes: + +- As long as the segment timestamps are arranged in ascending order, it is not an error for some of them to be in the + past. Requirements: +- Must not be delegate called. +- `params.depositAmount` must be greater than zero. +- `params.timestamps.start` must be greater than zero and less than the first segment's timestamp. +- `segments` must have at least one segment. +- The segment timestamps must be arranged in ascending order. +- `params.timestamps.end` must be equal to the last segment's timestamp. +- The sum of the segment amounts must equal the deposit amount. +- `params.recipient` must not be the zero address. +- `params.sender` must not be the zero address. +- `msg.sender` must have allowed this contract to spend at least `params.depositAmount` tokens. +- `params.token` must not be the native token. +- `params.shape.length` must not be greater than 32 characters.\* + +```solidity +function createWithTimestampsLD( + Lockup.CreateWithTimestamps calldata params, + LockupDynamic.Segment[] calldata segments +) + external + payable + returns (uint256 streamId); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | ----------------------------- | ------------------------------------------------------------------------------------ | +| `params` | `Lockup.CreateWithTimestamps` | Struct encapsulating the function parameters, which are documented in {Lockup} type. | +| `segments` | `LockupDynamic.Segment[]` | Segments used to compose the dynamic distribution function. | + +**Returns** + +| Name | Type | Description | +| ---------- | --------- | ----------------------------------- | +| `streamId` | `uint256` | The ID of the newly created stream. | + +## Events + +### CreateLockupDynamicStream + +Emitted when an LD stream is created. + +```solidity +event CreateLockupDynamicStream( + uint256 indexed streamId, Lockup.CreateEventCommon commonParams, LockupDynamic.Segment[] segments +); +``` + +**Parameters** + +| Name | Type | Description | +| -------------- | -------------------------- | ---------------------------------------------------------------------------- | +| `streamId` | `uint256` | The ID of the newly created stream. | +| `commonParams` | `Lockup.CreateEventCommon` | Common parameters emitted in Create events across all Lockup models. | +| `segments` | `LockupDynamic.Segment[]` | The segments the protocol uses to compose the dynamic distribution function. | diff --git a/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupLinear.md b/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupLinear.md new file mode 100644 index 00000000..2f4aa890 --- /dev/null +++ b/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupLinear.md @@ -0,0 +1,113 @@ +# ISablierLockupLinear + +[Git Source](https://github.com/sablier-labs/lockup/blob/58eaac45c20c57a93b73d887c714e68f061ec3e6/src/interfaces/ISablierLockupLinear.sol) + +**Inherits:** [ISablierLockupState](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupState.md) + +Creates Lockup streams with linear distribution model. + +## Functions + +### createWithDurationsLL + +Creates a stream by setting the start time to `block.timestamp`, and the end time to the sum of `block.timestamp` and +`durations.total`. The stream is funded by `msg.sender` and is wrapped in an ERC-721 NFT. + +\*Emits a {Transfer}, {CreateLockupLinearStream} and {MetadataUpdate} event. Requirements: + +- All requirements in {createWithTimestampsLL} must be met for the calculated parameters.\* + +```solidity +function createWithDurationsLL( + Lockup.CreateWithDurations calldata params, + LockupLinear.UnlockAmounts calldata unlockAmounts, + LockupLinear.Durations calldata durations +) + external + payable + returns (uint256 streamId); +``` + +**Parameters** + +| Name | Type | Description | +| --------------- | ---------------------------- | ---------------------------------------------------------------------------------------------------------------- | +| `params` | `Lockup.CreateWithDurations` | Struct encapsulating the function parameters, which are documented in {Lockup} type. | +| `unlockAmounts` | `LockupLinear.UnlockAmounts` | Struct encapsulating (i) the amount to unlock at the start time and (ii) the amount to unlock at the cliff time. | +| `durations` | `LockupLinear.Durations` | Struct encapsulating (i) cliff period duration and (ii) total stream duration, both in seconds. | + +**Returns** + +| Name | Type | Description | +| ---------- | --------- | ----------------------------------- | +| `streamId` | `uint256` | The ID of the newly created stream. | + +### createWithTimestampsLL + +Creates a stream with the provided start time and end time. The stream is funded by `msg.sender` and is wrapped in an +ERC-721 NFT. + +\*Emits a {Transfer}, {CreateLockupLinearStream} and {MetadataUpdate} event. Notes: + +- A cliff time of zero means there is no cliff. +- As long as the times are ordered, it is not an error for the start or the cliff time to be in the past. Requirements: +- Must not be delegate called. +- `params.depositAmount` must be greater than zero. +- `params.timestamps.start` must be greater than zero and less than `params.timestamps.end`. +- If set, `cliffTime` must be greater than `params.timestamps.start` and less than `params.timestamps.end`. +- `params.recipient` must not be the zero address. +- `params.sender` must not be the zero address. +- The sum of `params.unlockAmounts.start` and `params.unlockAmounts.cliff` must be less than or equal to deposit amount. +- If `params.timestamps.cliff` not set, the `params.unlockAmounts.cliff` must be zero. +- `msg.sender` must have allowed this contract to spend at least `params.depositAmount` tokens. +- `params.token` must not be the native token. +- `params.shape.length` must not be greater than 32 characters.\* + +```solidity +function createWithTimestampsLL( + Lockup.CreateWithTimestamps calldata params, + LockupLinear.UnlockAmounts calldata unlockAmounts, + uint40 cliffTime +) + external + payable + returns (uint256 streamId); +``` + +**Parameters** + +| Name | Type | Description | +| --------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------- | +| `params` | `Lockup.CreateWithTimestamps` | Struct encapsulating the function parameters, which are documented in {Lockup} type. | +| `unlockAmounts` | `LockupLinear.UnlockAmounts` | Struct encapsulating (i) the amount to unlock at the start time and (ii) the amount to unlock at the cliff time. | +| `cliffTime` | `uint40` | The Unix timestamp for the cliff period's end. A value of zero means there is no cliff. | + +**Returns** + +| Name | Type | Description | +| ---------- | --------- | ----------------------------------- | +| `streamId` | `uint256` | The ID of the newly created stream. | + +## Events + +### CreateLockupLinearStream + +Emitted when an LL stream is created. + +```solidity +event CreateLockupLinearStream( + uint256 indexed streamId, + Lockup.CreateEventCommon commonParams, + uint40 cliffTime, + LockupLinear.UnlockAmounts unlockAmounts +); +``` + +**Parameters** + +| Name | Type | Description | +| --------------- | ---------------------------- | ---------------------------------------------------------------------------------------------------------------- | +| `streamId` | `uint256` | The ID of the newly created stream. | +| `commonParams` | `Lockup.CreateEventCommon` | Common parameters emitted in Create events across all Lockup models. | +| `cliffTime` | `uint40` | The Unix timestamp for the cliff period's end. A value of zero means there is no cliff. | +| `unlockAmounts` | `LockupLinear.UnlockAmounts` | Struct encapsulating (i) the amount to unlock at the start time and (ii) the amount to unlock at the cliff time. | diff --git a/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupRecipient.md b/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupRecipient.md index f7d69b29..895dd2cc 100644 --- a/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupRecipient.md +++ b/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupRecipient.md @@ -1,14 +1,14 @@ # ISablierLockupRecipient -[Git Source](https://github.com/sablier-labs/lockup/blob/463278dbb461b1733d6424cf0aeee3b8d6bc036a/src/interfaces/ISablierLockupRecipient.sol) +[Git Source](https://github.com/sablier-labs/lockup/blob/58eaac45c20c57a93b73d887c714e68f061ec3e6/src/interfaces/ISablierLockupRecipient.sol) **Inherits:** IERC165 Interface for recipient contracts capable of reacting to cancellations and withdrawals. For this to be able to hook into -Sablier, it must fully implement this interface and it must have been allowlisted by the Lockup contract's admin. +Sablier, it must fully implement this interface and it must have been allowlisted in the Lockup contract. -_See [IERC165-supportsInterface](https://eips.ethereum.org/EIPS/eip-165#supportsinterface). The implementation MUST -implement the {IERC165-supportsInterface} method, which MUST return `true` when called with `0xf8ee98d3`, i.e. +_See [IERC165-supportsInterface](https://eips.ethereum.org/EIPS/eip-165). The implementation MUST implement the +{IERC165-supportsInterface} method, which MUST return `true` when called with `0xf8ee98d3`, i.e. `type(ISablierLockupRecipient).interfaceId`._ ## Functions @@ -17,10 +17,10 @@ implement the {IERC165-supportsInterface} method, which MUST return `true` when Responds to cancellations. -Notes: +\*Notes: - The function MUST return the selector `ISablierLockupRecipient.onSablierLockupCancel.selector`. -- If this function reverts, the execution in the Lockup contract will revert as well. +- If this function reverts, the execution in the Lockup contract will revert as well.\* ```solidity function onSablierLockupCancel( @@ -52,10 +52,10 @@ function onSablierLockupCancel( Responds to withdrawals triggered by any address except the contract implementing this interface. -Notes: +\*Notes: - The function MUST return the selector `ISablierLockupRecipient.onSablierLockupWithdraw.selector`. -- If this function reverts, the execution in the Lockup contract will revert as well. +- If this function reverts, the execution in the Lockup contract will revert as well.\* ```solidity function onSablierLockupWithdraw( diff --git a/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupState.md b/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupState.md new file mode 100644 index 00000000..8138cf9f --- /dev/null +++ b/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupState.md @@ -0,0 +1,359 @@ +# ISablierLockupState + +[Git Source](https://github.com/sablier-labs/lockup/blob/58eaac45c20c57a93b73d887c714e68f061ec3e6/src/interfaces/ISablierLockupState.sol) + +Contract with state variables (storage and constants) for the +[SablierLockup](/docs/reference/lockup/contracts/contract.SablierLockup.md) contract, their respective getters and +helpful modifiers. + +## Functions + +### aggregateAmount + +Retrieves the aggregate amount across all streams, denoted in units of the token's decimals. + +_If tokens are directly transferred to the contract without using the stream creation functions, the ERC-20 balance may +be greater than the aggregate amount._ + +```solidity +function aggregateAmount(IERC20 token) external view returns (uint256); +``` + +**Parameters** + +| Name | Type | Description | +| ------- | -------- | ------------------------------- | +| `token` | `IERC20` | The ERC-20 token for the query. | + +### getCliffTime + +Retrieves the stream's cliff time, which is a Unix timestamp. A value of zero means there is no cliff. + +_Reverts if `streamId` references either a null stream or a non-LL stream._ + +```solidity +function getCliffTime(uint256 streamId) external view returns (uint40 cliffTime); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getDepositedAmount + +Retrieves the amount deposited in the stream, denoted in units of the token's decimals. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getDepositedAmount(uint256 streamId) external view returns (uint128 depositedAmount); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getEndTime + +Retrieves the stream's end time, which is a Unix timestamp. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getEndTime(uint256 streamId) external view returns (uint40 endTime); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getLockupModel + +Retrieves the distribution models used to create the stream. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getLockupModel(uint256 streamId) external view returns (Lockup.Model lockupModel); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getRefundedAmount + +Retrieves the amount refunded to the sender after a cancellation, denoted in units of the token's decimals. This amount +is always zero unless the stream was canceled. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getRefundedAmount(uint256 streamId) external view returns (uint128 refundedAmount); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getSegments + +Retrieves the segments used to compose the dynamic distribution function. + +_Reverts if `streamId` references either a null stream or a non-LD stream._ + +```solidity +function getSegments(uint256 streamId) external view returns (LockupDynamic.Segment[] memory segments); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +**Returns** + +| Name | Type | Description | +| ---------- | ------------------------- | ---------------------------------------------- | +| `segments` | `LockupDynamic.Segment[]` | See the documentation in {LockupDynamic} type. | + +### getSender + +Retrieves the stream's sender. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getSender(uint256 streamId) external view returns (address sender); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getStartTime + +Retrieves the stream's start time, which is a Unix timestamp. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getStartTime(uint256 streamId) external view returns (uint40 startTime); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getTranches + +Retrieves the tranches used to compose the tranched distribution function. + +_Reverts if `streamId` references either a null stream or a non-LT stream._ + +```solidity +function getTranches(uint256 streamId) external view returns (LockupTranched.Tranche[] memory tranches); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +**Returns** + +| Name | Type | Description | +| ---------- | -------------------------- | ----------------------------------------------- | +| `tranches` | `LockupTranched.Tranche[]` | See the documentation in {LockupTranched} type. | + +### getUnderlyingToken + +Retrieves the address of the underlying ERC-20 token being distributed. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getUnderlyingToken(uint256 streamId) external view returns (IERC20 token); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getUnlockAmounts + +Retrieves the unlock amounts used to compose the linear distribution function. + +_Reverts if `streamId` references either a null stream or a non-LL stream._ + +```solidity +function getUnlockAmounts(uint256 streamId) external view returns (LockupLinear.UnlockAmounts memory unlockAmounts); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +**Returns** + +| Name | Type | Description | +| --------------- | ---------------------------- | --------------------------------------------- | +| `unlockAmounts` | `LockupLinear.UnlockAmounts` | See the documentation in {LockupLinear} type. | + +### getWithdrawnAmount + +Retrieves the amount withdrawn from the stream, denoted in units of the token's decimals. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getWithdrawnAmount(uint256 streamId) external view returns (uint128 withdrawnAmount); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### isAllowedToHook + +Retrieves a flag indicating whether the provided address is a contract allowed to hook to Sablier when a stream is +canceled or when tokens are withdrawn. + +_See [ISablierLockupRecipient](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupRecipient.md) for +more information._ + +```solidity +function isAllowedToHook(address recipient) external view returns (bool result); +``` + +### isCancelable + +Retrieves a flag indicating whether the stream can be canceled. When the stream is cold, this flag is always `false`. + +_Reverts if `streamId` references a null stream._ + +```solidity +function isCancelable(uint256 streamId) external view returns (bool result); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### isDepleted + +Retrieves a flag indicating whether the stream is depleted. + +_Reverts if `streamId` references a null stream._ + +```solidity +function isDepleted(uint256 streamId) external view returns (bool result); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### isStream + +Retrieves a flag indicating whether the stream exists. + +_Does not revert if `streamId` references a null stream._ + +```solidity +function isStream(uint256 streamId) external view returns (bool result); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### isTransferable + +Retrieves a flag indicating whether the stream NFT can be transferred. + +_Reverts if `streamId` references a null stream._ + +```solidity +function isTransferable(uint256 streamId) external view returns (bool result); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### nativeToken + +Retrieves the address of the ERC-20 interface of the native token, if it exists. + +_The native tokens on some chains have a dual interface as ERC-20. For example, on Polygon the $POL token is the native +token and has an ERC-20 version at 0x0000000000000000000000000000000000001010. This means that `address(this).balance` +returns the same value as `balanceOf(address(this))`. To avoid any unintended behavior, these tokens cannot be used in +Sablier. As an alternative, users can use the Wrapped version of the token, i.e. WMATIC, which is a standard ERC-20 +token._ + +```solidity +function nativeToken() external view returns (address); +``` + +### nextStreamId + +Counter for stream IDs, used in the create functions. + +```solidity +function nextStreamId() external view returns (uint256); +``` + +### nftDescriptor + +Contract that generates the non-fungible token URI. + +```solidity +function nftDescriptor() external view returns (ILockupNFTDescriptor); +``` + +### wasCanceled + +Retrieves a flag indicating whether the stream was canceled. + +_Reverts if `streamId` references a null stream._ + +```solidity +function wasCanceled(uint256 streamId) external view returns (bool result); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | diff --git a/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupTranched.md b/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupTranched.md new file mode 100644 index 00000000..9028aaac --- /dev/null +++ b/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupTranched.md @@ -0,0 +1,107 @@ +# ISablierLockupTranched + +[Git Source](https://github.com/sablier-labs/lockup/blob/58eaac45c20c57a93b73d887c714e68f061ec3e6/src/interfaces/ISablierLockupTranched.sol) + +**Inherits:** [ISablierLockupState](/docs/reference/lockup/contracts/interfaces/interface.ISablierLockupState.md) + +Creates Lockup streams with tranched distribution model. + +## Functions + +### createWithDurationsLT + +Creates a stream by setting the start time to `block.timestamp`, and the end time to the sum of `block.timestamp` and +all specified time durations. The tranche timestamps are derived from these durations. The stream is funded by +`msg.sender` and is wrapped in an ERC-721 NFT. + +\*Emits a {Transfer}, {CreateLockupTrancheStream} and {MetadataUpdate} event. Requirements: + +- All requirements in {createWithTimestampsLT} must be met for the calculated parameters.\* + +```solidity +function createWithDurationsLT( + Lockup.CreateWithDurations calldata params, + LockupTranched.TrancheWithDuration[] calldata tranchesWithDuration +) + external + payable + returns (uint256 streamId); +``` + +**Parameters** + +| Name | Type | Description | +| ---------------------- | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `params` | `Lockup.CreateWithDurations` | Struct encapsulating the function parameters, which are documented in {Lockup} type. | +| `tranchesWithDuration` | `LockupTranched.TrancheWithDuration[]` | Tranches with durations used to compose the tranched distribution function. Timestamps are calculated by starting from `block.timestamp` and adding each duration to the previous timestamp. | + +**Returns** + +| Name | Type | Description | +| ---------- | --------- | ----------------------------------- | +| `streamId` | `uint256` | The ID of the newly created stream. | + +### createWithTimestampsLT + +Creates a stream with the provided tranche timestamps, implying the end time from the last timestamp. The stream is +funded by `msg.sender` and is wrapped in an ERC-721 NFT. + +\*Emits a {Transfer}, {CreateLockupTrancheStream} and {MetadataUpdate} event. Notes: + +- As long as the tranche timestamps are arranged in ascending order, it is not an error for some of them to be in the + past. Requirements: +- Must not be delegate called. +- `params.depositAmount` must be greater than zero. +- `params.timestamps.start` must be greater than zero and less than the first tranche's timestamp. +- `tranches` must have at least one tranche. +- The tranche timestamps must be arranged in ascending order. +- `params.timestamps.end` must be equal to the last tranche's timestamp. +- The sum of the tranche amounts must equal the deposit amount. +- `params.recipient` must not be the zero address. +- `params.sender` must not be the zero address. +- `msg.sender` must have allowed this contract to spend at least `params.depositAmount` tokens. +- `params.token` must not be the native token. +- `params.shape.length` must not be greater than 32 characters.\* + +```solidity +function createWithTimestampsLT( + Lockup.CreateWithTimestamps calldata params, + LockupTranched.Tranche[] calldata tranches +) + external + payable + returns (uint256 streamId); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | ----------------------------- | ------------------------------------------------------------------------------------ | +| `params` | `Lockup.CreateWithTimestamps` | Struct encapsulating the function parameters, which are documented in {Lockup} type. | +| `tranches` | `LockupTranched.Tranche[]` | Tranches used to compose the tranched distribution function. | + +**Returns** + +| Name | Type | Description | +| ---------- | --------- | ----------------------------------- | +| `streamId` | `uint256` | The ID of the newly created stream. | + +## Events + +### CreateLockupTranchedStream + +Emitted when an LT stream is created. + +```solidity +event CreateLockupTranchedStream( + uint256 indexed streamId, Lockup.CreateEventCommon commonParams, LockupTranched.Tranche[] tranches +); +``` + +**Parameters** + +| Name | Type | Description | +| -------------- | -------------------------- | ----------------------------------------------------------------------------- | +| `streamId` | `uint256` | The ID of the newly created stream. | +| `commonParams` | `Lockup.CreateEventCommon` | Common parameters emitted in Create events across all Lockup models. | +| `tranches` | `LockupTranched.Tranche[]` | The tranches the protocol uses to compose the tranched distribution function. | diff --git a/docs/reference/lockup/contracts/libraries/library.Errors.md b/docs/reference/lockup/contracts/libraries/library.Errors.md index 431826d8..525d3822 100644 --- a/docs/reference/lockup/contracts/libraries/library.Errors.md +++ b/docs/reference/lockup/contracts/libraries/library.Errors.md @@ -1,57 +1,17 @@ # Errors -[Git Source](https://github.com/sablier-labs/lockup/blob/463278dbb461b1733d6424cf0aeee3b8d6bc036a/src/libraries/Errors.sol) +[Git Source](https://github.com/sablier-labs/lockup/blob/58eaac45c20c57a93b73d887c714e68f061ec3e6/src/libraries/Errors.sol) Library containing all custom errors the protocol may revert with. ## Errors -### BatchError - -Thrown when an unexpected error occurs during a batch call. - -```solidity -error BatchError(bytes errorData); -``` - -### CallerNotAdmin - -Thrown when `msg.sender` is not the admin. - -```solidity -error CallerNotAdmin(address admin, address caller); -``` - -### DelegateCall - -Thrown when trying to delegate call to a function that disallows delegate calls. - -```solidity -error DelegateCall(); -``` - ### SablierBatchLockup_BatchSizeZero ```solidity error SablierBatchLockup_BatchSizeZero(); ``` -### LockupNFTDescriptor_UnknownNFT - -Thrown when trying to generate the token URI for an unknown ERC-721 NFT contract. - -```solidity -error LockupNFTDescriptor_UnknownNFT(IERC721Metadata nft, string symbol); -``` - -### SablierHelpers_BrokerFeeTooHigh - -Thrown when the broker fee exceeds the maximum allowed fee. - -```solidity -error SablierHelpers_BrokerFeeTooHigh(UD60x18 brokerFee, UD60x18 maxBrokerFee); -``` - ### SablierHelpers_CliffTimeNotLessThanEndTime Thrown when trying to create a linear stream with a cliff time not strictly less than the end time. @@ -68,6 +28,14 @@ Thrown when trying to create a stream with a non zero cliff unlock amount when t error SablierHelpers_CliffTimeZeroUnlockAmountNotZero(uint128 cliffUnlockAmount); ``` +### SablierHelpers_CreateNativeToken + +Thrown when trying to create a stream with the native token. + +```solidity +error SablierHelpers_CreateNativeToken(address nativeToken); +``` + ### SablierHelpers_DepositAmountNotEqualToSegmentAmountsSum Thrown when trying to create a dynamic stream with a deposit amount not equal to the sum of the segment amounts. @@ -108,14 +76,6 @@ Thrown when trying to create a tranched stream with end time not equal to the la error SablierHelpers_EndTimeNotEqualToLastTrancheTimestamp(uint40 endTime, uint40 lastTrancheTimestamp); ``` -### SablierHelpers_SegmentCountTooHigh - -Thrown when trying to create a dynamic stream with more segments than the maximum allowed. - -```solidity -error SablierHelpers_SegmentCountTooHigh(uint256 count); -``` - ### SablierHelpers_SegmentCountZero Thrown when trying to create a dynamic stream with no segments. @@ -189,14 +149,6 @@ Thrown when trying to create a stream with a zero start time. error SablierHelpers_StartTimeZero(); ``` -### SablierHelpers_TrancheCountTooHigh - -Thrown when trying to create a tranched stream with more tranches than the maximum allowed. - -```solidity -error SablierHelpers_TrancheCountTooHigh(uint256 count); -``` - ### SablierHelpers_TrancheCountZero Thrown when trying to create a tranched stream with no tranches. @@ -223,147 +175,163 @@ error SablierHelpers_UnlockAmountsSumTooHigh( ); ``` -### SablierLockupBase_AllowToHookUnsupportedInterface +### SablierLockup_AllowToHookUnsupportedInterface Thrown when trying to allow to hook a contract that doesn't implement the interface correctly. ```solidity -error SablierLockupBase_AllowToHookUnsupportedInterface(address recipient); +error SablierLockup_AllowToHookUnsupportedInterface(address recipient); ``` -### SablierLockupBase_AllowToHookZeroCodeSize +### SablierLockup_AllowToHookZeroCodeSize Thrown when trying to allow to hook an address with no code. ```solidity -error SablierLockupBase_AllowToHookZeroCodeSize(address recipient); +error SablierLockup_AllowToHookZeroCodeSize(address recipient); ``` -### SablierLockupBase_FeeTransferFail +### SablierLockup_InsufficientFeePayment + +Thrown when trying to withdraw with a fee amount less than the minimum fee. + +```solidity +error SablierLockup_InsufficientFeePayment(uint256 feePaid, uint256 minFeeWei); +``` + +### SablierLockup_FeeTransferFailed Thrown when the fee transfer fails. ```solidity -error SablierLockupBase_FeeTransferFail(address admin, uint256 feeAmount); +error SablierLockup_FeeTransferFailed(address comptroller, uint256 feeAmount); ``` -### SablierLockupBase_InvalidHookSelector +### SablierLockup_InvalidHookSelector Thrown when the hook does not return the correct selector. ```solidity -error SablierLockupBase_InvalidHookSelector(address recipient); +error SablierLockup_InvalidHookSelector(address recipient); ``` -### SablierLockupBase_NotTransferable +### SablierLockup_NativeTokenAlreadySet -Thrown when trying to transfer Stream NFT when transferability is disabled. +Thrown when trying to set the native token address when it is already set. ```solidity -error SablierLockupBase_NotTransferable(uint256 tokenId); +error SablierLockup_NativeTokenAlreadySet(address nativeToken); ``` -### SablierLockupBase_Null +### SablierLockup_NotTransferable -Thrown when the ID references a null stream. +Thrown when trying to transfer Stream NFT when transferability is disabled. ```solidity -error SablierLockupBase_Null(uint256 streamId); +error SablierLockup_NotTransferable(uint256 tokenId); ``` -### SablierLockupBase_Overdraw +### SablierLockup_Overdraw Thrown when trying to withdraw an amount greater than the withdrawable amount. ```solidity -error SablierLockupBase_Overdraw(uint256 streamId, uint128 amount, uint128 withdrawableAmount); +error SablierLockup_Overdraw(uint256 streamId, uint128 amount, uint128 withdrawableAmount); ``` -### SablierLockupBase_StreamCanceled +### SablierLockup_StreamCanceled Thrown when trying to cancel or renounce a canceled stream. ```solidity -error SablierLockupBase_StreamCanceled(uint256 streamId); +error SablierLockup_StreamCanceled(uint256 streamId); ``` -### SablierLockupBase_StreamDepleted +### SablierLockup_StreamDepleted Thrown when trying to cancel, renounce, or withdraw from a depleted stream. ```solidity -error SablierLockupBase_StreamDepleted(uint256 streamId); +error SablierLockup_StreamDepleted(uint256 streamId); ``` -### SablierLockupBase_StreamNotCancelable +### SablierLockup_StreamNotCancelable Thrown when trying to cancel or renounce a stream that is not cancelable. ```solidity -error SablierLockupBase_StreamNotCancelable(uint256 streamId); +error SablierLockup_StreamNotCancelable(uint256 streamId); ``` -### SablierLockupBase_StreamNotDepleted +### SablierLockup_StreamNotDepleted Thrown when trying to burn a stream that is not depleted. ```solidity -error SablierLockupBase_StreamNotDepleted(uint256 streamId); +error SablierLockup_StreamNotDepleted(uint256 streamId); ``` -### SablierLockupBase_StreamSettled +### SablierLockup_StreamSettled Thrown when trying to cancel or renounce a settled stream. ```solidity -error SablierLockupBase_StreamSettled(uint256 streamId); +error SablierLockup_StreamSettled(uint256 streamId); ``` -### SablierLockupBase_Unauthorized +### SablierLockup_Unauthorized Thrown when `msg.sender` lacks authorization to perform an action. ```solidity -error SablierLockupBase_Unauthorized(uint256 streamId, address caller); +error SablierLockup_Unauthorized(uint256 streamId, address caller); ``` -### SablierLockupBase_WithdrawalAddressNotRecipient +### SablierLockup_WithdrawalAddressNotRecipient Thrown when trying to withdraw to an address other than the recipient's. ```solidity -error SablierLockupBase_WithdrawalAddressNotRecipient(uint256 streamId, address caller, address to); +error SablierLockup_WithdrawalAddressNotRecipient(uint256 streamId, address caller, address to); ``` -### SablierLockupBase_WithdrawAmountZero +### SablierLockup_WithdrawAmountZero Thrown when trying to withdraw zero tokens from a stream. ```solidity -error SablierLockupBase_WithdrawAmountZero(uint256 streamId); +error SablierLockup_WithdrawAmountZero(uint256 streamId); ``` -### SablierLockupBase_WithdrawArrayCountsNotEqual +### SablierLockup_WithdrawArrayCountsNotEqual Thrown when trying to withdraw from multiple streams and the number of stream IDs does not match the number of withdraw amounts. ```solidity -error SablierLockupBase_WithdrawArrayCountsNotEqual(uint256 streamIdsCount, uint256 amountsCount); +error SablierLockup_WithdrawArrayCountsNotEqual(uint256 streamIdsCount, uint256 amountsCount); ``` -### SablierLockupBase_WithdrawToZeroAddress +### SablierLockup_WithdrawToZeroAddress Thrown when trying to withdraw to the zero address. ```solidity -error SablierLockupBase_WithdrawToZeroAddress(uint256 streamId); +error SablierLockup_WithdrawToZeroAddress(uint256 streamId); ``` -### SablierLockup_NotExpectedModel +### SablierLockupState_NotExpectedModel Thrown when a function is called on a stream that does not use the expected Lockup model. ```solidity -error SablierLockup_NotExpectedModel(Lockup.Model actualLockupModel, Lockup.Model expectedLockupModel); +error SablierLockupState_NotExpectedModel(Lockup.Model actualLockupModel, Lockup.Model expectedLockupModel); +``` + +### SablierLockupState_Null + +Thrown when the ID references a null stream. + +```solidity +error SablierLockupState_Null(uint256 streamId); ``` diff --git a/docs/reference/lockup/contracts/libraries/library.Helpers.md b/docs/reference/lockup/contracts/libraries/library.Helpers.md index 4b10df4b..ec565c53 100644 --- a/docs/reference/lockup/contracts/libraries/library.Helpers.md +++ b/docs/reference/lockup/contracts/libraries/library.Helpers.md @@ -1,8 +1,8 @@ # Helpers -[Git Source](https://github.com/sablier-labs/lockup/blob/463278dbb461b1733d6424cf0aeee3b8d6bc036a/src/libraries/Helpers.sol) +[Git Source](https://github.com/sablier-labs/lockup/blob/58eaac45c20c57a93b73d887c714e68f061ec3e6/src/libraries/Helpers.sol) -Library with functions needed to validate input parameters across lockup streams. +Library with functions needed to validate input parameters across Lockup streams. ## Functions @@ -34,85 +34,70 @@ function calculateTrancheTimestamps( returns (LockupTranched.Tranche[] memory tranchesWithTimestamps); ``` -### checkCreateLockupDynamic +### checkCreateLD -_Checks the parameters of the {SablierLockup-\_createLD} function._ +_Checks the parameters of the +[SablierLockup-\_createLD](/docs/reference/lockup/contracts/abstracts/abstract.SablierLockupDynamic.md#_createld) +function._ ```solidity -function checkCreateLockupDynamic( +function checkCreateLD( address sender, Lockup.Timestamps memory timestamps, - uint128 totalAmount, + uint128 depositAmount, LockupDynamic.Segment[] memory segments, - uint256 maxCount, - UD60x18 brokerFee, - string memory shape, - UD60x18 maxBrokerFee + address token, + address nativeToken, + string memory shape ) public - pure - returns (Lockup.CreateAmounts memory createAmounts); + pure; ``` -### checkCreateLockupLinear +### checkCreateLL -_Checks the parameters of the {SablierLockup-\_createLL} function._ +_Checks the parameters of the +[SablierLockup-\_createLL](/docs/reference/lockup/contracts/abstracts/abstract.SablierLockupLinear.md#_createll) +function._ ```solidity -function checkCreateLockupLinear( +function checkCreateLL( address sender, Lockup.Timestamps memory timestamps, uint40 cliffTime, - uint128 totalAmount, + uint128 depositAmount, LockupLinear.UnlockAmounts memory unlockAmounts, - UD60x18 brokerFee, - string memory shape, - UD60x18 maxBrokerFee + address token, + address nativeToken, + string memory shape ) public - pure - returns (Lockup.CreateAmounts memory createAmounts); + pure; ``` -### checkCreateLockupTranched +### checkCreateLT -_Checks the parameters of the {SablierLockup-\_createLT} function._ +_Checks the parameters of the +[SablierLockup-\_createLT](/docs/reference/lockup/contracts/abstracts/abstract.SablierLockupTranched.md#_createlt) +function._ ```solidity -function checkCreateLockupTranched( +function checkCreateLT( address sender, Lockup.Timestamps memory timestamps, - uint128 totalAmount, + uint128 depositAmount, LockupTranched.Tranche[] memory tranches, - uint256 maxCount, - UD60x18 brokerFee, - string memory shape, - UD60x18 maxBrokerFee + address token, + address nativeToken, + string memory shape ) public - pure - returns (Lockup.CreateAmounts memory createAmounts); -``` - -### \_checkAndCalculateBrokerFee - -_Checks the broker fee is not greater than `maxBrokerFee`, and then calculates the broker fee amount and the deposit -amount from the total amount._ - -```solidity -function _checkAndCalculateBrokerFee( - uint128 totalAmount, - UD60x18 brokerFee, - UD60x18 maxBrokerFee -) - private - pure - returns (Lockup.CreateAmounts memory amounts); + pure; ``` ### \_checkTimestampsAndUnlockAmounts -_Checks the user-provided cliff, end times and unlock amounts of a lockup linear stream._ +_Checks the user-provided cliff, end times, and unlock amounts of an LL stream._ ```solidity function _checkTimestampsAndUnlockAmounts( @@ -127,13 +112,15 @@ function _checkTimestampsAndUnlockAmounts( ### \_checkCreateStream -_Checks the user-provided common parameters across lockup streams._ +_Checks the user-provided common parameters across Lockup streams._ ```solidity function _checkCreateStream( address sender, uint128 depositAmount, uint40 startTime, + address token, + address nativeToken, string memory shape ) private @@ -142,20 +129,19 @@ function _checkCreateStream( ### \_checkSegments -Checks: +\*Checks: 1. The first timestamp is strictly greater than the start time. 2. The timestamps are ordered chronologically. 3. There are no duplicate timestamps. 4. The deposit amount is equal to the sum of all segment amounts. -5. The end time equals the last segment's timestamp. +5. The end time equals the last segment's timestamp.\* ```solidity function _checkSegments( LockupDynamic.Segment[] memory segments, uint128 depositAmount, - Lockup.Timestamps memory timestamps, - uint256 maxSegmentCount + Lockup.Timestamps memory timestamps ) private pure; @@ -163,20 +149,19 @@ function _checkSegments( ### \_checkTranches -Checks: +\*Checks: 1. The first timestamp is strictly greater than the start time. 2. The timestamps are ordered chronologically. 3. There are no duplicate timestamps. 4. The deposit amount is equal to the sum of all tranche amounts. -5. The end time equals the last tranche's timestamp. +5. The end time equals the last tranche's timestamp.\* ```solidity function _checkTranches( LockupTranched.Tranche[] memory tranches, uint128 depositAmount, - Lockup.Timestamps memory timestamps, - uint256 maxTrancheCount + Lockup.Timestamps memory timestamps ) private pure; diff --git a/docs/reference/lockup/contracts/libraries/library.VestingMath.md b/docs/reference/lockup/contracts/libraries/library.LockupMath.md similarity index 55% rename from docs/reference/lockup/contracts/libraries/library.VestingMath.md rename to docs/reference/lockup/contracts/libraries/library.LockupMath.md index fb988288..31864a18 100644 --- a/docs/reference/lockup/contracts/libraries/library.VestingMath.md +++ b/docs/reference/lockup/contracts/libraries/library.LockupMath.md @@ -1,16 +1,17 @@ -# VestingMath +# LockupMath -[Git Source](https://github.com/sablier-labs/lockup/blob/463278dbb461b1733d6424cf0aeee3b8d6bc036a/src/libraries/VestingMath.sol) +[Git Source](https://github.com/sablier-labs/lockup/blob/58eaac45c20c57a93b73d887c714e68f061ec3e6/src/libraries/LockupMath.sol) -Library with functions needed to calculate vested amount across lockup streams. +Provides functions for calculating the streamed amounts in Lockup streams. Note that 'streamed' is synonymous with +'vested'. ## Functions -### calculateLockupDynamicStreamedAmount +### calculateStreamedAmountLD -Calculates the streamed amount for a Lockup dynamic stream. +Calculates the streamed amount of LD streams. -Lockup dynamic model uses the following distribution function: +\*The LD streaming model uses the following distribution function: $$ f(x) = x^{exp} * csa + \Sigma(esa) @@ -21,7 +22,7 @@ Where: - $x$ is the elapsed time divided by the total duration of the current segment. - $exp$ is the current segment exponent. - $csa$ is the current segment amount. -- $\Sigma(esa)$ is the sum of all vested segments' amounts. Notes: +- $\Sigma(esa)$ is the sum of all streamed segments' amounts. Notes: 1. Normalization to 18 decimals is not needed because there is no mix of amounts with different decimals. 2. The stream's start time must be in the past so that the calculations below do not overflow. @@ -30,26 +31,26 @@ Where: 4. The sum of all segment amounts does not overflow uint128 and equals the deposited amount. 5. The first segment's timestamp is greater than the start time. 6. The last segment's timestamp equals the end time. -7. The segment timestamps are arranged in ascending order. +7. The segment timestamps are arranged in ascending order.\* ```solidity -function calculateLockupDynamicStreamedAmount( +function calculateStreamedAmountLD( uint128 depositedAmount, - LockupDynamic.Segment[] memory segments, - uint40 blockTimestamp, - Lockup.Timestamps memory timestamps, + uint40 endTime, + LockupDynamic.Segment[] calldata segments, + uint40 startTime, uint128 withdrawnAmount ) - public - pure + external + view returns (uint128); ``` -### calculateLockupLinearStreamedAmount +### calculateStreamedAmountLL -Calculates the streamed amount for a Lockup linear stream. +Calculates the streamed amount of LL streams. -Lockup linear model uses the following distribution function: +\*The LL streaming model uses the following distribution function: $$ ( x * sa + s, block timestamp < cliff time @@ -67,27 +68,27 @@ Where: 1. The sum of the unlock amounts (start and cliff) does not overflow uint128 and is less than or equal to the deposit amount. 2. The start time is before the end time. -3. If the cliff time is not zero, it is after the start time and before the end time. +3. If the cliff time is not zero, it is after the start time and before the end time.\* ```solidity -function calculateLockupLinearStreamedAmount( - uint128 depositedAmount, - uint40 blockTimestamp, - Lockup.Timestamps memory timestamps, +function calculateStreamedAmountLL( uint40 cliffTime, - LockupLinear.UnlockAmounts memory unlockAmounts, + uint128 depositedAmount, + uint40 endTime, + uint40 startTime, + LockupLinear.UnlockAmounts calldata unlockAmounts, uint128 withdrawnAmount ) - public - pure + external + view returns (uint128); ``` -### calculateLockupTranchedStreamedAmount +### calculateStreamedAmountLT -Calculates the streamed amount for a Lockup tranched stream. +Calculates the streamed amount of LT streams. -Lockup tranched model uses the following distribution function: +\*The LT streaming model uses the following distribution function: $$ f(x) = \Sigma(eta) @@ -95,21 +96,21 @@ $$ Where: -- $\Sigma(eta)$ is the sum of all vested tranches' amounts. Assumptions: +- $\Sigma(eta)$ is the sum of all streamed tranches' amounts. Assumptions: 1. The sum of all tranche amounts does not overflow uint128, and equals the deposited amount. 2. The first tranche's timestamp is greater than the start time. 3. The last tranche's timestamp equals the end time. -4. The tranche timestamps are arranged in ascending order. +4. The tranche timestamps are arranged in ascending order.\* ```solidity -function calculateLockupTranchedStreamedAmount( +function calculateStreamedAmountLT( uint128 depositedAmount, - uint40 blockTimestamp, - Lockup.Timestamps memory timestamps, - LockupTranched.Tranche[] memory tranches + uint40 endTime, + uint40 startTime, + LockupTranched.Tranche[] calldata tranches ) - public - pure + external + view returns (uint128); ``` diff --git a/docs/reference/lockup/contracts/libraries/library.NFTSVG.md b/docs/reference/lockup/contracts/libraries/library.NFTSVG.md index ee781d9c..b4059625 100644 --- a/docs/reference/lockup/contracts/libraries/library.NFTSVG.md +++ b/docs/reference/lockup/contracts/libraries/library.NFTSVG.md @@ -1,6 +1,6 @@ # NFTSVG -[Git Source](https://github.com/sablier-labs/lockup/blob/463278dbb461b1733d6424cf0aeee3b8d6bc036a/src/libraries/NFTSVG.sol) +[Git Source](https://github.com/sablier-labs/lockup/blob/58eaac45c20c57a93b73d887c714e68f061ec3e6/src/libraries/NFTSVG.sol) ## State Variables diff --git a/docs/reference/lockup/contracts/libraries/library.SVGElements.md b/docs/reference/lockup/contracts/libraries/library.SVGElements.md index 94b4218c..9fd23595 100644 --- a/docs/reference/lockup/contracts/libraries/library.SVGElements.md +++ b/docs/reference/lockup/contracts/libraries/library.SVGElements.md @@ -1,6 +1,6 @@ # SVGElements -[Git Source](https://github.com/sablier-labs/lockup/blob/463278dbb461b1733d6424cf0aeee3b8d6bc036a/src/libraries/SVGElements.sol) +[Git Source](https://github.com/sablier-labs/lockup/blob/58eaac45c20c57a93b73d887c714e68f061ec3e6/src/libraries/SVGElements.sol) ## State Variables @@ -159,12 +159,12 @@ function progressCircle(uint256 progressNumerical, string memory accentColor) in Calculates the pixel width of the provided string. -Notes: +\*Notes: - A factor of ~0.6 is applied to the two font sizes used in the SVG (26px and 22px) to approximate the average character width. - It is assumed that escaped characters are placed at the beginning of `text`. -- It is further assumed that there is no other semicolon in `text`. +- It is further assumed that there is no other semicolon in `text`.\* ```solidity function calculatePixelWidth(string memory text, bool largeFont) internal pure returns (uint256 width); diff --git a/docs/reference/lockup/contracts/types/library.BatchLockup.md b/docs/reference/lockup/contracts/types/library.BatchLockup.md index ff2b3f90..dd0efdc2 100644 --- a/docs/reference/lockup/contracts/types/library.BatchLockup.md +++ b/docs/reference/lockup/contracts/types/library.BatchLockup.md @@ -1,114 +1,120 @@ # BatchLockup -[Git Source](https://github.com/sablier-labs/lockup/blob/463278dbb461b1733d6424cf0aeee3b8d6bc036a/src/types/DataTypes.sol) +[Git Source](https://github.com/sablier-labs/lockup/blob/58eaac45c20c57a93b73d887c714e68f061ec3e6/src/types/BatchLockup.sol) -_Namespace for the structs used in `BatchLockup` contract._ +_Namespace for the structs used in `SablierBatchLockup` contract._ ## Structs ### CreateWithDurationsLD -A struct encapsulating all parameters of {SablierLockup.createWithDurationsLD} except for the token. +A struct encapsulating all parameters of +[SablierLockupDynamic.createWithDurationsLD](docs/reference/lockup/contracts/abstracts/abstract.SablierLockupDynamic.md#createwithdurationsld) +except for the token. ```solidity struct CreateWithDurationsLD { address sender; address recipient; - uint128 totalAmount; + uint128 depositAmount; bool cancelable; bool transferable; LockupDynamic.SegmentWithDuration[] segmentsWithDuration; string shape; - Broker broker; } ``` ### CreateWithDurationsLL -A struct encapsulating all parameters of {SablierLockup.createWithDurationsLL} except for the token. +A struct encapsulating all parameters of +[SablierLockupLinear.createWithDurationsLL](docs/reference/lockup/contracts/abstracts/abstract.SablierLockupLinear.md#createwithdurationsll) +except for the token. ```solidity struct CreateWithDurationsLL { address sender; address recipient; - uint128 totalAmount; + uint128 depositAmount; bool cancelable; bool transferable; LockupLinear.Durations durations; LockupLinear.UnlockAmounts unlockAmounts; string shape; - Broker broker; } ``` ### CreateWithDurationsLT -A struct encapsulating all parameters of {SablierLockup.createWithDurationsLT} except for the token. +A struct encapsulating all parameters of +[SablierLockupTranched.createWithDurationsLT](docs/reference/lockup/contracts/abstracts/abstract.SablierLockupTranched.md#createwithdurationslt) +except for the token. ```solidity struct CreateWithDurationsLT { address sender; address recipient; - uint128 totalAmount; + uint128 depositAmount; bool cancelable; bool transferable; LockupTranched.TrancheWithDuration[] tranchesWithDuration; string shape; - Broker broker; } ``` ### CreateWithTimestampsLD -A struct encapsulating all parameters of {SablierLockup.createWithTimestampsLD} except for the token. +A struct encapsulating all parameters of +[SablierLockupDynamic.createWithTimestampsLD](docs/reference/lockup/contracts/abstracts/abstract.SablierLockupDynamic.md#createwithtimestampsld) +except for the token. ```solidity struct CreateWithTimestampsLD { address sender; address recipient; - uint128 totalAmount; + uint128 depositAmount; bool cancelable; bool transferable; uint40 startTime; LockupDynamic.Segment[] segments; string shape; - Broker broker; } ``` ### CreateWithTimestampsLL -A struct encapsulating all parameters of {SablierLockup.createWithTimestampsLL} except for the token. +A struct encapsulating all parameters of +[SablierLockupLinear.createWithTimestampsLL](docs/reference/lockup/contracts/abstracts/abstract.SablierLockupLinear.md#createwithtimestampsll) +except for the token. ```solidity struct CreateWithTimestampsLL { address sender; address recipient; - uint128 totalAmount; + uint128 depositAmount; bool cancelable; bool transferable; Lockup.Timestamps timestamps; uint40 cliffTime; LockupLinear.UnlockAmounts unlockAmounts; string shape; - Broker broker; } ``` ### CreateWithTimestampsLT -A struct encapsulating all parameters of {SablierLockup.createWithTimestampsLT} except for the token. +A struct encapsulating all parameters of +[SablierLockupTranched.createWithTimestampsLT](docs/reference/lockup/contracts/abstracts/abstract.SablierLockupTranched.md#createwithtimestampslt) +except for the token. ```solidity struct CreateWithTimestampsLT { address sender; address recipient; - uint128 totalAmount; + uint128 depositAmount; bool cancelable; bool transferable; uint40 startTime; LockupTranched.Tranche[] tranches; string shape; - Broker broker; } ``` diff --git a/docs/reference/lockup/contracts/types/library.Lockup.md b/docs/reference/lockup/contracts/types/library.Lockup.md index 3ff33aec..32a5d227 100644 --- a/docs/reference/lockup/contracts/types/library.Lockup.md +++ b/docs/reference/lockup/contracts/types/library.Lockup.md @@ -1,8 +1,8 @@ # Lockup -[Git Source](https://github.com/sablier-labs/lockup/blob/463278dbb461b1733d6424cf0aeee3b8d6bc036a/src/types/DataTypes.sol) +[Git Source](https://github.com/sablier-labs/lockup/blob/58eaac45c20c57a93b73d887c714e68f061ec3e6/src/types/Lockup.sol) -Namespace for the structs used in all Lockup models. +Namespace for the structs shared by all Lockup models. ## Structs @@ -10,7 +10,7 @@ Namespace for the structs used in all Lockup models. Struct encapsulating the deposit, withdrawn, and refunded amounts, all denoted in units of the token's decimals. -_Because the deposited and the withdrawn amount are often read together, declaring them in the same slot saves gas._ +_The deposited and withdrawn amount are often read together, so declaring them in the same slot saves gas._ ```solidity struct Amounts { @@ -24,62 +24,41 @@ struct Amounts { | Name | Type | Description | | ----------- | --------- | --------------------------------------------------------------------------------------- | -| `deposited` | `uint128` | The initial amount deposited in the stream, net of broker fee. | +| `deposited` | `uint128` | The amount deposited in the stream. | | `withdrawn` | `uint128` | The cumulative amount withdrawn from the stream. | | `refunded` | `uint128` | The amount refunded to the sender. Unless the stream was canceled, this is always zero. | -### CreateAmounts - -Struct encapsulating (i) the deposit amount and (ii) the broker fee amount, both denoted in units of the token's -decimals. - -```solidity -struct CreateAmounts { - uint128 deposit; - uint128 brokerFee; -} -``` - -**Properties** - -| Name | Type | Description | -| ----------- | --------- | ------------------------------------ | -| `deposit` | `uint128` | The amount to deposit in the stream. | -| `brokerFee` | `uint128` | The broker fee amount. | - ### CreateEventCommon -Struct encapsulating the common parameters emitted in the `Create` event. +Struct encapsulating the common parameters emitted in the stream creation events. ```solidity struct CreateEventCommon { address funder; address sender; address recipient; - Lockup.CreateAmounts amounts; + uint128 depositAmount; IERC20 token; bool cancelable; bool transferable; Lockup.Timestamps timestamps; string shape; - address broker; } ``` **Properties** -| Name | Type | Description | -| -------------- | ---------------------- | --------------------------------------------------------------------------------------------------------------------------- | -| `funder` | `address` | The address which has funded the stream. | -| `sender` | `address` | The address distributing the tokens, which is able to cancel the stream. | -| `recipient` | `address` | The address receiving the tokens, as well as the NFT owner. | -| `amounts` | `Lockup.CreateAmounts` | Struct encapsulating (i) the deposit amount, and (ii) the broker fee amount, both denoted in units of the token's decimals. | -| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | -| `cancelable` | `bool` | Boolean indicating whether the stream is cancelable or not. | -| `transferable` | `bool` | Boolean indicating whether the stream NFT is transferable or not. | -| `timestamps` | `Lockup.Timestamps` | Struct encapsulating (i) the stream's start time and (ii) end time, all as Unix timestamps. | -| `shape` | `string` | An optional parameter to specify the shape of the distribution function. This helps differentiate streams in the UI. | -| `broker` | `address` | The address of the broker who has helped create the stream, e.g. a front-end website. | +| Name | Type | Description | +| --------------- | ------------------- | -------------------------------------------------------------------------------------------------------------------- | +| `funder` | `address` | The address funding the stream. | +| `sender` | `address` | The address distributing the tokens, which is able to cancel the stream. | +| `recipient` | `address` | The address receiving the tokens, as well as the NFT owner. | +| `depositAmount` | `uint128` | The deposit amount, denoted in units of the token's decimals. | +| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | +| `cancelable` | `bool` | Boolean indicating whether the stream is cancelable or not. | +| `transferable` | `bool` | Boolean indicating whether the stream NFT is transferable or not. | +| `timestamps` | `Lockup.Timestamps` | Struct encapsulating (i) the stream's start time and (ii) end time, all as Unix timestamps. | +| `shape` | `string` | An optional parameter to specify the shape of the distribution function. This helps differentiate streams in the UI. | ### CreateWithDurations @@ -89,27 +68,25 @@ Struct encapsulating the parameters of the `createWithDurations` functions. struct CreateWithDurations { address sender; address recipient; - uint128 totalAmount; + uint128 depositAmount; IERC20 token; bool cancelable; bool transferable; string shape; - Broker broker; } ``` **Properties** -| Name | Type | Description | -| -------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `sender` | `address` | The address distributing the tokens, with the ability to cancel the stream. It doesn't have to be the same as `msg.sender`. | -| `recipient` | `address` | The address receiving the tokens, as well as the NFT owner. | -| `totalAmount` | `uint128` | The total amount, including the deposit and any broker fee, denoted in units of the token's decimals. | -| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | -| `cancelable` | `bool` | Indicates if the stream is cancelable. | -| `transferable` | `bool` | Indicates if the stream NFT is transferable. | -| `shape` | `string` | An optional parameter to specify the shape of the distribution function. This helps differentiate streams in the UI. | -| `broker` | `Broker` | Struct encapsulating (i) the address of the broker assisting in creating the stream, and (ii) the percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point number. Both can be set to zero. | +| Name | Type | Description | +| --------------- | --------- | --------------------------------------------------------------------------------------------------------------------------- | +| `sender` | `address` | The address distributing the tokens, with the ability to cancel the stream. It doesn't have to be the same as `msg.sender`. | +| `recipient` | `address` | The address receiving the tokens, as well as the NFT owner. | +| `depositAmount` | `uint128` | The deposit amount, denoted in units of the token's decimals. | +| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | +| `cancelable` | `bool` | Indicates if the stream is cancelable. | +| `transferable` | `bool` | Indicates if the stream NFT is transferable. | +| `shape` | `string` | An optional parameter to specify the shape of the distribution function. This helps differentiate streams in the UI. | ### CreateWithTimestamps @@ -119,29 +96,27 @@ Struct encapsulating the parameters of the `createWithTimestamps` functions. struct CreateWithTimestamps { address sender; address recipient; - uint128 totalAmount; + uint128 depositAmount; IERC20 token; bool cancelable; bool transferable; Timestamps timestamps; string shape; - Broker broker; } ``` **Properties** -| Name | Type | Description | -| -------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `sender` | `address` | The address distributing the tokens, with the ability to cancel the stream. It doesn't have to be the same as `msg.sender`. | -| `recipient` | `address` | The address receiving the tokens, as well as the NFT owner. | -| `totalAmount` | `uint128` | The total amount, including the deposit and any broker fee, denoted in units of the token's decimals. | -| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | -| `cancelable` | `bool` | Indicates if the stream is cancelable. | -| `transferable` | `bool` | Indicates if the stream NFT is transferable. | -| `timestamps` | `Timestamps` | Struct encapsulating (i) the stream's start time and (ii) end time, both as Unix timestamps. | -| `shape` | `string` | An optional parameter to specify the shape of the distribution function. This helps differentiate streams in the UI. | -| `broker` | `Broker` | Struct encapsulating (i) the address of the broker assisting in creating the stream, and (ii) the percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point number. Both can be set to zero. | +| Name | Type | Description | +| --------------- | ------------ | --------------------------------------------------------------------------------------------------------------------------- | +| `sender` | `address` | The address distributing the tokens, with the ability to cancel the stream. It doesn't have to be the same as `msg.sender`. | +| `recipient` | `address` | The address receiving the tokens, as well as the NFT owner. | +| `depositAmount` | `uint128` | The deposit amount, denoted in units of the token's decimals. | +| `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | +| `cancelable` | `bool` | Indicates if the stream is cancelable. | +| `transferable` | `bool` | Indicates if the stream NFT is transferable. | +| `timestamps` | `Timestamps` | Struct encapsulating (i) the stream's start time and (ii) end time, both as Unix timestamps. | +| `shape` | `string` | An optional parameter to specify the shape of the distribution function. This helps differentiate streams in the UI. | ### Stream @@ -158,7 +133,6 @@ struct Stream { bool wasCanceled; IERC20 token; bool isDepleted; - bool isStream; bool isTransferable; Model lockupModel; Amounts amounts; @@ -176,7 +150,6 @@ struct Stream { | `wasCanceled` | `bool` | Boolean indicating if the stream was canceled. | | `token` | `IERC20` | The contract address of the ERC-20 token to be distributed. | | `isDepleted` | `bool` | Boolean indicating if the stream is depleted. | -| `isStream` | `bool` | Boolean indicating if the struct entity exists. | | `isTransferable` | `bool` | Boolean indicating if the stream NFT is transferable. | | `lockupModel` | `Model` | The distribution model of the stream. | | `amounts` | `Amounts` | Struct encapsulating the deposit, withdrawn, and refunded amounts, both denoted in units of the token's decimals. | @@ -203,9 +176,9 @@ struct Timestamps { ### Model -Enum representing the different distribution models used to create lockup streams. +Enum representing the different distribution models used to create Lockup streams. -_These distribution models determine the vesting function used in the calculations of the unlocked tokens._ +_This determines the streaming function used in the calculations of the unlocked tokens._ ```solidity enum Model { @@ -219,10 +192,10 @@ enum Model { Enum representing the different statuses of a stream. -The status can have a "temperature": +\*The status can have a "temperature": 1. Warm: Pending, Streaming. The passage of time alone can change the status. -2. Cold: Settled, Canceled, Depleted. The passage of time alone cannot change the status. +2. Cold: Settled, Canceled, Depleted. The passage of time alone cannot change the status.\* **Notes:** diff --git a/docs/reference/lockup/contracts/types/library.LockupDynamic.md b/docs/reference/lockup/contracts/types/library.LockupDynamic.md index 0f88f903..37942853 100644 --- a/docs/reference/lockup/contracts/types/library.LockupDynamic.md +++ b/docs/reference/lockup/contracts/types/library.LockupDynamic.md @@ -1,14 +1,14 @@ # LockupDynamic -[Git Source](https://github.com/sablier-labs/lockup/blob/463278dbb461b1733d6424cf0aeee3b8d6bc036a/src/types/DataTypes.sol) +[Git Source](https://github.com/sablier-labs/lockup/blob/58eaac45c20c57a93b73d887c714e68f061ec3e6/src/types/LockupDynamic.sol) -Namespace for the structs used only in Lockup Dynamic model. +Namespace for the structs used only in LD streams. ## Structs ### Segment -Segment struct to be stored in the Lockup Dynamic model. +Segment struct stored to represent LD streams. ```solidity struct Segment { @@ -28,7 +28,9 @@ struct Segment { ### SegmentWithDuration -Segment struct used at runtime in {SablierLockup.createWithDurationsLD} function. +Segment struct used at runtime in +[SablierLockupDynamic.createWithDurationsLD](docs/reference/lockup/contracts/abstracts/abstract.SablierLockupDynamic.md#createwithdurationsld) +function. ```solidity struct SegmentWithDuration { diff --git a/docs/reference/lockup/contracts/types/library.LockupLinear.md b/docs/reference/lockup/contracts/types/library.LockupLinear.md index 2976257b..bab1ef4d 100644 --- a/docs/reference/lockup/contracts/types/library.LockupLinear.md +++ b/docs/reference/lockup/contracts/types/library.LockupLinear.md @@ -1,14 +1,15 @@ # LockupLinear -[Git Source](https://github.com/sablier-labs/lockup/blob/463278dbb461b1733d6424cf0aeee3b8d6bc036a/src/types/DataTypes.sol) +[Git Source](https://github.com/sablier-labs/lockup/blob/58eaac45c20c57a93b73d887c714e68f061ec3e6/src/types/LockupLinear.sol) -Namespace for the structs used only in Lockup Linear model. +Namespace for the structs used only in LL streams. ## Structs ### Durations -Struct encapsulating the cliff duration and the total duration used at runtime in {SablierLockup.createWithDurationsLL} +Struct encapsulating the cliff duration and the total duration used at runtime in +[SablierLockupLinear.createWithDurationsLL](docs/reference/lockup/contracts/abstracts/abstract.SablierLockupLinear.md#createwithdurationsll) function. ```solidity diff --git a/docs/reference/lockup/contracts/types/library.LockupTranched.md b/docs/reference/lockup/contracts/types/library.LockupTranched.md index d1ce6ab8..6b05be24 100644 --- a/docs/reference/lockup/contracts/types/library.LockupTranched.md +++ b/docs/reference/lockup/contracts/types/library.LockupTranched.md @@ -1,14 +1,14 @@ # LockupTranched -[Git Source](https://github.com/sablier-labs/lockup/blob/463278dbb461b1733d6424cf0aeee3b8d6bc036a/src/types/DataTypes.sol) +[Git Source](https://github.com/sablier-labs/lockup/blob/58eaac45c20c57a93b73d887c714e68f061ec3e6/src/types/LockupTranched.sol) -Namespace for the structs used only in Lockup Tranched model. +Namespace for the structs used only in LT streams. ## Structs ### Tranche -Tranche struct to be stored in the Lockup Tranched model. +Tranche struct stored to represent LT streams. ```solidity struct Tranche { @@ -26,7 +26,9 @@ struct Tranche { ### TrancheWithDuration -Tranche struct used at runtime in {SablierLockup.createWithDurationsLT} function. +Tranche struct used at runtime in +[SablierLockupTranched.createWithDurationsLT](docs/reference/lockup/contracts/abstracts/abstract.SablierLockupTranched.md#createwithdurationslt) +function. ```solidity struct TrancheWithDuration { diff --git a/docs/reference/lockup/contracts/types/struct.Broker.md b/docs/reference/lockup/contracts/types/struct.Broker.md deleted file mode 100644 index 22f47c59..00000000 --- a/docs/reference/lockup/contracts/types/struct.Broker.md +++ /dev/null @@ -1,19 +0,0 @@ -# Broker - -[Git Source](https://github.com/sablier-labs/lockup/blob/463278dbb461b1733d6424cf0aeee3b8d6bc036a/src/types/DataTypes.sol) - -Struct encapsulating the broker parameters passed to the create functions. Both can be set to zero. - -```solidity -struct Broker { - address account; - UD60x18 fee; -} -``` - -**Properties** - -| Name | Type | Description | -| --------- | --------- | ------------------------------------------------------------------------------------------------------ | -| `account` | `address` | The address receiving the broker's fee. | -| `fee` | `UD60x18` | The broker's percentage fee from the total amount, denoted as a fixed-point number where 1e18 is 100%. | diff --git a/docusaurus.config.ts b/docusaurus.config.ts index 3cee934e..3f93640d 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -16,11 +16,11 @@ const config: Config = { markdown: { format: "detect", hooks: { - onBrokenMarkdownLinks: "throw", + onBrokenMarkdownLinks: "warn", // TODO: change it to "throw" }, mermaid: true, }, - onBrokenLinks: "throw", + onBrokenLinks: "warn", // TODO: change it to "throw" organizationName: "sablier-labs", plugins, presets, diff --git a/repos/evm-utils b/repos/evm-utils new file mode 160000 index 00000000..d7d6c051 --- /dev/null +++ b/repos/evm-utils @@ -0,0 +1 @@ +Subproject commit d7d6c051a39cbacadef672e92ed9d57628c80dc4