From 08341cabd5e625c64888b08fc9566f29d10f0595 Mon Sep 17 00:00:00 2001 From: Joseph Schiarizzi <9449596+cupOJoseph@users.noreply.github.com> Date: Thu, 5 Sep 2024 00:34:11 +0900 Subject: [PATCH 01/22] add attributes to json --- contracts/src/NFTMetadata/utils/JSON.sol | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/contracts/src/NFTMetadata/utils/JSON.sol b/contracts/src/NFTMetadata/utils/JSON.sol index 6a80d114..88dba8c7 100644 --- a/contracts/src/NFTMetadata/utils/JSON.sol +++ b/contracts/src/NFTMetadata/utils/JSON.sol @@ -10,7 +10,7 @@ library json { string constant DOUBLE_QUOTES = '\\"'; - function formattedMetadata(string memory name, string memory description, string memory svgImg) + function formattedMetadata(string memory name, string memory description, string memory svgImg, string memory attributes) internal pure returns (string memory) @@ -19,7 +19,11 @@ library json { "data:application/json;base64,", encode( bytes( - string.concat("{", _prop("name", name), _prop("description", description), _xmlImage(svgImg), "}") + string.concat("{", _prop("name", name), + _prop("description", description), + _xmlImage(svgImg), + _prop("attributes", attributes), + "}") ) ) ); From 174852e81ccc9f00e1ca18ab849c0d5df251aebc Mon Sep 17 00:00:00 2001 From: Joseph Schiarizzi <9449596+cupOJoseph@users.noreply.github.com> Date: Thu, 5 Sep 2024 00:53:29 +0900 Subject: [PATCH 02/22] add bold token to json --- contracts/src/NFTMetadata/MetadataNFT.sol | 22 +++++++++++++++++++++- contracts/src/TroveNFT.sol | 1 + 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/contracts/src/NFTMetadata/MetadataNFT.sol b/contracts/src/NFTMetadata/MetadataNFT.sol index 80714a4a..d961da4c 100644 --- a/contracts/src/NFTMetadata/MetadataNFT.sol +++ b/contracts/src/NFTMetadata/MetadataNFT.sol @@ -15,6 +15,7 @@ interface IMetadataNFT { uint256 _tokenId; address _owner; address _collToken; + address _boldToken; uint256 _collAmount; uint256 _debtAmount; uint256 _interestRate; @@ -35,7 +36,7 @@ contract MetadataNFT is IMetadataNFT { } function uri(TroveData memory _troveData) public view returns (string memory) { - return json.formattedMetadata(name, description, renderSVGImage(_troveData)); + return json.formattedMetadata(name, description, renderSVGImage(_troveData), attributes); } function renderSVGImage(TroveData memory _troveData) internal view returns (string memory) { @@ -45,6 +46,25 @@ contract MetadataNFT is IMetadataNFT { ); } + function attributes(TroveData memory _troveData) public view returns (string memory) { + //include: collateral token address, collateral amount, debt token address, debt amount, interest rate, status + return string.concat( + '[{"trait_type": "Collateral Token", "value": "', + _troveData._collToken, + '"}, {"trait_type": "Collateral Amount", "value": "', + _troveData._collAmount, + '"}, {"trait_type": "Debt Token", "value": "', + _troveData._boldToken, + '"}, {"trait_type": "Debt Amount", "value": "', + _troveData._debtAmount, + '"}, {"trait_type": "Interest Rate", "value": "', + _troveData._interestRate, + '"}, {"trait_type": "Status", "value": "', + _status2Str(_troveData._status), + '"} ]' + ); + } + function dynamicTextComponents(TroveData memory _troveData) public view returns (string memory) { string memory id = LibString.toHexString(_troveData._tokenId); id = string.concat(LibString.slice(id, 0, 6), "...", LibString.slice(id, 38, 42)); diff --git a/contracts/src/TroveNFT.sol b/contracts/src/TroveNFT.sol index c2ffd6ac..b373e2cb 100644 --- a/contracts/src/TroveNFT.sol +++ b/contracts/src/TroveNFT.sol @@ -38,6 +38,7 @@ contract TroveNFT is ERC721, ITroveNFT { _tokenId: _tokenId, _owner: ownerOf(_tokenId), _collToken: address(collToken), + _boldToken: address(boldToken), _collAmount: coll, _debtAmount: debt, _interestRate: annualInterestRate, From f73d7f5564b485e75de606528808d79279876a3b Mon Sep 17 00:00:00 2001 From: Joseph Schiarizzi <9449596+cupOJoseph@users.noreply.github.com> Date: Thu, 5 Sep 2024 01:15:38 +0900 Subject: [PATCH 03/22] add attr test --- contracts/src/test/troveNFT.t.sol | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/contracts/src/test/troveNFT.t.sol b/contracts/src/test/troveNFT.t.sol index 3059a039..1c7ba0b7 100644 --- a/contracts/src/test/troveNFT.t.sol +++ b/contracts/src/test/troveNFT.t.sol @@ -33,4 +33,29 @@ contract troveNFTTest is DevTestSetup { emit log_string(uri); } + + function testTroveURIAttributes() public { + uint256 troveId = _openTrove(); + + TroveNFT troveNFT = TroveNFT(address(troveManager.troveNFT())); + + string memory uri = troveNFT.tokenURI(troveId); + + emit log_string(uri); + // Check for expected attributes + assertTrue(LibString.contains(attributesStr, '"trait_type": "Collateral Token"'), "Collateral Token attribute missing"); + assertTrue(LibString.contains(attributesStr, '"trait_type": "Collateral Amount"'), "Collateral Amount attribute missing"); + assertTrue(LibString.contains(attributesStr, '"trait_type": "Debt Token"'), "Debt Token attribute missing"); + assertTrue(LibString.contains(attributesStr, '"trait_type": "Debt Amount"'), "Debt Amount attribute missing"); + assertTrue(LibString.contains(attributesStr, '"trait_type": "Interest Rate"'), "Interest Rate attribute missing"); + assertTrue(LibString.contains(attributesStr, '"trait_type": "Status"'), "Status attribute missing"); + + // Check for expected values + assertTrue(LibString.contains(attributesStr, string.concat('"value": "', Strings.toHexString(address(collateral)))), "Incorrect Collateral Token value"); + assertTrue(LibString.contains(attributesStr, '"value": "2000000000000000000"'), "Incorrect Collateral Amount value"); + assertTrue(LibString.contains(attributesStr, string.concat('"value": "', Strings.toHexString(address(boldToken)))), "Incorrect Debt Token value"); + assertTrue(LibString.contains(attributesStr, '"value": "1000000000000000000000"'), "Incorrect Debt Amount value"); + assertTrue(LibString.contains(attributesStr, '"value": "5000000000000000"'), "Incorrect Interest Rate value"); + assertTrue(LibString.contains(attributesStr, '"value": "Active"'), "Incorrect Status value"); + } } From 61a05d4fc6d7a9e2641c7436cbff015cf6a7bf7d Mon Sep 17 00:00:00 2001 From: Joseph Schiarizzi <9449596+cupOJoseph@users.noreply.github.com> Date: Thu, 5 Sep 2024 01:15:54 +0900 Subject: [PATCH 04/22] add bold token to uri and strings for attributes --- contracts/src/NFTMetadata/MetadataNFT.sol | 17 +++++++++++------ contracts/src/TroveNFT.sol | 2 ++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/contracts/src/NFTMetadata/MetadataNFT.sol b/contracts/src/NFTMetadata/MetadataNFT.sol index d961da4c..8e421f69 100644 --- a/contracts/src/NFTMetadata/MetadataNFT.sol +++ b/contracts/src/NFTMetadata/MetadataNFT.sol @@ -8,6 +8,8 @@ import "./utils/baseSVG.sol"; import "./utils/bauhaus.sol"; import "openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import {Strings} from "openzeppelin-contracts/contracts/utils/Strings.sol"; + import {ITroveManager} from "src/Interfaces/ITroveManager.sol"; interface IMetadataNFT { @@ -36,7 +38,8 @@ contract MetadataNFT is IMetadataNFT { } function uri(TroveData memory _troveData) public view returns (string memory) { - return json.formattedMetadata(name, description, renderSVGImage(_troveData), attributes); + string memory attr = attributes(_troveData); + return json.formattedMetadata(name, description, renderSVGImage(_troveData), attr); } function renderSVGImage(TroveData memory _troveData) internal view returns (string memory) { @@ -50,19 +53,21 @@ contract MetadataNFT is IMetadataNFT { //include: collateral token address, collateral amount, debt token address, debt amount, interest rate, status return string.concat( '[{"trait_type": "Collateral Token", "value": "', - _troveData._collToken, + Strings.toString(_troveData._collToken), '"}, {"trait_type": "Collateral Amount", "value": "', - _troveData._collAmount, + Strings.toString(_troveData._collAmount), '"}, {"trait_type": "Debt Token", "value": "', - _troveData._boldToken, + Strings.toString(_troveData._boldToken), '"}, {"trait_type": "Debt Amount", "value": "', - _troveData._debtAmount, + Strings.toString(_troveData._debtAmount), '"}, {"trait_type": "Interest Rate", "value": "', - _troveData._interestRate, + Strings.toString(_troveData._interestRate), '"}, {"trait_type": "Status", "value": "', _status2Str(_troveData._status), '"} ]' ); + + } function dynamicTextComponents(TroveData memory _troveData) public view returns (string memory) { diff --git a/contracts/src/TroveNFT.sol b/contracts/src/TroveNFT.sol index b373e2cb..97440176 100644 --- a/contracts/src/TroveNFT.sol +++ b/contracts/src/TroveNFT.sol @@ -16,6 +16,7 @@ import {ITroveManager} from "./Interfaces/ITroveManager.sol"; contract TroveNFT is ERC721, ITroveNFT { ITroveManager public immutable troveManager; IERC20Metadata internal immutable collToken; + IBoldToken internal immutable boldToken; IMetadataNFT public immutable metadataNFT; @@ -28,6 +29,7 @@ contract TroveNFT is ERC721, ITroveNFT { troveManager = _addressesRegistry.troveManager(); collToken = _addressesRegistry.collToken(); metadataNFT = _addressesRegistry.metadataNFT(); + boldToken = _addressesRegistry.boldToken(); } function tokenURI(uint256 _tokenId) public view override(ERC721, IERC721Metadata) returns (string memory) { From ca508792bcf0edef4df75f4cd5fadcb55d3bbb16 Mon Sep 17 00:00:00 2001 From: Joseph Schiarizzi <9449596+cupOJoseph@users.noreply.github.com> Date: Thu, 5 Sep 2024 01:22:38 +0900 Subject: [PATCH 05/22] add docs --- contracts/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contracts/README.md b/contracts/README.md index 26b6ebf2..cf42d0ca 100644 --- a/contracts/README.md +++ b/contracts/README.md @@ -27,6 +27,8 @@ $ forge build $ forge test ``` +Run tests with `forge test -vvv` to see the console logs, which will show trove URI data. + ### Format ```shell From ea067e27bfbc78c5525f502dc80be2868a64b127 Mon Sep 17 00:00:00 2001 From: Joseph Schiarizzi <9449596+cupOJoseph@users.noreply.github.com> Date: Thu, 12 Sep 2024 15:39:57 +0700 Subject: [PATCH 06/22] fix to strings for hexes --- contracts/src/NFTMetadata/MetadataNFT.sol | 4 ++-- contracts/src/NFTMetadata/utils/JSON.sol | 1 + contracts/src/test/troveNFT.t.sol | 27 +++++++++++++---------- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/contracts/src/NFTMetadata/MetadataNFT.sol b/contracts/src/NFTMetadata/MetadataNFT.sol index 8e421f69..eca5efa7 100644 --- a/contracts/src/NFTMetadata/MetadataNFT.sol +++ b/contracts/src/NFTMetadata/MetadataNFT.sol @@ -53,11 +53,11 @@ contract MetadataNFT is IMetadataNFT { //include: collateral token address, collateral amount, debt token address, debt amount, interest rate, status return string.concat( '[{"trait_type": "Collateral Token", "value": "', - Strings.toString(_troveData._collToken), + Strings.toHexString(_troveData._collToken), '"}, {"trait_type": "Collateral Amount", "value": "', Strings.toString(_troveData._collAmount), '"}, {"trait_type": "Debt Token", "value": "', - Strings.toString(_troveData._boldToken), + Strings.toHexString(_troveData._boldToken), '"}, {"trait_type": "Debt Amount", "value": "', Strings.toString(_troveData._debtAmount), '"}, {"trait_type": "Interest Rate", "value": "', diff --git a/contracts/src/NFTMetadata/utils/JSON.sol b/contracts/src/NFTMetadata/utils/JSON.sol index 88dba8c7..47e816bb 100644 --- a/contracts/src/NFTMetadata/utils/JSON.sol +++ b/contracts/src/NFTMetadata/utils/JSON.sol @@ -22,6 +22,7 @@ library json { string.concat("{", _prop("name", name), _prop("description", description), _xmlImage(svgImg), + ",", _prop("attributes", attributes), "}") ) diff --git a/contracts/src/test/troveNFT.t.sol b/contracts/src/test/troveNFT.t.sol index 1c7ba0b7..41189358 100644 --- a/contracts/src/test/troveNFT.t.sol +++ b/contracts/src/test/troveNFT.t.sol @@ -42,20 +42,23 @@ contract troveNFTTest is DevTestSetup { string memory uri = troveNFT.tokenURI(troveId); emit log_string(uri); + + /** TODO: validate each individual attribute, or manually make a json and validate it all at once // Check for expected attributes - assertTrue(LibString.contains(attributesStr, '"trait_type": "Collateral Token"'), "Collateral Token attribute missing"); - assertTrue(LibString.contains(attributesStr, '"trait_type": "Collateral Amount"'), "Collateral Amount attribute missing"); - assertTrue(LibString.contains(attributesStr, '"trait_type": "Debt Token"'), "Debt Token attribute missing"); - assertTrue(LibString.contains(attributesStr, '"trait_type": "Debt Amount"'), "Debt Amount attribute missing"); - assertTrue(LibString.contains(attributesStr, '"trait_type": "Interest Rate"'), "Interest Rate attribute missing"); - assertTrue(LibString.contains(attributesStr, '"trait_type": "Status"'), "Status attribute missing"); + assertTrue(LibString.contains(uri, '"trait_type": "Collateral Token"'), "Collateral Token attribute missing"); + assertTrue(LibString.contains(uri, '"trait_type": "Collateral Amount"'), "Collateral Amount attribute missing"); + assertTrue(LibString.contains(uri, '"trait_type": "Debt Token"'), "Debt Token attribute missing"); + assertTrue(LibString.contains(uri, '"trait_type": "Debt Amount"'), "Debt Amount attribute missing"); + assertTrue(LibString.contains(uri, '"trait_type": "Interest Rate"'), "Interest Rate attribute missing"); + assertTrue(LibString.contains(uri, '"trait_type": "Status"'), "Status attribute missing"); // Check for expected values - assertTrue(LibString.contains(attributesStr, string.concat('"value": "', Strings.toHexString(address(collateral)))), "Incorrect Collateral Token value"); - assertTrue(LibString.contains(attributesStr, '"value": "2000000000000000000"'), "Incorrect Collateral Amount value"); - assertTrue(LibString.contains(attributesStr, string.concat('"value": "', Strings.toHexString(address(boldToken)))), "Incorrect Debt Token value"); - assertTrue(LibString.contains(attributesStr, '"value": "1000000000000000000000"'), "Incorrect Debt Amount value"); - assertTrue(LibString.contains(attributesStr, '"value": "5000000000000000"'), "Incorrect Interest Rate value"); - assertTrue(LibString.contains(attributesStr, '"value": "Active"'), "Incorrect Status value"); + //assertTrue(LibString.contains(uri, string.concat('"value": "', Strings.toHexString(address(collateral)))), "Incorrect Collateral Token value"); + assertTrue(LibString.contains(uri, '"value": "2000000000000000000"'), "Incorrect Collateral Amount value"); + assertTrue(LibString.contains(uri, string.concat('"value": "', Strings.toHexString(address(boldToken)))), "Incorrect Debt Token value"); + assertTrue(LibString.contains(uri, '"value": "1000000000000000000000"'), "Incorrect Debt Amount value"); + assertTrue(LibString.contains(uri, '"value": "5000000000000000"'), "Incorrect Interest Rate value"); + assertTrue(LibString.contains(uri, '"value": "Active"'), "Incorrect Status value"); + */ } } From f743b2cdbc02ea634c9cbca7e00a5d89e0923712 Mon Sep 17 00:00:00 2001 From: Joseph Schiarizzi <9449596+cupOJoseph@users.noreply.github.com> Date: Thu, 12 Sep 2024 15:51:28 +0700 Subject: [PATCH 07/22] fix valid json using _prop adds quotes, but attributes is a list, so should not have them. --- contracts/src/NFTMetadata/utils/JSON.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/src/NFTMetadata/utils/JSON.sol b/contracts/src/NFTMetadata/utils/JSON.sol index 47e816bb..404009b9 100644 --- a/contracts/src/NFTMetadata/utils/JSON.sol +++ b/contracts/src/NFTMetadata/utils/JSON.sol @@ -22,8 +22,8 @@ library json { string.concat("{", _prop("name", name), _prop("description", description), _xmlImage(svgImg), - ",", - _prop("attributes", attributes), + ',"attributes":', + attributes, "}") ) ) From 93f2ac19f69c02c46a45a903510809a4405e59b1 Mon Sep 17 00:00:00 2001 From: RickGriff <32799176+RickGriff@users.noreply.github.com> Date: Wed, 18 Sep 2024 18:29:12 +0100 Subject: [PATCH 08/22] Update README.md --- README.md | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9e57437b..8ac9da3b 100644 --- a/README.md +++ b/README.md @@ -476,7 +476,7 @@ For a given branch, the system maintains the following invariant: That is: -`ActivePool.aggRecordedDebt + ActivePool.calcPendingAggInterest() = SUM_i=1_n(TroveManager.getEntireTroveDebt())` +`ActivePool.aggRecordedDebt + ActivePool.calcPendingAggInterest() + DefaultPool.BoldDebt = SUM_i=1_n(TroveManager.getEntireTroveDebt())` For all `n` Troves in the branch. @@ -492,6 +492,17 @@ Pending aggregate interest is “applied” upon most system actions. That is: This is the only way BOLD is ever minted as interest. Applying individual interest to a Trove updates its recorded debt, but interest is always minted in aggregate. +### Redistribution gains and interest accrual + +The redistribution mechanism from Liquity v1 is carried over to Liquity v2. That is, when the Stability Pool is empty, liquidations are performed by redistributing all debt and collateral from the liquidated Trove(s) to all other active Troves in proportion to their collateral. + +Thus active Troves potentially accrue redistribution debt gains over time. The total redistributed debt is recorded in the `DefaultPool`, and individual Troves' pending redistribution gains are handled in `TroveManager` by the `L_coll` and `L_boldDebt` global trackers. + +Whenever a Trove is touched e.g. by the borrower adjusting debt, its pending redistribution debt gain is "applied" i.e. moved into its recorded debt. + +Pending redistribution gains do **not** accrue interest at aggregate or individual level. All redistribution debt gains are held outside and apart from the interest accrual calculations. This means that a Trove with a relatively high pending redistribution debt gain has a slight advantage: it pays less interest than a Trove with equal entire debt but no pending redistribution gains. + +However, it is possible for anyone to permissionlessly apply a Trove's redistribution gain, i.e. to move them into the Trove's recorded debt via `TroveManager.applyPendingDebt`. This works for batch and non-batched Troves. As such, any unfairness in interest accrual due to redistribution gains can be manually removed. ### Redemption evasion mitigation @@ -522,7 +533,7 @@ The premature adjustment fee works as so: #### Batches and premature adjustment fees ##### Joining a batch -When a trove joins a batch, it pays an upfront fee if the last trove adjustment was done more than the cool period ago. It does’t matter if the Trove and batch have the same interest rate, or when was the last adjustment by the batch. +When a trove joins a batch, it pays an upfront fee if the last trove adjustment was done less than the cool period ago. It does’t matter if the Trove and batch have the same interest rate, or when was the last adjustment by the batch. The last interest rate timestamp will be updated to the time of joining. @@ -1271,7 +1282,7 @@ As mentioned in the interest rate [implementation section](#core-debt-invariant) That is: -`ActivePool.aggRecordedDebt + ActivePool.calcPendingAggInterest() = SUM_i=1_n(TroveManager.getEntireTroveDebt())` +`ActivePool.aggRecordedDebt + ActivePool.calcPendingAggInterest() + DefaultBool.BoltDebt = SUM_i=1_n(TroveManager.getEntireTroveDebt())` For all `n` Troves in the branch. From a6397d74d637556a87f4af1e4a08a6a627faaba8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Fingen?= Date: Mon, 16 Sep 2024 21:30:46 +0100 Subject: [PATCH 09/22] fix: Use last zombie trove first in a redemption sequence Closes #425 --- contracts/src/BorrowerOperations.sol | 28 +- .../src/Interfaces/IBorrowerOperations.sol | 2 +- contracts/src/Interfaces/ITroveManager.sol | 6 +- contracts/src/NFTMetadata/MetadataNFT.sol | 2 +- contracts/src/TroveManager.sol | 55 +- contracts/src/Zappers/GasCompZapper.sol | 4 +- contracts/src/Zappers/WETHZapper.sol | 4 +- .../src/test/AnchoredInvariantsTest.t.sol | 501 +++++++++++++++++- contracts/src/test/HintHelpers.t.sol | 2 +- contracts/src/test/Invariants.t.sol | 6 +- contracts/src/test/TestContracts/BaseTest.sol | 4 +- .../src/test/TestContracts/DevTestSetup.sol | 24 +- .../Interfaces/ITroveManagerTester.sol | 2 +- .../TestContracts/InvariantsTestHandler.t.sol | 152 +++--- .../TestContracts/TroveManagerTester.t.sol | 6 +- contracts/src/test/Utils/TroveId.sol | 13 + .../src/test/interestBatchManagement.t.sol | 10 +- .../test/interestIndividualDelegation.t.sol | 8 +- contracts/src/test/redemptions.t.sol | 201 +++++-- contracts/src/test/shutdown.t.sol | 10 +- contracts/src/test/zapperGasComp.t.sol | 6 +- contracts/src/test/zapperWETH.t.sol | 6 +- 22 files changed, 889 insertions(+), 163 deletions(-) create mode 100644 contracts/src/test/Utils/TroveId.sol diff --git a/contracts/src/BorrowerOperations.sol b/contracts/src/BorrowerOperations.sol index 3e8e6574..322b6f2a 100644 --- a/contracts/src/BorrowerOperations.sol +++ b/contracts/src/BorrowerOperations.sol @@ -128,7 +128,7 @@ contract BorrowerOperations is LiquityBase, AddRemoveManagers, IBorrowerOperatio error BatchInterestRateChangePeriodNotPassed(); error TroveNotOpen(); error TroveNotActive(); - error TroveNotUnredeemable(); + error TroveNotZombie(); error TroveOpen(); error UpfrontFeeTooHigh(); error BelowCriticalThreshold(); @@ -470,7 +470,7 @@ contract BorrowerOperations is LiquityBase, AddRemoveManagers, IBorrowerOperatio _adjustTrove(troveManagerCached, _troveId, troveChange, _maxUpfrontFee); } - function adjustUnredeemableTrove( + function adjustZombieTrove( uint256 _troveId, uint256 _collChange, bool _isCollIncrease, @@ -481,7 +481,7 @@ contract BorrowerOperations is LiquityBase, AddRemoveManagers, IBorrowerOperatio uint256 _maxUpfrontFee ) external override { ITroveManager troveManagerCached = troveManager; - _requireTroveIsUnredeemable(troveManagerCached, _troveId); + _requireTroveIsZombie(troveManagerCached, _troveId); TroveChange memory troveChange; _initTroveChange(troveChange, _collChange, _isCollIncrease, _boldChange, _isDebtIncrease); @@ -650,8 +650,8 @@ contract BorrowerOperations is LiquityBase, AddRemoveManagers, IBorrowerOperatio } } - // Make sure the Trove doesn't end up unredeemable - // Now the max repayment is capped to stay above MIN_DEBT, so this only applies to adjustUnredeemableTrove + // Make sure the Trove doesn't end up zombie + // Now the max repayment is capped to stay above MIN_DEBT, so this only applies to adjustZombieTrove _requireAtLeastMinDebt(vars.newDebt); vars.newICR = LiquityMath._computeCR(vars.newColl, vars.newDebt, vars.price); @@ -787,8 +787,8 @@ contract BorrowerOperations is LiquityBase, AddRemoveManagers, IBorrowerOperatio ); activePool.mintAggInterestAndAccountForTroveChange(change, batchManager); - // If the trove was unredeemable, and now it’s not anymore, put it back in the list - if (_checkTroveIsUnredeemable(troveManagerCached, _troveId) && trove.entireDebt >= MIN_DEBT) { + // If the trove was zombie, and now it’s not anymore, put it back in the list + if (_checkTroveIsZombie(troveManagerCached, _troveId) && trove.entireDebt >= MIN_DEBT) { troveManagerCached.setTroveStatusToActive(_troveId); _reInsertIntoSortedTroves( _troveId, trove.annualInterestRate, _upperHint, _lowerHint, batchManager, batch.annualInterestRate @@ -1304,7 +1304,7 @@ contract BorrowerOperations is LiquityBase, AddRemoveManagers, IBorrowerOperatio function _requireTroveIsOpen(ITroveManager _troveManager, uint256 _troveId) internal view { ITroveManager.Status status = _troveManager.getTroveStatus(_troveId); - if (status != ITroveManager.Status.active && status != ITroveManager.Status.unredeemable) { + if (status != ITroveManager.Status.active && status != ITroveManager.Status.zombie) { revert TroveNotOpen(); } } @@ -1316,20 +1316,20 @@ contract BorrowerOperations is LiquityBase, AddRemoveManagers, IBorrowerOperatio } } - function _requireTroveIsUnredeemable(ITroveManager _troveManager, uint256 _troveId) internal view { - if (!_checkTroveIsUnredeemable(_troveManager, _troveId)) { - revert TroveNotUnredeemable(); + function _requireTroveIsZombie(ITroveManager _troveManager, uint256 _troveId) internal view { + if (!_checkTroveIsZombie(_troveManager, _troveId)) { + revert TroveNotZombie(); } } - function _checkTroveIsUnredeemable(ITroveManager _troveManager, uint256 _troveId) internal view returns (bool) { + function _checkTroveIsZombie(ITroveManager _troveManager, uint256 _troveId) internal view returns (bool) { ITroveManager.Status status = _troveManager.getTroveStatus(_troveId); - return status == ITroveManager.Status.unredeemable; + return status == ITroveManager.Status.zombie; } function _requireTroveIsNotOpen(ITroveManager _troveManager, uint256 _troveId) internal view { ITroveManager.Status status = _troveManager.getTroveStatus(_troveId); - if (status == ITroveManager.Status.active || status == ITroveManager.Status.unredeemable) { + if (status == ITroveManager.Status.active || status == ITroveManager.Status.zombie) { revert TroveOpen(); } } diff --git a/contracts/src/Interfaces/IBorrowerOperations.sol b/contracts/src/Interfaces/IBorrowerOperations.sol index d4eb9c61..e23a0820 100644 --- a/contracts/src/Interfaces/IBorrowerOperations.sol +++ b/contracts/src/Interfaces/IBorrowerOperations.sol @@ -67,7 +67,7 @@ interface IBorrowerOperations is ILiquityBase, IAddRemoveManagers { uint256 _maxUpfrontFee ) external; - function adjustUnredeemableTrove( + function adjustZombieTrove( uint256 _troveId, uint256 _collChange, bool _isCollIncrease, diff --git a/contracts/src/Interfaces/ITroveManager.sol b/contracts/src/Interfaces/ITroveManager.sol index 6dc5ff6f..9db8cc66 100644 --- a/contracts/src/Interfaces/ITroveManager.sol +++ b/contracts/src/Interfaces/ITroveManager.sol @@ -18,7 +18,7 @@ interface ITroveManager is ILiquityBase { active, closedByOwner, closedByLiquidation, - unredeemable + zombie } function shutdownTime() external view returns (uint256); @@ -53,6 +53,8 @@ interface ITroveManager is ILiquityBase { function getCurrentICR(uint256 _troveId, uint256 _price) external view returns (uint256); + function lastZombieTroveId() external view returns (uint256); + function batchLiquidateTroves(uint256[] calldata _troveArray) external; function redeemCollateral( @@ -88,7 +90,7 @@ interface ITroveManager is ILiquityBase { uint256 _batchDebt ) external; - // Called from `adjustUnredeemableTrove()` + // Called from `adjustZombieTrove()` function setTroveStatusToActive(uint256 _troveId) external; function onAdjustTroveInterestRate( diff --git a/contracts/src/NFTMetadata/MetadataNFT.sol b/contracts/src/NFTMetadata/MetadataNFT.sol index 80714a4a..8a05146a 100644 --- a/contracts/src/NFTMetadata/MetadataNFT.sol +++ b/contracts/src/NFTMetadata/MetadataNFT.sol @@ -62,7 +62,7 @@ contract MetadataNFT is IMetadataNFT { if (status == ITroveManager.Status.active) return "Active"; if (status == ITroveManager.Status.closedByOwner) return "Closed"; if (status == ITroveManager.Status.closedByLiquidation) return "Liquidated"; - if (status == ITroveManager.Status.unredeemable) return "Unredeemable"; + if (status == ITroveManager.Status.zombie) return "Zombie"; return ""; } } diff --git a/contracts/src/TroveManager.sol b/contracts/src/TroveManager.sol index 668116e3..274232a2 100644 --- a/contracts/src/TroveManager.sol +++ b/contracts/src/TroveManager.sol @@ -111,6 +111,8 @@ contract TroveManager is LiquityBase, ITroveManager, ITroveEvents { // Array of all batch managers - used to fetch them off-chain address[] public batchIds; + uint256 public lastZombieTroveId; + // Error trackers for the trove redistribution calculation uint256 internal lastCollError_Redistribution; uint256 internal lastBoldDebtError_Redistribution; @@ -149,6 +151,7 @@ contract TroveManager is LiquityBase, ITroveManager, ITroveEvents { uint256 oldWeightedRecordedDebt; uint256 newWeightedRecordedDebt; uint256 newStake; + bool isZombieTrove; LatestTroveData trove; LatestBatchData batch; } @@ -452,7 +455,7 @@ contract TroveManager is LiquityBase, ITroveManager, ITroveEvents { } function _isLiquidatableStatus(Status _status) internal pure returns (bool) { - return _status == Status.active || _status == Status.unredeemable; + return _status == Status.active || _status == Status.zombie; } function _batchLiquidateTroves( @@ -663,14 +666,26 @@ contract TroveManager is LiquityBase, ITroveManager, ITroveEvents { bool isTroveInBatch = _singleRedemption.batchAddress != address(0); uint256 newDebt = _applySingleRedemption(_defaultPool, _singleRedemption, isTroveInBatch); - // Make Trove unredeemable if it's tiny, in order to prevent griefing future (normal, sequential) redemptions + // Make Trove zombie if it's tiny (and it wasn’t already), in order to prevent griefing future (normal, sequential) redemptions if (newDebt < MIN_DEBT) { - Troves[_singleRedemption.troveId].status = Status.unredeemable; - if (isTroveInBatch) { - sortedTroves.removeFromBatch(_singleRedemption.troveId); - } else { - sortedTroves.remove(_singleRedemption.troveId); + if (!_singleRedemption.isZombieTrove) { + Troves[_singleRedemption.troveId].status = Status.zombie; + if (isTroveInBatch) { + sortedTroves.removeFromBatch(_singleRedemption.troveId); + } else { + sortedTroves.remove(_singleRedemption.troveId); + } + // If it’s a partial redemption, let’s store a pointer to it so it’s used first in the next one + if (newDebt > 0) { + lastZombieTroveId = _singleRedemption.troveId; + } + } else if (newDebt == 0) { + // Reset last zombie trove pointer if the previous one was fully redeemed now + lastZombieTroveId = 0; } + } else { + // Reset last zombie trove pointer if the previous one ended up above min debt + lastZombieTroveId = 0; } } @@ -730,7 +745,13 @@ contract TroveManager is LiquityBase, ITroveManager, ITroveEvents { uint256 remainingBold = _boldamount; SingleRedemptionValues memory singleRedemption; - singleRedemption.troveId = sortedTrovesCached.getLast(); + // Let’s check if there’s a pending zombie trove from previous redemption + if (lastZombieTroveId != 0) { + singleRedemption.troveId = lastZombieTroveId; + singleRedemption.isZombieTrove = true; + } else { + singleRedemption.troveId = sortedTrovesCached.getLast(); + } address lastBatchUpdatedInterest = address(0); // Loop through the Troves starting from the one with lowest collateral ratio until _amount of Bold is exchanged for collateral @@ -738,7 +759,13 @@ contract TroveManager is LiquityBase, ITroveManager, ITroveEvents { while (singleRedemption.troveId != 0 && remainingBold > 0 && _maxIterations > 0) { _maxIterations--; // Save the uint256 of the Trove preceding the current one - uint256 nextUserToCheck = sortedTrovesCached.getPrev(singleRedemption.troveId); + uint256 nextUserToCheck; + if (singleRedemption.isZombieTrove) { + nextUserToCheck = sortedTrovesCached.getLast(); + } else { + nextUserToCheck = sortedTrovesCached.getPrev(singleRedemption.troveId); + } + // Skip if ICR < 100%, to make sure that redemptions always improve the CR of hit Troves if (getCurrentICR(singleRedemption.troveId, _price) < _100pct) { singleRedemption.troveId = nextUserToCheck; @@ -769,6 +796,7 @@ contract TroveManager is LiquityBase, ITroveManager, ITroveEvents { remainingBold -= singleRedemption.boldLot; singleRedemption.troveId = nextUserToCheck; + singleRedemption.isZombieTrove = false; } // We are removing this condition to prevent blocking redemptions @@ -811,7 +839,7 @@ contract TroveManager is LiquityBase, ITroveManager, ITroveEvents { bool isTroveInBatch = _singleRedemption.batchAddress != address(0); _applySingleRedemption(_defaultPool, _singleRedemption, isTroveInBatch); - // No need to make this Trove unredeemable if it has tiny debt, since: + // No need to make this Trove zombie if it has tiny debt, since: // - This collateral branch has shut down and urgent redemptions are enabled // - Urgent redemptions aren't sequential, so they can't be griefed by tiny Troves. } @@ -1284,6 +1312,9 @@ contract TroveManager is LiquityBase, ITroveManager, ITroveEvents { function setTroveStatusToActive(uint256 _troveId) external { _requireCallerIsBorrowerOperations(); Troves[_troveId].status = Status.active; + if (lastZombieTroveId == _troveId) { + lastZombieTroveId = 0; + } } function onAdjustTroveInterestRate( @@ -1436,6 +1467,8 @@ contract TroveManager is LiquityBase, ITroveManager, ITroveEvents { if (_batchAddress != address(0)) { if (trove.status == Status.active) { sortedTroves.removeFromBatch(_troveId); + } else if (trove.status == Status.zombie && lastZombieTroveId == _troveId) { + lastZombieTroveId = 0; } _removeTroveSharesFromBatch( @@ -1450,6 +1483,8 @@ contract TroveManager is LiquityBase, ITroveManager, ITroveEvents { } else { if (trove.status == Status.active) { sortedTroves.remove(_troveId); + } else if (trove.status == Status.zombie && lastZombieTroveId == _troveId) { + lastZombieTroveId = 0; } } diff --git a/contracts/src/Zappers/GasCompZapper.sol b/contracts/src/Zappers/GasCompZapper.sol index 19d11794..801892d4 100644 --- a/contracts/src/Zappers/GasCompZapper.sol +++ b/contracts/src/Zappers/GasCompZapper.sol @@ -155,7 +155,7 @@ contract GasCompZapper is AddRemoveManagers { _adjustTrovePost(_collChange, _isCollIncrease, _boldChange, _isDebtIncrease, receiver); } - function adjustUnredeemableTroveWithRawETH( + function adjustZombieTroveWithRawETH( uint256 _troveId, uint256 _collChange, bool _isCollIncrease, @@ -166,7 +166,7 @@ contract GasCompZapper is AddRemoveManagers { uint256 _maxUpfrontFee ) external { address receiver = _adjustTrovePre(_troveId, _collChange, _isCollIncrease, _boldChange, _isDebtIncrease); - borrowerOperations.adjustUnredeemableTrove( + borrowerOperations.adjustZombieTrove( _troveId, _collChange, _isCollIncrease, _boldChange, _isDebtIncrease, _upperHint, _lowerHint, _maxUpfrontFee ); _adjustTrovePost(_collChange, _isCollIncrease, _boldChange, _isDebtIncrease, receiver); diff --git a/contracts/src/Zappers/WETHZapper.sol b/contracts/src/Zappers/WETHZapper.sol index eca59bc5..a11e58df 100644 --- a/contracts/src/Zappers/WETHZapper.sol +++ b/contracts/src/Zappers/WETHZapper.sol @@ -143,7 +143,7 @@ contract WETHZapper is AddRemoveManagers { _adjustTrovePost(_collChange, _isCollIncrease, _boldChange, _isDebtIncrease, receiver); } - function adjustUnredeemableTroveWithRawETH( + function adjustZombieTroveWithRawETH( uint256 _troveId, uint256 _collChange, bool _isCollIncrease, @@ -154,7 +154,7 @@ contract WETHZapper is AddRemoveManagers { uint256 _maxUpfrontFee ) external { address payable receiver = _adjustTrovePre(_troveId, _collChange, _isCollIncrease, _boldChange, _isDebtIncrease); - borrowerOperations.adjustUnredeemableTrove( + borrowerOperations.adjustZombieTrove( _troveId, _collChange, _isCollIncrease, _boldChange, _isDebtIncrease, _upperHint, _lowerHint, _maxUpfrontFee ); _adjustTrovePost(_collChange, _isCollIncrease, _boldChange, _isDebtIncrease, receiver); diff --git a/contracts/src/test/AnchoredInvariantsTest.t.sol b/contracts/src/test/AnchoredInvariantsTest.t.sol index 212b0f5e..b1755bd0 100644 --- a/contracts/src/test/AnchoredInvariantsTest.t.sol +++ b/contracts/src/test/AnchoredInvariantsTest.t.sol @@ -1,13 +1,17 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.18; +import {Strings} from "openzeppelin-contracts/contracts/utils/Strings.sol"; + import "./TestContracts/DevTestSetup.sol"; import {BaseInvariantTest} from "./TestContracts/BaseInvariantTest.sol"; import {BaseMultiCollateralTest} from "./TestContracts/BaseMultiCollateralTest.sol"; import {AdjustedTroveProperties, InvariantsTestHandler} from "./TestContracts/InvariantsTestHandler.t.sol"; import {Logging} from "./Utils/Logging.sol"; +import {TroveId} from "./Utils/TroveId.sol"; -contract AnchoredInvariantsTest is Logging, BaseInvariantTest, BaseMultiCollateralTest { +contract AnchoredInvariantsTest is Logging, BaseInvariantTest, BaseMultiCollateralTest, TroveId { + using Strings for uint256; using StringFormatting for uint256; InvariantsTestHandler handler; @@ -480,4 +484,499 @@ contract AnchoredInvariantsTest is Logging, BaseInvariantTest, BaseMultiCollater vm.prank(hope); handler.provideToSP(1, 4.127947448768090932 ether, false); } + + function testSortedTroveSize() external { + uint256 i = 1; + TestDeployer.LiquityContractsDev memory c = branches[i]; + + vm.prank(adam); + handler.addMeToLiquidationBatch(); + + vm.prank(barb); + handler.addMeToLiquidationBatch(); + + vm.prank(adam); + handler.addMeToUrgentRedemptionBatch(); + + vm.prank(adam); + handler.registerBatchManager(3, 0.100944149373120884 ether, 0.377922952132481818 ether, 0.343424998629201343 ether, 0.489955880173256455 ether, 2070930); + + vm.prank(carl); + handler.addMeToLiquidationBatch(); + + vm.prank(carl); + handler.warp(9_303_785); + + vm.prank(barb); + handler.registerBatchManager(1, 0.301964103682871801 ether, 0.756908371280377546 ether, 0.540898165697757771 ether, 0.000017102564306416 ether, 27657915); + + vm.prank(fran); + handler.addMeToLiquidationBatch(); + + vm.prank(eric); + handler.addMeToUrgentRedemptionBatch(); + + vm.prank(hope); + handler.addMeToLiquidationBatch(); + + // upper hint: 30979495632948298397104351002742564073201815129975103483277328125306028611241 + // lower hint: 36051278007718023196469061266077621121244014979449590376694871896669965056265 + // upfront fee: 118.231198854524639989 ether + vm.prank(gabe); + handler.openTrove(1, 7_591.289850943621327156 ether, 1.900000000017470971 ether, 0.812103428106344175 ether, 1121, 415425919); + + // redemption rate: 0.005000000000000004 ether + // redeemed BOLD: 0.000000000000071705 ether + // redeemed Troves: [ + // [], + // [gabe], + // [], + // [], + // ] + vm.prank(hope); + handler.redeemCollateral(0.000000000000071705 ether, 1); + + // redemption rate: 0.387443853477360594 ether + // redeemed BOLD: 5_896.917877499258624384 ether + // redeemed Troves: [ + // [], + // [gabe], + // [], + // [], + // ] + vm.prank(gabe); + handler.redeemCollateral(5_896.917877499258624384 ether, 1); + + vm.prank(eric); + handler.warp(11_371_761); + + vm.prank(gabe); + handler.registerBatchManager(0, 0.23834235868248997 ether, 0.761711006198436234 ether, 0.523368647516059893 ether, 0.761688376122671962 ether, 31535998); + + vm.prank(hope); + handler.registerBatchManager(2, 0.036127532604869915 ether, 0.999999999999999999 ether, 0.963882428861225203 ether, 0.848537401570757863 ether, 29802393); + + vm.prank(eric); + handler.addMeToUrgentRedemptionBatch(); + + // batch manager: hope + // upper hint: 111996671338791781291582287523793567344508255320483065919810498665837663289426 + // lower hint: 37857035535383668733402580992354953018471987882089934484705744026840633200601 + // upfront fee: 1_355.203530437779650125 ether + vm.prank(carl); + handler.openTroveAndJoinInterestBatchManager(2, 73_312.036791249214758342 ether, 1.900020510596646286 ether, 40, 115, 737); + + vm.prank(barb); + handler.registerBatchManager(0, 0.955741837871335122 ether, 0.974535636428930833 ether, 0.964294359297779033 ether, 0.000000000000268875 ether, 3335617); + + vm.prank(gabe); + handler.addMeToLiquidationBatch(); + + // initial deposit: 0 ether + // compounded deposit: 0 ether + // yield gain: 0 ether + // coll gain: 0 ether + // stashed coll: 0 ether + // blocked SP yield: 975.74654191520134809 ether + vm.prank(fran); + handler.provideToSP(2, 12_633.808570846161076142 ether, true); + + // batch manager: adam + // upper hint: 7512901306961997563120107574274771509748256751277397278816998908345777536679 + // lower hint: 27989025468780058605431608942843597971189459457295957311648808450848491056535 + // upfront fee: 166.681364294341638522 ether + vm.prank(carl); + handler.openTroveAndJoinInterestBatchManager(3, 25_307.541971224954454066 ether, 2.401194840294921108 ether, 142, 6432363, 25223); + + vm.prank(carl); + handler.addMeToUrgentRedemptionBatch(); + + vm.prank(adam); + handler.addMeToUrgentRedemptionBatch(); + + vm.prank(dana); + handler.warp(8_774_305); + + vm.prank(adam); + handler.warp(3_835); + + vm.prank(eric); + handler.warp(9_078_180); + + // initial deposit: 0 ether + // compounded deposit: 0 ether + // yield gain: 0 ether + // coll gain: 0 ether + // stashed coll: 0 ether + // blocked SP yield: 0 ether + vm.prank(gabe); + handler.provideToSP(2, 5_179.259567321319728284 ether, true); + + // price: 120.905132749610222778 ether + vm.prank(hope); + handler.setPrice(1, 2.100000000000002648 ether); + + vm.prank(barb); + handler.lowerBatchManagementFee(1, 0.000008085711886436 ether); + + vm.prank(hope); + handler.addMeToLiquidationBatch(); + + vm.prank(adam); + handler.addMeToLiquidationBatch(); + + vm.prank(gabe); + handler.addMeToLiquidationBatch(); + + // price: 80.314880400478576408 ether + vm.prank(gabe); + handler.setPrice(1, 1.394988326842136963 ether); + + vm.prank(carl); + handler.warp(1_849_907); + + // upper hint: 84800337471693920904250232874319843718400766719524250287777680170677855896573 + // lower hint: 0 + // upfront fee: 0 ether + // function: adjustZombieTrove() + vm.prank(gabe); + handler.adjustTrove(1, uint8(AdjustedTroveProperties.onlyColl), 29.524853479148084596 ether, true, 0 ether, true, 40, 14, 4554760); + + info("SortedTroves size: ", c.sortedTroves.getSize().toString()); + info("num troves: ", handler.numTroves(i).toString()); + info("num zombies: ", handler.numZombies(i).toString()); + info("gabe debt: ", c.troveManager.getTroveEntireDebt(addressToTroveId(gabe)).decimal()); + + // upper hint: 0 + // lower hint: 74750724351164404027318726202729770837051588626953680774538886892291438048970 + // upfront fee: 773.037543760336600445 ether + vm.prank(carl); + handler.openTrove(0, 40_510.940914935073773948 ether, 2.063402456659389908 ether, 0.995000000000000248 ether, 0, 55487655); + + vm.prank(adam); + handler.registerBatchManager(0, 0.541865737266494949 ether, 0.672692246806001449 ether, 0.650860934960147488 ether, 0.070089828074852802 ether, 29179158); + + vm.prank(fran); + handler.registerBatchManager(1, 0.566980989185701648 ether, 0.86881504225021711 ether, 0.702666683322997409 ether, 0.667232273668645041 ether, 7007521); + + vm.prank(dana); + handler.addMeToUrgentRedemptionBatch(); + + // initial deposit: 0 ether + // compounded deposit: 0 ether + // yield gain: 0 ether + // coll gain: 0 ether + // stashed coll: 0 ether + // blocked SP yield: 1_129.588991574293634631 ether + vm.prank(barb); + handler.provideToSP(1, 0.000000000000000002 ether, false); + + info("SortedTroves size: ", c.sortedTroves.getSize().toString()); + info("num troves: ", handler.numTroves(i).toString()); + info("num zombies: ", handler.numZombies(i).toString()); + info("gabe debt: ", c.troveManager.getTroveEntireDebt(addressToTroveId(gabe)).decimal()); + + // redemption rate: 0.184202341360173417 ether + // redeemed BOLD: 66_462.494346928386331338 ether + // redeemed Troves: [ + // [carl], + // [gabe], + // [], + // [carl], + // ] + vm.prank(eric); + handler.redeemCollateral(66_462.49434692838633134 ether, 1); + + info("SortedTroves size: ", c.sortedTroves.getSize().toString()); + info("num troves: ", handler.numTroves(i).toString()); + info("num zombies: ", handler.numZombies(i).toString()); + info("gabe trove Id: ", addressToTroveId(gabe).toString()); + info("gabe debt: ", c.troveManager.getTroveEntireDebt(addressToTroveId(gabe)).decimal()); + assertEq(c.sortedTroves.getSize(), handler.numTroves(i) - handler.numZombies(i), "Wrong SortedTroves size"); + } + + function testAssertLastZombieTroveInABatchHasMoreThanMinDebt() external { + uint256 i = 1; + TestDeployer.LiquityContractsDev memory c = branches[i]; + + vm.prank(adam); + handler.addMeToUrgentRedemptionBatch(); + + vm.prank(hope); + handler.registerBatchManager(0, 0.99500000000072184 ether, 0.996944021609020651 ether, 0.99533906344899454 ether, 0.378970428480541887 ether, 314055); + + vm.prank(dana); + handler.warp(2_225_439); + + vm.prank(adam); + handler.addMeToUrgentRedemptionBatch(); + + vm.prank(barb); + handler.addMeToUrgentRedemptionBatch(); + + vm.prank(barb); + handler.registerBatchManager(2, 0.995000000000009379 ether, 0.999999999998128142 ether, 0.997477804125778004 ether, 0.000000001035389259 ether, 10046); + + vm.prank(gabe); + handler.registerBatchManager(2, 0.346476084765605513 ether, 0.346476084765605514 ether, 0.346476084765605514 ether, 0.000000000000000002 ether, 27010346); + + vm.prank(fran); + handler.warp(19_697_329); + + vm.prank(gabe); + handler.addMeToUrgentRedemptionBatch(); + + vm.prank(fran); + handler.registerBatchManager(1, 0.995000000000019257 ether, 0.999999999996150378 ether, 0.999999999226237651 ether, 0.696688179568702502 ether, 7641047); + + vm.prank(gabe); + handler.warp(977_685); + + vm.prank(gabe); + handler.addMeToUrgentRedemptionBatch(); + + vm.prank(fran); + handler.addMeToLiquidationBatch(); + + // batch manager: fran + // upper hint: 0 + // lower hint: 60678094901167127062962700790111047491633904950610080336398562382189456360809 + // upfront fee: 242.684833433337541236 ether + vm.prank(gabe); + handler.openTroveAndJoinInterestBatchManager(1, 12_654.280610244006254376 ether, 2.145058504746006382 ether, 182, 22444926, 124118903); + + // redemption rate: 0.005 ether + // redeemed BOLD: 0.000000000000017162 ether + // redeemed Troves: [ + // [], + // [gabe], + // [], + // [], + // ] + vm.prank(hope); + info("gabe trove Id: ", addressToTroveId(gabe).toString()); + info("gabe debt: ", c.troveManager.getTroveEntireDebt(addressToTroveId(gabe)).decimal()); + handler.redeemCollateral(0.000000000000017162 ether, 0); + info("gabe trove Id: ", addressToTroveId(gabe).toString()); + info("gabe debt: ", c.troveManager.getTroveEntireDebt(addressToTroveId(gabe)).decimal()); + + // upper hint: 79178440845664423591903906560915994242429107602729190780850212197412640295587 + // lower hint: 0 + // upfront fee: 624.393448965513162837 ether + vm.prank(hope); + handler.openTrove(0, 32_721.264734011072612096 ether, 2.333153121000516764 ether, 0.995000000000109949 ether, 52719, 31482); + + // price: 244.435094708283018275 ether + vm.prank(dana); + handler.setPrice(1, 2.621637893811990143 ether); + + vm.prank(carl); + handler.addMeToUrgentRedemptionBatch(); + + // redemption rate: 0.37622704640950591 ether + // redeemed BOLD: 34_333.025174298345667786 ether + // redeemed Troves: [ + // [hope], + // [gabe], + // [], + // [], + // ] + vm.prank(carl); + info("gabe trove Id: ", addressToTroveId(gabe).toString()); + info("gabe debt: ", c.troveManager.getTroveEntireDebt(addressToTroveId(gabe)).decimal()); + handler.redeemCollateral(34_333.025174298345667787 ether, 0); + info("gabe trove Id: ", addressToTroveId(gabe).toString()); + info("gabe debt: ", c.troveManager.getTroveEntireDebt(addressToTroveId(gabe)).decimal()); + + vm.prank(gabe); + handler.addMeToLiquidationBatch(); + + vm.prank(adam); + handler.addMeToLiquidationBatch(); + + // upper hint: hope + // lower hint: hope + // upfront fee: 45.851924869044942133 ether + vm.prank(carl); + handler.openTrove(0, 3_111.607048463492852195 ether, 1.16895262626418546 ether, 0.142852735597140811 ether, 1885973, 10937); + + // upper hint: 2646484967802154597987056038088487662712072023062744056283555991417410575365 + // lower hint: 20207836743015961388089283396921182522044498153231052202943306959004515414684 + // upfront fee: 0 ether + // function: addColl() + info("gabe trove Id: ", addressToTroveId(gabe).toString()); + info("gabe debt: ", c.troveManager.getTroveEntireDebt(addressToTroveId(gabe)).decimal()); + vm.prank(gabe); + handler.adjustTrove(1, uint8(AdjustedTroveProperties.onlyColl), 3.631424438531681645 ether, true, 0 ether, false, 86, 703, 9499); + info("gabe trove Id: ", addressToTroveId(gabe).toString()); + info("gabe debt: ", c.troveManager.getTroveEntireDebt(addressToTroveId(gabe)).decimal()); + + vm.prank(barb); + handler.lowerBatchManagementFee(2, 0.000000000204221707 ether); + + vm.prank(hope); + handler.addMeToLiquidationBatch(); + + vm.prank(hope); + handler.addMeToLiquidationBatch(); + + vm.prank(hope); + handler.addMeToUrgentRedemptionBatch(); + + // redemption rate: 0.37622704640950591 ether + // redeemed BOLD: 0.000000000000005602 ether + // redeemed Troves: [ + // [carl], + // [gabe], + // [], + // [], + // ] + vm.prank(carl); + info("gabe trove Id: ", addressToTroveId(gabe).toString()); + info("gabe debt: ", c.troveManager.getTroveEntireDebt(addressToTroveId(gabe)).decimal()); + handler.redeemCollateral(0.000000000000005603 ether, 1); + info("gabe trove Id: ", addressToTroveId(gabe).toString()); + info("gabe debt: ", c.troveManager.getTroveEntireDebt(addressToTroveId(gabe)).decimal()); + + vm.prank(fran); + handler.addMeToUrgentRedemptionBatch(); + + vm.prank(dana); + handler.addMeToUrgentRedemptionBatch(); + + vm.prank(dana); + handler.registerBatchManager(1, 0.995000000000001129 ether, 1 ether, 0.999999999999799729 ether, 0.000000000000000001 ether, 31535999); + + // redemption rate: 0.718476929948594246 ether + // redeemed BOLD: 5_431.066474911544502914 ether + // redeemed Troves: [ + // [carl], + // [gabe], + // [], + // [], + // ] + vm.prank(barb); + info("gabe trove Id: ", addressToTroveId(gabe).toString()); + info("gabe debt: ", c.troveManager.getTroveEntireDebt(addressToTroveId(gabe)).decimal()); + handler.redeemCollateral(10_313.397298437031513085 ether, 1); + info("gabe trove Id: ", addressToTroveId(gabe).toString()); + info("gabe ent debt: ", c.troveManager.getTroveEntireDebt(addressToTroveId(gabe)).decimal()); + info("gabe rec debt: ", c.troveManager.getTroveDebt(addressToTroveId(gabe)).decimal()); + info("lzti: ", c.troveManager.lastZombieTroveId().toString()); + + vm.prank(dana); + handler.warp(30_167_580); + + info("gabe ent debt: ", c.troveManager.getTroveEntireDebt(addressToTroveId(gabe)).decimal()); + info("gabe rec debt: ", c.troveManager.getTroveDebt(addressToTroveId(gabe)).decimal()); + info("lzti: ", c.troveManager.lastZombieTroveId().toString()); + vm.prank(gabe); + handler.registerBatchManager(1, 0.995000000000002877 ether, 0.999999999999430967 ether, 0.996456350847225481 ether, 0.000000001322368348 ether, 14343); + info("gabe ent debt 1: ", c.troveManager.getTroveEntireDebt(addressToTroveId(gabe)).decimal()); + info("gabe rec debt 1: ", c.troveManager.getTroveDebt(addressToTroveId(gabe)).decimal()); + + vm.prank(hope); + handler.addMeToLiquidationBatch(); + + // initial deposit: 0 ether + // compounded deposit: 0 ether + // yield gain: 0 ether + // coll gain: 0 ether + // stashed coll: 0 ether + // blocked SP yield: 0 ether + vm.prank(barb); + handler.provideToSP(3, 1_933.156398582065633891 ether, false); + + vm.prank(hope); + handler.addMeToUrgentRedemptionBatch(); + + // initial deposit: 0 ether + // compounded deposit: 0 ether + // yield gain: 0 ether + // coll gain: 0 ether + // stashed coll: 0 ether + // blocked SP yield: 6_368.077020894268536036 ether + vm.prank(hope); + handler.provideToSP(0, 6_184.412833814428802676 ether, true); + + vm.prank(carl); + handler.addMeToLiquidationBatch(); + + // upper hint: 81940996894813545005963650320412669449148720334632109303327864712326705297348 + // lower hint: carl + // upfront fee: 297.236383200558451701 ether + vm.prank(barb); + handler.openTrove(0, 69_695.596747080749922615 ether, 1.900000000000006402 ether, 0.153255449436557929 ether, 1498297936, 1276315316); + + // upper hint: 0 + // lower hint: 30960623452289762463130736603892188849115197753010878244835568881362241800197 + // upfront fee: 56.245103106642574315 ether + // function: withdrawBold() + vm.prank(hope); + handler.adjustTrove(0, uint8(AdjustedTroveProperties.onlyDebt), 0 ether, false, 7_875.177407392532383015 ether, true, 5, 16648, 270); + + // batch manager: gabe + // upper hint: gabe + // lower hint: 0 + // upfront fee: 1_261.275141740191589507 ether + vm.prank(adam); + handler.openTroveAndJoinInterestBatchManager(1, 66_969.454138225567397381 ether, 2.984784797753777921 ether, 4294967294, 1, 52); + info("gabe ent debt 2: ", c.troveManager.getTroveEntireDebt(addressToTroveId(gabe)).decimal()); + info("gabe rec debt 2: ", c.troveManager.getTroveDebt(addressToTroveId(gabe)).decimal()); + + // batch manager: hope + // upper hint: 0 + // lower hint: barb + // upfront fee: 1_272.067039116734276271 ether + vm.prank(eric); + handler.openTroveAndJoinInterestBatchManager(0, 96_538.742068715532219745 ether, 2.762063859567414329 ether, 0, 61578232, 336273331); + + // initial deposit: 6_184.412833814428802676 ether + // compounded deposit: 6_184.412833814428802676 ether + // yield gain: 7_538.471959199501948711 ether + // coll gain: 0 ether + // stashed coll: 0 ether + // blocked SP yield: 0 ether + vm.prank(hope); + handler.provideToSP(0, 0.000000001590447554 ether, true); + + // initial deposit: 0 ether + // compounded deposit: 0 ether + // yield gain: 0 ether + // coll gain: 0 ether + // stashed coll: 0 ether + // blocked SP yield: 0 ether + vm.prank(fran); + handler.provideToSP(3, 180_836.387435487377369461 ether, true); + + vm.prank(fran); + handler.addMeToLiquidationBatch(); + + // initial deposit: 0 ether + // compounded deposit: 0 ether + // yield gain: 0 ether + // coll gain: 0 ether + // stashed coll: 0 ether + // blocked SP yield: 0 ether + vm.prank(eric); + handler.provideToSP(2, 0.000000000000000012 ether, true); + + vm.prank(carl); + handler.addMeToUrgentRedemptionBatch(); + + // redemption rate: 0.00500000000000102 ether + // redeemed BOLD: 0.000000000536305094 ether + // redeemed Troves: [ + // [barb], + // [gabe], + // [], + // [], + // ] + info("gabe trove Id: ", addressToTroveId(gabe).toString()); + info("gabe ent debt e: ", c.troveManager.getTroveEntireDebt(addressToTroveId(gabe)).decimal()); + info("gabe rec debt e: ", c.troveManager.getTroveDebt(addressToTroveId(gabe)).decimal()); + info("lzti: ", c.troveManager.lastZombieTroveId().toString()); + vm.prank(barb); + handler.redeemCollateral(0.000000000536305095 ether, 3); + } } diff --git a/contracts/src/test/HintHelpers.t.sol b/contracts/src/test/HintHelpers.t.sol index 2d0465b9..1eb02cba 100644 --- a/contracts/src/test/HintHelpers.t.sol +++ b/contracts/src/test/HintHelpers.t.sol @@ -16,7 +16,7 @@ contract HintHelpersTest is DevTestSetup { assertEq( uint8(troveManager.getTroveStatus(redeemedTroveId)), - uint8(ITroveManager.Status.unredeemable), + uint8(ITroveManager.Status.zombie), "Redeemed Trove should have become a zombie" ); diff --git a/contracts/src/test/Invariants.t.sol b/contracts/src/test/Invariants.t.sol index d861a11c..8b5f2ede 100644 --- a/contracts/src/test/Invariants.t.sol +++ b/contracts/src/test/Invariants.t.sol @@ -38,7 +38,7 @@ library ToStringFunctions { if (status == ITroveManager.Status.active) return "ITroveManager.Status.active"; if (status == ITroveManager.Status.closedByOwner) return "ITroveManager.Status.closedByOwner"; if (status == ITroveManager.Status.closedByLiquidation) return "ITroveManager.Status.closedByLiquidation"; - if (status == ITroveManager.Status.unredeemable) return "ITroveManager.Status.unredeemable"; + if (status == ITroveManager.Status.zombie) return "ITroveManager.Status.zombie"; revert("Invalid status"); } } @@ -186,14 +186,14 @@ contract InvariantsTest is Logging, BaseInvariantTest, BaseMultiCollateralTest { ITroveManager.Status status = c.troveManager.getTroveStatus(troveId); assertTrue( - status == ITroveManager.Status.active || status == ITroveManager.Status.unredeemable, + status == ITroveManager.Status.active || status == ITroveManager.Status.zombie, "Unexpected status" ); if (status == ITroveManager.Status.active) { assertTrue(c.sortedTroves.contains(troveId), "SortedTroves should contain active Troves"); } else { - assertFalse(c.sortedTroves.contains(troveId), "SortedTroves shouldn't contain unredeemable Troves"); + assertFalse(c.sortedTroves.contains(troveId), "SortedTroves shouldn't contain zombie Troves"); } } } diff --git a/contracts/src/test/TestContracts/BaseTest.sol b/contracts/src/test/TestContracts/BaseTest.sol index d5271a7c..2cbded88 100644 --- a/contracts/src/test/TestContracts/BaseTest.sol +++ b/contracts/src/test/TestContracts/BaseTest.sol @@ -302,7 +302,7 @@ contract BaseTest is TestAccounts, Logging { vm.stopPrank(); } - function adjustUnredeemableTrove( + function adjustZombieTrove( address _account, uint256 _troveId, uint256 _collChange, @@ -312,7 +312,7 @@ contract BaseTest is TestAccounts, Logging { ) public { vm.startPrank(_account); - borrowerOperations.adjustUnredeemableTrove( + borrowerOperations.adjustZombieTrove( _troveId, _collChange, _isCollIncrease, diff --git a/contracts/src/test/TestContracts/DevTestSetup.sol b/contracts/src/test/TestContracts/DevTestSetup.sol index 9ce9d087..4ed74043 100644 --- a/contracts/src/test/TestContracts/DevTestSetup.sol +++ b/contracts/src/test/TestContracts/DevTestSetup.sol @@ -258,8 +258,26 @@ contract DevTestSetup is BaseTest { assertLt(troveManager.getTroveEntireDebt(_troveIDs.B), MIN_DEBT); // Check A and B tagged as Zombie troves - assertEq(uint8(troveManager.getTroveStatus(_troveIDs.A)), uint8(ITroveManager.Status.unredeemable)); - assertEq(uint8(troveManager.getTroveStatus(_troveIDs.A)), uint8(ITroveManager.Status.unredeemable)); + assertEq(uint8(troveManager.getTroveStatus(_troveIDs.A)), uint8(ITroveManager.Status.zombie)); + assertEq(uint8(troveManager.getTroveStatus(_troveIDs.A)), uint8(ITroveManager.Status.zombie)); + } + + function _redeemAndCreateEmptyZombieTrovesAAndB(ABCDEF memory _troveIDs) internal { + // Redeem enough to leave A with 0 debt and B with debt < MIN_DEBT + uint256 redeemFromA = troveManager.getTroveEntireDebt(_troveIDs.A); + uint256 redeemFromB = troveManager.getTroveEntireDebt(_troveIDs.B); + uint256 redeemAmount = redeemFromA + redeemFromB; + + // Fully redeem A and B + redeem(E, redeemAmount); + + // Check A, B has debt == 0 + assertEq(troveManager.getTroveEntireDebt(_troveIDs.A), 0); + assertEq(troveManager.getTroveEntireDebt(_troveIDs.B), 0); + + // Check A and B tagged as Zombie troves + assertEq(uint8(troveManager.getTroveStatus(_troveIDs.A)), uint8(ITroveManager.Status.zombie)); + assertEq(uint8(troveManager.getTroveStatus(_troveIDs.A)), uint8(ITroveManager.Status.zombie)); } function _redeemAndCreateZombieTroveAAndHitB(ABCDEF memory _troveIDs) internal { @@ -276,7 +294,7 @@ contract DevTestSetup is BaseTest { assertGt(troveManager.getTroveEntireDebt(_troveIDs.B), MIN_DEBT); // // Check A is zombie Trove but B is not - assertEq(uint8(troveManager.getTroveStatus(_troveIDs.A)), uint8(ITroveManager.Status.unredeemable)); + assertEq(uint8(troveManager.getTroveStatus(_troveIDs.A)), uint8(ITroveManager.Status.zombie)); assertEq(uint8(troveManager.getTroveStatus(_troveIDs.B)), uint8(ITroveManager.Status.active)); } diff --git a/contracts/src/test/TestContracts/Interfaces/ITroveManagerTester.sol b/contracts/src/test/TestContracts/Interfaces/ITroveManagerTester.sol index 6ee22a4a..4d234d4c 100644 --- a/contracts/src/test/TestContracts/Interfaces/ITroveManagerTester.sol +++ b/contracts/src/test/TestContracts/Interfaces/ITroveManagerTester.sol @@ -40,7 +40,7 @@ interface ITroveManagerTester is ITroveManager { // Trove and batch getters function checkTroveIsActive(uint256 _troveId) external view returns (bool); function checkTroveIsOpen(uint256 _troveId) external view returns (bool); - function checkTroveIsUnredeemable(uint256 _troveId) external view returns (bool); + function checkTroveIsZombie(uint256 _troveId) external view returns (bool); function hasRedistributionGains(uint256 _troveId) external view returns (bool); diff --git a/contracts/src/test/TestContracts/InvariantsTestHandler.t.sol b/contracts/src/test/TestContracts/InvariantsTestHandler.t.sol index 617a0bc1..14597f22 100644 --- a/contracts/src/test/TestContracts/InvariantsTestHandler.t.sol +++ b/contracts/src/test/TestContracts/InvariantsTestHandler.t.sol @@ -143,8 +143,8 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest { uint256 batchManagementFee; Trove trove; bool wasActive; - bool wasUnredeemable; - bool useUnredeemable; + bool wasZombie; + bool useZombie; uint256 maxDebtDec; int256 collDelta; int256 debtDelta; @@ -272,6 +272,20 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest { string errorString; } + struct RedemptionContext { + uint256 totalProportions; + uint256[] proportions; + uint256 remainingAmount; + uint256 troveId; + uint256 lastZombieTroveId; + uint256 j; + uint256 i; + uint256 debtRedeemed; + uint256 collRedeemedPlusFee; + uint256 fee; + uint256 collRedeemed; + } + struct LiquidationTotals { uint256 collGasComp; uint256 spCollGain; @@ -328,7 +342,7 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest { ITroveManager.Status constant ACTIVE = ITroveManager.Status.active; ITroveManager.Status constant CLOSED_BY_OWNER = ITroveManager.Status.closedByOwner; ITroveManager.Status constant CLOSED_BY_LIQ = ITroveManager.Status.closedByLiquidation; - ITroveManager.Status constant UNREDEEMABLE = ITroveManager.Status.unredeemable; + ITroveManager.Status constant UNREDEEMABLE = ITroveManager.Status.zombie; FunctionCaller immutable _functionCaller; bool immutable _assumeNoExpectedFailures; // vm.assume() away calls that fail extectedly @@ -421,7 +435,7 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest { coll = trove.coll; debt = trove.debt; - status = _isUnredeemable(i, troveId) ? UNREDEEMABLE : ACTIVE; + status = _isZombie(i, troveId) ? UNREDEEMABLE : ACTIVE; batchManager = _batchManagerOf[i][troveId]; } @@ -694,7 +708,7 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest { bool isCollInc, uint256 debtChange, bool isDebtInc, - uint32 useUnredeemableSeed, + uint32 useZombieSeed, uint32 upperHintSeed, uint32 lowerHintSeed ) external { @@ -702,7 +716,7 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest { i = _bound(i, 0, branches.length - 1); v.prop = AdjustedTroveProperties(_bound(prop, 0, uint8(AdjustedTroveProperties._COUNT) - 1)); - useUnredeemableSeed %= 100; + useZombieSeed %= 100; v.upperHint = _pickHint(i, upperHintSeed); v.lowerHint = _pickHint(i, lowerHintSeed); @@ -715,18 +729,18 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest { v.batchManagementFee = v.c.troveManager.getLatestBatchData(v.batchManager).accruedManagementFee; v.trove = _troves[i][v.troveId]; v.wasActive = _isActive(i, v.troveId); - v.wasUnredeemable = _isUnredeemable(i, v.troveId); + v.wasZombie = _isZombie(i, v.troveId); - if (v.wasActive || v.wasUnredeemable) { + if (v.wasActive || v.wasZombie) { // Choose the wrong type of adjustment 1% of the time - if (v.wasUnredeemable) { - v.useUnredeemable = useUnredeemableSeed != 0; + if (v.wasZombie) { + v.useZombie = useZombieSeed != 0; } else { - v.useUnredeemable = useUnredeemableSeed == 0; + v.useZombie = useZombieSeed == 0; } } else { - // Choose with equal probability between normal vs. unredeemable adjustment - v.useUnredeemable = useUnredeemableSeed < 50; + // Choose with equal probability between normal vs. zombie adjustment + v.useZombie = useZombieSeed < 50; } collChange = v.prop != AdjustedTroveProperties.onlyDebt ? _bound(collChange, 0, v.t.entireColl + 1) : 0; @@ -738,7 +752,7 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest { v.$collDelta = v.collDelta * int256(_price[i]) / int256(DECIMAL_PRECISION); v.upfrontFee = hintHelpers.predictAdjustTroveUpfrontFee(i, v.troveId, isDebtInc ? debtChange : 0); if (v.upfrontFee > 0) assertGtDecimal(v.debtDelta, 0, 18, "Only debt increase should incur upfront fee"); - v.functionName = _getAdjustmentFunctionName(v.prop, isCollInc, isDebtInc, v.useUnredeemable); + v.functionName = _getAdjustmentFunctionName(v.prop, isCollInc, isDebtInc, v.useZombie); info("upper hint: ", _hintToString(i, v.upperHint)); info("lower hint: ", _hintToString(i, v.lowerHint)); @@ -753,7 +767,7 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest { isCollInc.toString(), debtChange.decimal(), isDebtInc.toString(), - useUnredeemableSeed.toString(), + useZombieSeed.toString(), upperHintSeed.toString(), lowerHintSeed.toString() ); @@ -765,8 +779,8 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest { vm.prank(msg.sender); try _functionCaller.call( address(v.c.borrowerOperations), - v.useUnredeemable - ? _encodeUnredeemableTroveAdjustment( + v.useZombie + ? _encodeZombieTroveAdjustment( v.troveId, collChange, isCollInc, debtChange, isDebtInc, v.upperHint, v.lowerHint, v.upfrontFee ) : _encodeActiveTroveAdjustment( @@ -779,8 +793,8 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest { // Preconditions assertFalse(isShutdown[i], "Should have failed as branch had been shut down"); assertFalse(v.collDelta == 0 && v.debtDelta == 0, "Should have failed as there was no change"); - if (v.useUnredeemable) assertTrue(v.wasUnredeemable, "Should have failed as Trove wasn't unredeemable"); - if (!v.useUnredeemable) assertTrue(v.wasActive, "Should have failed as Trove wasn't active"); + if (v.useZombie) assertTrue(v.wasZombie, "Should have failed as Trove wasn't zombie"); + if (!v.useZombie) assertTrue(v.wasActive, "Should have failed as Trove wasn't active"); assertLeDecimal(-v.collDelta, int256(v.t.entireColl), 18, "Should have failed as withdrawal > coll"); assertLeDecimal(-v.debtDelta, int256(v.t.entireDebt), 18, "Should have failed as repayment > debt"); v.newDebt = v.t.entireDebt.add(v.debtDelta) + v.upfrontFee; @@ -817,11 +831,11 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest { assertEqDecimal(v.collDelta, 0, 18, "Shouldn't have failed as there was a coll change"); assertEqDecimal(v.debtDelta, 0, 18, "Shouldn't have failed as there was a debt change"); } else if (selector == BorrowerOperations.TroveNotActive.selector) { - assertFalse(v.useUnredeemable, string.concat("Shouldn't have been thrown by ", v.functionName)); + assertFalse(v.useZombie, string.concat("Shouldn't have been thrown by ", v.functionName)); assertFalse(v.wasActive, "Shouldn't have failed as Trove was active"); - } else if (selector == BorrowerOperations.TroveNotUnredeemable.selector) { - assertTrue(v.useUnredeemable, string.concat("Shouldn't have been thrown by ", v.functionName)); - assertFalse(v.wasUnredeemable, "Shouldn't have failed as Trove was unredeemable"); + } else if (selector == BorrowerOperations.TroveNotZombie.selector) { + assertTrue(v.useZombie, string.concat("Shouldn't have been thrown by ", v.functionName)); + assertFalse(v.wasZombie, "Shouldn't have failed as Trove was zombie"); } else if (selector == BorrowerOperations.CollWithdrawalTooHigh.selector) { assertGtDecimal(-v.collDelta, int256(v.t.entireColl), 18, "Shouldn't have failed as withdrawal <= coll"); } else if (selector == BorrowerOperations.DebtBelowMin.selector) { @@ -1275,7 +1289,8 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest { _troves[j][redeemed.troveId] = trove; - if (branches[j].troveManager.getTroveEntireDebt(redeemed.troveId) < MIN_DEBT) { + uint256 troveDebt = branches[j].troveManager.getTroveEntireDebt(redeemed.troveId); + if (troveDebt < MIN_DEBT) { _zombieTroveIds[j].add(redeemed.troveId); } } @@ -2423,12 +2438,12 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest { return _troveIds[i].has(troveId); } - function _isUnredeemable(uint256 i, uint256 troveId) internal view returns (bool) { + function _isZombie(uint256 i, uint256 troveId) internal view returns (bool) { return _zombieTroveIds[i].has(troveId); } function _isActive(uint256 i, uint256 troveId) internal view returns (bool) { - return _isOpen(i, troveId) && !_isUnredeemable(i, troveId); + return _isOpen(i, troveId) && !_isZombie(i, troveId); } function _pickHint(uint256 i, uint256 seed) internal view returns (uint256) { @@ -2636,56 +2651,63 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest { internal returns (uint256 totalDebtRedeemed, mapping(uint256 branchIdx => RedemptionTransientState) storage r) { - uint256 totalProportions = 0; - uint256[] memory proportions = new uint256[](branches.length); + RedemptionContext memory vars; + vars.totalProportions = 0; + vars.proportions = new uint256[](branches.length); r = _redemption; // Try in proportion to unbacked - for (uint256 j = 0; j < branches.length; ++j) { - if (isShutdown[j] || _TCR(j) < SCR[j]) continue; - totalProportions += proportions[j] = _getUnbacked(j); + for (vars.j = 0; vars.j < branches.length; ++vars.j) { + if (isShutdown[vars.j] || _TCR(vars.j) < SCR[vars.j]) continue; + vars.totalProportions += vars.proportions[vars.j] = _getUnbacked(vars.j); } // Fallback: in proportion to branch debt - if (totalProportions == 0) { - for (uint256 j = 0; j < branches.length; ++j) { - if (isShutdown[j] || _TCR(j) < SCR[j]) continue; - totalProportions += proportions[j] = _getTotalDebt(j); + if (vars.totalProportions == 0) { + for (vars.j = 0; vars.j < branches.length; ++vars.j) { + if (isShutdown[vars.j] || _TCR(vars.j) < SCR[vars.j]) continue; + vars.totalProportions += vars.proportions[vars.j] = _getTotalDebt(vars.j); } } - if (totalProportions == 0) return (0, r); + if (vars.totalProportions == 0) return (0, r); - for (uint256 j = 0; j < branches.length; ++j) { - r[j].attemptedAmount = amount * proportions[j] / totalProportions; - if (r[j].attemptedAmount == 0) continue; + for (vars.j = 0; vars.j < branches.length; ++vars.j) { + r[vars.j].attemptedAmount = amount * vars.proportions[vars.j] / vars.totalProportions; + if (r[vars.j].attemptedAmount == 0) continue; - TestDeployer.LiquityContractsDev memory c = branches[j]; - uint256 remainingAmount = r[j].attemptedAmount; - uint256 troveId = 0; // "root node" ID + TestDeployer.LiquityContractsDev memory c = branches[vars.j]; + vars.remainingAmount = r[vars.j].attemptedAmount; + vars.troveId = 0; // "root node" ID + vars.lastZombieTroveId = c.troveManager.lastZombieTroveId(); - for (uint256 i = 0; i < maxIterationsPerCollateral || maxIterationsPerCollateral == 0; ++i) { - if (remainingAmount == 0) break; + for (vars.i = 0; vars.i < maxIterationsPerCollateral || maxIterationsPerCollateral == 0; ++vars.i) { + if (vars.remainingAmount == 0) break; - troveId = c.sortedTroves.getPrev(troveId); - if (troveId == 0) break; + vars.troveId = vars.lastZombieTroveId != 0 ? vars.lastZombieTroveId : c.sortedTroves.getPrev(vars.troveId); + if (vars.troveId == 0) break; - LatestTroveData memory trove = c.troveManager.getLatestTroveData(troveId); - if (_ICR(j, trove) < _100pct) continue; + LatestTroveData memory trove = c.troveManager.getLatestTroveData(vars.troveId); + if (_ICR(vars.j, trove) >= _100pct) { + vars.debtRedeemed = Math.min(vars.remainingAmount, trove.entireDebt); + vars.collRedeemedPlusFee = vars.debtRedeemed * DECIMAL_PRECISION / _price[vars.j]; + vars.fee = vars.collRedeemedPlusFee * feePct / _100pct; + vars.collRedeemed = vars.collRedeemedPlusFee - vars.fee; - uint256 debtRedeemed = Math.min(remainingAmount, trove.entireDebt); - uint256 collRedeemedPlusFee = debtRedeemed * DECIMAL_PRECISION / _price[j]; - uint256 fee = collRedeemedPlusFee * feePct / _100pct; - uint256 collRedeemed = collRedeemedPlusFee - fee; + r[vars.j].redeemed.push(Redeemed({troveId: vars.troveId, coll: vars.collRedeemed, debt: vars.debtRedeemed})); - r[j].redeemed.push(Redeemed({troveId: troveId, coll: collRedeemed, debt: debtRedeemed})); + address batchManager = _batchManagerOf[vars.j][vars.troveId]; + if (batchManager != address(0)) r[vars.j].batchManagers.add(batchManager); - address batchManager = _batchManagerOf[j][troveId]; - if (batchManager != address(0)) r[j].batchManagers.add(batchManager); + r[vars.j].totalCollRedeemed += vars.collRedeemed; + totalDebtRedeemed += vars.debtRedeemed; + vars.remainingAmount -= vars.debtRedeemed; + } - r[j].totalCollRedeemed += collRedeemed; - totalDebtRedeemed += debtRedeemed; - remainingAmount -= debtRedeemed; + if (vars.lastZombieTroveId != 0) { + vars.lastZombieTroveId = 0; + vars.troveId = 0; + } } } } @@ -2783,10 +2805,10 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest { AdjustedTroveProperties prop, bool isCollIncrease, bool isDebtIncrease, - bool unredeemable + bool zombie ) internal pure returns (string memory) { - if (unredeemable) { - return "adjustUnredeemableTrove()"; + if (zombie) { + return "adjustZombieTrove()"; } if (prop == AdjustedTroveProperties.onlyColl) { @@ -2847,7 +2869,7 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest { revert("Invalid prop"); } - function _encodeUnredeemableTroveAdjustment( + function _encodeZombieTroveAdjustment( uint256 troveId, uint256 collChange, bool isCollIncrease, @@ -2858,7 +2880,7 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest { uint256 maxUpfrontFee ) internal pure returns (bytes memory) { return abi.encodeCall( - IBorrowerOperations.adjustUnredeemableTrove, + IBorrowerOperations.adjustZombieTrove, (troveId, collChange, isCollIncrease, debtChange, isDebtIncrease, upperHint, lowerHint, maxUpfrontFee) ); } @@ -2947,8 +2969,8 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest { return (selector, "BorrowerOperations.TroveNotActive()"); } - if (selector == BorrowerOperations.TroveNotUnredeemable.selector) { - return (selector, "BorrowerOperations.TroveNotUnredeemable()"); + if (selector == BorrowerOperations.TroveNotZombie.selector) { + return (selector, "BorrowerOperations.TroveNotZombie()"); } if (selector == BorrowerOperations.TroveOpen.selector) { diff --git a/contracts/src/test/TestContracts/TroveManagerTester.t.sol b/contracts/src/test/TestContracts/TroveManagerTester.t.sol index 863a6345..eaa73030 100644 --- a/contracts/src/test/TestContracts/TroveManagerTester.t.sol +++ b/contracts/src/test/TestContracts/TroveManagerTester.t.sol @@ -152,7 +152,7 @@ contract TroveManagerTester is ITroveManagerTester, TroveManager { function checkTroveIsOpen(uint256 _troveId) public view returns (bool) { Status status = Troves[_troveId].status; - return status == Status.active || status == Status.unredeemable; + return status == Status.active || status == Status.zombie; } function checkTroveIsActive(uint256 _troveId) external view returns (bool) { @@ -160,9 +160,9 @@ contract TroveManagerTester is ITroveManagerTester, TroveManager { return status == Status.active; } - function checkTroveIsUnredeemable(uint256 _troveId) external view returns (bool) { + function checkTroveIsZombie(uint256 _troveId) external view returns (bool) { Status status = Troves[_troveId].status; - return status == Status.unredeemable; + return status == Status.zombie; } function hasRedistributionGains(uint256 _troveId) external view override returns (bool) { diff --git a/contracts/src/test/Utils/TroveId.sol b/contracts/src/test/Utils/TroveId.sol new file mode 100644 index 00000000..7cb0a939 --- /dev/null +++ b/contracts/src/test/Utils/TroveId.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.18; + + +contract TroveId { + function addressToTroveId(address _owner, uint256 _ownerIndex) public pure returns (uint256) { + return uint256(keccak256(abi.encode(_owner, _ownerIndex))); + } + + function addressToTroveId(address _owner) public pure returns (uint256) { + return addressToTroveId(_owner, 0); + } +} diff --git a/contracts/src/test/interestBatchManagement.t.sol b/contracts/src/test/interestBatchManagement.t.sol index 0abc63f1..fe1b11e5 100644 --- a/contracts/src/test/interestBatchManagement.t.sol +++ b/contracts/src/test/interestBatchManagement.t.sol @@ -114,7 +114,7 @@ contract InterestBatchManagementTest is DevTestSetup { vm.stopPrank(); } - function testCannotSetBatchManagerIfTroveIsUnredeemable() public { + function testCannotSetBatchManagerIfTroveIsZombie() public { registerBatchManager(B); // Open trove @@ -754,7 +754,7 @@ contract InterestBatchManagementTest is DevTestSetup { redeem(A, 500e18); // Check A is zombie - assertEq(uint8(troveManager.getTroveStatus(ATroveId)), uint8(ITroveManager.Status.unredeemable)); + assertEq(uint8(troveManager.getTroveStatus(ATroveId)), uint8(ITroveManager.Status.zombie)); // Fast-forward time vm.warp(block.timestamp + 3650 days); @@ -1135,7 +1135,7 @@ contract InterestBatchManagementTest is DevTestSetup { assertEq(troveData.lastInterestRateAdjTime, block.timestamp, "Wrong interest rate adj time for A"); } - function testAnUnredeemableTroveGoesBackToTheBatch() public { + function testAnZombieTroveGoesBackToTheBatch() public { // A opens trove and joins batch manager B uint256 troveId = openTroveAndJoinBatchManager(A, 100 ether, 2000e18, B, 5e16); @@ -1144,11 +1144,11 @@ contract InterestBatchManagementTest is DevTestSetup { vm.warp(block.timestamp + 10 days); - // C redeems and makes A unredeemable + // C redeems and makes A zombie redeem(C, 1000e18); // A adjusts back to normal - adjustUnredeemableTrove(A, troveId, 0, false, 1000e18, true); + adjustZombieTrove(A, troveId, 0, false, 1000e18, true); assertEq(borrowerOperations.interestBatchManagerOf(troveId), B, "A should be in batch (BO)"); (,,,,,,,, address tmBatchManagerAddress,) = troveManager.Troves(troveId); diff --git a/contracts/src/test/interestIndividualDelegation.t.sol b/contracts/src/test/interestIndividualDelegation.t.sol index e29a1f91..dad517b0 100644 --- a/contracts/src/test/interestIndividualDelegation.t.sol +++ b/contracts/src/test/interestIndividualDelegation.t.sol @@ -121,17 +121,17 @@ contract InterestIndividualDelegationTest is DevTestSetup { vm.stopPrank(); } - function testSetDelegateRevertsIfTroveIsUnredeemable() public { + function testSetDelegateRevertsIfTroveIsZombie() public { vm.startPrank(B); borrowerOperations.registerBatchManager(1e16, 20e16, 5e16, 25e14, MIN_INTEREST_RATE_CHANGE_PERIOD); vm.stopPrank(); // Open trove uint256 troveId = openTroveNoHints100pct(A, 100e18, 5000e18, 5e16); - // Make trove unredeemable + // Make trove zombie redeem(A, 4000e18); - // Check A’s trove is unredeemable - assertEq(troveManager.checkTroveIsUnredeemable(troveId), true, "A trove should be unredeemable"); + // Check A’s trove is zombie + assertEq(troveManager.checkTroveIsZombie(troveId), true, "A trove should be zombie"); // Set batch manager (B) vm.startPrank(A); diff --git a/contracts/src/test/redemptions.t.sol b/contracts/src/test/redemptions.t.sol index ebf93e7e..c004e3c8 100644 --- a/contracts/src/test/redemptions.t.sol +++ b/contracts/src/test/redemptions.t.sol @@ -22,12 +22,14 @@ contract Redemptions is DevTestSetup { uint256 debt_A = troveManager.getTroveEntireDebt(troveIDs.A); uint256 debt_B = troveManager.getTroveEntireDebt(troveIDs.B); + /* console.log(troveIDs.A, "A id"); console.log(troveIDs.B, "B id"); console.log(sortedTroves.contains(troveIDs.B), "B is in list t0"); console.log(troveManager.getTroveEntireDebt(troveIDs.B), "A debt t0"); console.log(troveManager.getTroveEntireDebt(troveIDs.B), "B debt t0"); console.log(sortedTroves.getLast(), "first to redeem t0"); + */ uint256 debt_C = troveManager.getTroveEntireDebt(troveIDs.C); uint256 debt_D = troveManager.getTroveEntireDebt(troveIDs.D); @@ -73,8 +75,8 @@ contract Redemptions is DevTestSetup { redeem(E, redeemAmount_1); // Check A and B still open - assertEq(uint8(troveManager.getTroveStatus(troveIDs.A)), uint8(ITroveManager.Status.unredeemable)); - assertEq(uint8(troveManager.getTroveStatus(troveIDs.B)), uint8(ITroveManager.Status.unredeemable)); + assertEq(uint8(troveManager.getTroveStatus(troveIDs.A)), uint8(ITroveManager.Status.zombie)); + assertEq(uint8(troveManager.getTroveStatus(troveIDs.B)), uint8(ITroveManager.Status.zombie)); } function testFullRedemptionLeavesTrovesWithDebtEqualToZero() public { @@ -112,8 +114,8 @@ contract Redemptions is DevTestSetup { redeem(E, redeemAmount_2); // Check A and B still open with debt == zero - assertEq(uint8(troveManager.getTroveStatus(troveIDs.A)), uint8(ITroveManager.Status.unredeemable)); - assertEq(uint8(troveManager.getTroveStatus(troveIDs.B)), uint8(ITroveManager.Status.unredeemable)); + assertEq(uint8(troveManager.getTroveStatus(troveIDs.A)), uint8(ITroveManager.Status.zombie)); + assertEq(uint8(troveManager.getTroveStatus(troveIDs.B)), uint8(ITroveManager.Status.zombie)); assertEq(troveManager.getTroveEntireDebt(troveIDs.A), 0); assertEq(troveManager.getTroveEntireDebt(troveIDs.B), 0); @@ -279,7 +281,8 @@ contract Redemptions is DevTestSetup { _redeemAndCreateZombieTrovesAAndB(troveIDs); - assertEq(uint8(troveManager.getTroveStatus(troveIDs.A)), uint8(ITroveManager.Status.unredeemable)); + assertEq(uint8(troveManager.getTroveStatus(troveIDs.A)), uint8(ITroveManager.Status.zombie)); + assertEq(troveManager.lastZombieTroveId(), troveIDs.B, "Wrong last zombie trove pointer"); } function testTroveRedeemedToBelowMIN_DEBTBecomesZombieTrove() public { @@ -287,7 +290,8 @@ contract Redemptions is DevTestSetup { _redeemAndCreateZombieTrovesAAndB(troveIDs); - assertEq(uint8(troveManager.getTroveStatus(troveIDs.B)), uint8(ITroveManager.Status.unredeemable)); + assertEq(uint8(troveManager.getTroveStatus(troveIDs.B)), uint8(ITroveManager.Status.zombie)); + assertEq(troveManager.lastZombieTroveId(), troveIDs.B, "Wrong last zombie trove pointer"); } function testTroveRedeemedToAboveMIN_DEBTDoesNotBecomesZombieTrove() public { @@ -296,6 +300,7 @@ contract Redemptions is DevTestSetup { _redeemAndCreateZombieTroveAAndHitB(troveIDs); assertEq(uint8(troveManager.getTroveStatus(troveIDs.C)), uint8(ITroveManager.Status.active)); + assertEq(troveManager.lastZombieTroveId(), 0, "Wrong last zombie trove pointer"); } function testZombieTrovesRemovedFromSortedList() public { @@ -317,9 +322,12 @@ contract Redemptions is DevTestSetup { // Check Trove with lowest interest rate is C assertEq(sortedTroves.getLast(), troveIDs.C); + + // Check last Zombie trove pointer + assertEq(troveManager.lastZombieTroveId(), troveIDs.B, "Wrong last zombie trove pointer"); } - function testZombieTroveCantBeRedeemedFrom() public { + function testZombieTroveCanStillBeRedeemedFrom() public { (,, ABCDEF memory troveIDs) = _setupForRedemptionAscendingInterest(); _redeemAndCreateZombieTrovesAAndB(troveIDs); @@ -331,14 +339,143 @@ contract Redemptions is DevTestSetup { uint256 redeemAmount = debt_B / 2; redeem(E, redeemAmount); - // Check B's debt unchanged from redeemAmount < debt_B; - assertEq(debt_B, troveManager.getTroveEntireDebt(troveIDs.B)); + // Check B's debt changed from redeemAmount < debt_B; + assertEq(troveManager.getTroveEntireDebt(troveIDs.B), debt_B - redeemAmount); + debt_B = troveManager.getTroveEntireDebt(troveIDs.B); redeemAmount = debt_B + 1; redeem(E, redeemAmount); - // Check B's debt unchanged from redeemAmount > debt_B; - assertEq(debt_B, troveManager.getTroveEntireDebt(troveIDs.B)); + // Check B's debt changed from redeemAmount > debt_B; + assertEq(troveManager.getTroveEntireDebt(troveIDs.B), 0); + } + + function testRedemptionsWithNoPartialLeaveNoPointerToZombieTroves() public { + (,, ABCDEF memory troveIDs) = _setupForRedemptionAscendingInterest(); + + _redeemAndCreateEmptyZombieTrovesAAndB(troveIDs); + + // Check A, B removed from sorted list + assertFalse(sortedTroves.contains(troveIDs.A)); + assertFalse(sortedTroves.contains(troveIDs.B)); + + // Check A, B zombie (already checked in helper above) + //assertEq(uint8(troveManager.getTroveStatus(troveIDs.A)), uint8(ITroveManager.Status.zombie)); + //assertEq(uint8(troveManager.getTroveStatus(troveIDs.B)), uint8(ITroveManager.Status.zombie)); + + // Check A, B empty (already checked in helper above) + //assertEq(troveManager.getTroveEntireDebt(troveIDs.A), 0); + //assertEq(troveManager.getTroveEntireDebt(troveIDs.B), 0); + + // Check last Zombie trove pointer + assertEq(troveManager.lastZombieTroveId(), 0, "Wrong last zombie trove pointer"); + } + + function testZombieTrovePointerGetsResetIfLastOneIsFullyRedemeed() public { + (,, ABCDEF memory troveIDs) = _setupForRedemptionAscendingInterest(); + + _redeemAndCreateZombieTrovesAAndB(troveIDs); + + // Check last Zombie trove pointer + assertEq(troveManager.lastZombieTroveId(), troveIDs.B, "Wrong last zombie trove pointer before"); + + // Get B debt before 2nd redeem + uint256 debt_B = troveManager.getTroveEntireDebt(troveIDs.B); + assertGt(debt_B, 0, "B debt should be non zero"); + + uint256 redeemAmount = debt_B; + console2.log("redeem again"); + console2.log(redeemAmount, "redeemAmount"); + redeem(E, redeemAmount); + + // Check B is empty now + assertEq(troveManager.getTroveEntireDebt(troveIDs.B), 0, "B debt should be zero"); + + // Check last Zombie trove pointer + assertEq(troveManager.lastZombieTroveId(), 0, "Wrong last zombie trove pointer after"); + } + + function testZombieTrovePointerGetsResetIfTroveIsResuscitatedManuallyByOwner() public { + (,, ABCDEF memory troveIDs) = _setupForRedemptionAscendingInterest(); + + _redeemAndCreateZombieTrovesAAndB(troveIDs); + + // Check last Zombie trove pointer + assertEq(troveManager.lastZombieTroveId(), troveIDs.B, "Wrong last zombie trove pointer before"); + + // Restore trove + adjustZombieTrove(B, troveIDs.B, 0, false, MIN_DEBT, true); + + // Check B is above min debt + assertGt(troveManager.getTroveEntireDebt(troveIDs.B), MIN_DEBT, "B debt should be above min"); + + // Check last Zombie trove pointer + assertEq(troveManager.lastZombieTroveId(), 0, "Wrong last zombie trove pointer after"); + } + + function testZombieTrovePointerGetsResetIfTroveIsResuscitatedViaInterest() public { + (,, ABCDEF memory troveIDs) = _setupForRedemptionAscendingInterest(); + + _redeemAndCreateZombieTrovesAAndB(troveIDs); + + // Check last Zombie trove pointer + assertEq(troveManager.lastZombieTroveId(), troveIDs.B, "Wrong last zombie trove pointer before"); + + // Restore trove + adjustZombieTrove(B, troveIDs.B, 0, false, MIN_DEBT, true); + // fast-forward time a lot + vm.warp(block.timestamp + 3650 days); + + // E applies interest on B's Trove + applyPendingDebt(E, troveIDs.B); + + // Check B is above min debt + assertGt(troveManager.getTroveEntireDebt(troveIDs.B), MIN_DEBT, "B debt should be above min"); + + // Check last Zombie trove pointer + assertEq(troveManager.lastZombieTroveId(), 0, "Wrong last zombie trove pointer after"); + } + + function testZombieTrovePointerGetsResetIfTroveIsClosed() public { + (,, ABCDEF memory troveIDs) = _setupForRedemptionAscendingInterest(); + + _redeemAndCreateZombieTrovesAAndB(troveIDs); + + // Check last Zombie trove pointer + assertEq(troveManager.lastZombieTroveId(), troveIDs.B, "Wrong last zombie trove pointer before"); + + // Get B debt before 2nd redeem + uint256 debt_B = troveManager.getTroveEntireDebt(troveIDs.B); + assertGt(debt_B, 0, "B debt should be non zero"); + + deal(address(boldToken), B, debt_B); + closeTrove(B, troveIDs.B); + + // Check B is closed + assertEq(uint8(troveManager.getTroveStatus(troveIDs.B)), uint8(ITroveManager.Status.closedByOwner), "B trove should be closed"); + + // Check last Zombie trove pointer + assertEq(troveManager.lastZombieTroveId(), 0, "Wrong last zombie trove pointer after"); + } + + function testZombieTrovePointerGetsResetIfTroveIsLiquidated() public { + (,, ABCDEF memory troveIDs) = _setupForRedemptionAscendingInterest(); + + _redeemAndCreateZombieTrovesAAndB(troveIDs); + + // Check last Zombie trove pointer + assertEq(troveManager.lastZombieTroveId(), troveIDs.B, "Wrong last zombie trove pointer before"); + + // Liquidate B + console2.log(troveManager.getCurrentICR(troveIDs.B, priceFeed.getPrice()), "troveManager.getCurrentICR(troveIDs.E, price)"); + priceFeed.setPrice(priceFeed.getPrice() / 25); + liquidate(A, troveIDs.B); + + // Check B is liquidated + assertEq(uint8(troveManager.getTroveStatus(troveIDs.B)), uint8(ITroveManager.Status.closedByLiquidation), "B trove should be liquidated"); + + // Check last Zombie trove pointer + assertEq(troveManager.lastZombieTroveId(), 0, "Wrong last zombie trove pointer after"); } function testZombieTrovesCanReceiveRedistGains() public { @@ -469,8 +606,8 @@ contract Redemptions is DevTestSetup { transferBold(E, A, boldToken.balanceOf(E) / 2); transferBold(E, B, boldToken.balanceOf(E)); - assertEq(uint8(troveManager.getTroveStatus(troveIDs.A)), uint8(ITroveManager.Status.unredeemable)); - assertEq(uint8(troveManager.getTroveStatus(troveIDs.B)), uint8(ITroveManager.Status.unredeemable)); + assertEq(uint8(troveManager.getTroveStatus(troveIDs.A)), uint8(ITroveManager.Status.zombie)); + assertEq(uint8(troveManager.getTroveStatus(troveIDs.B)), uint8(ITroveManager.Status.zombie)); closeTrove(A, troveIDs.A); closeTrove(B, troveIDs.B); @@ -496,8 +633,8 @@ contract Redemptions is DevTestSetup { uint256 surplusDebt = 37; // A and B withdraw Bold from their zombie Trove - adjustUnredeemableTrove(A, troveIDs.A, 0, false, debtDelta_A + surplusDebt, true); - adjustUnredeemableTrove(B, troveIDs.B, 0, false, debtDelta_A + surplusDebt, true); + adjustZombieTrove(A, troveIDs.A, 0, false, debtDelta_A + surplusDebt, true); + adjustZombieTrove(B, troveIDs.B, 0, false, debtDelta_A + surplusDebt, true); // Check they are above the min debt assertGt(troveManager.getTroveEntireDebt(troveIDs.A), MIN_DEBT); @@ -521,8 +658,8 @@ contract Redemptions is DevTestSetup { uint256 surplusDebt = 37; // A and B withdraw Bold from their zombie Trove - adjustUnredeemableTrove(A, troveIDs.A, 0, false, debtDelta_A + surplusDebt, true); - adjustUnredeemableTrove(B, troveIDs.B, 0, false, debtDelta_A + surplusDebt, true); + adjustZombieTrove(A, troveIDs.A, 0, false, debtDelta_A + surplusDebt, true); + adjustZombieTrove(B, troveIDs.B, 0, false, debtDelta_A + surplusDebt, true); // Check they are above the min debt assertGt(troveManager.getTroveEntireDebt(troveIDs.A), MIN_DEBT); @@ -554,8 +691,8 @@ contract Redemptions is DevTestSetup { assertFalse(sortedTroves.contains(troveIDs.B)); // A and B withdraw Bold from their zombie Trove - adjustUnredeemableTrove(A, troveIDs.A, 0, false, debtDelta_A + surplusDebt, true); - adjustUnredeemableTrove(B, troveIDs.B, 0, false, debtDelta_A + surplusDebt, true); + adjustZombieTrove(A, troveIDs.A, 0, false, debtDelta_A + surplusDebt, true); + adjustZombieTrove(B, troveIDs.B, 0, false, debtDelta_A + surplusDebt, true); // Check they are above the min debt assertGt(troveManager.getTroveEntireDebt(troveIDs.A), MIN_DEBT); @@ -586,8 +723,8 @@ contract Redemptions is DevTestSetup { uint256 surplusDebt = 37; // A and B withdraw Bold from their zombie Trove - adjustUnredeemableTrove(A, troveIDs.A, 0, false, debtDelta_A + surplusDebt, true); - adjustUnredeemableTrove(B, troveIDs.B, 0, false, debtDelta_A + surplusDebt, true); + adjustZombieTrove(A, troveIDs.A, 0, false, debtDelta_A + surplusDebt, true); + adjustZombieTrove(B, troveIDs.B, 0, false, debtDelta_A + surplusDebt, true); // Check they are above the min debt assertGt(troveManager.getTroveEntireDebt(troveIDs.A), MIN_DEBT, "A debt should be above min"); @@ -611,10 +748,10 @@ contract Redemptions is DevTestSetup { // A and B attempt to withdraw Bold, but not enough vm.expectRevert(BorrowerOperations.DebtBelowMin.selector); - this.adjustUnredeemableTrove(A, troveIDs.A, 0, false, borrow_A, true); + this.adjustZombieTrove(A, troveIDs.A, 0, false, borrow_A, true); vm.expectRevert(BorrowerOperations.DebtBelowMin.selector); - this.adjustUnredeemableTrove(B, troveIDs.B, 0, false, borrow_B, true); + this.adjustZombieTrove(B, troveIDs.B, 0, false, borrow_B, true); } function testZombieTroveBorrowerCanNotRepayDebt() public { @@ -723,9 +860,9 @@ contract Redemptions is DevTestSetup { assertEq(troveManager.calcTroveAccruedInterest(troveIDs.A), 0); assertGt(troveManager.calcTroveAccruedInterest(troveIDs.B), 0); // Troves are zombie - assertTrue(troveManager.checkTroveIsUnredeemable(troveIDs.A)); + assertTrue(troveManager.checkTroveIsZombie(troveIDs.A)); assertFalse(sortedTroves.contains(troveIDs.A)); - assertTrue(troveManager.checkTroveIsUnredeemable(troveIDs.B)); + assertTrue(troveManager.checkTroveIsZombie(troveIDs.B)); assertFalse(sortedTroves.contains(troveIDs.B)); // E applies interest on A and B's Troves @@ -736,9 +873,9 @@ contract Redemptions is DevTestSetup { assertEq(troveManager.calcTroveAccruedInterest(troveIDs.B), 0); // Troves are still zombie - assertTrue(troveManager.checkTroveIsUnredeemable(troveIDs.A)); + assertTrue(troveManager.checkTroveIsZombie(troveIDs.A)); assertFalse(sortedTroves.contains(troveIDs.A)); - assertTrue(troveManager.checkTroveIsUnredeemable(troveIDs.B)); + assertTrue(troveManager.checkTroveIsZombie(troveIDs.B)); assertFalse(sortedTroves.contains(troveIDs.B)); } @@ -753,9 +890,9 @@ contract Redemptions is DevTestSetup { assertEq(troveManager.calcTroveAccruedInterest(troveIDs.A), 0); assertGt(troveManager.calcTroveAccruedInterest(troveIDs.B), 0); // Troves are zombie - assertTrue(troveManager.checkTroveIsUnredeemable(troveIDs.A)); + assertTrue(troveManager.checkTroveIsZombie(troveIDs.A)); assertFalse(sortedTroves.contains(troveIDs.A)); - assertTrue(troveManager.checkTroveIsUnredeemable(troveIDs.B)); + assertTrue(troveManager.checkTroveIsZombie(troveIDs.B)); assertFalse(sortedTroves.contains(troveIDs.B)); // E applies interest on A and B's Troves @@ -765,9 +902,9 @@ contract Redemptions is DevTestSetup { assertEq(troveManager.calcTroveAccruedInterest(troveIDs.A), 0); assertEq(troveManager.calcTroveAccruedInterest(troveIDs.B), 0); // Troves B is not zombie anymore (A still is) - assertTrue(troveManager.checkTroveIsUnredeemable(troveIDs.A)); + assertTrue(troveManager.checkTroveIsZombie(troveIDs.A)); assertFalse(sortedTroves.contains(troveIDs.A)); - assertFalse(troveManager.checkTroveIsUnredeemable(troveIDs.B)); + assertFalse(troveManager.checkTroveIsZombie(troveIDs.B)); assertTrue(sortedTroves.contains(troveIDs.B)); } @@ -791,7 +928,7 @@ contract Redemptions is DevTestSetup { // assertFalse(troveManager.checkBelowCriticalThreshold(price)); assertLt(troveManager.getCurrentICR(troveIDs.B, price), MCR); - assertEq(uint8(troveManager.getTroveStatus(troveIDs.B)), uint8(ITroveManager.Status.unredeemable)); + assertEq(uint8(troveManager.getTroveStatus(troveIDs.B)), uint8(ITroveManager.Status.zombie)); // E liquidates B liquidate(E, troveIDs.B); diff --git a/contracts/src/test/shutdown.t.sol b/contracts/src/test/shutdown.t.sol index 540297b9..1f7e677b 100644 --- a/contracts/src/test/shutdown.t.sol +++ b/contracts/src/test/shutdown.t.sol @@ -219,11 +219,11 @@ contract ShutdownTest is DevTestSetup { vm.stopPrank(); } - function testCannotAdjustUnredeemableTroveAfterShutdown() public { + function testCannotAdjustZombieTroveAfterShutdown() public { uint256 troveId = openMulticollateralTroveNoHints100pctWithIndex(0, A, 0, 11e18, 10000e18, 5e16); openMulticollateralTroveNoHints100pctWithIndex(0, B, 0, 22e18, 20000e18, 6e16); - // B redeems from A’s trove, to make it unredeemable + // B redeems from A’s trove, to make it zombie //deal(address(boldToken), B, 20000e18); vm.startPrank(B); collateralRegistry.redeemCollateral(10000e18, 0, 1e18); @@ -234,12 +234,12 @@ contract ShutdownTest is DevTestSetup { contractsArray[0].priceFeed.setPrice(500e18); contractsArray[0].borrowerOperations.shutdown(); - // Check A’s trove is unredeemable - assertEq(troveManager.checkTroveIsUnredeemable(troveId), true, "A trove should be unredeemable"); + // Check A’s trove is zombie + assertEq(troveManager.checkTroveIsZombie(troveId), true, "A trove should be zombie"); vm.startPrank(A); vm.expectRevert(BorrowerOperations.IsShutDown.selector); - borrowerOperations.adjustUnredeemableTrove(troveId, 1e18, true, 0, false, 0, 0, 1000e18); + borrowerOperations.adjustZombieTrove(troveId, 1e18, true, 0, false, 0, 0, 1000e18); vm.stopPrank(); } diff --git a/contracts/src/test/zapperGasComp.t.sol b/contracts/src/test/zapperGasComp.t.sol index 1a21afb7..4c5e41e6 100644 --- a/contracts/src/test/zapperGasComp.t.sol +++ b/contracts/src/test/zapperGasComp.t.sol @@ -307,7 +307,7 @@ contract ZapperGasCompTest is DevTestSetup { } // TODO: more adjustment combinations - function testCanAdjustUnredeemableTroveWithdrawCollAndBold() external { + function testCanAdjustZombieTroveWithdrawCollAndBold() external { uint256 collAmount1 = 10 ether; uint256 collAmount2 = 1 ether; uint256 boldAmount1 = 10000e18; @@ -335,7 +335,7 @@ contract ZapperGasCompTest is DevTestSetup { gasCompZapper.setRemoveManagerWithReceiver(troveId, B, A); vm.stopPrank(); - // Redeem to make trove unredeemable + // Redeem to make trove zombie vm.startPrank(A); collateralRegistry.redeemCollateral(boldAmount1 - boldAmount2, 10, 1e18); vm.stopPrank(); @@ -347,7 +347,7 @@ contract ZapperGasCompTest is DevTestSetup { // Adjust (withdraw coll and Bold) vm.startPrank(B); - gasCompZapper.adjustUnredeemableTroveWithRawETH( + gasCompZapper.adjustZombieTroveWithRawETH( troveId, collAmount2, false, boldAmount2, true, 0, 0, boldAmount2 ); vm.stopPrank(); diff --git a/contracts/src/test/zapperWETH.t.sol b/contracts/src/test/zapperWETH.t.sol index 78df9d3d..2d5bb28c 100644 --- a/contracts/src/test/zapperWETH.t.sol +++ b/contracts/src/test/zapperWETH.t.sol @@ -342,7 +342,7 @@ contract ZapperWETHTest is DevTestSetup { } // TODO: more adjustment combinations - function testCanAdjustUnredeemableTroveWithdrawCollAndBold() external { + function testCanAdjustZombieTroveWithdrawCollAndBold() external { uint256 ethAmount1 = 10 ether; uint256 ethAmount2 = 1 ether; uint256 boldAmount1 = 10000e18; @@ -369,7 +369,7 @@ contract ZapperWETHTest is DevTestSetup { wethZapper.setRemoveManagerWithReceiver(troveId, B, A); vm.stopPrank(); - // Redeem to make trove unredeemable + // Redeem to make trove zombie vm.startPrank(A); collateralRegistry.redeemCollateral(boldAmount1 - boldAmount2, 10, 1e18); vm.stopPrank(); @@ -381,7 +381,7 @@ contract ZapperWETHTest is DevTestSetup { // Adjust (withdraw coll and Bold) vm.startPrank(B); - wethZapper.adjustUnredeemableTroveWithRawETH(troveId, ethAmount2, false, boldAmount2, true, 0, 0, boldAmount2); + wethZapper.adjustZombieTroveWithRawETH(troveId, ethAmount2, false, boldAmount2, true, 0, 0, boldAmount2); vm.stopPrank(); assertEq(troveManager.getTroveEntireColl(troveId), troveCollBefore - ethAmount2, "Trove coll mismatch"); From 4c91464649b289942f64f4b3c4b72d28f563dc44 Mon Sep 17 00:00:00 2001 From: Daniel Simon Date: Thu, 19 Sep 2024 14:09:35 +0700 Subject: [PATCH 10/22] chore: the author's barely-disguised OCD --- contracts/src/test/Invariants.t.sol | 4 +- .../TestContracts/InvariantsTestHandler.t.sol | 120 +++++++++--------- 2 files changed, 64 insertions(+), 60 deletions(-) diff --git a/contracts/src/test/Invariants.t.sol b/contracts/src/test/Invariants.t.sol index 8b5f2ede..46e7ffb9 100644 --- a/contracts/src/test/Invariants.t.sol +++ b/contracts/src/test/Invariants.t.sol @@ -109,6 +109,7 @@ contract InvariantsTest is Logging, BaseInvariantTest, BaseMultiCollateralTest { TestDeployer.LiquityContractsDev memory c = branches[i]; assertEq(c.troveManager.getTroveIdsCount(), handler.numTroves(i), "Wrong number of Troves"); + assertEq(c.troveManager.lastZombieTroveId(), handler.designatedVictimId(i), "Wrong designated victim"); assertEq(c.sortedTroves.getSize(), handler.numTroves(i) - handler.numZombies(i), "Wrong SortedTroves size"); assertApproxEqAbsDecimal( c.activePool.calcPendingAggInterest(), handler.getPendingInterest(i), 1e-10 ether, 18, "Wrong interest" @@ -186,8 +187,7 @@ contract InvariantsTest is Logging, BaseInvariantTest, BaseMultiCollateralTest { ITroveManager.Status status = c.troveManager.getTroveStatus(troveId); assertTrue( - status == ITroveManager.Status.active || status == ITroveManager.Status.zombie, - "Unexpected status" + status == ITroveManager.Status.active || status == ITroveManager.Status.zombie, "Unexpected status" ); if (status == ITroveManager.Status.active) { diff --git a/contracts/src/test/TestContracts/InvariantsTestHandler.t.sol b/contracts/src/test/TestContracts/InvariantsTestHandler.t.sol index 14597f22..9a22bfe6 100644 --- a/contracts/src/test/TestContracts/InvariantsTestHandler.t.sol +++ b/contracts/src/test/TestContracts/InvariantsTestHandler.t.sol @@ -272,20 +272,6 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest { string errorString; } - struct RedemptionContext { - uint256 totalProportions; - uint256[] proportions; - uint256 remainingAmount; - uint256 troveId; - uint256 lastZombieTroveId; - uint256 j; - uint256 i; - uint256 debtRedeemed; - uint256 collRedeemedPlusFee; - uint256 fee; - uint256 collRedeemed; - } - struct LiquidationTotals { uint256 collGasComp; uint256 spCollGain; @@ -314,6 +300,7 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest { uint256 totalCollRedeemed; Redeemed[] redeemed; EnumerableAddressSet batchManagers; // batch managers touched by redemption + uint256 newDesignatedVictimId; } struct UrgentRedemptionTransientState { @@ -355,6 +342,7 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest { mapping(uint256 branchIdx => uint256) LIQ_PENALTY_REDIST; // Public ghost variables (per branch, exposed to InvariantsTest) + mapping(uint256 branchIdx => uint256) public designatedVictimId; // ID of zombie Trove that'll be redeemed first mapping(uint256 branchIdx => uint256) public collSurplus; mapping(uint256 branchIdx => uint256) public spBoldDeposits; mapping(uint256 branchIdx => uint256) public spBoldYield; @@ -814,6 +802,7 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest { v.trove.debt = v.trove.debt.add(v.debtDelta) + v.upfrontFee; _troves[i][v.troveId] = v.trove; _zombieTroveIds[i].remove(v.troveId); + if (designatedVictimId[i] == v.troveId) designatedVictimId[i] = 0; // Effects (batch) if (v.batchManager != address(0)) _touchBatch(i, v.batchManager); @@ -1028,6 +1017,7 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest { delete _timeSinceLastTroveInterestRateAdjustment[i][v.troveId]; _troveIds[i].remove(v.troveId); _zombieTroveIds[i].remove(v.troveId); + if (designatedVictimId[i] == v.troveId) designatedVictimId[i] = 0; // Effects (batch) if (v.batchManager != address(0)) { @@ -1126,6 +1116,7 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest { delete _timeSinceLastTroveInterestRateAdjustment[i][troveId]; _troveIds[i].remove(troveId); _zombieTroveIds[i].remove(troveId); + if (designatedVictimId[i] == troveId) designatedVictimId[i] = 0; if (batchManager != address(0)) _batches[i][batchManager].troves.remove(troveId); } @@ -1289,12 +1280,13 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest { _troves[j][redeemed.troveId] = trove; - uint256 troveDebt = branches[j].troveManager.getTroveEntireDebt(redeemed.troveId); - if (troveDebt < MIN_DEBT) { + if (branches[j].troveManager.getTroveEntireDebt(redeemed.troveId) < MIN_DEBT) { _zombieTroveIds[j].add(redeemed.troveId); } } + designatedVictimId[j] = r[j].newDesignatedVictimId; + // Effects (batches) for (uint256 i = 0; i < r[j].batchManagers.size(); ++i) { _touchBatch(j, r[j].batchManagers.get(i)); @@ -1524,7 +1516,11 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest { // Effects (Trove) v.trove.applyPending(); _troves[i][v.troveId] = v.trove; - if (v.t.entireDebt >= MIN_DEBT) _zombieTroveIds[i].remove(v.troveId); + + if (v.t.entireDebt >= MIN_DEBT) { + _zombieTroveIds[i].remove(v.troveId); + if (designatedVictimId[i] == v.troveId) designatedVictimId[i] = 0; + } // Effects (batch) if (v.batchManager != address(0)) _touchBatch(i, v.batchManager); @@ -2647,67 +2643,75 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest { delete _liquidation; } + function _planOneRedemption(uint256 i, uint256 troveId, uint256 remainingAmount, uint256 feePct) + internal + returns (uint256 debtRedeemed) + { + LatestTroveData memory trove = branches[i].troveManager.getLatestTroveData(troveId); + if (_ICR(i, trove) < _100pct) return 0; + + debtRedeemed = Math.min(remainingAmount, trove.entireDebt); + uint256 collRedeemedPlusFee = debtRedeemed * DECIMAL_PRECISION / _price[i]; + uint256 fee = collRedeemedPlusFee * feePct / _100pct; + uint256 collRedeemed = collRedeemedPlusFee - fee; + + mapping(uint256 branchIdx => RedemptionTransientState) storage r = _redemption; + r[i].redeemed.push(Redeemed({troveId: troveId, coll: collRedeemed, debt: debtRedeemed})); + r[i].totalCollRedeemed += collRedeemed; + + address batchManager = _batchManagerOf[i][troveId]; + if (batchManager != address(0)) r[i].batchManagers.add(batchManager); + + uint256 newDebt = trove.entireDebt - debtRedeemed; + r[i].newDesignatedVictimId = 0 < newDebt && newDebt < MIN_DEBT ? troveId : 0; + } + function _planRedemption(uint256 amount, uint256 maxIterationsPerCollateral, uint256 feePct) internal returns (uint256 totalDebtRedeemed, mapping(uint256 branchIdx => RedemptionTransientState) storage r) { - RedemptionContext memory vars; - vars.totalProportions = 0; - vars.proportions = new uint256[](branches.length); + uint256 totalProportions = 0; + uint256[] memory proportions = new uint256[](branches.length); r = _redemption; // Try in proportion to unbacked - for (vars.j = 0; vars.j < branches.length; ++vars.j) { - if (isShutdown[vars.j] || _TCR(vars.j) < SCR[vars.j]) continue; - vars.totalProportions += vars.proportions[vars.j] = _getUnbacked(vars.j); + for (uint256 i = 0; i < branches.length; ++i) { + if (isShutdown[i] || _TCR(i) < SCR[i]) continue; + totalProportions += proportions[i] = _getUnbacked(i); } // Fallback: in proportion to branch debt - if (vars.totalProportions == 0) { - for (vars.j = 0; vars.j < branches.length; ++vars.j) { - if (isShutdown[vars.j] || _TCR(vars.j) < SCR[vars.j]) continue; - vars.totalProportions += vars.proportions[vars.j] = _getTotalDebt(vars.j); + if (totalProportions == 0) { + for (uint256 i = 0; i < branches.length; ++i) { + if (isShutdown[i] || _TCR(i) < SCR[i]) continue; + totalProportions += proportions[i] = _getTotalDebt(i); } } - if (vars.totalProportions == 0) return (0, r); + if (totalProportions == 0) return (0, r); - for (vars.j = 0; vars.j < branches.length; ++vars.j) { - r[vars.j].attemptedAmount = amount * vars.proportions[vars.j] / vars.totalProportions; - if (r[vars.j].attemptedAmount == 0) continue; - - TestDeployer.LiquityContractsDev memory c = branches[vars.j]; - vars.remainingAmount = r[vars.j].attemptedAmount; - vars.troveId = 0; // "root node" ID - vars.lastZombieTroveId = c.troveManager.lastZombieTroveId(); + for (uint256 i = 0; i < branches.length; ++i) { + r[i].newDesignatedVictimId = designatedVictimId[i]; - for (vars.i = 0; vars.i < maxIterationsPerCollateral || maxIterationsPerCollateral == 0; ++vars.i) { - if (vars.remainingAmount == 0) break; + r[i].attemptedAmount = amount * proportions[i] / totalProportions; + if (r[i].attemptedAmount == 0) continue; - vars.troveId = vars.lastZombieTroveId != 0 ? vars.lastZombieTroveId : c.sortedTroves.getPrev(vars.troveId); - if (vars.troveId == 0) break; + uint256 remainingAmount = r[i].attemptedAmount; + uint256 lastTrove = branches[i].sortedTroves.getPrev(0); - LatestTroveData memory trove = c.troveManager.getLatestTroveData(vars.troveId); - if (_ICR(vars.j, trove) >= _100pct) { - vars.debtRedeemed = Math.min(vars.remainingAmount, trove.entireDebt); - vars.collRedeemedPlusFee = vars.debtRedeemed * DECIMAL_PRECISION / _price[vars.j]; - vars.fee = vars.collRedeemedPlusFee * feePct / _100pct; - vars.collRedeemed = vars.collRedeemedPlusFee - vars.fee; + (uint256 troveId, uint256 nextTroveId) = designatedVictimId[i] != 0 + ? (designatedVictimId[i], lastTrove) + : (lastTrove, branches[i].sortedTroves.getPrev(lastTrove)); - r[vars.j].redeemed.push(Redeemed({troveId: vars.troveId, coll: vars.collRedeemed, debt: vars.debtRedeemed})); + for (uint256 j = 0; j < maxIterationsPerCollateral || maxIterationsPerCollateral == 0; ++j) { + if (remainingAmount == 0 || troveId == 0) break; - address batchManager = _batchManagerOf[vars.j][vars.troveId]; - if (batchManager != address(0)) r[vars.j].batchManagers.add(batchManager); + uint256 debtRedeemed = _planOneRedemption(i, troveId, remainingAmount, feePct); + totalDebtRedeemed += debtRedeemed; + remainingAmount -= debtRedeemed; - r[vars.j].totalCollRedeemed += vars.collRedeemed; - totalDebtRedeemed += vars.debtRedeemed; - vars.remainingAmount -= vars.debtRedeemed; - } - - if (vars.lastZombieTroveId != 0) { - vars.lastZombieTroveId = 0; - vars.troveId = 0; - } + troveId = nextTroveId; + nextTroveId = branches[i].sortedTroves.getPrev(nextTroveId); } } } From f432021cc551b65e3cdfa2889381801445406225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Fingen?= Date: Thu, 19 Sep 2024 10:48:28 +0100 Subject: [PATCH 11/22] chore: forge fmt --- contracts/src/NFTMetadata/MetadataNFT.sol | 2 - contracts/src/NFTMetadata/utils/JSON.sol | 26 +-- contracts/src/scripts/DeployLiquity2.s.sol | 13 +- .../src/test/AnchoredInvariantsTest.t.sol | 185 +++++++++++++++--- contracts/src/test/Utils/TroveId.sol | 1 - contracts/src/test/redemptions.t.sol | 17 +- contracts/src/test/troveNFT.t.sol | 39 ++-- contracts/src/test/zapperGasComp.t.sol | 4 +- 8 files changed, 212 insertions(+), 75 deletions(-) diff --git a/contracts/src/NFTMetadata/MetadataNFT.sol b/contracts/src/NFTMetadata/MetadataNFT.sol index 73a2f5ca..73b65f52 100644 --- a/contracts/src/NFTMetadata/MetadataNFT.sol +++ b/contracts/src/NFTMetadata/MetadataNFT.sol @@ -66,8 +66,6 @@ contract MetadataNFT is IMetadataNFT { _status2Str(_troveData._status), '"} ]' ); - - } function dynamicTextComponents(TroveData memory _troveData) public view returns (string memory) { diff --git a/contracts/src/NFTMetadata/utils/JSON.sol b/contracts/src/NFTMetadata/utils/JSON.sol index 404009b9..9fd422b1 100644 --- a/contracts/src/NFTMetadata/utils/JSON.sol +++ b/contracts/src/NFTMetadata/utils/JSON.sol @@ -10,21 +10,25 @@ library json { string constant DOUBLE_QUOTES = '\\"'; - function formattedMetadata(string memory name, string memory description, string memory svgImg, string memory attributes) - internal - pure - returns (string memory) - { + function formattedMetadata( + string memory name, + string memory description, + string memory svgImg, + string memory attributes + ) internal pure returns (string memory) { return string.concat( "data:application/json;base64,", encode( bytes( - string.concat("{", _prop("name", name), - _prop("description", description), - _xmlImage(svgImg), - ',"attributes":', - attributes, - "}") + string.concat( + "{", + _prop("name", name), + _prop("description", description), + _xmlImage(svgImg), + ',"attributes":', + attributes, + "}" + ) ) ) ); diff --git a/contracts/src/scripts/DeployLiquity2.s.sol b/contracts/src/scripts/DeployLiquity2.s.sol index 0967dbfc..5508898e 100644 --- a/contracts/src/scripts/DeployLiquity2.s.sol +++ b/contracts/src/scripts/DeployLiquity2.s.sol @@ -478,19 +478,12 @@ contract DeployLiquity2Script is Script, StdCheats, MetadataDeployment { // deploy zappers (contracts.gasCompZapper, contracts.wethZapper) = - _deployZappers(contracts.addressesRegistry, contracts.collToken, _weth); + _deployZappers(contracts.addressesRegistry, contracts.collToken, _weth); } - function _deployZappers( - IAddressesRegistry _addressesRegistry, - IERC20 _collToken, - IWETH _weth - ) + function _deployZappers(IAddressesRegistry _addressesRegistry, IERC20 _collToken, IWETH _weth) internal - returns ( - GasCompZapper gasCompZapper, - WETHZapper wethZapper - ) + returns (GasCompZapper gasCompZapper, WETHZapper wethZapper) { bool lst = _collToken != _weth; if (lst) { diff --git a/contracts/src/test/AnchoredInvariantsTest.t.sol b/contracts/src/test/AnchoredInvariantsTest.t.sol index b1755bd0..e45f3cb9 100644 --- a/contracts/src/test/AnchoredInvariantsTest.t.sol +++ b/contracts/src/test/AnchoredInvariantsTest.t.sol @@ -499,7 +499,14 @@ contract AnchoredInvariantsTest is Logging, BaseInvariantTest, BaseMultiCollater handler.addMeToUrgentRedemptionBatch(); vm.prank(adam); - handler.registerBatchManager(3, 0.100944149373120884 ether, 0.377922952132481818 ether, 0.343424998629201343 ether, 0.489955880173256455 ether, 2070930); + handler.registerBatchManager( + 3, + 0.100944149373120884 ether, + 0.377922952132481818 ether, + 0.343424998629201343 ether, + 0.489955880173256455 ether, + 2070930 + ); vm.prank(carl); handler.addMeToLiquidationBatch(); @@ -508,7 +515,14 @@ contract AnchoredInvariantsTest is Logging, BaseInvariantTest, BaseMultiCollater handler.warp(9_303_785); vm.prank(barb); - handler.registerBatchManager(1, 0.301964103682871801 ether, 0.756908371280377546 ether, 0.540898165697757771 ether, 0.000017102564306416 ether, 27657915); + handler.registerBatchManager( + 1, + 0.301964103682871801 ether, + 0.756908371280377546 ether, + 0.540898165697757771 ether, + 0.000017102564306416 ether, + 27657915 + ); vm.prank(fran); handler.addMeToLiquidationBatch(); @@ -523,7 +537,9 @@ contract AnchoredInvariantsTest is Logging, BaseInvariantTest, BaseMultiCollater // lower hint: 36051278007718023196469061266077621121244014979449590376694871896669965056265 // upfront fee: 118.231198854524639989 ether vm.prank(gabe); - handler.openTrove(1, 7_591.289850943621327156 ether, 1.900000000017470971 ether, 0.812103428106344175 ether, 1121, 415425919); + handler.openTrove( + 1, 7_591.289850943621327156 ether, 1.900000000017470971 ether, 0.812103428106344175 ether, 1121, 415425919 + ); // redemption rate: 0.005000000000000004 ether // redeemed BOLD: 0.000000000000071705 ether @@ -551,10 +567,24 @@ contract AnchoredInvariantsTest is Logging, BaseInvariantTest, BaseMultiCollater handler.warp(11_371_761); vm.prank(gabe); - handler.registerBatchManager(0, 0.23834235868248997 ether, 0.761711006198436234 ether, 0.523368647516059893 ether, 0.761688376122671962 ether, 31535998); + handler.registerBatchManager( + 0, + 0.23834235868248997 ether, + 0.761711006198436234 ether, + 0.523368647516059893 ether, + 0.761688376122671962 ether, + 31535998 + ); vm.prank(hope); - handler.registerBatchManager(2, 0.036127532604869915 ether, 0.999999999999999999 ether, 0.963882428861225203 ether, 0.848537401570757863 ether, 29802393); + handler.registerBatchManager( + 2, + 0.036127532604869915 ether, + 0.999999999999999999 ether, + 0.963882428861225203 ether, + 0.848537401570757863 ether, + 29802393 + ); vm.prank(eric); handler.addMeToUrgentRedemptionBatch(); @@ -564,10 +594,19 @@ contract AnchoredInvariantsTest is Logging, BaseInvariantTest, BaseMultiCollater // lower hint: 37857035535383668733402580992354953018471987882089934484705744026840633200601 // upfront fee: 1_355.203530437779650125 ether vm.prank(carl); - handler.openTroveAndJoinInterestBatchManager(2, 73_312.036791249214758342 ether, 1.900020510596646286 ether, 40, 115, 737); + handler.openTroveAndJoinInterestBatchManager( + 2, 73_312.036791249214758342 ether, 1.900020510596646286 ether, 40, 115, 737 + ); vm.prank(barb); - handler.registerBatchManager(0, 0.955741837871335122 ether, 0.974535636428930833 ether, 0.964294359297779033 ether, 0.000000000000268875 ether, 3335617); + handler.registerBatchManager( + 0, + 0.955741837871335122 ether, + 0.974535636428930833 ether, + 0.964294359297779033 ether, + 0.000000000000268875 ether, + 3335617 + ); vm.prank(gabe); handler.addMeToLiquidationBatch(); @@ -586,7 +625,9 @@ contract AnchoredInvariantsTest is Logging, BaseInvariantTest, BaseMultiCollater // lower hint: 27989025468780058605431608942843597971189459457295957311648808450848491056535 // upfront fee: 166.681364294341638522 ether vm.prank(carl); - handler.openTroveAndJoinInterestBatchManager(3, 25_307.541971224954454066 ether, 2.401194840294921108 ether, 142, 6432363, 25223); + handler.openTroveAndJoinInterestBatchManager( + 3, 25_307.541971224954454066 ether, 2.401194840294921108 ether, 142, 6432363, 25223 + ); vm.prank(carl); handler.addMeToUrgentRedemptionBatch(); @@ -640,7 +681,17 @@ contract AnchoredInvariantsTest is Logging, BaseInvariantTest, BaseMultiCollater // upfront fee: 0 ether // function: adjustZombieTrove() vm.prank(gabe); - handler.adjustTrove(1, uint8(AdjustedTroveProperties.onlyColl), 29.524853479148084596 ether, true, 0 ether, true, 40, 14, 4554760); + handler.adjustTrove( + 1, + uint8(AdjustedTroveProperties.onlyColl), + 29.524853479148084596 ether, + true, + 0 ether, + true, + 40, + 14, + 4554760 + ); info("SortedTroves size: ", c.sortedTroves.getSize().toString()); info("num troves: ", handler.numTroves(i).toString()); @@ -651,13 +702,29 @@ contract AnchoredInvariantsTest is Logging, BaseInvariantTest, BaseMultiCollater // lower hint: 74750724351164404027318726202729770837051588626953680774538886892291438048970 // upfront fee: 773.037543760336600445 ether vm.prank(carl); - handler.openTrove(0, 40_510.940914935073773948 ether, 2.063402456659389908 ether, 0.995000000000000248 ether, 0, 55487655); + handler.openTrove( + 0, 40_510.940914935073773948 ether, 2.063402456659389908 ether, 0.995000000000000248 ether, 0, 55487655 + ); vm.prank(adam); - handler.registerBatchManager(0, 0.541865737266494949 ether, 0.672692246806001449 ether, 0.650860934960147488 ether, 0.070089828074852802 ether, 29179158); + handler.registerBatchManager( + 0, + 0.541865737266494949 ether, + 0.672692246806001449 ether, + 0.650860934960147488 ether, + 0.070089828074852802 ether, + 29179158 + ); vm.prank(fran); - handler.registerBatchManager(1, 0.566980989185701648 ether, 0.86881504225021711 ether, 0.702666683322997409 ether, 0.667232273668645041 ether, 7007521); + handler.registerBatchManager( + 1, + 0.566980989185701648 ether, + 0.86881504225021711 ether, + 0.702666683322997409 ether, + 0.667232273668645041 ether, + 7007521 + ); vm.prank(dana); handler.addMeToUrgentRedemptionBatch(); @@ -703,7 +770,14 @@ contract AnchoredInvariantsTest is Logging, BaseInvariantTest, BaseMultiCollater handler.addMeToUrgentRedemptionBatch(); vm.prank(hope); - handler.registerBatchManager(0, 0.99500000000072184 ether, 0.996944021609020651 ether, 0.99533906344899454 ether, 0.378970428480541887 ether, 314055); + handler.registerBatchManager( + 0, + 0.99500000000072184 ether, + 0.996944021609020651 ether, + 0.99533906344899454 ether, + 0.378970428480541887 ether, + 314055 + ); vm.prank(dana); handler.warp(2_225_439); @@ -715,10 +789,24 @@ contract AnchoredInvariantsTest is Logging, BaseInvariantTest, BaseMultiCollater handler.addMeToUrgentRedemptionBatch(); vm.prank(barb); - handler.registerBatchManager(2, 0.995000000000009379 ether, 0.999999999998128142 ether, 0.997477804125778004 ether, 0.000000001035389259 ether, 10046); + handler.registerBatchManager( + 2, + 0.995000000000009379 ether, + 0.999999999998128142 ether, + 0.997477804125778004 ether, + 0.000000001035389259 ether, + 10046 + ); vm.prank(gabe); - handler.registerBatchManager(2, 0.346476084765605513 ether, 0.346476084765605514 ether, 0.346476084765605514 ether, 0.000000000000000002 ether, 27010346); + handler.registerBatchManager( + 2, + 0.346476084765605513 ether, + 0.346476084765605514 ether, + 0.346476084765605514 ether, + 0.000000000000000002 ether, + 27010346 + ); vm.prank(fran); handler.warp(19_697_329); @@ -727,7 +815,14 @@ contract AnchoredInvariantsTest is Logging, BaseInvariantTest, BaseMultiCollater handler.addMeToUrgentRedemptionBatch(); vm.prank(fran); - handler.registerBatchManager(1, 0.995000000000019257 ether, 0.999999999996150378 ether, 0.999999999226237651 ether, 0.696688179568702502 ether, 7641047); + handler.registerBatchManager( + 1, + 0.995000000000019257 ether, + 0.999999999996150378 ether, + 0.999999999226237651 ether, + 0.696688179568702502 ether, + 7641047 + ); vm.prank(gabe); handler.warp(977_685); @@ -743,7 +838,9 @@ contract AnchoredInvariantsTest is Logging, BaseInvariantTest, BaseMultiCollater // lower hint: 60678094901167127062962700790111047491633904950610080336398562382189456360809 // upfront fee: 242.684833433337541236 ether vm.prank(gabe); - handler.openTroveAndJoinInterestBatchManager(1, 12_654.280610244006254376 ether, 2.145058504746006382 ether, 182, 22444926, 124118903); + handler.openTroveAndJoinInterestBatchManager( + 1, 12_654.280610244006254376 ether, 2.145058504746006382 ether, 182, 22444926, 124118903 + ); // redemption rate: 0.005 ether // redeemed BOLD: 0.000000000000017162 ether @@ -764,7 +861,9 @@ contract AnchoredInvariantsTest is Logging, BaseInvariantTest, BaseMultiCollater // lower hint: 0 // upfront fee: 624.393448965513162837 ether vm.prank(hope); - handler.openTrove(0, 32_721.264734011072612096 ether, 2.333153121000516764 ether, 0.995000000000109949 ether, 52719, 31482); + handler.openTrove( + 0, 32_721.264734011072612096 ether, 2.333153121000516764 ether, 0.995000000000109949 ether, 52719, 31482 + ); // price: 244.435094708283018275 ether vm.prank(dana); @@ -798,7 +897,9 @@ contract AnchoredInvariantsTest is Logging, BaseInvariantTest, BaseMultiCollater // lower hint: hope // upfront fee: 45.851924869044942133 ether vm.prank(carl); - handler.openTrove(0, 3_111.607048463492852195 ether, 1.16895262626418546 ether, 0.142852735597140811 ether, 1885973, 10937); + handler.openTrove( + 0, 3_111.607048463492852195 ether, 1.16895262626418546 ether, 0.142852735597140811 ether, 1885973, 10937 + ); // upper hint: 2646484967802154597987056038088487662712072023062744056283555991417410575365 // lower hint: 20207836743015961388089283396921182522044498153231052202943306959004515414684 @@ -807,7 +908,9 @@ contract AnchoredInvariantsTest is Logging, BaseInvariantTest, BaseMultiCollater info("gabe trove Id: ", addressToTroveId(gabe).toString()); info("gabe debt: ", c.troveManager.getTroveEntireDebt(addressToTroveId(gabe)).decimal()); vm.prank(gabe); - handler.adjustTrove(1, uint8(AdjustedTroveProperties.onlyColl), 3.631424438531681645 ether, true, 0 ether, false, 86, 703, 9499); + handler.adjustTrove( + 1, uint8(AdjustedTroveProperties.onlyColl), 3.631424438531681645 ether, true, 0 ether, false, 86, 703, 9499 + ); info("gabe trove Id: ", addressToTroveId(gabe).toString()); info("gabe debt: ", c.troveManager.getTroveEntireDebt(addressToTroveId(gabe)).decimal()); @@ -845,7 +948,9 @@ contract AnchoredInvariantsTest is Logging, BaseInvariantTest, BaseMultiCollater handler.addMeToUrgentRedemptionBatch(); vm.prank(dana); - handler.registerBatchManager(1, 0.995000000000001129 ether, 1 ether, 0.999999999999799729 ether, 0.000000000000000001 ether, 31535999); + handler.registerBatchManager( + 1, 0.995000000000001129 ether, 1 ether, 0.999999999999799729 ether, 0.000000000000000001 ether, 31535999 + ); // redemption rate: 0.718476929948594246 ether // redeemed BOLD: 5_431.066474911544502914 ether @@ -871,7 +976,14 @@ contract AnchoredInvariantsTest is Logging, BaseInvariantTest, BaseMultiCollater info("gabe rec debt: ", c.troveManager.getTroveDebt(addressToTroveId(gabe)).decimal()); info("lzti: ", c.troveManager.lastZombieTroveId().toString()); vm.prank(gabe); - handler.registerBatchManager(1, 0.995000000000002877 ether, 0.999999999999430967 ether, 0.996456350847225481 ether, 0.000000001322368348 ether, 14343); + handler.registerBatchManager( + 1, + 0.995000000000002877 ether, + 0.999999999999430967 ether, + 0.996456350847225481 ether, + 0.000000001322368348 ether, + 14343 + ); info("gabe ent debt 1: ", c.troveManager.getTroveEntireDebt(addressToTroveId(gabe)).decimal()); info("gabe rec debt 1: ", c.troveManager.getTroveDebt(addressToTroveId(gabe)).decimal()); @@ -906,21 +1018,40 @@ contract AnchoredInvariantsTest is Logging, BaseInvariantTest, BaseMultiCollater // lower hint: carl // upfront fee: 297.236383200558451701 ether vm.prank(barb); - handler.openTrove(0, 69_695.596747080749922615 ether, 1.900000000000006402 ether, 0.153255449436557929 ether, 1498297936, 1276315316); + handler.openTrove( + 0, + 69_695.596747080749922615 ether, + 1.900000000000006402 ether, + 0.153255449436557929 ether, + 1498297936, + 1276315316 + ); // upper hint: 0 // lower hint: 30960623452289762463130736603892188849115197753010878244835568881362241800197 // upfront fee: 56.245103106642574315 ether // function: withdrawBold() vm.prank(hope); - handler.adjustTrove(0, uint8(AdjustedTroveProperties.onlyDebt), 0 ether, false, 7_875.177407392532383015 ether, true, 5, 16648, 270); + handler.adjustTrove( + 0, + uint8(AdjustedTroveProperties.onlyDebt), + 0 ether, + false, + 7_875.177407392532383015 ether, + true, + 5, + 16648, + 270 + ); // batch manager: gabe // upper hint: gabe // lower hint: 0 // upfront fee: 1_261.275141740191589507 ether vm.prank(adam); - handler.openTroveAndJoinInterestBatchManager(1, 66_969.454138225567397381 ether, 2.984784797753777921 ether, 4294967294, 1, 52); + handler.openTroveAndJoinInterestBatchManager( + 1, 66_969.454138225567397381 ether, 2.984784797753777921 ether, 4294967294, 1, 52 + ); info("gabe ent debt 2: ", c.troveManager.getTroveEntireDebt(addressToTroveId(gabe)).decimal()); info("gabe rec debt 2: ", c.troveManager.getTroveDebt(addressToTroveId(gabe)).decimal()); @@ -929,7 +1060,9 @@ contract AnchoredInvariantsTest is Logging, BaseInvariantTest, BaseMultiCollater // lower hint: barb // upfront fee: 1_272.067039116734276271 ether vm.prank(eric); - handler.openTroveAndJoinInterestBatchManager(0, 96_538.742068715532219745 ether, 2.762063859567414329 ether, 0, 61578232, 336273331); + handler.openTroveAndJoinInterestBatchManager( + 0, 96_538.742068715532219745 ether, 2.762063859567414329 ether, 0, 61578232, 336273331 + ); // initial deposit: 6_184.412833814428802676 ether // compounded deposit: 6_184.412833814428802676 ether diff --git a/contracts/src/test/Utils/TroveId.sol b/contracts/src/test/Utils/TroveId.sol index 7cb0a939..fef9f3e8 100644 --- a/contracts/src/test/Utils/TroveId.sol +++ b/contracts/src/test/Utils/TroveId.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.18; - contract TroveId { function addressToTroveId(address _owner, uint256 _ownerIndex) public pure returns (uint256) { return uint256(keccak256(abi.encode(_owner, _ownerIndex))); diff --git a/contracts/src/test/redemptions.t.sol b/contracts/src/test/redemptions.t.sol index c004e3c8..85c8b2cc 100644 --- a/contracts/src/test/redemptions.t.sol +++ b/contracts/src/test/redemptions.t.sol @@ -452,7 +452,11 @@ contract Redemptions is DevTestSetup { closeTrove(B, troveIDs.B); // Check B is closed - assertEq(uint8(troveManager.getTroveStatus(troveIDs.B)), uint8(ITroveManager.Status.closedByOwner), "B trove should be closed"); + assertEq( + uint8(troveManager.getTroveStatus(troveIDs.B)), + uint8(ITroveManager.Status.closedByOwner), + "B trove should be closed" + ); // Check last Zombie trove pointer assertEq(troveManager.lastZombieTroveId(), 0, "Wrong last zombie trove pointer after"); @@ -467,12 +471,19 @@ contract Redemptions is DevTestSetup { assertEq(troveManager.lastZombieTroveId(), troveIDs.B, "Wrong last zombie trove pointer before"); // Liquidate B - console2.log(troveManager.getCurrentICR(troveIDs.B, priceFeed.getPrice()), "troveManager.getCurrentICR(troveIDs.E, price)"); + console2.log( + troveManager.getCurrentICR(troveIDs.B, priceFeed.getPrice()), + "troveManager.getCurrentICR(troveIDs.E, price)" + ); priceFeed.setPrice(priceFeed.getPrice() / 25); liquidate(A, troveIDs.B); // Check B is liquidated - assertEq(uint8(troveManager.getTroveStatus(troveIDs.B)), uint8(ITroveManager.Status.closedByLiquidation), "B trove should be liquidated"); + assertEq( + uint8(troveManager.getTroveStatus(troveIDs.B)), + uint8(ITroveManager.Status.closedByLiquidation), + "B trove should be liquidated" + ); // Check last Zombie trove pointer assertEq(troveManager.lastZombieTroveId(), 0, "Wrong last zombie trove pointer after"); diff --git a/contracts/src/test/troveNFT.t.sol b/contracts/src/test/troveNFT.t.sol index 41189358..9079e7c6 100644 --- a/contracts/src/test/troveNFT.t.sol +++ b/contracts/src/test/troveNFT.t.sol @@ -41,24 +41,25 @@ contract troveNFTTest is DevTestSetup { string memory uri = troveNFT.tokenURI(troveId); - emit log_string(uri); - - /** TODO: validate each individual attribute, or manually make a json and validate it all at once - // Check for expected attributes - assertTrue(LibString.contains(uri, '"trait_type": "Collateral Token"'), "Collateral Token attribute missing"); - assertTrue(LibString.contains(uri, '"trait_type": "Collateral Amount"'), "Collateral Amount attribute missing"); - assertTrue(LibString.contains(uri, '"trait_type": "Debt Token"'), "Debt Token attribute missing"); - assertTrue(LibString.contains(uri, '"trait_type": "Debt Amount"'), "Debt Amount attribute missing"); - assertTrue(LibString.contains(uri, '"trait_type": "Interest Rate"'), "Interest Rate attribute missing"); - assertTrue(LibString.contains(uri, '"trait_type": "Status"'), "Status attribute missing"); - - // Check for expected values - //assertTrue(LibString.contains(uri, string.concat('"value": "', Strings.toHexString(address(collateral)))), "Incorrect Collateral Token value"); - assertTrue(LibString.contains(uri, '"value": "2000000000000000000"'), "Incorrect Collateral Amount value"); - assertTrue(LibString.contains(uri, string.concat('"value": "', Strings.toHexString(address(boldToken)))), "Incorrect Debt Token value"); - assertTrue(LibString.contains(uri, '"value": "1000000000000000000000"'), "Incorrect Debt Amount value"); - assertTrue(LibString.contains(uri, '"value": "5000000000000000"'), "Incorrect Interest Rate value"); - assertTrue(LibString.contains(uri, '"value": "Active"'), "Incorrect Status value"); - */ + emit log_string(uri); + + /** + * TODO: validate each individual attribute, or manually make a json and validate it all at once + * // Check for expected attributes + * assertTrue(LibString.contains(uri, '"trait_type": "Collateral Token"'), "Collateral Token attribute missing"); + * assertTrue(LibString.contains(uri, '"trait_type": "Collateral Amount"'), "Collateral Amount attribute missing"); + * assertTrue(LibString.contains(uri, '"trait_type": "Debt Token"'), "Debt Token attribute missing"); + * assertTrue(LibString.contains(uri, '"trait_type": "Debt Amount"'), "Debt Amount attribute missing"); + * assertTrue(LibString.contains(uri, '"trait_type": "Interest Rate"'), "Interest Rate attribute missing"); + * assertTrue(LibString.contains(uri, '"trait_type": "Status"'), "Status attribute missing"); + * + * // Check for expected values + * //assertTrue(LibString.contains(uri, string.concat('"value": "', Strings.toHexString(address(collateral)))), "Incorrect Collateral Token value"); + * assertTrue(LibString.contains(uri, '"value": "2000000000000000000"'), "Incorrect Collateral Amount value"); + * assertTrue(LibString.contains(uri, string.concat('"value": "', Strings.toHexString(address(boldToken)))), "Incorrect Debt Token value"); + * assertTrue(LibString.contains(uri, '"value": "1000000000000000000000"'), "Incorrect Debt Amount value"); + * assertTrue(LibString.contains(uri, '"value": "5000000000000000"'), "Incorrect Interest Rate value"); + * assertTrue(LibString.contains(uri, '"value": "Active"'), "Incorrect Status value"); + */ } } diff --git a/contracts/src/test/zapperGasComp.t.sol b/contracts/src/test/zapperGasComp.t.sol index 4c5e41e6..9db79bda 100644 --- a/contracts/src/test/zapperGasComp.t.sol +++ b/contracts/src/test/zapperGasComp.t.sol @@ -347,9 +347,7 @@ contract ZapperGasCompTest is DevTestSetup { // Adjust (withdraw coll and Bold) vm.startPrank(B); - gasCompZapper.adjustZombieTroveWithRawETH( - troveId, collAmount2, false, boldAmount2, true, 0, 0, boldAmount2 - ); + gasCompZapper.adjustZombieTroveWithRawETH(troveId, collAmount2, false, boldAmount2, true, 0, 0, boldAmount2); vm.stopPrank(); assertEq(troveManager.getTroveEntireColl(troveId), troveCollBefore - collAmount2, "Trove coll mismatch"); From 3d7d4ce1039ee171d9efe96cf2ecab863eecd88e Mon Sep 17 00:00:00 2001 From: RickGriff <32799176+RickGriff@users.noreply.github.com> Date: Thu, 19 Sep 2024 13:12:17 +0100 Subject: [PATCH 12/22] Update README.md --- README.md | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 8ac9da3b..b0ec6a0e 100644 --- a/README.md +++ b/README.md @@ -1210,8 +1210,8 @@ When `lastGoodPrice` is used to price the LST, the _real_ market price may be hi | Scenario | Consequence | |------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------| -| lastGoodPrice > market price | Urgent redemptions return too little LST collateral, and may be unprofitable even when BOLD trades at $1 or below | -| lastGoodPrice < market price | Urgent redemptions return too much LST collateral. They may be too profitable, compared to the market price. | +| lastGoodPrice > real market price | Urgent redemptions return too little LST collateral, and may be unprofitable even when BOLD trades at $1 or below | +| lastGoodPrice < real market price | Urgent redemptions return too much LST collateral. They may be too profitable, compared to the market price. | #### Solution @@ -1226,15 +1226,25 @@ If the primary oracle setup fails on a given LST branch, then using `lastGoodPri However, a fallback price utilizing the ETH-USD price and the LST's canonical rate could be used. The proposed fallback price calculation for each branch is here: -| Collateral | Primary price calc | Fallback price calc | -|------------|----------------------------------------------------------------|--------------------------------------------| -| WETH | ETH-USD | lastGoodPrice | -| WSTETH | STETH-USD * WSTETH-STETH_canonical | ETH-USD * WSTETH-STETH_canonical | -| RETH | min(ETH-USD * RETH-ETH, ETH-USD * RETH-ETH_canonical) | ETH-USD * RETH-ETH_canonical | +| Collateral | Primary price calc | Fallback if LST market oracle fails | Fallback if ETH-USD market oracle fails | Fallback if canonical rate fails | +|------------|---------------------------------------------------------|------------------------------------------------------------|-----------------------------------------|----------------------------------| +| WETH | ETH-USD | N/A | lastGoodPrice | N/A | +| WSTETH | STETH-USD * WSTETH-STETH_canonical | min(lastGoodPrice, ETH-USD * WSTETH-STETH_canonical) | lastGoodPrice | lastGoodPrice | +| RETH | min(ETH-USD * RETH-ETH, ETH-USD * RETH-ETH_canonical) | min(lastGoodPrice, ETH-USD * RETH-ETH_canonical) | lastGoodPrice | lastGoodPrice | -During shutdown no borrower ops are allowed, so the main risk of a manipulated canonical rate (inflated price and excess BOLD minting) is eliminated, and it will be safe to use the canonical rate in conjunction with ETH-USD. -Additionally, if the _ETH-USD_ oracle fails after shut down, then the LST PriceFeed should finally switch to the `lastGoodPrice`, and the branch remains shut down. +## Primary LST feed failure + +During shutdown no borrower ops are allowed, so the main risk of a manipulated canonical rate (inflated price and excess BOLD minting) is eliminated. However, in this case we still take a minimum: `min(lastGoodPrice, ETH-USD * canonical_rate)`. This ensures that if the canonical rate is also manipulated up, we still give urgent redemptions a chance of being profitable (and clearing bad debt) with the `lastGoodPrice`. + +## Canonical rate failure +The LST canonical exchange rate is used in all calculations on all PriceFeeds. If it fails, the branch falls back to using the `lastGoodPrice`, and the branch gets shut down if it is live. If the canonical rate fails _after_ shut down, then the LST PriceFeed switches `lastGoodPrice` and the branch remains shut down. When calling the LST contract externally to fetch the canonical rate, failure is defined as: + +- The returned rate is 0, or +- The external call reverts + +## ETH-USD feed failure +The ETH-USD market oracle is used in all calculations on all PriceFeeds. If it fails, the branch falls back to using the `lastGoodPrice`, and the branch gets shut down if it is live. If the ETH-USD oracle fails _after_ shut down, then the LST PriceFeed switches `lastGoodPrice` and the branch remains shut down. The full logic is implemented in this PR: https://github.com/liquity/bold/pull/393 From a2fcb51508529036378b72187a895eb4b21a7a5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Fingen?= Date: Fri, 20 Sep 2024 10:56:37 +0100 Subject: [PATCH 13/22] fix: Allow owner to set any interest rate even if trove has delegate --- contracts/src/BorrowerOperations.sol | 22 ++++++++++--------- .../test/interestIndividualDelegation.t.sol | 16 ++++++++++++++ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/contracts/src/BorrowerOperations.sol b/contracts/src/BorrowerOperations.sol index 322b6f2a..d1478df0 100644 --- a/contracts/src/BorrowerOperations.sol +++ b/contracts/src/BorrowerOperations.sol @@ -520,7 +520,7 @@ contract BorrowerOperations is LiquityBase, AddRemoveManagers, IBorrowerOperatio _requireIsNotInBatch(_troveId); address owner = troveNFT.ownerOf(_troveId); _requireSenderIsOwnerOrInterestManager(_troveId, owner); - _requireInterestRateInDelegateRange(_troveId, _newAnnualInterestRate); + _requireInterestRateInDelegateRange(_troveId, _newAnnualInterestRate, owner); _requireTroveIsActive(troveManagerCached, _troveId); LatestTroveData memory trove = troveManagerCached.getLatestTroveData(_troveId); @@ -1287,6 +1287,17 @@ contract BorrowerOperations is LiquityBase, AddRemoveManagers, IBorrowerOperatio } } + function _requireInterestRateInDelegateRange(uint256 _troveId, uint256 _annualInterestRate, address _owner) internal view { + InterestIndividualDelegate memory individualDelegate = interestIndividualDelegateOf[_troveId]; + // We have previously checked that sender is either owner or delegate + // If it’s owner, this restriction doesn’t apply + if (individualDelegate.account == msg.sender) { + _requireInterestRateInRange( + _annualInterestRate, individualDelegate.minInterestRate, individualDelegate.maxInterestRate + ); + } + } + function _requireIsNotInBatch(uint256 _troveId) internal view { if (interestBatchManagerOf[_troveId] != address(0)) { revert TroveInBatch(); @@ -1442,15 +1453,6 @@ contract BorrowerOperations is LiquityBase, AddRemoveManagers, IBorrowerOperatio if (_minInterestRate >= _maxInterestRate) revert MinGeMax(); } - function _requireInterestRateInDelegateRange(uint256 _troveId, uint256 _annualInterestRate) internal view { - InterestIndividualDelegate memory individualDelegate = interestIndividualDelegateOf[_troveId]; - if (individualDelegate.account != address(0)) { - _requireInterestRateInRange( - _annualInterestRate, individualDelegate.minInterestRate, individualDelegate.maxInterestRate - ); - } - } - function _requireInterestRateInBatchManagerRange(address _interestBatchManagerAddress, uint256 _annualInterestRate) internal view diff --git a/contracts/src/test/interestIndividualDelegation.t.sol b/contracts/src/test/interestIndividualDelegation.t.sol index dad517b0..f8a8c5b1 100644 --- a/contracts/src/test/interestIndividualDelegation.t.sol +++ b/contracts/src/test/interestIndividualDelegation.t.sol @@ -102,6 +102,22 @@ contract InterestIndividualDelegationTest is DevTestSetup { vm.stopPrank(); } + function testOwnerCanSetInterestBelowMin() public { + uint256 troveId = openTroveAndSetIndividualDelegate(); + + vm.startPrank(A); + borrowerOperations.adjustTroveInterestRate(troveId, MIN_ANNUAL_INTEREST_RATE, 0, 0, 1e24); + vm.stopPrank(); + } + + function testOwnerCanSetInterestAboveMax() public { + uint256 troveId = openTroveAndSetIndividualDelegate(); + + vm.startPrank(A); + borrowerOperations.adjustTroveInterestRate(troveId, 50e16, 0, 0, 1e24); + vm.stopPrank(); + } + function testSetDelegateRevertsIfTroveIsClosed() public { vm.startPrank(B); borrowerOperations.registerBatchManager(1e16, 20e16, 5e16, 25e14, MIN_INTEREST_RATE_CHANGE_PERIOD); From 095e4b9494fbca23ef27d6921bb74522f31e8260 Mon Sep 17 00:00:00 2001 From: RickGriff <32799176+RickGriff@users.noreply.github.com> Date: Fri, 20 Sep 2024 14:01:40 +0100 Subject: [PATCH 14/22] Update README.md --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b0ec6a0e..a38c4387 100644 --- a/README.md +++ b/README.md @@ -1233,17 +1233,21 @@ However, a fallback price utilizing the ETH-USD price and the LST's canonical ra | RETH | min(ETH-USD * RETH-ETH, ETH-USD * RETH-ETH_canonical) | min(lastGoodPrice, ETH-USD * RETH-ETH_canonical) | lastGoodPrice | lastGoodPrice | -## Primary LST feed failure +## Primary LST oracle failure During shutdown no borrower ops are allowed, so the main risk of a manipulated canonical rate (inflated price and excess BOLD minting) is eliminated. However, in this case we still take a minimum: `min(lastGoodPrice, ETH-USD * canonical_rate)`. This ensures that if the canonical rate is also manipulated up, we still give urgent redemptions a chance of being profitable (and clearing bad debt) with the `lastGoodPrice`. +#### STETH-USD oracle failure + +When this oracle fails, the WSTETH PriceFeed switches to pricing WSTETH in USD with `min(lastGoodPrice, ETH-USD * WSTETH-STETH_canonical)`. Since we substitute the failed STETH-USD oracle with the ETH-USD oracle, this inherently assumes that 1 STETH is worth 1 ETH. This is not guaranteed, though its deemed a reasonable assumption during branch shut down, where the system's priority is purely to clear bad debt via urgent redemptions. + ## Canonical rate failure The LST canonical exchange rate is used in all calculations on all PriceFeeds. If it fails, the branch falls back to using the `lastGoodPrice`, and the branch gets shut down if it is live. If the canonical rate fails _after_ shut down, then the LST PriceFeed switches `lastGoodPrice` and the branch remains shut down. When calling the LST contract externally to fetch the canonical rate, failure is defined as: - The returned rate is 0, or - The external call reverts -## ETH-USD feed failure +## ETH-USD oracle failure The ETH-USD market oracle is used in all calculations on all PriceFeeds. If it fails, the branch falls back to using the `lastGoodPrice`, and the branch gets shut down if it is live. If the ETH-USD oracle fails _after_ shut down, then the LST PriceFeed switches `lastGoodPrice` and the branch remains shut down. The full logic is implemented in this PR: From d94c5ea82130d77fa274379736077c986612b2ec Mon Sep 17 00:00:00 2001 From: RickGriff <32799176+RickGriff@users.noreply.github.com> Date: Fri, 20 Sep 2024 20:11:13 +0100 Subject: [PATCH 15/22] Update README.md --- README.md | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a38c4387..5a2937a2 100644 --- a/README.md +++ b/README.md @@ -1404,7 +1404,7 @@ This was chosen over other approaches because: If there is remaining collateral in the shutdown branch (albeit perhaps at zero USD value) and there are liquidateable Troves, Governance could alternatively vote to direct fees to a permissionless contract that deposits the BOLD to the SP of the shutdown branch and liquidates the Troves against those funds. The resulting collateral gains could, if they have non-zero value, be swapped on a DEX, e.g. for BOLD which could be then directed to LP incentives. All deposits and swaps could be handled permissionlessly by this governance-deployed contract. -### 11 - ## Inaccurate calculation of average branch interest rate +### 11 - Inaccurate calculation of average branch interest rate `getNewApproxAvgInterestRateFromTroveChange` does not actually calculate the correct average interest rate for a collateral branch. Ideally, we would like to calculate the debt-weighted average interest of all Troves within the branch, upon which our calculation of the upfront fee is based. The desired formula would be: @@ -1464,6 +1464,50 @@ sum(debt_i) While this wouldn't result in the most accurate estimation of the average interest rate either — considering we'd be using outdated debt values sampled at different times for each Trove as weights — at least we would have consistent weights in the numerator and denominator of our weighted average. To implement this though, we'd have to keep track of this modified sum (i.e. the sum of recorded Trove debts) in `ActivePool`, which we currently don't do. +## 12 - Borrower can create multiple unredeemable Troves and evade redemptions + +Brought up by @javalasers on Discord: + +Description + +(credit @javalasers) There's an attack vector where the user can: + +- Create a trove with MIN_DEBT of debt and MIN_ANNUAL_INTEREST_RATE interest. +- Redeem a tiny amount of BOLD worth of collateral from the protocol +- If they hit their own Trove, They now have a trove paying the min interest but with `debt < MIN_DEBT`, which (in previous system logic) makes this Trove unredeemable. +- This operation could be repeated in order to create multiple Troves at `debt < MIN_DEBT`, for a total unredeemable debt of ~ `n * MIN_DEBT` + +This has been fixed in this PR: +https://github.com/liquity/bold/pull/426 + +Here is the original impact, pre-fix: + +**Impact:** +If this attack were profitable, it may break the whole equilibrium and game theory of the user set interest rate. + +Some math should be done, and it heavily depends on gas price, but some considerations: + +- The interest wouldn’t be zero due to the min. interest rate, so eventually the Trove would become redeemable again when it's debt rises above `MIN_DEBT` close to `MIN_DEBT`. So if the aim is to keep it 1 year, at min interest rate of 0.5%, the zombie troves should have 1,990 BOLD debt. +- To set it up `~2n` txs are needed, where `n ~= total debt / MIN_DEBT` +- There’s an additional `(n-1) * ETH_GAS_COMPENSATION` ETH that needs to be locked up. + +Also, the management of the Trove needs to be considered, so: +- Either they all have a very high CR -> not capital efficient, it’s kind of a hidden cost +- Or then 2n times more gas have to be spent to adjust troves every time if the attacker is trying to have a low CR and actively manage them (for each trove there’s 1 adjustment that brings it up above `MIN_DEBT` and then again a redemption). + +**Potential Solutions** + +1. Keep a pointer to the last redemeed zombie trove, and use that one first when the next redemption happens (h/t @danielattilasimon ). The attack would still work with redistributions - even after having debt reduced to 0 redistributions could result in the attacker's Trove at `debt < MIN_DEBT` but that’s far more unlikely and much harder to perform (with an extra cost of 5% of the SP size, a huge trove to be liquidated could be opened and then go for the redistributions - however, it’s hard, expensive, can’t be done in 1 tx, it depends on ETH fluctuations, on the global TCR...). + +2. When a trove gets redeemed and ends up with non zero debt, automatically set it to the max interest rate (h/t @cvalkan) + +**Chosen solution** +Solution 1. was implemented in this PR: +https://github.com/liquity/bold/pull/426 + +Note: with this approach, it can happen that a zombie Trove belonging to a batch gets its debt increased to above `MIN_DEBT` due to its batch being updated but without a direct adjustment occurring on the Trove itself - in which case, the Trove remains a zombie and holds the pointer to the last zombie trove, so it will get still redeemed first in the list upon the next redemption. + +However this seems like quite an edge case: the Trove needs to be batched, get partially redeemed, become a zombie, and then the batch updated before the borrower touches it and debt increased to above MIN_DEBT, and then redeemed _again_ as first in the list. The borrower can easily prevent the last step if desired by touching the Trove and updating its debt to `debt > MIN_DEBT` beforehand. ## Requirements From 438e74fbb85031b0c7b37c71803a10cae465e024 Mon Sep 17 00:00:00 2001 From: RickGriff <32799176+RickGriff@users.noreply.github.com> Date: Fri, 20 Sep 2024 20:12:55 +0100 Subject: [PATCH 16/22] Update README.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5a2937a2..48bbfe21 100644 --- a/README.md +++ b/README.md @@ -1468,11 +1468,11 @@ While this wouldn't result in the most accurate estimation of the average intere Brought up by @javalasers on Discord: -Description +**Description:** (credit @javalasers) There's an attack vector where the user can: -- Create a trove with MIN_DEBT of debt and MIN_ANNUAL_INTEREST_RATE interest. +- Create a trove with `MIN_DEBT` of debt and `MIN_ANNUAL_INTEREST_RATE` interest. - Redeem a tiny amount of BOLD worth of collateral from the protocol - If they hit their own Trove, They now have a trove paying the min interest but with `debt < MIN_DEBT`, which (in previous system logic) makes this Trove unredeemable. - This operation could be repeated in order to create multiple Troves at `debt < MIN_DEBT`, for a total unredeemable debt of ~ `n * MIN_DEBT` @@ -1483,6 +1483,7 @@ https://github.com/liquity/bold/pull/426 Here is the original impact, pre-fix: **Impact:** + If this attack were profitable, it may break the whole equilibrium and game theory of the user set interest rate. Some math should be done, and it heavily depends on gas price, but some considerations: @@ -1502,6 +1503,7 @@ Also, the management of the Trove needs to be considered, so: 2. When a trove gets redeemed and ends up with non zero debt, automatically set it to the max interest rate (h/t @cvalkan) **Chosen solution** + Solution 1. was implemented in this PR: https://github.com/liquity/bold/pull/426 From 4f9927ac1a5b8ed5fb98bbaa89c98f3ad6668155 Mon Sep 17 00:00:00 2001 From: RickGriff <32799176+RickGriff@users.noreply.github.com> Date: Tue, 24 Sep 2024 09:39:40 +0100 Subject: [PATCH 17/22] Update README.md --- README.md | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 48bbfe21..9b0331fb 100644 --- a/README.md +++ b/README.md @@ -1379,26 +1379,21 @@ Various solutions have been fielded. Generally, any solution which appears to cr 4. **New multi-collateral Stability Pool.** This pool would absorb some fraction of liquidations from all branches, including shut down branches. -5. **Governance can direct BOLD interest to pay down bad debt**. BOLD interest could be voted to be redirected to paying down the bad debt over time. +5. **Governance can direct BOLD interest to pay down bad debt**. BOLD interest could be voted to be redirected to paying down the bad debt over time. Although this would not directly clear the bad debt, economically, it should have the same impact - since ultimately, it is the redeemability of _circulating_ BOLD that determines the peg. When an amount equal to the bad debt has been burned, then all circulating BOLD is fully redeemable. -And some additional solutions that may help reduce the chance of bad debt occurring in the first place: - -6. **Restrict SP withdrawals when TCR < 100%**. This ensure that SP depositors can’t flee when their branch is insolvent, and would be forced to eat the loss. This could lead to less bad debt than otherwise. On the other hand, when TCR > 100%, the expectation of this restriction kicking in could force pre-empting SP fleeing, which may limit liquidations and make bad debt _more_ likely. An alternative would be to restrict SP withdrawals only when the LST-ETH price falls significantly below 1, indicating an adverse LST depeg event. - -7. **Pro-rata redemptions at TCR < 100% (branch specific, not routed)**. Urgent redemptions are helpful for shrinking the debt of a shut down branch when it is at `TCR > 100%`. However, at `TCR < 100%`, urgent redemptions do not help clear the bad debt. They simply remove all collateral and push it into its final state faster (and in fact, make it slightly worse since they pay a slight collateral bonus). At `TCR < 100%`, we could offer special pro-rata redemptions only on the shut down branch - e.g. at `TCR = 80%`, users may redeem 1 BOLD for $0.80 worth of collateral. This would (in principle) allow someone to completely clear the bad debt via redemption. At first glance it seems unprofitable, but if the redeemer has reason to believe the collateral is underpriced and the price may rebound at some point in future, they may believe it to be profitable to redeem pro-rata. +See this example: -**Chosen solution** +image -Solution 5 is chosen. Governance can vote to burn the interest under its control by sending the minted BOLD to a burn address. Although this does not directly clear the bad debt, economically, it should have the same impact - since ultimately, it is the redeemability of _circulating_ BOLD that determines the peg. When an amount equal to the bad debt has been burned, then all circulating BOLD is fully redeemable. +This provides a credible way of eventually "filling the hole" created by bad debt (unlike other approaches such as the SP haircut, which depends on SP funds). No additional core system code nor additional governance features are required. Governance may simply propose to redirect BOLD interest to a burn address. -See this example: +And some additional solutions that may help reduce the chance of bad debt occurring in the first place: -image +6. **Restrict SP withdrawals when TCR < 100%**. This ensure that SP depositors can’t flee when their branch is insolvent, and would be forced to eat the loss. This could lead to less bad debt than otherwise. On the other hand, when TCR > 100%, the expectation of this restriction kicking in could force pre-empting SP fleeing, which may limit liquidations and make bad debt _more_ likely. An alternative would be to restrict SP withdrawals only when the LST-ETH price falls significantly below 1, indicating an adverse LST depeg event. -This was chosen over other approaches because: +7. **Pro-rata redemptions at TCR < 100% (branch specific, not routed)**. Urgent redemptions are helpful for shrinking the debt of a shut down branch when it is at `TCR > 100%`. However, at `TCR < 100%`, urgent redemptions do not help clear the bad debt. They simply remove all collateral and push it into its final state faster (and in fact, make it slightly worse since they pay a slight collateral bonus). At `TCR < 100%`, we could offer special pro-rata redemptions only on the shut down branch - e.g. at `TCR = 80%`, users may redeem 1 BOLD for $0.80 worth of collateral. This would (in principle) allow someone to completely clear the bad debt via redemption. At first glance it seems unprofitable, but if the redeemer has reason to believe the collateral is underpriced and the price may rebound at some point in future, they may believe it to be profitable to redeem pro-rata. -- It provides a credible way of eventually "filling the hole" created by bad debt (unlike other approaches such as the SP haircut, which depends on SP funds) -- No additional core system code nor additional governance features are required. Governance can simply propose to redirect BOLD interest to a burn address. +Ultimately, no measures have been implemented in the protocol directly, so the protocol may end up with some bad debt in the case of a branch shut down. In case of bad debt, there is a theoretical possibility that BOLD supply may be reduced by either users accidentally burning BOLD or that borrower's interest could be directed by governance to burn BOLD, which would restore its backing. **Extension: governance can liquidate and swap collateral gains** From 146a9a85577645be6b8b580423f662c79d3c5915 Mon Sep 17 00:00:00 2001 From: RickGriff <32799176+RickGriff@users.noreply.github.com> Date: Tue, 24 Sep 2024 09:40:44 +0100 Subject: [PATCH 18/22] Update README.md --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9b0331fb..5bc94b85 100644 --- a/README.md +++ b/README.md @@ -1387,17 +1387,18 @@ See this example: This provides a credible way of eventually "filling the hole" created by bad debt (unlike other approaches such as the SP haircut, which depends on SP funds). No additional core system code nor additional governance features are required. Governance may simply propose to redirect BOLD interest to a burn address. +If there is remaining collateral in the shutdown branch (albeit perhaps at zero USD value) and there are liquidateable Troves, Governance could alternatively vote to direct fees to a permissionless contract that deposits the BOLD to the SP of the shutdown branch and liquidates the Troves against those funds. The resulting collateral gains could, if they have non-zero value, be swapped on a DEX, e.g. for BOLD which could be then directed to LP incentives. All deposits and swaps could be handled permissionlessly by this governance-deployed contract. + And some additional solutions that may help reduce the chance of bad debt occurring in the first place: 6. **Restrict SP withdrawals when TCR < 100%**. This ensure that SP depositors can’t flee when their branch is insolvent, and would be forced to eat the loss. This could lead to less bad debt than otherwise. On the other hand, when TCR > 100%, the expectation of this restriction kicking in could force pre-empting SP fleeing, which may limit liquidations and make bad debt _more_ likely. An alternative would be to restrict SP withdrawals only when the LST-ETH price falls significantly below 1, indicating an adverse LST depeg event. 7. **Pro-rata redemptions at TCR < 100% (branch specific, not routed)**. Urgent redemptions are helpful for shrinking the debt of a shut down branch when it is at `TCR > 100%`. However, at `TCR < 100%`, urgent redemptions do not help clear the bad debt. They simply remove all collateral and push it into its final state faster (and in fact, make it slightly worse since they pay a slight collateral bonus). At `TCR < 100%`, we could offer special pro-rata redemptions only on the shut down branch - e.g. at `TCR = 80%`, users may redeem 1 BOLD for $0.80 worth of collateral. This would (in principle) allow someone to completely clear the bad debt via redemption. At first glance it seems unprofitable, but if the redeemer has reason to believe the collateral is underpriced and the price may rebound at some point in future, they may believe it to be profitable to redeem pro-rata. -Ultimately, no measures have been implemented in the protocol directly, so the protocol may end up with some bad debt in the case of a branch shut down. In case of bad debt, there is a theoretical possibility that BOLD supply may be reduced by either users accidentally burning BOLD or that borrower's interest could be directed by governance to burn BOLD, which would restore its backing. +**Conclusion** -**Extension: governance can liquidate and swap collateral gains** +Ultimately, no measures have been implemented in the protocol directly, so the protocol may end up with some bad debt in the case of a branch shut down. In case of bad debt, there is a theoretical possibility that BOLD supply may be reduced by either users accidentally burning BOLD or that borrower's interest could be directed by governance to burn BOLD, which would restore its backing. -If there is remaining collateral in the shutdown branch (albeit perhaps at zero USD value) and there are liquidateable Troves, Governance could alternatively vote to direct fees to a permissionless contract that deposits the BOLD to the SP of the shutdown branch and liquidates the Troves against those funds. The resulting collateral gains could, if they have non-zero value, be swapped on a DEX, e.g. for BOLD which could be then directed to LP incentives. All deposits and swaps could be handled permissionlessly by this governance-deployed contract. ### 11 - Inaccurate calculation of average branch interest rate From 247c1063d9356290d827982b5ee3b0a5fd5a8bbd Mon Sep 17 00:00:00 2001 From: RickGriff <32799176+RickGriff@users.noreply.github.com> Date: Tue, 24 Sep 2024 09:43:15 +0100 Subject: [PATCH 19/22] Update README.md --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5bc94b85..d408f629 100644 --- a/README.md +++ b/README.md @@ -1379,9 +1379,7 @@ Various solutions have been fielded. Generally, any solution which appears to cr 4. **New multi-collateral Stability Pool.** This pool would absorb some fraction of liquidations from all branches, including shut down branches. -5. **Governance can direct BOLD interest to pay down bad debt**. BOLD interest could be voted to be redirected to paying down the bad debt over time. Although this would not directly clear the bad debt, economically, it should have the same impact - since ultimately, it is the redeemability of _circulating_ BOLD that determines the peg. When an amount equal to the bad debt has been burned, then all circulating BOLD is fully redeemable. - -See this example: +5. **Governance can direct BOLD interest to pay down bad debt**. BOLD interest could be voted to be redirected to paying down the bad debt over time. Although this would not directly clear the bad debt, economically, it should have the same impact - since ultimately, it is the redeemability of _circulating_ BOLD that determines the peg. When an amount equal to the bad debt has been burned, then all circulating BOLD is fully redeemable. See this example: image @@ -1397,7 +1395,7 @@ And some additional solutions that may help reduce the chance of bad debt occurr **Conclusion** -Ultimately, no measures have been implemented in the protocol directly, so the protocol may end up with some bad debt in the case of a branch shut down. In case of bad debt, there is a theoretical possibility that BOLD supply may be reduced by either users accidentally burning BOLD or that borrower's interest could be directed by governance to burn BOLD, which would restore its backing. +Ultimately, no measures have been implemented in the protocol directly, so the protocol may end up with some bad debt in the case of a branch shut down. Here there is a theoretical possibility that the BOLD supply may be reduced by either users accidentally burning BOLD, or that borrower's interest on that branch could be directed by governance to burn BOLD, which would restore its backing over time. ### 11 - Inaccurate calculation of average branch interest rate From 270a25171ea0b6a100aa4fb48e2d5217befc773f Mon Sep 17 00:00:00 2001 From: RickGriff <32799176+RickGriff@users.noreply.github.com> Date: Tue, 24 Sep 2024 10:16:51 +0100 Subject: [PATCH 20/22] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d408f629..b30cad17 100644 --- a/README.md +++ b/README.md @@ -1395,7 +1395,7 @@ And some additional solutions that may help reduce the chance of bad debt occurr **Conclusion** -Ultimately, no measures have been implemented in the protocol directly, so the protocol may end up with some bad debt in the case of a branch shut down. Here there is a theoretical possibility that the BOLD supply may be reduced by either users accidentally burning BOLD, or that borrower's interest on that branch could be directed by governance to burn BOLD, which would restore its backing over time. +Ultimately, no measures have been implemented in the protocol directly, so the protocol may end up with some bad debt in the case of a branch shut down. Here there is a theoretical possibility that the BOLD supply may be reduced by either users accidentally burning BOLD, or that borrower's interest could be directed by governance to burn BOLD, which would restore its backing over time. ### 11 - Inaccurate calculation of average branch interest rate From 4fcc30f059532e3a7be177771cedfdef920070c3 Mon Sep 17 00:00:00 2001 From: Pierre Bertet Date: Tue, 24 Sep 2024 12:16:40 +0100 Subject: [PATCH 21/22] Subgraph (#375) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See subgraph/README.md for instructions on how to deploy the subgraph locally. - Add `subgraph/` to the workspaces. - A script, `./deploy-subgraph`, can be used to deploy the subgraph in a convenient way. See `--help` for details. Some context: - The subgraph uses data source templates [1] for the collateral contracts. - The script can update the collateral registry address in the `subgraph.yaml` if it doesn’t match the one found in the latest deployment context. - In `./deploy-subgraph`, only the local preset is implemented for now. [1] https://thegraph.com/docs/en/developing/creating-a-subgraph/#data-source-templates --- contracts/src/scripts/DeployLiquity2.s.sol | 24 +- dprint.json | 5 +- pnpm-lock.yaml | 1530 ++++++++++++++++++-- pnpm-workspace.yaml | 1 + subgraph/.gitignore | 2 + subgraph/README.md | 27 + subgraph/cli/deploy-subgraph.ts | 201 +++ subgraph/cli/start-graph.ts | 66 + subgraph/deploy-subgraph | 8 + subgraph/docker-compose.yml | 53 + subgraph/package.json | 16 + subgraph/schema.graphql | 47 + subgraph/src/BoldToken.mapping.ts | 74 + subgraph/src/TroveManager.mapping.ts | 121 ++ subgraph/start-graph | 8 + subgraph/subgraph.yaml | 56 + 16 files changed, 2142 insertions(+), 97 deletions(-) create mode 100644 subgraph/.gitignore create mode 100644 subgraph/README.md create mode 100644 subgraph/cli/deploy-subgraph.ts create mode 100644 subgraph/cli/start-graph.ts create mode 100755 subgraph/deploy-subgraph create mode 100644 subgraph/docker-compose.yml create mode 100644 subgraph/package.json create mode 100644 subgraph/schema.graphql create mode 100644 subgraph/src/BoldToken.mapping.ts create mode 100644 subgraph/src/TroveManager.mapping.ts create mode 100755 subgraph/start-graph create mode 100644 subgraph/subgraph.yaml diff --git a/contracts/src/scripts/DeployLiquity2.s.sol b/contracts/src/scripts/DeployLiquity2.s.sol index 5508898e..d487927c 100644 --- a/contracts/src/scripts/DeployLiquity2.s.sol +++ b/contracts/src/scripts/DeployLiquity2.s.sol @@ -218,7 +218,7 @@ contract DeployLiquity2Script is Script, StdCheats, MetadataDeployment { demoTroves[6] = DemoTroveParams(0, demoAccounts[6], 0, 33.92e18, 5500e18, 3.8e16); demoTroves[7] = DemoTroveParams(0, demoAccounts[7], 0, 47.2e18, 6000e18, 4.3e16); - demoTroves[8] = DemoTroveParams(1, demoAccounts[0], 0, 21e18, 2000e18, 3.3e16); + demoTroves[8] = DemoTroveParams(1, demoAccounts[0], 1, 21e18, 2000e18, 3.3e16); demoTroves[9] = DemoTroveParams(1, demoAccounts[1], 1, 16e18, 2000e18, 4.1e16); demoTroves[10] = DemoTroveParams(1, demoAccounts[2], 1, 18e18, 2300e18, 3.8e16); demoTroves[11] = DemoTroveParams(1, demoAccounts[3], 1, 22e18, 2200e18, 4.3e16); @@ -274,17 +274,17 @@ contract DeployLiquity2Script is Script, StdCheats, MetadataDeployment { } IBorrowerOperations(contracts.borrowerOperations).openTrove( - vm.addr(trove.owner), // _owner - trove.ownerIndex, // _ownerIndex - trove.coll, // _collAmount - trove.debt, // _boldAmount - 0, // _upperHint - 0, // _lowerHint - 0.05e18, // _annualInterestRate - type(uint256).max, // _maxUpfrontFee - address(0), // _addManager - address(0), // _removeManager - address(0) // _receiver + vm.addr(trove.owner), // _owner + trove.ownerIndex, // _ownerIndex + trove.coll, // _collAmount + trove.debt, // _boldAmount + 0, // _upperHint + 0, // _lowerHint + trove.annualInterestRate, // _annualInterestRate + type(uint256).max, // _maxUpfrontFee + address(0), // _addManager + address(0), // _removeManager + address(0) // _receiver ); vm.stopBroadcast(); diff --git a/dprint.json b/dprint.json index 24a51e8f..942a12c2 100644 --- a/dprint.json +++ b/dprint.json @@ -5,7 +5,7 @@ "json": {}, "markdown": {}, "toml": {}, - "includes": ["**/*.{ts,tsx,js,jsx,mjs,json,md,html,css}"], + "includes": ["**/*.{ts,tsx,js,jsx,mjs,json,md,html,css,graphql}"], "excludes": [ "**/node_modules", "**/*-lock.json", @@ -20,6 +20,7 @@ "https://plugins.dprint.dev/json-0.19.2.wasm", "https://plugins.dprint.dev/markdown-0.16.4.wasm", "https://plugins.dprint.dev/toml-0.6.1.wasm", - "https://plugins.dprint.dev/g-plane/malva-v0.1.5.wasm" + "https://plugins.dprint.dev/g-plane/malva-v0.1.5.wasm", + "https://plugins.dprint.dev/g-plane/pretty_graphql-v0.2.0.wasm" ] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2bee735a..a6c26c7f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -315,6 +315,25 @@ importers: specifier: ^5.5.4 version: 5.5.4 + subgraph: + dependencies: + '@graphprotocol/graph-ts': + specifier: ^0.35.1 + version: 0.35.1 + tsx: + specifier: ^4.16.5 + version: 4.16.5 + yaml: + specifier: ^2.5.0 + version: 2.5.0 + zx: + specifier: ^8.1.4 + version: 8.1.4 + devDependencies: + '@graphprotocol/graph-cli': + specifier: ^0.80.0 + version: 0.80.1(@types/node@22.0.2)(node-fetch@2.7.0)(typescript@5.5.4) + packages: /@adobe/css-tools@4.4.0: @@ -394,7 +413,7 @@ packages: '@babel/traverse': 7.25.3 '@babel/types': 7.25.2 convert-source-map: 2.0.0 - debug: 4.3.6 + debug: 4.3.6(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -523,7 +542,7 @@ packages: '@babel/core': 7.25.2 '@babel/helper-compilation-targets': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - debug: 4.3.6 + debug: 4.3.6(supports-color@8.1.1) lodash.debounce: 4.0.8 resolve: 1.22.8 transitivePeerDependencies: @@ -2098,7 +2117,7 @@ packages: '@babel/helper-split-export-declaration': 7.24.5 '@babel/parser': 7.24.5 '@babel/types': 7.24.5 - debug: 4.3.6 + debug: 4.3.6(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -2116,7 +2135,7 @@ packages: '@babel/helper-split-export-declaration': 7.24.7 '@babel/parser': 7.24.7 '@babel/types': 7.24.7 - debug: 4.3.6 + debug: 4.3.6(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -2130,7 +2149,7 @@ packages: '@babel/parser': 7.25.3 '@babel/template': 7.25.0 '@babel/types': 7.25.2 - debug: 4.3.6 + debug: 4.3.6(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -2376,7 +2395,6 @@ packages: cpu: [ppc64] os: [aix] requiresBuild: true - dev: true optional: true /@esbuild/android-arm64@0.20.2: @@ -2393,7 +2411,6 @@ packages: cpu: [arm64] os: [android] requiresBuild: true - dev: true optional: true /@esbuild/android-arm@0.20.2: @@ -2410,7 +2427,6 @@ packages: cpu: [arm] os: [android] requiresBuild: true - dev: true optional: true /@esbuild/android-x64@0.20.2: @@ -2427,7 +2443,6 @@ packages: cpu: [x64] os: [android] requiresBuild: true - dev: true optional: true /@esbuild/darwin-arm64@0.20.2: @@ -2444,7 +2459,6 @@ packages: cpu: [arm64] os: [darwin] requiresBuild: true - dev: true optional: true /@esbuild/darwin-x64@0.20.2: @@ -2461,7 +2475,6 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true - dev: true optional: true /@esbuild/freebsd-arm64@0.20.2: @@ -2478,7 +2491,6 @@ packages: cpu: [arm64] os: [freebsd] requiresBuild: true - dev: true optional: true /@esbuild/freebsd-x64@0.20.2: @@ -2495,7 +2507,6 @@ packages: cpu: [x64] os: [freebsd] requiresBuild: true - dev: true optional: true /@esbuild/linux-arm64@0.20.2: @@ -2512,7 +2523,6 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true - dev: true optional: true /@esbuild/linux-arm@0.20.2: @@ -2529,7 +2539,6 @@ packages: cpu: [arm] os: [linux] requiresBuild: true - dev: true optional: true /@esbuild/linux-ia32@0.20.2: @@ -2546,7 +2555,6 @@ packages: cpu: [ia32] os: [linux] requiresBuild: true - dev: true optional: true /@esbuild/linux-loong64@0.20.2: @@ -2563,7 +2571,6 @@ packages: cpu: [loong64] os: [linux] requiresBuild: true - dev: true optional: true /@esbuild/linux-mips64el@0.20.2: @@ -2580,7 +2587,6 @@ packages: cpu: [mips64el] os: [linux] requiresBuild: true - dev: true optional: true /@esbuild/linux-ppc64@0.20.2: @@ -2597,7 +2603,6 @@ packages: cpu: [ppc64] os: [linux] requiresBuild: true - dev: true optional: true /@esbuild/linux-riscv64@0.20.2: @@ -2614,7 +2619,6 @@ packages: cpu: [riscv64] os: [linux] requiresBuild: true - dev: true optional: true /@esbuild/linux-s390x@0.20.2: @@ -2631,7 +2635,6 @@ packages: cpu: [s390x] os: [linux] requiresBuild: true - dev: true optional: true /@esbuild/linux-x64@0.20.2: @@ -2648,7 +2651,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: true optional: true /@esbuild/netbsd-x64@0.20.2: @@ -2665,7 +2667,6 @@ packages: cpu: [x64] os: [netbsd] requiresBuild: true - dev: true optional: true /@esbuild/openbsd-x64@0.20.2: @@ -2682,7 +2683,6 @@ packages: cpu: [x64] os: [openbsd] requiresBuild: true - dev: true optional: true /@esbuild/sunos-x64@0.20.2: @@ -2699,7 +2699,6 @@ packages: cpu: [x64] os: [sunos] requiresBuild: true - dev: true optional: true /@esbuild/win32-arm64@0.20.2: @@ -2716,7 +2715,6 @@ packages: cpu: [arm64] os: [win32] requiresBuild: true - dev: true optional: true /@esbuild/win32-ia32@0.20.2: @@ -2733,7 +2731,6 @@ packages: cpu: [ia32] os: [win32] requiresBuild: true - dev: true optional: true /@esbuild/win32-x64@0.20.2: @@ -2750,7 +2747,6 @@ packages: cpu: [x64] os: [win32] requiresBuild: true - dev: true optional: true /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0): @@ -2848,6 +2844,20 @@ packages: ethereum-cryptography: 2.1.3 micro-ftch: 0.3.1 + /@ethersproject/abi@5.0.7: + resolution: {integrity: sha512-Cqktk+hSIckwP/W8O47Eef60VwmoSC/L3lY0+dIBhQPCNn9E4V7rwmm2aFrNRRDJfFlGuZ1khkQUOc3oBX+niw==} + dependencies: + '@ethersproject/address': 5.7.0 + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/constants': 5.7.0 + '@ethersproject/hash': 5.7.0 + '@ethersproject/keccak256': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/properties': 5.7.0 + '@ethersproject/strings': 5.7.0 + dev: true + /@ethersproject/abi@5.7.0: resolution: {integrity: sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==} dependencies: @@ -3168,6 +3178,16 @@ packages: engines: {node: '>=14'} dev: true + /@float-capital/float-subgraph-uncrashable@0.0.0-internal-testing.5: + resolution: {integrity: sha512-yZ0H5e3EpAYKokX/AbtplzlvSxEJY7ZfpvQyDzyODkks0hakAAlDG6fQu1SlDJMWorY7bbq1j7fCiFeTWci6TA==} + hasBin: true + dependencies: + '@rescript/std': 9.0.0 + graphql: 16.9.0 + graphql-import-node: 0.0.5(graphql@16.9.0) + js-yaml: 4.1.0 + dev: true + /@floating-ui/core@1.6.3: resolution: {integrity: sha512-1ZpCvYf788/ZXOhRQGFxnYQOVgeU+pi0i+d0Ow34La7qjIXETi6RNswGVKkA6KcDO8/+Ysu2E/CeUmmeEBDvTg==} dependencies: @@ -3196,6 +3216,57 @@ packages: resolution: {integrity: sha512-XGndio0l5/Gvd6CLIABvsav9HHezgDFFhDfHk1bvLfr9ni8dojqLSvBbotJEjmIwNHL7vK4QzBJTdBRoB+c1ww==} dev: false + /@graphprotocol/graph-cli@0.80.1(@types/node@22.0.2)(node-fetch@2.7.0)(typescript@5.5.4): + resolution: {integrity: sha512-Kg1o3Ww2B4Q1IhCvYBCJ4fMCv+EqVtLgGvLCZdVyZo4a994Uj76apqkr1KVwRBSW60jgrGkTtpoE2JTNpgbaXg==} + engines: {node: '>=18'} + hasBin: true + dependencies: + '@float-capital/float-subgraph-uncrashable': 0.0.0-internal-testing.5 + '@oclif/core': 2.8.6(@types/node@22.0.2)(typescript@5.5.4) + '@oclif/plugin-autocomplete': 2.3.10(@types/node@22.0.2)(typescript@5.5.4) + '@oclif/plugin-not-found': 2.4.3(@types/node@22.0.2)(typescript@5.5.4) + '@whatwg-node/fetch': 0.8.8 + assemblyscript: 0.19.23 + binary-install-raw: 0.0.13(debug@4.3.4) + chalk: 3.0.0 + chokidar: 3.5.3 + debug: 4.3.4(supports-color@8.1.1) + docker-compose: 0.23.19 + dockerode: 2.5.8 + fs-extra: 9.1.0 + glob: 9.3.5 + gluegun: 5.1.6(debug@4.3.4) + graphql: 15.5.0 + immutable: 4.2.1 + ipfs-http-client: 55.0.0(node-fetch@2.7.0) + jayson: 4.0.0 + js-yaml: 3.14.1 + open: 8.4.2 + prettier: 3.0.3 + semver: 7.4.0 + sync-request: 6.1.0 + tmp-promise: 3.0.3 + web3-eth-abi: 1.7.0 + which: 2.0.2 + yaml: 1.10.2 + transitivePeerDependencies: + - '@swc/core' + - '@swc/wasm' + - '@types/node' + - bufferutil + - encoding + - node-fetch + - supports-color + - typescript + - utf-8-validate + dev: true + + /@graphprotocol/graph-ts@0.35.1: + resolution: {integrity: sha512-74CfuQmf7JI76/XCC34FTkMMKeaf+3Pn0FIV3m9KNeaOJ+OI3CvjMIVRhOZdKcJxsFCBGaCCl0eQjh47xTjxKA==} + dependencies: + assemblyscript: 0.19.10 + dev: false + /@hapi/hoek@9.3.0: resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} dev: false @@ -3414,6 +3485,26 @@ packages: dev: false optional: true + /@ipld/dag-cbor@7.0.3: + resolution: {integrity: sha512-1VVh2huHsuohdXC1bGJNE8WR72slZ9XE2T3wbBBq31dm7ZBatmKLLxrB+XAqafxfRFjv08RZmj/W/ZqaM13AuA==} + dependencies: + cborg: 1.10.2 + multiformats: 9.9.0 + dev: true + + /@ipld/dag-json@8.0.11: + resolution: {integrity: sha512-Pea7JXeYHTWXRTIhBqBlhw7G53PJ7yta3G/sizGEZyzdeEwhZRr0od5IQ0r2ZxOt1Do+2czddjeEPp+YTxDwCA==} + dependencies: + cborg: 1.10.2 + multiformats: 9.9.0 + dev: true + + /@ipld/dag-pb@2.1.18: + resolution: {integrity: sha512-ZBnf2fuX9y3KccADURG5vb9FaOeMjFkCrNysB0PtftME/4iCTjxfaLoNq/IAh5fTqUOMXvryN6Jyka4ZGuMLIg==} + dependencies: + multiformats: 9.9.0 + dev: true + /@isaacs/cliui@8.0.2: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -3668,7 +3759,7 @@ packages: bufferutil: 4.0.8 cross-fetch: 4.0.0 date-fns: 2.30.0 - debug: 4.3.6 + debug: 4.3.6(supports-color@8.1.1) eciesjs: 0.3.19 eventemitter2: 6.4.9 readable-stream: 3.6.2 @@ -3719,7 +3810,7 @@ packages: '@types/dom-screen-wake-lock': 1.0.3 bowser: 2.11.0 cross-fetch: 4.0.0 - debug: 4.3.6 + debug: 4.3.6(supports-color@8.1.1) eciesjs: 0.3.19 eth-rpc-errors: 4.0.3 eventemitter2: 6.4.9 @@ -3756,7 +3847,7 @@ packages: dependencies: '@ethereumjs/tx': 4.2.0 '@types/debug': 4.1.12 - debug: 4.3.6 + debug: 4.3.6(supports-color@8.1.1) semver: 7.6.3 superstruct: 1.0.4 transitivePeerDependencies: @@ -3772,7 +3863,7 @@ packages: '@noble/hashes': 1.4.0 '@scure/base': 1.1.7 '@types/debug': 4.1.12 - debug: 4.3.6 + debug: 4.3.6(supports-color@8.1.1) pony-cause: 2.1.11 semver: 7.6.3 uuid: 9.0.1 @@ -3789,7 +3880,7 @@ packages: '@noble/hashes': 1.4.0 '@scure/base': 1.1.7 '@types/debug': 4.1.12 - debug: 4.3.6 + debug: 4.3.6(supports-color@8.1.1) pony-cause: 2.1.11 semver: 7.6.3 uuid: 9.0.1 @@ -4447,6 +4538,114 @@ packages: - utf-8-validate dev: true + /@oclif/core@2.16.0(@types/node@22.0.2)(typescript@5.5.4): + resolution: {integrity: sha512-dL6atBH0zCZl1A1IXCKJgLPrM/wR7K+Wi401E/IvqsK8m2iCHW+0TEOGrans/cuN3oTW+uxIyJFHJ8Im0k4qBw==} + engines: {node: '>=14.0.0'} + dependencies: + '@types/cli-progress': 3.11.6 + ansi-escapes: 4.3.2 + ansi-styles: 4.3.0 + cardinal: 2.1.1 + chalk: 4.1.2 + clean-stack: 3.0.1 + cli-progress: 3.12.0 + debug: 4.3.6(supports-color@8.1.1) + ejs: 3.1.10 + get-package-type: 0.1.0 + globby: 11.1.0 + hyperlinker: 1.0.0 + indent-string: 4.0.0 + is-wsl: 2.2.0 + js-yaml: 3.14.1 + natural-orderby: 2.0.3 + object-treeify: 1.1.33 + password-prompt: 1.1.3 + slice-ansi: 4.0.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + supports-color: 8.1.1 + supports-hyperlinks: 2.3.0 + ts-node: 10.9.2(@types/node@22.0.2)(typescript@5.5.4) + tslib: 2.6.3 + widest-line: 3.1.0 + wordwrap: 1.0.0 + wrap-ansi: 7.0.0 + transitivePeerDependencies: + - '@swc/core' + - '@swc/wasm' + - '@types/node' + - typescript + dev: true + + /@oclif/core@2.8.6(@types/node@22.0.2)(typescript@5.5.4): + resolution: {integrity: sha512-1QlPaHMhOORySCXkQyzjsIsy2GYTilOw3LkjeHkCgsPJQjAT4IclVytJusWktPbYNys9O+O4V23J44yomQvnBQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@types/cli-progress': 3.11.6 + ansi-escapes: 4.3.2 + ansi-styles: 4.3.0 + cardinal: 2.1.1 + chalk: 4.1.2 + clean-stack: 3.0.1 + cli-progress: 3.12.0 + debug: 4.3.6(supports-color@8.1.1) + ejs: 3.1.10 + fs-extra: 9.1.0 + get-package-type: 0.1.0 + globby: 11.1.0 + hyperlinker: 1.0.0 + indent-string: 4.0.0 + is-wsl: 2.2.0 + js-yaml: 3.14.1 + natural-orderby: 2.0.3 + object-treeify: 1.1.33 + password-prompt: 1.1.3 + semver: 7.6.3 + string-width: 4.2.3 + strip-ansi: 6.0.1 + supports-color: 8.1.1 + supports-hyperlinks: 2.3.0 + ts-node: 10.9.2(@types/node@22.0.2)(typescript@5.5.4) + tslib: 2.6.3 + widest-line: 3.1.0 + wordwrap: 1.0.0 + wrap-ansi: 7.0.0 + transitivePeerDependencies: + - '@swc/core' + - '@swc/wasm' + - '@types/node' + - typescript + dev: true + + /@oclif/plugin-autocomplete@2.3.10(@types/node@22.0.2)(typescript@5.5.4): + resolution: {integrity: sha512-Ow1AR8WtjzlyCtiWWPgzMyT8SbcDJFr47009riLioHa+MHX2BCDtVn2DVnN/E6b9JlPV5ptQpjefoRSNWBesmg==} + engines: {node: '>=12.0.0'} + dependencies: + '@oclif/core': 2.16.0(@types/node@22.0.2)(typescript@5.5.4) + chalk: 4.1.2 + debug: 4.3.6(supports-color@8.1.1) + transitivePeerDependencies: + - '@swc/core' + - '@swc/wasm' + - '@types/node' + - supports-color + - typescript + dev: true + + /@oclif/plugin-not-found@2.4.3(@types/node@22.0.2)(typescript@5.5.4): + resolution: {integrity: sha512-nIyaR4y692frwh7wIHZ3fb+2L6XEecQwRDIb4zbEam0TvaVmBQWZoColQyWA84ljFBPZ8XWiQyTz+ixSwdRkqg==} + engines: {node: '>=12.0.0'} + dependencies: + '@oclif/core': 2.16.0(@types/node@22.0.2)(typescript@5.5.4) + chalk: 4.1.2 + fast-levenshtein: 3.0.0 + transitivePeerDependencies: + - '@swc/core' + - '@swc/wasm' + - '@types/node' + - typescript + dev: true + /@openzeppelin/contract-loader@0.6.3: resolution: {integrity: sha512-cOFIjBjwbGgZhDZsitNgJl0Ye1rd5yu/Yx5LMgeq3u0ZYzldm4uObzHDFq4gjDdoypvyORjjJa3BlFA7eAnVIg==} dependencies: @@ -4860,6 +5059,32 @@ packages: '@parcel/watcher-win32-x64': 2.4.1 dev: false + /@peculiar/asn1-schema@2.3.13: + resolution: {integrity: sha512-3Xq3a01WkHRZL8X04Zsfg//mGaA21xlL4tlVn4v2xGT0JStiztATRkMwa5b+f/HXmY2smsiLXYK46Gwgzvfg3g==} + dependencies: + asn1js: 3.0.5 + pvtsutils: 1.3.5 + tslib: 2.6.3 + dev: true + + /@peculiar/json-schema@1.1.12: + resolution: {integrity: sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==} + engines: {node: '>=8.0.0'} + dependencies: + tslib: 2.6.3 + dev: true + + /@peculiar/webcrypto@1.5.0: + resolution: {integrity: sha512-BRs5XUAwiyCDQMsVA9IDvDa7UBR9gAvPHgugOeGng3YN6vJ9JYonyDc0lNczErgtCWtucjR5N7VtaonboD/ezg==} + engines: {node: '>=10.12.0'} + dependencies: + '@peculiar/asn1-schema': 2.3.13 + '@peculiar/json-schema': 1.1.12 + pvtsutils: 1.3.5 + tslib: 2.6.3 + webcrypto-core: 1.8.0 + dev: true + /@pkgjs/parseargs@0.11.0: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -4867,6 +5092,49 @@ packages: dev: true optional: true + /@protobufjs/aspromise@1.1.2: + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + dev: true + + /@protobufjs/base64@1.1.2: + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + dev: true + + /@protobufjs/codegen@2.0.4: + resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} + dev: true + + /@protobufjs/eventemitter@1.1.0: + resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} + dev: true + + /@protobufjs/fetch@1.1.0: + resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/inquire': 1.1.0 + dev: true + + /@protobufjs/float@1.0.2: + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + dev: true + + /@protobufjs/inquire@1.1.0: + resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} + dev: true + + /@protobufjs/path@1.1.2: + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + dev: true + + /@protobufjs/pool@1.1.0: + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + dev: true + + /@protobufjs/utf8@1.1.0: + resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + dev: true + /@rainbow-me/rainbowkit@2.1.3(@tanstack/react-query@5.51.16)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1)(viem@2.18.7)(wagmi@2.12.2): resolution: {integrity: sha512-teeB0HVQR75xSOUqMWCI0m6JJ/TvYXmbDSMr252/oElkV2UF0m/FFKGW04MBtQOg6wo9WK3nD5HVNEola4p7yA==} engines: {node: '>=12.4'} @@ -5355,6 +5623,10 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false + /@rescript/std@9.0.0: + resolution: {integrity: sha512-zGzFsgtZ44mgL4Xef2gOy1hrRVdrs9mcxCOOKZrIPsmbZW14yTkaF591GXxpQvjXiHtgZ/iA9qLyWH6oSReIxQ==} + dev: true + /@rnx-kit/chromium-edge-launcher@1.0.0: resolution: {integrity: sha512-lzD84av1ZQhYUS+jsGqJiCMaJO2dn9u+RTT9n9q6D3SaKVwWqv+7AoRKqBu19bkwyE+iFRl1ymr40QS90jVFYg==} engines: {node: '>=14.15'} @@ -6391,7 +6663,7 @@ packages: big.js: 6.2.1 bn.js: 5.2.1 cbor: 5.2.0 - debug: 4.3.6 + debug: 4.3.6(supports-color@8.1.1) lodash: 4.17.21 semver: 7.6.0 utf8: 3.0.0 @@ -6641,12 +6913,24 @@ packages: resolution: {integrity: sha512-Wj71sXE4Q4AkGdG9Tvq1u/fquNz9EdG4LIJMwVVII7ashjD/8cf8fyIfJAjRr6YcsXnSE8cOGQPq1gqeR8z+3w==} dev: true + /@types/cli-progress@3.11.6: + resolution: {integrity: sha512-cE3+jb9WRlu+uOSAugewNpITJDt1VF8dHOopPO4IABFc3SXYL5WE/+PTz/FCdZRRfIujiWW3n3aMbv1eIGVRWA==} + dependencies: + '@types/node': 22.0.2 + dev: true + /@types/concat-stream@1.6.1: resolution: {integrity: sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==} dependencies: '@types/node': 22.0.2 dev: true + /@types/connect@3.4.38: + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + dependencies: + '@types/node': 22.0.2 + dev: true + /@types/debug@4.1.12: resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} dependencies: @@ -6673,7 +6957,6 @@ packages: dependencies: '@types/jsonfile': 6.1.4 '@types/node': 22.0.2 - dev: true optional: true /@types/glob@7.2.0: @@ -6718,7 +7001,6 @@ packages: requiresBuild: true dependencies: '@types/node': 22.0.2 - dev: true optional: true /@types/keyv@3.1.4: @@ -6727,10 +7009,18 @@ packages: '@types/node': 12.20.55 dev: true + /@types/long@4.0.2: + resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==} + dev: true + /@types/lru-cache@5.1.1: resolution: {integrity: sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==} dev: true + /@types/minimatch@3.0.5: + resolution: {integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==} + dev: true + /@types/minimatch@5.1.2: resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} dev: true @@ -6775,6 +7065,10 @@ packages: resolution: {integrity: sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==} dev: true + /@types/parse-json@4.0.2: + resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + dev: true + /@types/pbkdf2@3.1.2: resolution: {integrity: sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==} dependencies: @@ -6823,6 +7117,12 @@ packages: resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} dev: false + /@types/ws@7.4.7: + resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==} + dependencies: + '@types/node': 22.0.2 + dev: true + /@types/yargs-parser@21.0.3: resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} dev: false @@ -6853,7 +7153,7 @@ packages: '@typescript-eslint/types': 7.2.0 '@typescript-eslint/typescript-estree': 7.2.0(typescript@5.5.4) '@typescript-eslint/visitor-keys': 7.2.0 - debug: 4.3.6 + debug: 4.3.6(supports-color@8.1.1) eslint: 8.57.0 typescript: 5.5.4 transitivePeerDependencies: @@ -6884,7 +7184,7 @@ packages: dependencies: '@typescript-eslint/types': 7.2.0 '@typescript-eslint/visitor-keys': 7.2.0 - debug: 4.3.6 + debug: 4.3.6(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 @@ -6975,7 +7275,7 @@ packages: dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 0.2.3 - debug: 4.3.6 + debug: 4.3.6(supports-color@8.1.1) istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 5.0.6 @@ -7575,6 +7875,46 @@ packages: tslib: 1.14.1 dev: false + /@whatwg-node/events@0.0.3: + resolution: {integrity: sha512-IqnKIDWfXBJkvy/k6tzskWTc2NK3LcqHlb+KHGCrjOCH4jfQckRX0NAiIcC/vIqQkzLYw2r2CTSwAxcrtcD6lA==} + dev: true + + /@whatwg-node/fetch@0.8.8: + resolution: {integrity: sha512-CdcjGC2vdKhc13KKxgsc6/616BQ7ooDIgPeTuAiE8qfCnS0mGzcfCOoZXypQSz73nxI+GWc7ZReIAVhxoE1KCg==} + dependencies: + '@peculiar/webcrypto': 1.5.0 + '@whatwg-node/node-fetch': 0.3.6 + busboy: 1.6.0 + urlpattern-polyfill: 8.0.2 + web-streams-polyfill: 3.3.3 + dev: true + + /@whatwg-node/node-fetch@0.3.6: + resolution: {integrity: sha512-w9wKgDO4C95qnXZRwZTfCmLWqyRnooGjcIwG0wADWjw9/HN0p7dtvtgSvItZtUyNteEvgTrd8QojNEqV6DAGTA==} + dependencies: + '@whatwg-node/events': 0.0.3 + busboy: 1.6.0 + fast-querystring: 1.1.2 + fast-url-parser: 1.1.3 + tslib: 2.6.3 + dev: true + + /JSONStream@1.3.2: + resolution: {integrity: sha512-mn0KSip7N4e0UDPZHnqDsHECo5uGQrixQKnAskOM1BIB8hd7QKbd6il8IPRPudPHOeHiECoCFqhyMaRO9+nWyA==} + hasBin: true + dependencies: + jsonparse: 1.3.1 + through: 2.3.8 + dev: true + + /JSONStream@1.3.5: + resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} + hasBin: true + dependencies: + jsonparse: 1.3.1 + through: 2.3.8 + dev: true + /abbrev@1.0.9: resolution: {integrity: sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==} dev: true @@ -7598,7 +7938,6 @@ packages: engines: {node: '>=6.5'} dependencies: event-target-shim: 5.0.1 - dev: false /abortcontroller-polyfill@1.7.5: resolution: {integrity: sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==} @@ -7648,7 +7987,7 @@ packages: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} dependencies: - debug: 4.3.6 + debug: 4.3.6(supports-color@8.1.1) transitivePeerDependencies: - supports-color dev: true @@ -7657,7 +7996,7 @@ packages: resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==} engines: {node: '>= 14'} dependencies: - debug: 4.3.6 + debug: 4.3.6(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -7746,7 +8085,6 @@ packages: /ansi-regex@4.1.1: resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==} engines: {node: '>=6'} - dev: false /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} @@ -7778,10 +8116,25 @@ packages: engines: {node: '>=12'} dev: true + /ansicolors@0.3.2: + resolution: {integrity: sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==} + dev: true + /antlr4ts@0.5.0-alpha.4: resolution: {integrity: sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==} dev: true + /any-signal@2.1.2: + resolution: {integrity: sha512-B+rDnWasMi/eWcajPcCWSlYc7muXOrcYrqgyzcdKisl2H/WTlQ0gip1KyQfr0ZlxJdsuWCj/LWwQm7fhyhRfIQ==} + dependencies: + abort-controller: 3.0.0 + native-abort-controller: 1.0.4(abort-controller@3.0.0) + dev: true + + /any-signal@3.0.1: + resolution: {integrity: sha512-xgZgJtKEa9YmDqXodIgl7Fl1C8yNXr8w6gXjqK3LW4GcEiYT+6AQfJSE/8SPsEpLLmcvbv8YU+qet94UewHxqg==} + dev: true + /anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} @@ -7789,6 +8142,18 @@ packages: normalize-path: 3.0.0 picomatch: 2.3.1 + /apisauce@2.1.6(debug@4.3.4): + resolution: {integrity: sha512-MdxR391op/FucS2YQRfB/NMRyCnHEPDd4h17LRIuVYi0BpGmMhpxc0shbOpfs5ahABuBEffNCGal5EcsydbBWg==} + dependencies: + axios: 0.21.4(debug@4.3.4) + transitivePeerDependencies: + - debug + dev: true + + /app-module-path@2.2.0: + resolution: {integrity: sha512-gkco+qxENJV+8vFcDiiFhuoSvRXb2a/QPqpSoWhVz829VNJfOTnELbBmPmNKFxf3xdNnw4DWCkzkDaavcX/1YQ==} + dev: true + /appdirsjs@1.2.7: resolution: {integrity: sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw==} dev: false @@ -7940,6 +8305,32 @@ packages: safer-buffer: 2.1.2 dev: true + /asn1js@3.0.5: + resolution: {integrity: sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==} + engines: {node: '>=12.0.0'} + dependencies: + pvtsutils: 1.3.5 + pvutils: 1.1.3 + tslib: 2.6.3 + dev: true + + /assemblyscript@0.19.10: + resolution: {integrity: sha512-HavcUBXB3mBTRGJcpvaQjmnmaqKHBGREjSPNsIvnAk2f9dj78y4BkMaSSdvBQYWcDDzsHQjyUC8stICFkD1Odg==} + hasBin: true + dependencies: + binaryen: 101.0.0-nightly.20210723 + long: 4.0.0 + dev: false + + /assemblyscript@0.19.23: + resolution: {integrity: sha512-fwOQNZVTMga5KRsfY80g7cpOl4PsFQczMwHzdtgoqLXaYhkhavufKb0sB0l3T1DUxpAufA0KNhlbpuuhZUwxMA==} + hasBin: true + dependencies: + binaryen: 102.0.0-nightly.20211028 + long: 5.2.3 + source-map-support: 0.5.21 + dev: true + /assert-plus@1.0.0: resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} engines: {node: '>=0.8'} @@ -7988,6 +8379,10 @@ packages: resolution: {integrity: sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==} dev: true + /async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + dev: true + /asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -8020,6 +8415,14 @@ packages: engines: {node: '>=4'} dev: true + /axios@0.21.4(debug@4.3.4): + resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==} + dependencies: + follow-redirects: 1.15.6(debug@4.3.4) + transitivePeerDependencies: + - debug + dev: true + /axios@1.6.8: resolution: {integrity: sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==} dependencies: @@ -8131,6 +8534,34 @@ packages: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} + /binary-install-raw@0.0.13(debug@4.3.4): + resolution: {integrity: sha512-v7ms6N/H7iciuk6QInon3/n2mu7oRX+6knJ9xFPsJ3rQePgAqcR3CRTwUheFd8SLbiq4LL7Z4G/44L9zscdt9A==} + engines: {node: '>=10'} + dependencies: + axios: 0.21.4(debug@4.3.4) + rimraf: 3.0.2 + tar: 6.2.1 + transitivePeerDependencies: + - debug + dev: true + + /binaryen@101.0.0-nightly.20210723: + resolution: {integrity: sha512-eioJNqhHlkguVSbblHOtLqlhtC882SOEPKmNFZaDuz1hzQjolxZ+eu3/kaS10n3sGPONsIZsO7R9fR00UyhEUA==} + hasBin: true + dev: false + + /binaryen@102.0.0-nightly.20211028: + resolution: {integrity: sha512-GCJBVB5exbxzzvyt8MGDv/MeUjs6gkXDvf4xOIItRBptYl0Tz5sm1o/uG95YK0L0VeG5ajDu3hRtkBP2kzqC5w==} + hasBin: true + dev: true + + /bl@1.2.3: + resolution: {integrity: sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==} + dependencies: + readable-stream: 2.3.8 + safe-buffer: 5.2.1 + dev: true + /bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} dependencies: @@ -8143,6 +8574,12 @@ packages: resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} dev: true + /blob-to-it@1.0.4: + resolution: {integrity: sha512-iCmk0W4NdbrWgRRuxOriU8aM5ijeVLI61Zulsmg/lUHNr7pYjoj+U77opLefNagevtrrbMt3JQ5Qip7ar178kA==} + dependencies: + browser-readablestream-to-it: 1.0.3 + dev: true + /bluebird@3.7.2: resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} dev: true @@ -8245,6 +8682,10 @@ packages: /brorand@1.1.0: resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} + /browser-readablestream-to-it@1.0.3: + resolution: {integrity: sha512-+12sHB+Br8HIh6VAMVEG5r3UXCyESIgDW7kzk3BjIXa43DVqVwL7GC5TW3jeh+72dtcH99pPVpw0X8i0jt+/kw==} + dev: true + /browser-stdout@1.3.1: resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} dev: true @@ -8311,6 +8752,21 @@ packages: node-int64: 0.4.0 dev: false + /buffer-alloc-unsafe@1.1.0: + resolution: {integrity: sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==} + dev: true + + /buffer-alloc@1.2.0: + resolution: {integrity: sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==} + dependencies: + buffer-alloc-unsafe: 1.1.0 + buffer-fill: 1.0.0 + dev: true + + /buffer-fill@1.0.0: + resolution: {integrity: sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==} + dev: true + /buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} @@ -8352,7 +8808,6 @@ packages: engines: {node: '>=10.16.0'} dependencies: streamsearch: 1.1.0 - dev: false /bytes@3.0.0: resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} @@ -8470,6 +8925,14 @@ packages: resolution: {integrity: sha512-dRg00gudiBDDTmUhClSdv3hqRfpbOnU28IpI1T6PBTLWa+kOj0681C8uML3PifYfREuBrVjDGhL3adYpBT6spw==} dev: false + /cardinal@2.1.1: + resolution: {integrity: sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==} + hasBin: true + dependencies: + ansicolors: 0.3.2 + redeyed: 2.1.1 + dev: true + /caseless@0.12.0: resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} dev: true @@ -8489,6 +8952,11 @@ packages: nofilter: 3.1.0 dev: true + /cborg@1.10.2: + resolution: {integrity: sha512-b3tFPA9pUr2zCUiCfRd2+wok2/LBSNUMKOuRRok+WlvvAgEt/PlbgPTsZUcwCOs53IJvLgTp0eotwtosE6njug==} + hasBin: true + dev: true + /chai-as-promised@7.1.1(chai@4.4.1): resolution: {integrity: sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==} peerDependencies: @@ -8650,6 +9118,11 @@ packages: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} dev: true + /chownr@2.0.0: + resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} + engines: {node: '>=10'} + dev: true + /chrome-launcher@0.15.2: resolution: {integrity: sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==} engines: {node: '>=12.13.0'} @@ -8705,6 +9178,13 @@ packages: engines: {node: '>=6'} dev: true + /clean-stack@3.0.1: + resolution: {integrity: sha512-lR9wNiMRcVQjSB3a7xXGLuz4cr4wJuuXlaAEbRutGowQTmlp7R72/DOgN21e8jdwblMWl9UOJMJXarX94pzKdg==} + engines: {node: '>=10'} + dependencies: + escape-string-regexp: 4.0.0 + dev: true + /cli-boxes@2.2.1: resolution: {integrity: sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==} engines: {node: '>=6'} @@ -8715,12 +9195,17 @@ packages: engines: {node: '>=8'} dependencies: restore-cursor: 3.1.0 - dev: false + + /cli-progress@3.12.0: + resolution: {integrity: sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==} + engines: {node: '>=4'} + dependencies: + string-width: 4.2.3 + dev: true /cli-spinners@2.9.2: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} - dev: false /cli-table3@0.5.1: resolution: {integrity: sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==} @@ -8732,6 +9217,16 @@ packages: colors: 1.4.0 dev: true + /cli-table3@0.6.0: + resolution: {integrity: sha512-gnB85c3MGC7Nm9I/FkiasNBOKjOiO1RNuXXarQms37q4QMpWdlbBgD/VnOStA2faG1dpXMv31RFApjX1/QdgWQ==} + engines: {node: 10.* || >= 12.*} + dependencies: + object-assign: 4.1.1 + string-width: 4.2.3 + optionalDependencies: + colors: 1.4.0 + dev: true + /client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} dev: false @@ -8795,7 +9290,6 @@ packages: /clone@1.0.4: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} - dev: false /clsx@1.2.1: resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==} @@ -8887,7 +9381,6 @@ packages: /commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - dev: false /commander@3.0.2: resolution: {integrity: sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==} @@ -9049,6 +9542,17 @@ packages: parse-json: 4.0.0 dev: false + /cosmiconfig@7.0.1: + resolution: {integrity: sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==} + engines: {node: '>=10'} + dependencies: + '@types/parse-json': 4.0.2 + import-fresh: 3.3.0 + parse-json: 5.2.0 + path-type: 4.0.0 + yaml: 1.10.2 + dev: true + /cosmiconfig@8.3.6(typescript@5.5.4): resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} engines: {node: '>=14'} @@ -9336,7 +9840,7 @@ packages: ms: 2.1.2 dev: true - /debug@4.3.6: + /debug@4.3.6(supports-color@8.1.1): resolution: {integrity: sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==} engines: {node: '>=6.0'} peerDependencies: @@ -9346,6 +9850,7 @@ packages: optional: true dependencies: ms: 2.1.2 + supports-color: 8.1.1 /decamelize@1.2.0: resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} @@ -9434,7 +9939,6 @@ packages: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} dependencies: clone: 1.0.4 - dev: false /defer-to-connect@2.0.1: resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} @@ -9466,6 +9970,11 @@ packages: resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} dev: false + /delay@5.0.0: + resolution: {integrity: sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==} + engines: {node: '>=10'} + dev: true + /delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -9541,12 +10050,53 @@ packages: path-type: 4.0.0 dev: true + /dns-over-http-resolver@1.2.3(node-fetch@2.7.0): + resolution: {integrity: sha512-miDiVSI6KSNbi4SVifzO/reD8rMnxgrlnkrlkugOLQpWQTe2qMdHsZp5DmfKjxNE+/T3VAAYLQUZMv9SMr6+AA==} + dependencies: + debug: 4.3.6(supports-color@8.1.1) + native-fetch: 3.0.0(node-fetch@2.7.0) + receptacle: 1.3.2 + transitivePeerDependencies: + - node-fetch + - supports-color + dev: true + /dnum@2.13.1: resolution: {integrity: sha512-4oZ+BtlvNtKFJji1Fc5073LyJFvgioBQ0PNu/C+r1A8P09Yvka/aXYYD5bsUHMTUPEu01iv4bk+5nPQmt5AA8A==} dependencies: from-exponential: 1.1.1 dev: false + /docker-compose@0.23.19: + resolution: {integrity: sha512-v5vNLIdUqwj4my80wxFDkNH+4S85zsRuH29SO7dCWVWPCMt/ohZBsGN6g6KXWifT0pzQ7uOxqEKCYCDPJ8Vz4g==} + engines: {node: '>= 6.0.0'} + dependencies: + yaml: 1.10.2 + dev: true + + /docker-modem@1.0.9: + resolution: {integrity: sha512-lVjqCSCIAUDZPAZIeyM125HXfNvOmYYInciphNrLrylUtKyW66meAjSPXWchKVzoIYZx69TPnAepVSSkeawoIw==} + engines: {node: '>= 0.8'} + dependencies: + JSONStream: 1.3.2 + debug: 3.2.7 + readable-stream: 1.0.34 + split-ca: 1.0.1 + transitivePeerDependencies: + - supports-color + dev: true + + /dockerode@2.5.8: + resolution: {integrity: sha512-+7iOUYBeDTScmOmQqpUYQaE7F4vvIt6+gIZNHWhqAQEI887tiPFB9OvXI/HzQYqfUNvukMK+9myLW63oTJPZpw==} + engines: {node: '>= 0.8'} + dependencies: + concat-stream: 1.6.2 + docker-modem: 1.0.9 + tar-fs: 1.16.3 + transitivePeerDependencies: + - supports-color + dev: true + /doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} @@ -9659,6 +10209,29 @@ packages: /ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + /ejs@3.1.10: + resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} + engines: {node: '>=0.10.0'} + hasBin: true + dependencies: + jake: 10.9.2 + dev: true + + /ejs@3.1.8: + resolution: {integrity: sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==} + engines: {node: '>=0.10.0'} + hasBin: true + dependencies: + jake: 10.9.2 + dev: true + + /electron-fetch@1.9.1: + resolution: {integrity: sha512-M9qw6oUILGVrcENMSRRefE1MbHPIz0h79EKIeJWK9v563aT9Qkh8aEHPO1H5vi970wPirNY+jO9OpFoLiMsMGA==} + engines: {node: '>=6'} + dependencies: + encoding: 0.1.13 + dev: true + /electron-to-chromium@1.4.751: resolution: {integrity: sha512-2DEPi++qa89SMGRhufWTiLmzqyuGmNF3SK4+PQetW1JKiZdEpF4XQonJXJCzyuYSA6mauiMhbyVhqYAP45Hvfw==} dev: true @@ -9716,6 +10289,12 @@ packages: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} + /encoding@0.1.13: + resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} + dependencies: + iconv-lite: 0.6.3 + dev: true + /end-of-stream@1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} dependencies: @@ -9725,7 +10304,7 @@ packages: resolution: {integrity: sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==} dependencies: '@socket.io/component-emitter': 3.1.2 - debug: 4.3.6 + debug: 4.3.6(supports-color@8.1.1) engine.io-parser: 5.2.3 ws: 8.17.1 xmlhttprequest-ssl: 2.0.0 @@ -9748,6 +10327,13 @@ packages: tapable: 2.2.1 dev: true + /enquirer@2.3.6: + resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==} + engines: {node: '>=8.6'} + dependencies: + ansi-colors: 4.1.3 + dev: true + /enquirer@2.4.1: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} engines: {node: '>=8.6'} @@ -9771,6 +10357,10 @@ packages: hasBin: true dev: false + /err-code@3.0.1: + resolution: {integrity: sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==} + dev: true + /error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: @@ -9940,6 +10530,12 @@ packages: resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} dev: true + /es6-promisify@5.0.0: + resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==} + dependencies: + es6-promise: 4.2.8 + dev: true + /es6-promisify@7.0.0: resolution: {integrity: sha512-ginqzK3J90Rd4/Yz7qRrqUeIpe3TwSXTPPZtPne7tGBPeAaQiU8qt4fpKApnxHcq1AwtUdHVg5P77x/yrggG8Q==} engines: {node: '>=6'} @@ -10012,7 +10608,6 @@ packages: '@esbuild/win32-arm64': 0.21.5 '@esbuild/win32-ia32': 0.21.5 '@esbuild/win32-x64': 0.21.5 - dev: true /escalade@3.1.2: resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} @@ -10089,7 +10684,7 @@ packages: eslint: '*' eslint-plugin-import: '*' dependencies: - debug: 4.3.6 + debug: 4.3.6(supports-color@8.1.1) enhanced-resolve: 5.17.1 eslint: 8.57.0 eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) @@ -10646,7 +11241,6 @@ packages: /event-target-shim@5.0.1: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} - dev: false /eventemitter2@6.4.9: resolution: {integrity: sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==} @@ -10689,7 +11283,6 @@ packages: onetime: 5.1.2 signal-exit: 3.0.7 strip-final-newline: 2.0.0 - dev: false /execa@8.0.1: resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} @@ -10806,6 +11399,11 @@ packages: engines: {'0': node >=0.6.0} dev: true + /eyes@0.1.8: + resolution: {integrity: sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==} + engines: {node: '> 0.1.90'} + dev: true + /fast-check@3.1.1: resolution: {integrity: sha512-3vtXinVyuUKCKFKYcwXhGE6NtGWkqF8Yh3rvMZNzmwz8EPrgoc/v4pDdLHyLnCyCI5MZpZZkDEwFyXyEONOxpA==} engines: {node: '>=8.0.0'} @@ -10813,9 +11411,17 @@ packages: pure-rand: 5.0.5 dev: true + /fast-decode-uri-component@1.0.1: + resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} + dev: true + /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + /fast-fifo@1.3.2: + resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + dev: true + /fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} @@ -10834,6 +11440,18 @@ packages: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} dev: true + /fast-levenshtein@3.0.0: + resolution: {integrity: sha512-hKKNajm46uNmTlhHSyZkmToAc56uZJwYq7yrciZjqOxnlfQwERDQJmHPUp7m1m9wx8vgOe8IaCKZ5Kv2k1DdCQ==} + dependencies: + fastest-levenshtein: 1.0.16 + dev: true + + /fast-querystring@1.1.2: + resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==} + dependencies: + fast-decode-uri-component: 1.0.1 + dev: true + /fast-redact@3.5.0: resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} engines: {node: '>=6'} @@ -10843,6 +11461,12 @@ packages: resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} dev: false + /fast-url-parser@1.1.3: + resolution: {integrity: sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==} + dependencies: + punycode: 1.4.1 + dev: true + /fast-xml-parser@4.4.1: resolution: {integrity: sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==} hasBin: true @@ -10850,6 +11474,11 @@ packages: strnum: 1.0.5 dev: false + /fastest-levenshtein@1.0.16: + resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} + engines: {node: '>= 4.9.1'} + dev: true + /fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} dependencies: @@ -10871,6 +11500,12 @@ packages: /file-size@1.0.0: resolution: {integrity: sha512-tLIdonWTpABkU6Axg2yGChYdrOsy4V8xcm0IcyAP8fSsu6jiXLm5pgs083e4sq5fzNRZuAYolUbZyYmPvCKfwQ==} + /filelist@1.0.4: + resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} + dependencies: + minimatch: 5.0.1 + dev: true + /filesize@10.1.4: resolution: {integrity: sha512-ryBwPIIeErmxgPnm6cbESAzXjuEFubs+yKYLBZvg3CaiNcmkJChoOGcBSrZ6IwkMwPABwPpVXE6IlNdGJJrvEg==} engines: {node: '>= 10.4.0'} @@ -11103,6 +11738,10 @@ packages: resolution: {integrity: sha512-VBE7f5OVnYwdgB3LHa+Qo29h8qVpxhVO9Trlc+AWm+/XNAgks1tAwMFHb33mjeiof77GglsJzeYF7OqXrROP/A==} dev: false + /fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + dev: true + /fs-extra@0.30.0: resolution: {integrity: sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==} dependencies: @@ -11156,12 +11795,26 @@ packages: universalify: 2.0.1 dev: true + /fs-jetpack@4.3.1: + resolution: {integrity: sha512-dbeOK84F6BiQzk2yqqCVwCPWTxAvVGJ3fMQc6E2wuEohS28mR6yHngbrKuVCK1KHRx/ccByDylqu4H5PCP2urQ==} + dependencies: + minimatch: 3.1.2 + rimraf: 2.7.1 + dev: true + /fs-minipass@1.2.7: resolution: {integrity: sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==} dependencies: minipass: 2.9.0 dev: true + /fs-minipass@2.1.0: + resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} + engines: {node: '>= 8'} + dependencies: + minipass: 3.3.6 + dev: true + /fs-readdir-recursive@1.1.0: resolution: {integrity: sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==} dev: true @@ -11232,11 +11885,20 @@ packages: has-symbols: 1.0.3 hasown: 2.0.2 + /get-iterator@1.0.2: + resolution: {integrity: sha512-v+dm9bNVfOYsY1OrhaCrmyOcYoSeVvbt+hHZ0Au+T+p1y+0Uyj9aMaGIeUTT6xdpRbWzDeYKvfOslPhggQMcsg==} + dev: true + /get-nonce@1.0.1: resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} engines: {node: '>=6'} dev: false + /get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + dev: true + /get-port-please@3.1.2: resolution: {integrity: sha512-Gxc29eLs1fbn6LQ4jSU4vXjlwyZhF5HsGuMAa7gqBP4Rw4yxxltyDUuF5MBclFzDTXO+ACchGQoeela4DSfzdQ==} dev: false @@ -11274,7 +11936,6 @@ packages: resolution: {integrity: sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA==} dependencies: resolve-pkg-maps: 1.0.0 - dev: true /getpass@0.1.7: resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} @@ -11380,6 +12041,16 @@ packages: once: 1.4.0 dev: true + /glob@9.3.5: + resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + fs.realpath: 1.0.0 + minimatch: 8.0.4 + minipass: 4.2.8 + path-scurry: 1.11.1 + dev: true + /global-modules@2.0.0: resolution: {integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==} engines: {node: '>=6'} @@ -11457,6 +12128,44 @@ packages: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} dev: true + /gluegun@5.1.6(debug@4.3.4): + resolution: {integrity: sha512-9zbi4EQWIVvSOftJWquWzr9gLX2kaDgPkNR5dYWbM53eVvCI3iKuxLlnKoHC0v4uPoq+Kr/+F569tjoFbA4DSA==} + hasBin: true + dependencies: + apisauce: 2.1.6(debug@4.3.4) + app-module-path: 2.2.0 + cli-table3: 0.6.0 + colors: 1.4.0 + cosmiconfig: 7.0.1 + cross-spawn: 7.0.3 + ejs: 3.1.8 + enquirer: 2.3.6 + execa: 5.1.1 + fs-jetpack: 4.3.1 + lodash.camelcase: 4.3.0 + lodash.kebabcase: 4.1.1 + lodash.lowercase: 4.3.0 + lodash.lowerfirst: 4.3.1 + lodash.pad: 4.5.1 + lodash.padend: 4.6.1 + lodash.padstart: 4.6.1 + lodash.repeat: 4.1.0 + lodash.snakecase: 4.1.1 + lodash.startcase: 4.4.0 + lodash.trim: 4.5.1 + lodash.trimend: 4.5.1 + lodash.trimstart: 4.5.1 + lodash.uppercase: 4.3.0 + lodash.upperfirst: 4.3.1 + ora: 4.0.2 + pluralize: 8.0.0 + semver: 7.3.5 + which: 2.0.2 + yargs-parser: 21.1.1 + transitivePeerDependencies: + - debug + dev: true + /gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} dependencies: @@ -11505,6 +12214,24 @@ packages: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} dev: true + /graphql-import-node@0.0.5(graphql@16.9.0): + resolution: {integrity: sha512-OXbou9fqh9/Lm7vwXT0XoRN9J5+WCYKnbiTalgFDvkQERITRmcfncZs6aVABedd5B85yQU5EULS4a5pnbpuI0Q==} + peerDependencies: + graphql: '*' + dependencies: + graphql: 16.9.0 + dev: true + + /graphql@15.5.0: + resolution: {integrity: sha512-OmaM7y0kaK31NKG31q4YbD2beNYa6jBBKtMFT6gLYJljHLJr42IqJ8KX08u3Li/0ifzTU5HjmoOOrwa5BRLeDA==} + engines: {node: '>= 10.x'} + dev: true + + /graphql@16.9.0: + resolution: {integrity: sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + dev: true + /h3@1.12.0: resolution: {integrity: sha512-Zi/CcNeWBXDrFNlV0hUBJQR9F7a96RjMeAZweW/ZWkR9fuXrMcvKnSA63f/zZ9l0GgQOZDVHGvXivNN9PWOwhA==} dependencies: @@ -11814,7 +12541,7 @@ packages: engines: {node: '>= 14'} dependencies: agent-base: 7.1.1 - debug: 4.3.6 + debug: 4.3.6(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -11898,19 +12625,23 @@ packages: engines: {node: '>= 14'} dependencies: agent-base: 7.1.1 - debug: 4.3.6 + debug: 4.3.6(supports-color@8.1.1) transitivePeerDependencies: - supports-color /human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} - dev: false /human-signals@5.0.0: resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} engines: {node: '>=16.17.0'} + /hyperlinker@1.0.0: + resolution: {integrity: sha512-Ty8UblRWFEcfSuIaajM34LdPXIhbs1ajEX/BBPv24J+enSVaEVY63xQ6lTO9VRYS5LAoghIG0IDJ+p+IPzKUQQ==} + engines: {node: '>=4'} + dev: true + /i18next-browser-languagedetector@7.1.0: resolution: {integrity: sha512-cr2k7u1XJJ4HTOjM9GyOMtbOA47RtUoWRAtt52z43r3AoMs2StYKyjS3URPhzHaf+mn10hY9dZWamga5WPQjhA==} dependencies: @@ -11963,6 +12694,10 @@ packages: queue: 6.0.2 dev: false + /immutable@4.2.1: + resolution: {integrity: sha512-7WYV7Q5BTs0nlQm7tl92rDYYoyELLKHoDMBKhrxEoiV4mrfVdRz8hzPiYOzH7yWjzoVEamxRuAqhxL2PLRwZYQ==} + dev: true + /immutable@4.3.5: resolution: {integrity: sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==} dev: true @@ -12011,6 +12746,18 @@ packages: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} dev: true + /interface-datastore@6.1.1: + resolution: {integrity: sha512-AmCS+9CT34pp2u0QQVXjKztkuq3y5T+BIciuiHDDtDZucZD8VudosnSdUyXJV6IsRkN5jc4RFDhCk1O6Q3Gxjg==} + dependencies: + interface-store: 2.0.2 + nanoid: 3.3.7 + uint8arrays: 3.1.0 + dev: true + + /interface-store@2.0.2: + resolution: {integrity: sha512-rScRlhDcz6k199EkHqT8NpM87ebN89ICOzILoBHgaG36/WX50N32BnU/kpZgCGPLhARRAWUUX5/cyaIjt7Kipg==} + dev: true + /internal-slot@1.0.7: resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} engines: {node: '>= 0.4'} @@ -12042,11 +12789,120 @@ packages: fp-ts: 1.19.3 dev: true + /ip-regex@4.3.0: + resolution: {integrity: sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==} + engines: {node: '>=8'} + dev: true + /ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} dev: true + /ipfs-core-types@0.9.0(node-fetch@2.7.0): + resolution: {integrity: sha512-VJ8vJSHvI1Zm7/SxsZo03T+zzpsg8pkgiIi5hfwSJlsrJ1E2v68QPlnLshGHUSYw89Oxq0IbETYl2pGTFHTWfg==} + deprecated: js-IPFS has been deprecated in favour of Helia - please see https://github.com/ipfs/js-ipfs/issues/4336 for details + dependencies: + interface-datastore: 6.1.1 + multiaddr: 10.0.1(node-fetch@2.7.0) + multiformats: 9.9.0 + transitivePeerDependencies: + - node-fetch + - supports-color + dev: true + + /ipfs-core-utils@0.13.0(node-fetch@2.7.0): + resolution: {integrity: sha512-HP5EafxU4/dLW3U13CFsgqVO5Ika8N4sRSIb/dTg16NjLOozMH31TXV0Grtu2ZWo1T10ahTzMvrfT5f4mhioXw==} + deprecated: js-IPFS has been deprecated in favour of Helia - please see https://github.com/ipfs/js-ipfs/issues/4336 for details + dependencies: + any-signal: 2.1.2 + blob-to-it: 1.0.4 + browser-readablestream-to-it: 1.0.3 + debug: 4.3.6(supports-color@8.1.1) + err-code: 3.0.1 + ipfs-core-types: 0.9.0(node-fetch@2.7.0) + ipfs-unixfs: 6.0.9 + ipfs-utils: 9.0.14 + it-all: 1.0.6 + it-map: 1.0.6 + it-peekable: 1.0.3 + it-to-stream: 1.0.0 + merge-options: 3.0.4 + multiaddr: 10.0.1(node-fetch@2.7.0) + multiaddr-to-uri: 8.0.0(node-fetch@2.7.0) + multiformats: 9.9.0 + nanoid: 3.3.7 + parse-duration: 1.1.0 + timeout-abort-controller: 2.0.0 + uint8arrays: 3.1.0 + transitivePeerDependencies: + - encoding + - node-fetch + - supports-color + dev: true + + /ipfs-http-client@55.0.0(node-fetch@2.7.0): + resolution: {integrity: sha512-GpvEs7C7WL9M6fN/kZbjeh4Y8YN7rY8b18tVWZnKxRsVwM25cIFrRI8CwNt3Ugin9yShieI3i9sPyzYGMrLNnQ==} + engines: {node: '>=14.0.0', npm: '>=3.0.0'} + deprecated: js-IPFS has been deprecated in favour of Helia - please see https://github.com/ipfs/js-ipfs/issues/4336 for details + dependencies: + '@ipld/dag-cbor': 7.0.3 + '@ipld/dag-json': 8.0.11 + '@ipld/dag-pb': 2.1.18 + abort-controller: 3.0.0 + any-signal: 2.1.2 + debug: 4.3.6(supports-color@8.1.1) + err-code: 3.0.1 + ipfs-core-types: 0.9.0(node-fetch@2.7.0) + ipfs-core-utils: 0.13.0(node-fetch@2.7.0) + ipfs-utils: 9.0.14 + it-first: 1.0.7 + it-last: 1.0.6 + merge-options: 3.0.4 + multiaddr: 10.0.1(node-fetch@2.7.0) + multiformats: 9.9.0 + native-abort-controller: 1.0.4(abort-controller@3.0.0) + parse-duration: 1.1.0 + stream-to-it: 0.2.4 + uint8arrays: 3.1.0 + transitivePeerDependencies: + - encoding + - node-fetch + - supports-color + dev: true + + /ipfs-unixfs@6.0.9: + resolution: {integrity: sha512-0DQ7p0/9dRB6XCb0mVCTli33GzIzSVx5udpJuVM47tGcD+W+Bl4LsnoLswd3ggNnNEakMv1FdoFITiEnchXDqQ==} + engines: {node: '>=16.0.0', npm: '>=7.0.0'} + dependencies: + err-code: 3.0.1 + protobufjs: 6.11.4 + dev: true + + /ipfs-utils@9.0.14: + resolution: {integrity: sha512-zIaiEGX18QATxgaS0/EOQNoo33W0islREABAcxXE8n7y2MGAlB+hdsxXn4J0hGZge8IqVQhW8sWIb+oJz2yEvg==} + engines: {node: '>=16.0.0', npm: '>=7.0.0'} + dependencies: + any-signal: 3.0.1 + browser-readablestream-to-it: 1.0.3 + buffer: 6.0.3 + electron-fetch: 1.9.1 + err-code: 3.0.1 + is-electron: 2.2.2 + iso-url: 1.2.1 + it-all: 1.0.6 + it-glob: 1.0.2 + it-to-stream: 1.0.0 + merge-options: 3.0.4 + nanoid: 3.3.7 + native-fetch: 3.0.0(node-fetch@2.7.0) + node-fetch: 2.7.0 + react-native-fetch-api: 3.0.0 + stream-to-it: 0.2.4 + transitivePeerDependencies: + - encoding + dev: true + /iron-webcrypto@1.2.1: resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} dev: false @@ -12157,6 +13013,10 @@ packages: hasBin: true dev: false + /is-electron@2.2.2: + resolution: {integrity: sha512-FO/Rhvz5tuw4MCWkpMzHFKWD2LsfHzIb7i6MdPYZ/KW7AlxawyLkqdy+jPZP1WubqEADE3O4FUENlJHDfQASRg==} + dev: true + /is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -12214,7 +13074,13 @@ packages: /is-interactive@1.0.0: resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} engines: {node: '>=8'} - dev: false + + /is-ip@3.1.0: + resolution: {integrity: sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q==} + engines: {node: '>=8'} + dependencies: + ip-regex: 4.3.0 + dev: true /is-lower-case@1.1.3: resolution: {integrity: sha512-+5A1e/WJpLLXZEDlgz4G//WYSHyQBD32qa4Jd3Lw06qQlv3fJHnp3YIHjTQSGzHMgzmVKz2ZP3rBxTHkPw/lxA==} @@ -12291,7 +13157,6 @@ packages: /is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} - dev: false /is-stream@3.0.0: resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} @@ -12383,6 +13248,10 @@ packages: system-architecture: 0.1.0 dev: false + /isarray@0.0.1: + resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==} + dev: true + /isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} @@ -12398,6 +13267,11 @@ packages: engines: {node: '>=16'} dev: true + /iso-url@1.2.1: + resolution: {integrity: sha512-9JPDgCN4B7QPkLtYAAOrEuAWvP9rWvR5offAr0/SeF046wIkglqH3VXgYYP6NcsKslH80UIVgmPqNe3j7tG2ng==} + engines: {node: '>=12'} + dev: true + /isobject@3.0.1: resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} engines: {node: '>=0.10.0'} @@ -12412,6 +13286,14 @@ packages: - encoding dev: false + /isomorphic-ws@4.0.1(ws@7.5.10): + resolution: {integrity: sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==} + peerDependencies: + ws: '*' + dependencies: + ws: 7.5.10 + dev: true + /isows@1.0.4(ws@8.17.1): resolution: {integrity: sha512-hEzjY+x9u9hPmBom9IIAqdJCwNLax+xrPb51vEPpERoFlIxgmZcHzsT5jKG06nvInKOBGvReAVz80Umed5CczQ==} peerDependencies: @@ -12443,7 +13325,7 @@ packages: engines: {node: '>=10'} dependencies: '@jridgewell/trace-mapping': 0.3.25 - debug: 4.3.6 + debug: 4.3.6(supports-color@8.1.1) istanbul-lib-coverage: 3.2.2 transitivePeerDependencies: - supports-color @@ -12457,6 +13339,44 @@ packages: istanbul-lib-report: 3.0.1 dev: true + /it-all@1.0.6: + resolution: {integrity: sha512-3cmCc6Heqe3uWi3CVM/k51fa/XbMFpQVzFoDsV0IZNHSQDyAXl3c4MjHkFX5kF3922OGj7Myv1nSEUgRtcuM1A==} + dev: true + + /it-first@1.0.7: + resolution: {integrity: sha512-nvJKZoBpZD/6Rtde6FXqwDqDZGF1sCADmr2Zoc0hZsIvnE449gRFnGctxDf09Bzc/FWnHXAdaHVIetY6lrE0/g==} + dev: true + + /it-glob@1.0.2: + resolution: {integrity: sha512-Ch2Dzhw4URfB9L/0ZHyY+uqOnKvBNeS/SMcRiPmJfpHiM0TsUZn+GkpcZxAoF3dJVdPm/PuIk3A4wlV7SUo23Q==} + dependencies: + '@types/minimatch': 3.0.5 + minimatch: 3.1.2 + dev: true + + /it-last@1.0.6: + resolution: {integrity: sha512-aFGeibeiX/lM4bX3JY0OkVCFkAw8+n9lkukkLNivbJRvNz8lI3YXv5xcqhFUV2lDJiraEK3OXRDbGuevnnR67Q==} + dev: true + + /it-map@1.0.6: + resolution: {integrity: sha512-XT4/RM6UHIFG9IobGlQPFQUrlEKkU4eBUFG3qhWhfAdh1JfF2x11ShCrKCdmZ0OiZppPfoLuzcfA4cey6q3UAQ==} + dev: true + + /it-peekable@1.0.3: + resolution: {integrity: sha512-5+8zemFS+wSfIkSZyf0Zh5kNN+iGyccN02914BY4w/Dj+uoFEoPSvj5vaWn8pNZJNSxzjW0zHRxC3LUb2KWJTQ==} + dev: true + + /it-to-stream@1.0.0: + resolution: {integrity: sha512-pLULMZMAB/+vbdvbZtebC0nWBTbG581lk6w8P7DfIIIKUfa8FbY7Oi0FxZcFPbxvISs7A9E+cMpLDBc1XhpAOA==} + dependencies: + buffer: 6.0.3 + fast-fifo: 1.3.2 + get-iterator: 1.0.2 + p-defer: 3.0.0 + p-fifo: 1.0.0 + readable-stream: 3.6.2 + dev: true + /iterator.prototype@1.1.2: resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} dependencies: @@ -12484,9 +13404,42 @@ packages: '@pkgjs/parseargs': 0.11.0 dev: true + /jake@10.9.2: + resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + async: 3.2.6 + chalk: 4.1.2 + filelist: 1.0.4 + minimatch: 3.1.2 + dev: true + /javascript-stringify@2.1.0: resolution: {integrity: sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==} + /jayson@4.0.0: + resolution: {integrity: sha512-v2RNpDCMu45fnLzSk47vx7I+QUaOsox6f5X0CUlabAFwxoP+8MfAY0NQRFwOEYXIxm8Ih5y6OaEa5KYiQMkyAA==} + engines: {node: '>=8'} + hasBin: true + dependencies: + '@types/connect': 3.4.38 + '@types/node': 12.20.55 + '@types/ws': 7.4.7 + JSONStream: 1.3.5 + commander: 2.20.3 + delay: 5.0.0 + es6-promisify: 5.0.0 + eyes: 0.1.8 + isomorphic-ws: 4.0.1(ws@7.5.10) + json-stringify-safe: 5.0.1 + uuid: 8.3.2 + ws: 7.5.10 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: true + /jest-environment-node@29.7.0: resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -12777,6 +13730,11 @@ packages: optionalDependencies: graceful-fs: 4.2.11 + /jsonparse@1.3.1: + resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} + engines: {'0': node >= 0.2.0} + dev: true + /jsonschema@1.4.1: resolution: {integrity: sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==} dev: true @@ -13105,16 +14063,64 @@ packages: /lodash.isequal@4.5.0: resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + /lodash.kebabcase@4.1.1: + resolution: {integrity: sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==} + dev: true + + /lodash.lowercase@4.3.0: + resolution: {integrity: sha512-UcvP1IZYyDKyEL64mmrwoA1AbFu5ahojhTtkOUr1K9dbuxzS9ev8i4TxMMGCqRC9TE8uDaSoufNAXxRPNTseVA==} + dev: true + + /lodash.lowerfirst@4.3.1: + resolution: {integrity: sha512-UUKX7VhP1/JL54NXg2aq/E1Sfnjjes8fNYTNkPU8ZmsaVeBvPHKdbNaN79Re5XRL01u6wbq3j0cbYZj71Fcu5w==} + dev: true + /lodash.memoize@4.1.2: resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + /lodash.pad@4.5.1: + resolution: {integrity: sha512-mvUHifnLqM+03YNzeTBS1/Gr6JRFjd3rRx88FHWUvamVaT9k2O/kXha3yBSOwB9/DTQrSTLJNHvLBBt2FdX7Mg==} + dev: true + + /lodash.padend@4.6.1: + resolution: {integrity: sha512-sOQs2aqGpbl27tmCS1QNZA09Uqp01ZzWfDUoD+xzTii0E7dSQfRKcRetFwa+uXaxaqL+TKm7CgD2JdKP7aZBSw==} + dev: true + + /lodash.padstart@4.6.1: + resolution: {integrity: sha512-sW73O6S8+Tg66eY56DBk85aQzzUJDtpoXFBgELMd5P/SotAguo+1kYO6RuYgXxA4HJH3LFTFPASX6ET6bjfriw==} + dev: true + + /lodash.repeat@4.1.0: + resolution: {integrity: sha512-eWsgQW89IewS95ZOcr15HHCX6FVDxq3f2PNUIng3fyzsPev9imFQxIYdFZ6crl8L56UR6ZlGDLcEb3RZsCSSqw==} + dev: true + + /lodash.snakecase@4.1.1: + resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==} + dev: true + + /lodash.startcase@4.4.0: + resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} + dev: true + /lodash.throttle@4.1.1: resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==} dev: false + /lodash.trim@4.5.1: + resolution: {integrity: sha512-nJAlRl/K+eiOehWKDzoBVrSMhK0K3A3YQsUNXHQa5yIrKBAhsZgSu3KoAFoFT+mEgiyBHddZ0pRk1ITpIp90Wg==} + dev: true + + /lodash.trimend@4.5.1: + resolution: {integrity: sha512-lsD+k73XztDsMBKPKvzHXRKFNMohTjoTKIIo4ADLn5dA65LZ1BqlAvSXhR2rPEC3BgAUQnzMnorqDtqn2z4IHA==} + dev: true + + /lodash.trimstart@4.5.1: + resolution: {integrity: sha512-b/+D6La8tU76L/61/aN0jULWHkT0EeJCmVstPBn/K9MtD2qBW83AsBNrr63dKuWYwVMO7ucv13QNO/Ek/2RKaQ==} + dev: true + /lodash.truncate@4.4.2: resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} dev: true @@ -13122,10 +14128,25 @@ packages: /lodash.uniq@4.5.0: resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} + /lodash.uppercase@4.3.0: + resolution: {integrity: sha512-+Nbnxkj7s8K5U8z6KnEYPGUOGp3woZbB7Ecs7v3LkkjLQSm2kP9SKIILitN1ktn2mB/tmM9oSlku06I+/lH7QA==} + dev: true + + /lodash.upperfirst@4.3.1: + resolution: {integrity: sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==} + dev: true + /lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} dev: true + /log-symbols@3.0.0: + resolution: {integrity: sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==} + engines: {node: '>=8'} + dependencies: + chalk: 2.4.2 + dev: true + /log-symbols@4.1.0: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} @@ -13142,6 +14163,13 @@ packages: yargs: 15.4.1 dev: false + /long@4.0.0: + resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} + + /long@5.2.3: + resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==} + dev: true + /look-it-up@2.1.0: resolution: {integrity: sha512-nMoGWW2HurtuJf6XAL56FWTDCWLOTSsanrgwOyaR5Y4e3zfG5N/0cU5xWZSEU3tBxhQugRbV1xL9jb+ug7yZww==} @@ -13317,6 +14345,13 @@ packages: resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} dev: true + /merge-options@3.0.4: + resolution: {integrity: sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==} + engines: {node: '>=10'} + dependencies: + is-plain-obj: 2.1.0 + dev: true + /merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -13595,7 +14630,6 @@ packages: /mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} - dev: false /mimic-fn@4.0.0: resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} @@ -13646,6 +14680,13 @@ packages: brace-expansion: 2.0.1 dev: true + /minimatch@8.0.4: + resolution: {integrity: sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + dev: true + /minimatch@9.0.3: resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} engines: {node: '>=16 || 14 >=14.17'} @@ -13676,6 +14717,23 @@ packages: yallist: 3.1.1 dev: true + /minipass@3.3.6: + resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} + engines: {node: '>=8'} + dependencies: + yallist: 4.0.0 + dev: true + + /minipass@4.2.8: + resolution: {integrity: sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==} + engines: {node: '>=8'} + dev: true + + /minipass@5.0.0: + resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} + engines: {node: '>=8'} + dev: true + /minipass@7.0.4: resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} engines: {node: '>=16 || 14 >=14.17'} @@ -13692,6 +14750,14 @@ packages: minipass: 2.9.0 dev: true + /minizlib@2.1.2: + resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} + engines: {node: '>= 8'} + dependencies: + minipass: 3.3.6 + yallist: 4.0.0 + dev: true + /mipd@0.0.7(typescript@5.5.4): resolution: {integrity: sha512-aAPZPNDQ3uMTdKbuO2YmAw2TxLHO0moa4YKAyETM/DTj5FloZo+a+8tU+iv4GmW+sOxKLSRwcSFuczk+Cpt6fg==} peerDependencies: @@ -13805,6 +14871,31 @@ packages: resolution: {integrity: sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==} dev: true + /multiaddr-to-uri@8.0.0(node-fetch@2.7.0): + resolution: {integrity: sha512-dq4p/vsOOUdVEd1J1gl+R2GFrXJQH8yjLtz4hodqdVbieg39LvBOdMQRdQnfbg5LSM/q1BYNVf5CBbwZFFqBgA==} + deprecated: This module is deprecated, please upgrade to @multiformats/multiaddr-to-uri + dependencies: + multiaddr: 10.0.1(node-fetch@2.7.0) + transitivePeerDependencies: + - node-fetch + - supports-color + dev: true + + /multiaddr@10.0.1(node-fetch@2.7.0): + resolution: {integrity: sha512-G5upNcGzEGuTHkzxezPrrD6CaIHR9uo+7MwqhNVcXTs33IInon4y7nMiGxl2CY5hG7chvYQUQhz5V52/Qe3cbg==} + deprecated: This module is deprecated, please upgrade to @multiformats/multiaddr + dependencies: + dns-over-http-resolver: 1.2.3(node-fetch@2.7.0) + err-code: 3.0.1 + is-ip: 3.1.0 + multiformats: 9.9.0 + uint8arrays: 3.1.0 + varint: 6.0.0 + transitivePeerDependencies: + - node-fetch + - supports-color + dev: true + /multibase@0.6.1: resolution: {integrity: sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw==} deprecated: This module has been superseded by the multiformats module @@ -13838,7 +14929,6 @@ packages: /multiformats@9.9.0: resolution: {integrity: sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==} - dev: false /multihashes@0.4.21: resolution: {integrity: sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw==} @@ -13861,10 +14951,30 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + /native-abort-controller@1.0.4(abort-controller@3.0.0): + resolution: {integrity: sha512-zp8yev7nxczDJMoP6pDxyD20IU0T22eX8VwN2ztDccKvSZhRaV33yP1BGwKSZfXuqWUzsXopVFjBdau9OOAwMQ==} + peerDependencies: + abort-controller: '*' + dependencies: + abort-controller: 3.0.0 + dev: true + + /native-fetch@3.0.0(node-fetch@2.7.0): + resolution: {integrity: sha512-G3Z7vx0IFb/FQ4JxvtqGABsOTIqRWvgQz6e+erkB+JJD6LrszQtMozEHI4EkmgZQvnGHrpLVzUWk7t4sJCIkVw==} + peerDependencies: + node-fetch: '*' + dependencies: + node-fetch: 2.7.0 + dev: true + /natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true + /natural-orderby@2.0.3: + resolution: {integrity: sha512-p7KTHxU0CUrcOXe62Zfrb5Z13nLvPhSWR/so3kFulUQU0sgUll2Z0LwpsLN351eOOD+hRGu/F1g+6xDfPeD++Q==} + dev: true + /negotiator@0.6.3: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} @@ -14046,7 +15156,6 @@ packages: engines: {node: '>=8'} dependencies: path-key: 3.1.1 - dev: false /npm-run-path@5.3.0: resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} @@ -14123,6 +15232,11 @@ packages: resolution: {integrity: sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==} engines: {node: '>= 10.12.0'} + /object-treeify@1.1.33: + resolution: {integrity: sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==} + engines: {node: '>= 10'} + dev: true + /object.assign@4.1.5: resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} engines: {node: '>= 0.4'} @@ -14224,7 +15338,6 @@ packages: engines: {node: '>=6'} dependencies: mimic-fn: 2.1.0 - dev: false /onetime@6.0.0: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} @@ -14279,6 +15392,19 @@ packages: word-wrap: 1.2.5 dev: true + /ora@4.0.2: + resolution: {integrity: sha512-YUOZbamht5mfLxPmk4M35CD/5DuOkAacxlEUbStVXpBAt4fyhBf+vZHI/HRkI++QUp3sNoeA2Gw4C+hi4eGSig==} + engines: {node: '>=8'} + dependencies: + chalk: 2.4.2 + cli-cursor: 3.1.0 + cli-spinners: 2.9.2 + is-interactive: 1.0.0 + log-symbols: 3.0.0 + strip-ansi: 5.2.0 + wcwidth: 1.0.1 + dev: true + /ora@5.4.1: resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} engines: {node: '>=10'} @@ -14338,6 +15464,18 @@ packages: engines: {node: '>=12.20'} dev: true + /p-defer@3.0.0: + resolution: {integrity: sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw==} + engines: {node: '>=8'} + dev: true + + /p-fifo@1.0.0: + resolution: {integrity: sha512-IjoCxXW48tqdtDFz6fqo5q1UfFVjjVZe8TC1QRflvNUJtNfCUhxOUw6MOVZhDPjqhSzc26xKdugsO17gmzd5+A==} + dependencies: + fast-fifo: 1.3.2 + p-defer: 3.0.0 + dev: true + /p-limit@1.3.0: resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} engines: {node: '>=4'} @@ -14424,6 +15562,10 @@ packages: resolution: {integrity: sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==} dev: true + /parse-duration@1.1.0: + resolution: {integrity: sha512-z6t9dvSJYaPoQq7quMzdEagSFtpGu+utzHqqxmpVWNNZRIXnvqyCvn9XsTdh7c/w0Bqmdz3RB3YnRaKtpRtEXQ==} + dev: true + /parse-headers@2.0.5: resolution: {integrity: sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==} dev: true @@ -14476,6 +15618,13 @@ packages: upper-case-first: 1.1.2 dev: true + /password-prompt@1.1.3: + resolution: {integrity: sha512-HkrjG2aJlvF0t2BMH0e2LB/EHf3Lcq3fNMzy4GYHcQblAvOl+QQji1Lx7WRBMqpVK8p+KR7bCg7oqAMXtdgqyw==} + dependencies: + ansi-escapes: 4.3.2 + cross-spawn: 7.0.3 + dev: true + /path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} @@ -14829,6 +15978,12 @@ packages: hasBin: true dev: true + /prettier@3.0.3: + resolution: {integrity: sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==} + engines: {node: '>=14'} + hasBin: true + dev: true + /prettier@3.2.5: resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} engines: {node: '>=14'} @@ -14894,6 +16049,26 @@ packages: object-assign: 4.1.1 react-is: 16.13.1 + /protobufjs@6.11.4: + resolution: {integrity: sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==} + hasBin: true + requiresBuild: true + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.4 + '@protobufjs/eventemitter': 1.1.0 + '@protobufjs/fetch': 1.1.0 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.0 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.0 + '@types/long': 4.0.2 + '@types/node': 22.0.2 + long: 4.0.0 + dev: true + /proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -14913,12 +16088,23 @@ packages: /psl@1.9.0: resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} + /pump@1.0.3: + resolution: {integrity: sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==} + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + dev: true + /pump@3.0.0: resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} dependencies: end-of-stream: 1.4.4 once: 1.4.0 + /punycode@1.4.1: + resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} + dev: true + /punycode@2.1.0: resolution: {integrity: sha512-Yxz2kRwT90aPiWEMHVYnEf4+rhwF1tBmmZ4KepCP+Wkium9JxtWnUm1nqGwpiAHr/tnTSeHqr3wb++jgSkXjhA==} engines: {node: '>=6'} @@ -14932,6 +16118,17 @@ packages: resolution: {integrity: sha512-BwQpbqxSCBJVpamI6ydzcKqyFmnd5msMWUGvzXLm1aXvusbbgkbOto/EUPM00hjveJEaJtdbhUjKSzWRhQVkaw==} dev: true + /pvtsutils@1.3.5: + resolution: {integrity: sha512-ARvb14YB9Nm2Xi6nBq1ZX6dAM0FsJnuk+31aUp4TrcZEdKUlSqOqsxJHUPJDNE3qiIp+iUPEIeR6Je/tgV7zsA==} + dependencies: + tslib: 2.6.3 + dev: true + + /pvutils@1.1.3: + resolution: {integrity: sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==} + engines: {node: '>=6.0.0'} + dev: true + /qr-code-styling@1.6.0-rc.1: resolution: {integrity: sha512-ModRIiW6oUnsP18QzrRYZSc/CFKFKIdj7pUs57AEVH20ajlglRpN3HukjHk0UbNMTlKGuaYl7Gt6/O5Gg2NU2Q==} dependencies: @@ -15159,6 +16356,12 @@ packages: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} dev: false + /react-native-fetch-api@3.0.0: + resolution: {integrity: sha512-g2rtqPjdroaboDKTsJCTlcmtw54E25OjyaunUP0anOZn4Fuo2IKs8BVfe02zVggA/UysbmfSnRJIqtNkAgggNA==} + dependencies: + p-defer: 3.0.0 + dev: true + /react-native-webview@11.26.1(react-native@0.74.4)(react@18.3.1): resolution: {integrity: sha512-hC7BkxOpf+z0UKhxFSFTPAM4shQzYmZHoELa6/8a/MspcjEP7ukYKpuSUTLDywQditT8yI9idfcKvfZDKQExGw==} peerDependencies: @@ -15319,6 +16522,15 @@ packages: path-type: 1.1.0 dev: true + /readable-stream@1.0.34: + resolution: {integrity: sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==} + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 0.0.1 + string_decoder: 0.10.31 + dev: true + /readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} dependencies: @@ -15363,6 +16575,12 @@ packages: tslib: 2.6.3 dev: false + /receptacle@1.3.2: + resolution: {integrity: sha512-HrsFvqZZheusncQRiEE7GatOAETrARKV/lnfYicIm8lbvp/JQOdADOfhjBd2DajvoszEyxSM6RlAAIZgEoeu/A==} + dependencies: + ms: 2.1.3 + dev: true + /rechoir@0.6.2: resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} engines: {node: '>= 0.10'} @@ -15385,6 +16603,12 @@ packages: strip-indent: 3.0.0 dev: true + /redeyed@2.1.1: + resolution: {integrity: sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ==} + dependencies: + esprima: 4.0.1 + dev: true + /reduce-flatten@2.0.0: resolution: {integrity: sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==} engines: {node: '>=6'} @@ -15537,7 +16761,6 @@ packages: /resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - dev: true /resolve@1.1.7: resolution: {integrity: sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==} @@ -15585,7 +16808,10 @@ packages: dependencies: onetime: 5.1.2 signal-exit: 3.0.7 - dev: false + + /retimer@3.0.0: + resolution: {integrity: sha512-WKE0j11Pa0ZJI5YIk0nflGI7SQsfl2ljihVy7ogh7DeQSeYAUi0ubZ/yEueGtDfUPk6GH5LRw1hBdLq4IwUBWA==} + dev: true /reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} @@ -15826,6 +17052,22 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true + /semver@7.3.5: + resolution: {integrity: sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: true + + /semver@7.4.0: + resolution: {integrity: sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: true + /semver@7.5.4: resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} engines: {node: '>=10'} @@ -16045,7 +17287,6 @@ packages: /signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - dev: false /signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} @@ -16112,7 +17353,7 @@ packages: engines: {node: '>=10.0.0'} dependencies: '@socket.io/component-emitter': 3.1.2 - debug: 4.3.6 + debug: 4.3.6(supports-color@8.1.1) engine.io-client: 6.5.4 socket.io-parser: 4.2.4 transitivePeerDependencies: @@ -16126,7 +17367,7 @@ packages: engines: {node: '>=10.0.0'} dependencies: '@socket.io/component-emitter': 3.1.2 - debug: 4.3.6 + debug: 4.3.6(supports-color@8.1.1) transitivePeerDependencies: - supports-color dev: false @@ -16249,6 +17490,10 @@ packages: resolution: {integrity: sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==} dev: true + /split-ca@1.0.1: + resolution: {integrity: sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ==} + dev: true + /split-on-first@1.1.0: resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==} engines: {node: '>=6'} @@ -16322,10 +17567,15 @@ packages: resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} dev: false + /stream-to-it@0.2.4: + resolution: {integrity: sha512-4vEbkSs83OahpmBybNJXlJd7d6/RxzkkSdT3I0mnGt79Xd2Kk+e1JqbvAvsQfCeKj3aKb0QIWkyK3/n0j506vQ==} + dependencies: + get-iterator: 1.0.2 + dev: true + /streamsearch@1.1.0: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} - dev: false /strict-uri-encode@1.1.0: resolution: {integrity: sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==} @@ -16439,6 +17689,10 @@ packages: es-object-atoms: 1.0.0 dev: true + /string_decoder@0.10.31: + resolution: {integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==} + dev: true + /string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} dependencies: @@ -16468,7 +17722,6 @@ packages: engines: {node: '>=6'} dependencies: ansi-regex: 4.1.1 - dev: false /strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} @@ -16497,7 +17750,6 @@ packages: /strip-final-newline@2.0.0: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} - dev: false /strip-final-newline@3.0.0: resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} @@ -16583,6 +17835,14 @@ packages: dependencies: has-flag: 4.0.0 + /supports-hyperlinks@2.3.0: + resolution: {integrity: sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + supports-color: 7.2.0 + dev: true + /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} @@ -16685,6 +17945,28 @@ packages: engines: {node: '>=6'} dev: true + /tar-fs@1.16.3: + resolution: {integrity: sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==} + dependencies: + chownr: 1.1.4 + mkdirp: 0.5.6 + pump: 1.0.3 + tar-stream: 1.6.2 + dev: true + + /tar-stream@1.6.2: + resolution: {integrity: sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==} + engines: {node: '>= 0.8.0'} + dependencies: + bl: 1.2.3 + buffer-alloc: 1.2.0 + end-of-stream: 1.4.4 + fs-constants: 1.0.0 + readable-stream: 2.3.8 + to-buffer: 1.1.1 + xtend: 4.0.2 + dev: true + /tar@4.4.19: resolution: {integrity: sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==} engines: {node: '>=4.5'} @@ -16698,6 +17980,18 @@ packages: yallist: 3.1.1 dev: true + /tar@6.2.1: + resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} + engines: {node: '>=10'} + dependencies: + chownr: 2.0.0 + fs-minipass: 2.1.0 + minipass: 5.0.0 + minizlib: 2.1.2 + mkdirp: 1.0.4 + yallist: 4.0.0 + dev: true + /temp-dir@2.0.0: resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==} engines: {node: '>=8'} @@ -16773,11 +18067,23 @@ packages: xtend: 4.0.2 dev: false + /through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + dev: true + /timed-out@4.0.1: resolution: {integrity: sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA==} engines: {node: '>=0.10.0'} dev: true + /timeout-abort-controller@2.0.0: + resolution: {integrity: sha512-2FAPXfzTPYEgw27bQGTHc0SzrbmnU2eso4qo172zMLZzaGqeu09PFa5B2FCUHM1tflgRqPgn5KQgp6+Vex4uNA==} + dependencies: + abort-controller: 3.0.0 + native-abort-controller: 1.0.4(abort-controller@3.0.0) + retimer: 3.0.0 + dev: true + /tinybench@2.8.0: resolution: {integrity: sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==} dev: true @@ -16804,6 +18110,12 @@ packages: upper-case: 1.1.3 dev: true + /tmp-promise@3.0.3: + resolution: {integrity: sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==} + dependencies: + tmp: 0.2.3 + dev: true + /tmp@0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} @@ -16811,10 +18123,19 @@ packages: os-tmpdir: 1.0.2 dev: true + /tmp@0.2.3: + resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==} + engines: {node: '>=14.14'} + dev: true + /tmpl@1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} dev: false + /to-buffer@1.1.1: + resolution: {integrity: sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==} + dev: true + /to-fast-properties@2.0.0: resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} engines: {node: '>=4'} @@ -16985,7 +18306,6 @@ packages: /tslib@2.6.3: resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} - dev: false /tsort@0.0.1: resolution: {integrity: sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==} @@ -17000,7 +18320,6 @@ packages: get-tsconfig: 4.7.6 optionalDependencies: fsevents: 2.3.3 - dev: true /tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} @@ -17184,7 +18503,6 @@ packages: resolution: {integrity: sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog==} dependencies: multiformats: 9.9.0 - dev: false /ultron@1.1.1: resolution: {integrity: sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==} @@ -17407,6 +18725,10 @@ packages: resolution: {integrity: sha512-3AChu4NiXquPfeckE5R5cGdiHCMWJx1dwCWOmWIL4KHAziJNOFIYJlpGFeKDvwLPHovZRCxK3cYlwzqI9Vp+Gg==} dev: true + /urlpattern-polyfill@8.0.2: + resolution: {integrity: sha512-Qp95D4TPJl1kC9SKigDcqgyM2VDVO4RiJc2d4qe5GrYm+zbIQCWWKAFaJNQ4BhdFeDGwBmAxqJBwWSJDb9T3BQ==} + dev: true + /use-callback-ref@1.3.2(@types/react@18.3.3)(react@18.3.1): resolution: {integrity: sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==} engines: {node: '>=10'} @@ -17541,6 +18863,10 @@ packages: resolution: {integrity: sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==} dev: true + /varint@6.0.0: + resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==} + dev: true + /vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -17584,7 +18910,7 @@ packages: hasBin: true dependencies: cac: 6.7.14 - debug: 4.3.6 + debug: 4.3.6(supports-color@8.1.1) pathe: 1.1.2 tinyrainbow: 1.2.0 vite: 5.3.5(@types/node@22.0.2) @@ -17632,7 +18958,7 @@ packages: vite: optional: true dependencies: - debug: 4.3.6 + debug: 4.3.6(supports-color@8.1.1) globrex: 0.1.2 tsconfck: 3.1.1(typescript@5.5.4) vite: 5.3.5(@types/node@22.0.2) @@ -17746,7 +19072,7 @@ packages: '@vitest/spy': 2.0.5 '@vitest/utils': 2.0.5 chai: 5.1.1 - debug: 4.3.6 + debug: 4.3.6(supports-color@8.1.1) execa: 8.0.1 jsdom: 24.1.1 magic-string: 0.30.11 @@ -17853,7 +19179,11 @@ packages: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} dependencies: defaults: 1.0.4 - dev: false + + /web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} + dev: true /web3-bzz@1.10.0: resolution: {integrity: sha512-o9IR59io3pDUsXTsps5pO5hW1D5zBmg46iNc2t4j2DkaYHNdDLwk2IP9ukoM2wg47QILfPEJYzhTfkS/CcX0KA==} @@ -18042,6 +19372,14 @@ packages: web3-utils: 1.10.4 dev: true + /web3-eth-abi@1.7.0: + resolution: {integrity: sha512-heqR0bWxgCJwjWIhq2sGyNj9bwun5+Xox/LdZKe+WMyTSy0cXDXEAgv3XKNkXC4JqdDt/ZlbTEx4TWak4TRMSg==} + engines: {node: '>=8.0.0'} + dependencies: + '@ethersproject/abi': 5.0.7 + web3-utils: 1.7.0 + dev: true + /web3-eth-accounts@1.10.0: resolution: {integrity: sha512-wiq39Uc3mOI8rw24wE2n15hboLE0E9BsQLdlmsL4Zua9diDS6B5abXG0XhFcoNsXIGMWXVZz4TOq3u4EdpXF/Q==} engines: {node: '>=8.0.0'} @@ -18399,6 +19737,19 @@ packages: utf8: 3.0.0 dev: true + /web3-utils@1.7.0: + resolution: {integrity: sha512-O8Tl4Ky40Sp6pe89Olk2FsaUkgHyb5QAXuaKo38ms3CxZZ4d3rPGfjP9DNKGm5+IUgAZBNpF1VmlSmNCqfDI1w==} + engines: {node: '>=8.0.0'} + dependencies: + bn.js: 4.12.0 + ethereum-bloom-filters: 1.2.0 + ethereumjs-util: 7.1.5 + ethjs-unit: 0.1.6 + number-to-bn: 1.7.0 + randombytes: 2.1.0 + utf8: 3.0.0 + dev: true + /web3@1.10.0: resolution: {integrity: sha512-YfKY9wSkGcM8seO+daR89oVTcbu18NsVfvOngzqMYGUU0pPSQmE57qQDvQzUeoIOHAnXEBNzrhjQJmm8ER0rng==} engines: {node: '>=8.0.0'} @@ -18444,6 +19795,16 @@ packages: '@noble/hashes': 1.4.0 dev: false + /webcrypto-core@1.8.0: + resolution: {integrity: sha512-kR1UQNH8MD42CYuLzvibfakG5Ew5seG85dMMoAM/1LqvckxaF6pUiidLuraIu4V+YCIFabYecUZAW0TuxAoaqw==} + dependencies: + '@peculiar/asn1-schema': 2.3.13 + '@peculiar/json-schema': 1.1.12 + asn1js: 3.0.5 + pvtsutils: 1.3.5 + tslib: 2.6.3 + dev: true + /webextension-polyfill@0.10.0: resolution: {integrity: sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==} dev: false @@ -18723,7 +20084,6 @@ packages: optional: true utf-8-validate: optional: true - dev: false /ws@7.5.9: resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==} @@ -18847,6 +20207,11 @@ packages: /yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + /yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + dev: true + /yaml@2.5.0: resolution: {integrity: sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==} engines: {node: '>= 14'} @@ -19000,4 +20365,3 @@ packages: optionalDependencies: '@types/fs-extra': 11.0.4 '@types/node': 22.0.2 - dev: true diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 1ddecd45..49c356a8 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -3,3 +3,4 @@ packages: - './frontend/app' - './frontend/uikit' - './frontend/uikit-gallery' + - './subgraph' diff --git a/subgraph/.gitignore b/subgraph/.gitignore new file mode 100644 index 00000000..52b33fb5 --- /dev/null +++ b/subgraph/.gitignore @@ -0,0 +1,2 @@ +/build/ +/generated/ diff --git a/subgraph/README.md b/subgraph/README.md new file mode 100644 index 00000000..893370ed --- /dev/null +++ b/subgraph/README.md @@ -0,0 +1,27 @@ +# Liquity v2 Subgraph + +## Run the subgraph locally + +```sh +# 1. Run anvil +anvil --host 0.0.0.0 --gas-limit 100000000000 --base-fee 1 + +# 2. Deploy the contracts +cd contracts +./deploy local +# use --open-demo-troves to start with some demo data: +# ./deploy local --open-demo-troves + +# 3. Run the graph node +cd subgraph +./start-graph +# use --reset to clear the state: +# ./start-graph --reset + +# 4. Deploy the subgraph +cd subgraph +# Note: this script detects if new versions of the contract it needs +# have been deployed, and will automatically update their addresses in the +# subgraph.yaml file (after confirmation). +./deploy-subgraph local --version v1 --create +``` diff --git a/subgraph/cli/deploy-subgraph.ts b/subgraph/cli/deploy-subgraph.ts new file mode 100644 index 00000000..384fe25b --- /dev/null +++ b/subgraph/cli/deploy-subgraph.ts @@ -0,0 +1,201 @@ +import YAML from "yaml"; +import { $, echo, fs, minimist, path, question } from "zx"; + +const SUBGRAPH_PATH = path.join(__dirname, "../subgraph.yaml"); +const LATEST_DEPLOYMENT_CONTEXT_PATH = path.join(__dirname, "../../contracts/deployment-context-latest.json"); + +const HELP = ` +deploy-subgraph - deploy the Liquity v2 subgraph + +Usage: + ./deploy-subgraph [NETWORK_PRESET] [OPTIONS] + +Arguments: + NETWORK_PRESET A network preset, which is a shorthand for setting certain options. + Options take precedence over network presets. Available presets: + - local: Deploy to a local network + - mainnet: Deploy to the Ethereum mainnet (not implemented) + - liquity-testnet: Deploy to the Liquity v2 testnet (not implemented) + + +Options: + --create Create the subgraph before deploying. + --debug Show debug output. + --graph-node The Graph Node URL to use. + --help, -h Show this help message. + --ipfs-node The IPFS node URL to use. + --name The subgraph name to use. + --version The subgraph version to use. +`; + +const argv = minimist(process.argv.slice(2), { + alias: { + h: "help", + }, + boolean: [ + "create", + "debug", + "help", + ], + string: [ + "graph-node", + "ipfs-node", + "name", + "version", + ], +}); + +export async function main() { + const { networkPreset, options } = await parseArgs(); + + if (options.help) { + echo`${HELP}`; + process.exit(0); + } + + options.name ??= "liquity2/liquity2"; + + // network preset: local + if (networkPreset === "local") { + options.graphNode ??= "http://localhost:8020/"; + options.ipfsNode ??= "http://localhost:5001/"; + } + + // network preset: liquity-testnet + if (networkPreset === "liquity-testnet") { + // TODO: implement + } + + // network preset: mainnet + if (networkPreset === "mainnet") { + // TODO: implement + } + + // handle missing options + if (!options.graphNode) { + throw new Error("--graph-node is required"); + } + if (!options.name) { + throw new Error("--name is required"); + } + if (!options.version) { + throw new Error("--version is required"); + } + if (!options.ipfsNode) { + throw new Error("--ipfs-node is required"); + } + + const graphCreateCommand: null | string[] = !options.create ? null : [ + "graph", + "create", + "--node", + options.graphNode, + options.name, + ]; + + const graphDeployCommand: string[] = [ + "graph", + "deploy", + "--node", + options.graphNode, + "--ipfs", + options.ipfsNode, + options.name, + "--version-label", + options.version, + ]; + + await updateDeclarationWithLatestBoldToken(); + + echo` +Deploying subgraph: + + NAME: ${options.name} + VERSION: ${options.version} + GRAPH NODE: ${options.graphNode} + IPFS NODE: ${options.ipfsNode} + CREATE: ${options.create ? "yes" : "no"} + DEBUG: ${options.debug ? "yes" : "no"} +`; + + $.verbose = options.debug; + + if (graphCreateCommand) { + await $`pnpm ${graphCreateCommand}`; + } + + await $`pnpm ${graphDeployCommand}`; + + echo("Subgraph deployment complete."); + echo(""); +} + +async function parseArgs() { + const options = { + debug: argv["debug"], + help: argv["help"], + create: argv["create"], + graphNode: argv["graph-node"], + ipfsNode: argv["ipfs-node"], + name: argv["name"], + version: argv["version"], + }; + + const [networkPreset] = argv._; + + return { options, networkPreset }; +} + +async function updateDeclarationWithLatestBoldToken() { + const declaration = subgraphDeclaration(); + const latestDeploymentContext = getLatestDeploymentContext(); + + const deployedAddress = latestDeploymentContext?.protocolContracts.BoldToken; + if (!deployedAddress || (declaration.boldTokenAddress === deployedAddress)) { + return; + } + + const answer = await question( + `\nNew BoldToken detected (${deployedAddress}). Update subgraph.yaml? [Y/n] `, + ); + + const confirmed = answer === "" || answer.toLowerCase() === "y" || answer.toLowerCase() === "yes"; + + if (!confirmed) { + return; + } + + declaration.updateBoldTokenAddress(deployedAddress); + console.log(""); + console.log("Subgraph declaration updated with CollateralRegistry:", deployedAddress); +} + +function subgraphDeclaration() { + const declaration = YAML.parse(fs.readFileSync(SUBGRAPH_PATH, "utf8")); + const boldToken = declaration.dataSources.find((ds: any) => ds.name === "BoldToken"); + return { + boldTokenAddress: boldToken.source.address, + updateBoldTokenAddress: (address: string) => { + const updatedDeclaration = { + ...declaration, + dataSources: declaration.dataSources.map((ds: any) => ( + ds.name === "BoldToken" + ? { ...ds, source: { ...ds.source, address } } + : ds + )), + }; + fs.writeFileSync( + SUBGRAPH_PATH, + YAML.stringify(updatedDeclaration, { lineWidth: 120 }), + ); + }, + }; +} + +function getLatestDeploymentContext() { + try { + return JSON.parse(fs.readFileSync(LATEST_DEPLOYMENT_CONTEXT_PATH, "utf8")); + } catch (_) { + return null; + } +} diff --git a/subgraph/cli/start-graph.ts b/subgraph/cli/start-graph.ts new file mode 100644 index 00000000..c4b35596 --- /dev/null +++ b/subgraph/cli/start-graph.ts @@ -0,0 +1,66 @@ +import { $, echo, minimist, question } from "zx"; + +const HELP = ` +start-graph - start a Graph Node + +Usage: + ./start-graph [OPTIONS] + +Options: + --reset Remove all containers and volumes. + --help, -h Show this help message. +`; + +const argv = minimist(process.argv.slice(2), { + alias: { + h: "help", + }, + boolean: [ + "reset", + "help", + ], +}); + +async function resetCheck() { + if (argv.reset) { + return true; + } + const response = ( + await question("Do you want to remove all containers and volumes? [y/N] ") + ).toLowerCase(); + return response === "y" || response === "yes"; +} + +export async function main() { + if (argv.help) { + echo`${HELP}`; + process.exit(0); + } + + $.verbose = true; + + if (await resetCheck()) { + echo``; + echo`Stopping and removing containers…`; + echo``; + await $`docker compose rm -fsv`; + + echo``; + echo`Removing volumes…`; + echo``; + await $`docker volume rm subgraph_ipfs`; + await $`docker volume rm subgraph_postgres`; + } + + echo``; + echo`Starting Graph Node…`; + + // TODO: handle SIGINT + // process.on("SIGINT", async () => { + // echo`Caught interrupt signal. Shutting down containers…`; + // await $`docker compose down`; + // process.exit(); + // }); + + await $`docker compose up`; +} diff --git a/subgraph/deploy-subgraph b/subgraph/deploy-subgraph new file mode 100755 index 00000000..03a77a12 --- /dev/null +++ b/subgraph/deploy-subgraph @@ -0,0 +1,8 @@ +#!/usr/bin/env -S pnpm exec tsx + +require("./cli/deploy-subgraph").main().catch(({ message }) => { + console.error(""); + console.error(` Error: ${message}`); + console.error(""); + process.exit(1); +}); diff --git a/subgraph/docker-compose.yml b/subgraph/docker-compose.yml new file mode 100644 index 00000000..d1b2b833 --- /dev/null +++ b/subgraph/docker-compose.yml @@ -0,0 +1,53 @@ +services: + graph-node: + image: graphprotocol/graph-node + ports: + - '8000:8000' + - '8001:8001' + - '8020:8020' + - '8030:8030' + - '8040:8040' + depends_on: + - ipfs + - postgres + extra_hosts: + - host.docker.internal:host-gateway + environment: + postgres_host: postgres + postgres_user: graph-node + postgres_pass: let-me-in + postgres_db: graph-node + ipfs: 'ipfs:5001' + ethereum: 'mainnet:http://host.docker.internal:8545' + GRAPH_LOG: info + ipfs: + image: ipfs/kubo:v0.17.0 + ports: + - '5001:5001' + volumes: + - ipfs:/data/ipfs + postgres: + image: postgres + ports: + - '5432:5432' + command: + [ + "postgres", + "-cshared_preload_libraries=pg_stat_statements", + "-cmax_connections=200" + ] + environment: + POSTGRES_USER: graph-node + POSTGRES_PASSWORD: let-me-in + POSTGRES_DB: graph-node + # FIXME: remove this env. var. which we shouldn't need. Introduced by + # , maybe as a + # workaround for https://github.com/docker/for-mac/issues/6270? + PGDATA: "/var/lib/postgresql/data" + POSTGRES_INITDB_ARGS: "-E UTF8 --locale=C" + volumes: + - postgres:/var/lib/postgresql/data + +volumes: + postgres: + ipfs: diff --git a/subgraph/package.json b/subgraph/package.json new file mode 100644 index 00000000..73d4baa9 --- /dev/null +++ b/subgraph/package.json @@ -0,0 +1,16 @@ +{ + "name": "@liquity2/subgraph", + "version": "1.0.0", + "scripts": { + "codegen": "pnpm graph codegen" + }, + "devDependencies": { + "@graphprotocol/graph-cli": "^0.80.0" + }, + "dependencies": { + "@graphprotocol/graph-ts": "^0.35.1", + "tsx": "^4.16.5", + "yaml": "^2.5.0", + "zx": "^8.1.4" + } +} diff --git a/subgraph/schema.graphql b/subgraph/schema.graphql new file mode 100644 index 00000000..64c029cd --- /dev/null +++ b/subgraph/schema.graphql @@ -0,0 +1,47 @@ +type Collateral @entity { + id: ID! + token: Token! + minCollRatio: BigInt! + troves: [Trove!]! @derivedFrom(field: "collateral") + addresses: CollateralAddresses! @derivedFrom(field: "collateral") + totalDeposited: BigInt! + totalDebt: BigInt! +} + +type Token @entity(immutable: true) { + id: ID! + collateral: Collateral! + name: String! + symbol: String! + decimals: Int! +} + +type CollateralAddresses @entity(immutable: true) { + id: ID! + borrowerOperations: Bytes! + collateral: Collateral! + sortedTroves: Bytes! + stabilityPool: Bytes! + token: Bytes! + troveManager: Bytes! + troveNft: Bytes! +} + +type InterestRateBracket @entity { + id: ID! + rate: BigInt! + totalDebt: BigInt! + totalTroves: Int! +} + +type Trove @entity { + id: ID! + borrower: Bytes! + debt: BigInt! + deposit: BigInt! + stake: BigInt! + interestRate: BigInt! + createdAt: BigInt! + closedAt: BigInt + collateral: Collateral! +} diff --git a/subgraph/src/BoldToken.mapping.ts b/subgraph/src/BoldToken.mapping.ts new file mode 100644 index 00000000..a5184be8 --- /dev/null +++ b/subgraph/src/BoldToken.mapping.ts @@ -0,0 +1,74 @@ +import { Address, BigInt, DataSourceContext } from "@graphprotocol/graph-ts"; +import { + CollateralRegistryAddressChanged as CollateralRegistryAddressChangedEvent, +} from "../generated/BoldToken/BoldToken"; +import { BorrowerOperations } from "../generated/BoldToken/BorrowerOperations"; +import { CollateralRegistry } from "../generated/BoldToken/CollateralRegistry"; +import { ERC20 } from "../generated/BoldToken/ERC20"; +import { TroveManager } from "../generated/BoldToken/TroveManager"; +import { Collateral, CollateralAddresses, Token } from "../generated/schema"; +import { TroveManager as TroveManagerTemplate } from "../generated/templates"; + +function addCollateral( + tokenAddress: Address, + troveManagerAddress: Address, +): void { + let id = tokenAddress.toHexString(); + let collateral = new Collateral(id); + collateral.token = id; + collateral.totalDebt = BigInt.fromI32(0); + collateral.totalDeposited = BigInt.fromI32(0); + + let token = new Token(id); + let tokenContract = ERC20.bind(tokenAddress); + token.collateral = id; + token.name = tokenContract.name(); + token.symbol = tokenContract.symbol(); + token.decimals = tokenContract.decimals(); + + let troveManager = TroveManager.bind(troveManagerAddress); + + let addresses = new CollateralAddresses(id); + addresses.collateral = id; + addresses.borrowerOperations = troveManager.borrowerOperations(); + addresses.sortedTroves = troveManager.sortedTroves(); + addresses.stabilityPool = troveManager.stabilityPool(); + addresses.token = tokenAddress; + addresses.troveManager = troveManagerAddress; + addresses.troveNft = troveManager.troveNFT(); + + collateral.minCollRatio = BorrowerOperations.bind(Address.fromBytes(addresses.borrowerOperations)).MCR(); + + collateral.save(); + addresses.save(); + token.save(); + + let context = new DataSourceContext(); + context.setBytes("address:borrowerOperations", addresses.borrowerOperations); + context.setBytes("address:sortedTroves", addresses.sortedTroves); + context.setBytes("address:stabilityPool", addresses.stabilityPool); + context.setBytes("address:token", addresses.token); + context.setBytes("address:troveManager", addresses.troveManager); + context.setBytes("address:troveNft", addresses.troveNft); + + TroveManagerTemplate.createWithContext(troveManagerAddress, context); +} + +export function handleCollateralRegistryAddressChanged(event: CollateralRegistryAddressChangedEvent): void { + let registry = CollateralRegistry.bind(event.params._newCollateralRegistryAddress); + let colls = registry.totalCollaterals().toI32(); + + for (let i = 0; i < colls; i++) { + let tokenAddress = Address.fromBytes(registry.getToken(BigInt.fromI32(i))); + let troveManagerAddress = Address.fromBytes(registry.getTroveManager(BigInt.fromI32(i))); + + if (tokenAddress.toHex() === Address.zero().toHex() || troveManagerAddress.toHex() === Address.zero().toHex()) { + break; + } + + // we use the token address as the id for the collateral + if (!Collateral.load(tokenAddress.toHexString())) { + addCollateral(tokenAddress, troveManagerAddress); + } + } +} diff --git a/subgraph/src/TroveManager.mapping.ts b/subgraph/src/TroveManager.mapping.ts new file mode 100644 index 00000000..b80269df --- /dev/null +++ b/subgraph/src/TroveManager.mapping.ts @@ -0,0 +1,121 @@ +import { Address, BigInt, dataSource } from "@graphprotocol/graph-ts"; +import { Collateral, InterestRateBracket, Trove } from "../generated/schema"; +import { TroveNFT } from "../generated/templates/TroveManager/TroveNFT"; +import { + TroveOperation as TroveOperationEvent, + TroveUpdated as TroveUpdatedEvent, +} from "../generated/TroveManager/TroveManager"; + +// see Operation enum in +// contracts/src/Interfaces/ITroveEvents.sol +let OP_CLOSE_TROVE = 1; +// let OP_OPEN_TROVE = 0; +// let OP_ADJUST_TROVE = 2; +// let OP_ADJUST_TROVE_INTEREST_RATE = 3; +// let OP_APPLY_TROVE_INTEREST_PERMISSIONLESS = 4; +// let OP_LIQUIDATE = 5; +// let OP_REDEEM_COLLATERAL = 6; + +function floorToDecimals(value: BigInt, decimals: u8): BigInt { + let factor = BigInt.fromI32(10).pow(18 - decimals); + return value.div(factor).times(factor); +} + +export function handleTroveOperation(event: TroveOperationEvent): void { + let id = event.params._troveId; + let trove = Trove.load(id.toHex()); + + if (!trove) { + return; + } + + if (event.params._operation === OP_CLOSE_TROVE) { + trove.closedAt = event.block.timestamp; + + // update rate bracket + let rateFloored = floorToDecimals(event.params._annualInterestRate, 3); + let rateBracket = InterestRateBracket.load(rateFloored.toString()); + if (rateBracket) { + rateBracket.totalDebt = rateBracket.totalDebt.minus(trove.debt); + rateBracket.totalTroves = rateBracket.totalTroves - 1; + rateBracket.save(); + } + + trove.interestRate = BigInt.fromI32(0); + trove.save(); + return; + } +} + +function loadOrCreateInterestRateBracket(rateFloored: BigInt): InterestRateBracket { + let rateBracket = InterestRateBracket.load(rateFloored.toString()); + if (!rateBracket) { + rateBracket = new InterestRateBracket(rateFloored.toString()); + rateBracket.rate = rateFloored; + rateBracket.totalDebt = BigInt.fromI32(0); + rateBracket.totalTroves = 0; + } + rateBracket.save(); + return rateBracket; +} + +export function handleTroveUpdated(event: TroveUpdatedEvent): void { + let id = event.params._troveId; + let trove = Trove.load(id.toHex()); + let context = dataSource.context(); + + // previous & new rates, floored to the nearest 0.1% (rate brackets) + let prevRateFloored = trove ? floorToDecimals(trove.interestRate, 3) : null; + let rateFloored = floorToDecimals(event.params._annualInterestRate, 3); + + let prevDeposit = trove ? trove.deposit : BigInt.fromI32(0); + let deposit = event.params._coll; + + let prevDebt = trove ? trove.debt : BigInt.fromI32(0); + let debt = event.params._debt; + + let collId = context.getBytes("address:token").toHexString(); + let collateral = Collateral.load(collId); + + // should never happen + if (!collateral) { + return; + } + + collateral.totalDeposited = collateral.totalDeposited.minus(prevDeposit).plus(deposit); + collateral.totalDebt = collateral.totalDebt.minus(prevDebt).plus(debt); + collateral.save(); + + // create trove if it doesn't exist + if (!trove) { + trove = new Trove(id.toHex()); + trove.borrower = TroveNFT.bind(Address.fromBytes(context.getBytes("address:troveNft"))).ownerOf(id); + trove.createdAt = event.block.timestamp; + } + + // update interest rate brackets + let rateBracket = loadOrCreateInterestRateBracket(rateFloored); + if (!prevRateFloored || rateFloored.notEqual(prevRateFloored)) { + let prevRateBracket = prevRateFloored ? InterestRateBracket.load(prevRateFloored.toString()) : null; + if (prevRateBracket) { + prevRateBracket.totalDebt = prevRateBracket.totalDebt.minus(trove.debt); + prevRateBracket.totalTroves = prevRateBracket.totalTroves - 1; + prevRateBracket.save(); + } + + rateBracket.totalDebt = rateBracket.totalDebt.plus(event.params._debt); + rateBracket.totalTroves = rateBracket.totalTroves + 1; + } else { + rateBracket.totalDebt = rateBracket.totalDebt.minus(trove.debt).plus(event.params._debt); + } + + rateBracket.save(); + + trove.deposit = event.params._coll; + trove.debt = event.params._debt; + trove.interestRate = event.params._annualInterestRate; + trove.collateral = context.getBytes("address:token").toHexString(); + trove.stake = event.params._stake; + + trove.save(); +} diff --git a/subgraph/start-graph b/subgraph/start-graph new file mode 100755 index 00000000..03dbcb96 --- /dev/null +++ b/subgraph/start-graph @@ -0,0 +1,8 @@ +#!/usr/bin/env -S pnpm exec tsx + +require("./cli/start-graph").main().catch(({ message }) => { + console.error(""); + console.error(` Error: ${message}`); + console.error(""); + process.exit(1); +}); diff --git a/subgraph/subgraph.yaml b/subgraph/subgraph.yaml new file mode 100644 index 00000000..95279d3a --- /dev/null +++ b/subgraph/subgraph.yaml @@ -0,0 +1,56 @@ +specVersion: 1.2.0 +schema: + file: ./schema.graphql +dataSources: + - name: BoldToken + kind: ethereum/contract + network: mainnet + source: + address: "0x2705179df91e93d2be0f3b56454002f52e27ef87" + abi: BoldToken + mapping: + kind: ethereum/events + apiVersion: 0.0.9 + language: wasm/assemblyscript + entities: + - Collateral + - CollateralAddresses + - Token + abis: + - name: BorrowerOperations + file: ../contracts/out/BorrowerOperations.sol/BorrowerOperations.json + - name: BoldToken + file: ../contracts/out/BoldToken.sol/BoldToken.json + - name: CollateralRegistry + file: ../contracts/out/CollateralRegistry.sol/CollateralRegistry.json + - name: ERC20 + file: ../contracts/out/ERC20.sol/ERC20.json + - name: TroveManager + file: ../contracts/out/TroveManager.sol/TroveManager.json + eventHandlers: + - event: CollateralRegistryAddressChanged(address) + handler: handleCollateralRegistryAddressChanged + file: ./src/BoldToken.mapping.ts +templates: + - name: TroveManager + kind: ethereum/contract + network: mainnet + source: + abi: TroveManager + mapping: + kind: ethereum/events + apiVersion: 0.0.9 + language: wasm/assemblyscript + file: ./src/TroveManager.mapping.ts + entities: + - Trove + abis: + - name: TroveManager + file: ../contracts/out/TroveManager.sol/TroveManager.json + - name: TroveNFT + file: ../contracts/out/TroveNFT.sol/TroveNFT.json + eventHandlers: + - event: TroveOperation(indexed uint256,uint8,uint256,uint256,uint256,int256,uint256,int256) + handler: handleTroveOperation + - event: TroveUpdated(indexed uint256,uint256,uint256,uint256,uint256,uint256,uint256) + handler: handleTroveUpdated From 530e28bcaaf881f9b2e16af62af92e4afaaf86f4 Mon Sep 17 00:00:00 2001 From: Pierre Bertet Date: Tue, 24 Sep 2024 13:57:29 +0100 Subject: [PATCH 22/22] App: fetch loans from the subgraph (#420) Various changes to make the app fetch the loans from the subgraph. --- frontend/app/.graphclient/index.ts | 1370 +++ .../.graphclient/persisted_operations.json | 3 + frontend/app/.graphclient/schema.graphql | 856 ++ .../sources/liquity2/introspectionSchema.ts | 10096 ++++++++++++++++ .../sources/liquity2/schema.graphql | 856 ++ .../.graphclient/sources/liquity2/types.ts | 856 ++ frontend/app/.graphclientrc.yml | 20 + frontend/app/package.json | 4 +- .../app/src/comps/AppLayout/AppLayout.tsx | 9 + frontend/app/src/comps/Debug/UpdatePrices.tsx | 2 +- .../InterestRateField/InterestRateField.tsx | 30 +- frontend/app/src/comps/Position/Position.tsx | 303 - .../app/src/comps/Positions/Positions.tsx | 166 +- .../src/comps/ProtocolStats/ProtocolStats.tsx | 222 +- frontend/app/src/demo-mode/demo-data.ts | 6 +- frontend/app/src/dnum-utils.ts | 4 + frontend/app/src/liquity-utils.ts | 23 +- .../src/screens/BorrowScreen/BorrowScreen.tsx | 6 +- .../screens/EarnPoolScreen/EarnPoolScreen.tsx | 17 +- .../screens/HomeScreen/HomeProtocolStats.tsx | 63 - .../app/src/screens/HomeScreen/HomeScreen.tsx | 8 - .../screens/LeverageScreen/LeverageScreen.tsx | 6 +- .../app/src/screens/LoanScreen/LoanCard.tsx | 513 + .../app/src/screens/LoanScreen/LoanScreen.tsx | 217 +- frontend/app/src/services/Prices.tsx | 3 +- frontend/app/src/subgraph-hooks.ts | 94 + frontend/app/src/subgraph-queries.graphql | 41 + frontend/app/src/types.ts | 10 +- frontend/uikit/src/tokens.ts | 4 + 29 files changed, 15120 insertions(+), 688 deletions(-) create mode 100644 frontend/app/.graphclient/index.ts create mode 100644 frontend/app/.graphclient/persisted_operations.json create mode 100644 frontend/app/.graphclient/schema.graphql create mode 100644 frontend/app/.graphclient/sources/liquity2/introspectionSchema.ts create mode 100644 frontend/app/.graphclient/sources/liquity2/schema.graphql create mode 100644 frontend/app/.graphclient/sources/liquity2/types.ts create mode 100644 frontend/app/.graphclientrc.yml delete mode 100644 frontend/app/src/comps/Position/Position.tsx create mode 100644 frontend/app/src/screens/LoanScreen/LoanCard.tsx create mode 100644 frontend/app/src/subgraph-hooks.ts create mode 100644 frontend/app/src/subgraph-queries.graphql diff --git a/frontend/app/.graphclient/index.ts b/frontend/app/.graphclient/index.ts new file mode 100644 index 00000000..87fe6975 --- /dev/null +++ b/frontend/app/.graphclient/index.ts @@ -0,0 +1,1370 @@ +// @ts-nocheck +import { GraphQLResolveInfo, SelectionSetNode, FieldNode, GraphQLScalarType, GraphQLScalarTypeConfig } from 'graphql'; +import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +import { gql } from '@graphql-mesh/utils'; + +import type { GetMeshOptions } from '@graphql-mesh/runtime'; +import type { YamlConfig } from '@graphql-mesh/types'; +import { PubSub } from '@graphql-mesh/utils'; +import { DefaultLogger } from '@graphql-mesh/utils'; +import MeshCache from "@graphql-mesh/cache-localforage"; +import { fetch as fetchFn } from '@whatwg-node/fetch'; + +import { MeshResolvedSource } from '@graphql-mesh/runtime'; +import { MeshTransform, MeshPlugin } from '@graphql-mesh/types'; +import GraphqlHandler from "@graphql-mesh/graphql" +import BareMerger from "@graphql-mesh/merger-bare"; +import { printWithCache } from '@graphql-mesh/utils'; +import { usePersistedOperations } from '@graphql-yoga/plugin-persisted-operations'; +import { createMeshHTTPHandler, MeshHTTPHandler } from '@graphql-mesh/http'; +import { getMesh, ExecuteMeshFn, SubscribeMeshFn, MeshContext as BaseMeshContext, MeshInstance } from '@graphql-mesh/runtime'; +import { MeshStore, FsStoreStorageAdapter } from '@graphql-mesh/store'; +import { path as pathModule } from '@graphql-mesh/cross-helpers'; +import { ImportFn } from '@graphql-mesh/types'; +import type { Liquity2Types } from './sources/liquity2/types'; +import * as importedModule$0 from "./sources/liquity2/introspectionSchema"; +export type Maybe = T | null; +export type InputMaybe = Maybe; +export type Exact = { [K in keyof T]: T[K] }; +export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; +export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; +export type MakeEmpty = { [_ in K]?: never }; +export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; +export type RequireFields = Omit & { [P in K]-?: NonNullable }; + + + +/** All built-in and custom scalars, mapped to their actual values */ +export type Scalars = { + ID: { input: string; output: string; } + String: { input: string; output: string; } + Boolean: { input: boolean; output: boolean; } + Int: { input: number; output: number; } + Float: { input: number; output: number; } + BigDecimal: { input: bigint; output: bigint; } + BigInt: { input: bigint; output: bigint; } + Bytes: { input: string; output: string; } + Int8: { input: number; output: number; } + Timestamp: { input: string; output: string; } +}; + +export type Aggregation_interval = + | 'hour' + | 'day'; + +export type BlockChangedFilter = { + readonly number_gte: Scalars['Int']['input']; +}; + +export type Block_height = { + readonly hash?: InputMaybe; + readonly number?: InputMaybe; + readonly number_gte?: InputMaybe; +}; + +export type Collateral = { + readonly id: Scalars['ID']['output']; + readonly token: Token; + readonly minCollRatio: Scalars['BigInt']['output']; + readonly troves: ReadonlyArray; + readonly addresses: CollateralAddresses; + readonly totalDeposited: Scalars['BigInt']['output']; + readonly totalDebt: Scalars['BigInt']['output']; +}; + + +export type CollateraltrovesArgs = { + skip?: InputMaybe; + first?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + where?: InputMaybe; +}; + +export type CollateralAddresses = { + readonly id: Scalars['ID']['output']; + readonly borrowerOperations: Scalars['Bytes']['output']; + readonly collateral: Collateral; + readonly sortedTroves: Scalars['Bytes']['output']; + readonly stabilityPool: Scalars['Bytes']['output']; + readonly token: Scalars['Bytes']['output']; + readonly troveManager: Scalars['Bytes']['output']; + readonly troveNft: Scalars['Bytes']['output']; +}; + +export type CollateralAddresses_filter = { + readonly id?: InputMaybe; + readonly id_not?: InputMaybe; + readonly id_gt?: InputMaybe; + readonly id_lt?: InputMaybe; + readonly id_gte?: InputMaybe; + readonly id_lte?: InputMaybe; + readonly id_in?: InputMaybe>; + readonly id_not_in?: InputMaybe>; + readonly borrowerOperations?: InputMaybe; + readonly borrowerOperations_not?: InputMaybe; + readonly borrowerOperations_gt?: InputMaybe; + readonly borrowerOperations_lt?: InputMaybe; + readonly borrowerOperations_gte?: InputMaybe; + readonly borrowerOperations_lte?: InputMaybe; + readonly borrowerOperations_in?: InputMaybe>; + readonly borrowerOperations_not_in?: InputMaybe>; + readonly borrowerOperations_contains?: InputMaybe; + readonly borrowerOperations_not_contains?: InputMaybe; + readonly collateral?: InputMaybe; + readonly collateral_not?: InputMaybe; + readonly collateral_gt?: InputMaybe; + readonly collateral_lt?: InputMaybe; + readonly collateral_gte?: InputMaybe; + readonly collateral_lte?: InputMaybe; + readonly collateral_in?: InputMaybe>; + readonly collateral_not_in?: InputMaybe>; + readonly collateral_contains?: InputMaybe; + readonly collateral_contains_nocase?: InputMaybe; + readonly collateral_not_contains?: InputMaybe; + readonly collateral_not_contains_nocase?: InputMaybe; + readonly collateral_starts_with?: InputMaybe; + readonly collateral_starts_with_nocase?: InputMaybe; + readonly collateral_not_starts_with?: InputMaybe; + readonly collateral_not_starts_with_nocase?: InputMaybe; + readonly collateral_ends_with?: InputMaybe; + readonly collateral_ends_with_nocase?: InputMaybe; + readonly collateral_not_ends_with?: InputMaybe; + readonly collateral_not_ends_with_nocase?: InputMaybe; + readonly collateral_?: InputMaybe; + readonly sortedTroves?: InputMaybe; + readonly sortedTroves_not?: InputMaybe; + readonly sortedTroves_gt?: InputMaybe; + readonly sortedTroves_lt?: InputMaybe; + readonly sortedTroves_gte?: InputMaybe; + readonly sortedTroves_lte?: InputMaybe; + readonly sortedTroves_in?: InputMaybe>; + readonly sortedTroves_not_in?: InputMaybe>; + readonly sortedTroves_contains?: InputMaybe; + readonly sortedTroves_not_contains?: InputMaybe; + readonly stabilityPool?: InputMaybe; + readonly stabilityPool_not?: InputMaybe; + readonly stabilityPool_gt?: InputMaybe; + readonly stabilityPool_lt?: InputMaybe; + readonly stabilityPool_gte?: InputMaybe; + readonly stabilityPool_lte?: InputMaybe; + readonly stabilityPool_in?: InputMaybe>; + readonly stabilityPool_not_in?: InputMaybe>; + readonly stabilityPool_contains?: InputMaybe; + readonly stabilityPool_not_contains?: InputMaybe; + readonly token?: InputMaybe; + readonly token_not?: InputMaybe; + readonly token_gt?: InputMaybe; + readonly token_lt?: InputMaybe; + readonly token_gte?: InputMaybe; + readonly token_lte?: InputMaybe; + readonly token_in?: InputMaybe>; + readonly token_not_in?: InputMaybe>; + readonly token_contains?: InputMaybe; + readonly token_not_contains?: InputMaybe; + readonly troveManager?: InputMaybe; + readonly troveManager_not?: InputMaybe; + readonly troveManager_gt?: InputMaybe; + readonly troveManager_lt?: InputMaybe; + readonly troveManager_gte?: InputMaybe; + readonly troveManager_lte?: InputMaybe; + readonly troveManager_in?: InputMaybe>; + readonly troveManager_not_in?: InputMaybe>; + readonly troveManager_contains?: InputMaybe; + readonly troveManager_not_contains?: InputMaybe; + readonly troveNft?: InputMaybe; + readonly troveNft_not?: InputMaybe; + readonly troveNft_gt?: InputMaybe; + readonly troveNft_lt?: InputMaybe; + readonly troveNft_gte?: InputMaybe; + readonly troveNft_lte?: InputMaybe; + readonly troveNft_in?: InputMaybe>; + readonly troveNft_not_in?: InputMaybe>; + readonly troveNft_contains?: InputMaybe; + readonly troveNft_not_contains?: InputMaybe; + /** Filter for the block changed event. */ + readonly _change_block?: InputMaybe; + readonly and?: InputMaybe>>; + readonly or?: InputMaybe>>; +}; + +export type CollateralAddresses_orderBy = + | 'id' + | 'borrowerOperations' + | 'collateral' + | 'collateral__id' + | 'collateral__minCollRatio' + | 'collateral__totalDeposited' + | 'collateral__totalDebt' + | 'sortedTroves' + | 'stabilityPool' + | 'token' + | 'troveManager' + | 'troveNft'; + +export type Collateral_filter = { + readonly id?: InputMaybe; + readonly id_not?: InputMaybe; + readonly id_gt?: InputMaybe; + readonly id_lt?: InputMaybe; + readonly id_gte?: InputMaybe; + readonly id_lte?: InputMaybe; + readonly id_in?: InputMaybe>; + readonly id_not_in?: InputMaybe>; + readonly token?: InputMaybe; + readonly token_not?: InputMaybe; + readonly token_gt?: InputMaybe; + readonly token_lt?: InputMaybe; + readonly token_gte?: InputMaybe; + readonly token_lte?: InputMaybe; + readonly token_in?: InputMaybe>; + readonly token_not_in?: InputMaybe>; + readonly token_contains?: InputMaybe; + readonly token_contains_nocase?: InputMaybe; + readonly token_not_contains?: InputMaybe; + readonly token_not_contains_nocase?: InputMaybe; + readonly token_starts_with?: InputMaybe; + readonly token_starts_with_nocase?: InputMaybe; + readonly token_not_starts_with?: InputMaybe; + readonly token_not_starts_with_nocase?: InputMaybe; + readonly token_ends_with?: InputMaybe; + readonly token_ends_with_nocase?: InputMaybe; + readonly token_not_ends_with?: InputMaybe; + readonly token_not_ends_with_nocase?: InputMaybe; + readonly token_?: InputMaybe; + readonly minCollRatio?: InputMaybe; + readonly minCollRatio_not?: InputMaybe; + readonly minCollRatio_gt?: InputMaybe; + readonly minCollRatio_lt?: InputMaybe; + readonly minCollRatio_gte?: InputMaybe; + readonly minCollRatio_lte?: InputMaybe; + readonly minCollRatio_in?: InputMaybe>; + readonly minCollRatio_not_in?: InputMaybe>; + readonly troves_?: InputMaybe; + readonly addresses_?: InputMaybe; + readonly totalDeposited?: InputMaybe; + readonly totalDeposited_not?: InputMaybe; + readonly totalDeposited_gt?: InputMaybe; + readonly totalDeposited_lt?: InputMaybe; + readonly totalDeposited_gte?: InputMaybe; + readonly totalDeposited_lte?: InputMaybe; + readonly totalDeposited_in?: InputMaybe>; + readonly totalDeposited_not_in?: InputMaybe>; + readonly totalDebt?: InputMaybe; + readonly totalDebt_not?: InputMaybe; + readonly totalDebt_gt?: InputMaybe; + readonly totalDebt_lt?: InputMaybe; + readonly totalDebt_gte?: InputMaybe; + readonly totalDebt_lte?: InputMaybe; + readonly totalDebt_in?: InputMaybe>; + readonly totalDebt_not_in?: InputMaybe>; + /** Filter for the block changed event. */ + readonly _change_block?: InputMaybe; + readonly and?: InputMaybe>>; + readonly or?: InputMaybe>>; +}; + +export type Collateral_orderBy = + | 'id' + | 'token' + | 'token__id' + | 'token__name' + | 'token__symbol' + | 'token__decimals' + | 'minCollRatio' + | 'troves' + | 'addresses' + | 'addresses__id' + | 'addresses__borrowerOperations' + | 'addresses__sortedTroves' + | 'addresses__stabilityPool' + | 'addresses__token' + | 'addresses__troveManager' + | 'addresses__troveNft' + | 'totalDeposited' + | 'totalDebt'; + +export type InterestRateBracket = { + readonly id: Scalars['ID']['output']; + readonly rate: Scalars['BigInt']['output']; + readonly totalDebt: Scalars['BigInt']['output']; + readonly totalTroves: Scalars['Int']['output']; +}; + +export type InterestRateBracket_filter = { + readonly id?: InputMaybe; + readonly id_not?: InputMaybe; + readonly id_gt?: InputMaybe; + readonly id_lt?: InputMaybe; + readonly id_gte?: InputMaybe; + readonly id_lte?: InputMaybe; + readonly id_in?: InputMaybe>; + readonly id_not_in?: InputMaybe>; + readonly rate?: InputMaybe; + readonly rate_not?: InputMaybe; + readonly rate_gt?: InputMaybe; + readonly rate_lt?: InputMaybe; + readonly rate_gte?: InputMaybe; + readonly rate_lte?: InputMaybe; + readonly rate_in?: InputMaybe>; + readonly rate_not_in?: InputMaybe>; + readonly totalDebt?: InputMaybe; + readonly totalDebt_not?: InputMaybe; + readonly totalDebt_gt?: InputMaybe; + readonly totalDebt_lt?: InputMaybe; + readonly totalDebt_gte?: InputMaybe; + readonly totalDebt_lte?: InputMaybe; + readonly totalDebt_in?: InputMaybe>; + readonly totalDebt_not_in?: InputMaybe>; + readonly totalTroves?: InputMaybe; + readonly totalTroves_not?: InputMaybe; + readonly totalTroves_gt?: InputMaybe; + readonly totalTroves_lt?: InputMaybe; + readonly totalTroves_gte?: InputMaybe; + readonly totalTroves_lte?: InputMaybe; + readonly totalTroves_in?: InputMaybe>; + readonly totalTroves_not_in?: InputMaybe>; + /** Filter for the block changed event. */ + readonly _change_block?: InputMaybe; + readonly and?: InputMaybe>>; + readonly or?: InputMaybe>>; +}; + +export type InterestRateBracket_orderBy = + | 'id' + | 'rate' + | 'totalDebt' + | 'totalTroves'; + +/** Defines the order direction, either ascending or descending */ +export type OrderDirection = + | 'asc' + | 'desc'; + +export type Query = { + readonly collateral?: Maybe; + readonly collaterals: ReadonlyArray; + readonly token?: Maybe; + readonly tokens: ReadonlyArray; + readonly collateralAddresses?: Maybe; + readonly collateralAddresses_collection: ReadonlyArray; + readonly interestRateBracket?: Maybe; + readonly interestRateBrackets: ReadonlyArray; + readonly trove?: Maybe; + readonly troves: ReadonlyArray; + /** Access to subgraph metadata */ + readonly _meta?: Maybe<_Meta_>; +}; + + +export type QuerycollateralArgs = { + id: Scalars['ID']['input']; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type QuerycollateralsArgs = { + skip?: InputMaybe; + first?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + where?: InputMaybe; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type QuerytokenArgs = { + id: Scalars['ID']['input']; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type QuerytokensArgs = { + skip?: InputMaybe; + first?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + where?: InputMaybe; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type QuerycollateralAddressesArgs = { + id: Scalars['ID']['input']; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type QuerycollateralAddresses_collectionArgs = { + skip?: InputMaybe; + first?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + where?: InputMaybe; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type QueryinterestRateBracketArgs = { + id: Scalars['ID']['input']; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type QueryinterestRateBracketsArgs = { + skip?: InputMaybe; + first?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + where?: InputMaybe; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type QuerytroveArgs = { + id: Scalars['ID']['input']; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type QuerytrovesArgs = { + skip?: InputMaybe; + first?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + where?: InputMaybe; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type Query_metaArgs = { + block?: InputMaybe; +}; + +export type Subscription = { + readonly collateral?: Maybe; + readonly collaterals: ReadonlyArray; + readonly token?: Maybe; + readonly tokens: ReadonlyArray; + readonly collateralAddresses?: Maybe; + readonly collateralAddresses_collection: ReadonlyArray; + readonly interestRateBracket?: Maybe; + readonly interestRateBrackets: ReadonlyArray; + readonly trove?: Maybe; + readonly troves: ReadonlyArray; + /** Access to subgraph metadata */ + readonly _meta?: Maybe<_Meta_>; +}; + + +export type SubscriptioncollateralArgs = { + id: Scalars['ID']['input']; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type SubscriptioncollateralsArgs = { + skip?: InputMaybe; + first?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + where?: InputMaybe; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type SubscriptiontokenArgs = { + id: Scalars['ID']['input']; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type SubscriptiontokensArgs = { + skip?: InputMaybe; + first?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + where?: InputMaybe; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type SubscriptioncollateralAddressesArgs = { + id: Scalars['ID']['input']; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type SubscriptioncollateralAddresses_collectionArgs = { + skip?: InputMaybe; + first?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + where?: InputMaybe; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type SubscriptioninterestRateBracketArgs = { + id: Scalars['ID']['input']; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type SubscriptioninterestRateBracketsArgs = { + skip?: InputMaybe; + first?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + where?: InputMaybe; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type SubscriptiontroveArgs = { + id: Scalars['ID']['input']; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type SubscriptiontrovesArgs = { + skip?: InputMaybe; + first?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + where?: InputMaybe; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type Subscription_metaArgs = { + block?: InputMaybe; +}; + +export type Token = { + readonly id: Scalars['ID']['output']; + readonly collateral: Collateral; + readonly name: Scalars['String']['output']; + readonly symbol: Scalars['String']['output']; + readonly decimals: Scalars['Int']['output']; +}; + +export type Token_filter = { + readonly id?: InputMaybe; + readonly id_not?: InputMaybe; + readonly id_gt?: InputMaybe; + readonly id_lt?: InputMaybe; + readonly id_gte?: InputMaybe; + readonly id_lte?: InputMaybe; + readonly id_in?: InputMaybe>; + readonly id_not_in?: InputMaybe>; + readonly collateral?: InputMaybe; + readonly collateral_not?: InputMaybe; + readonly collateral_gt?: InputMaybe; + readonly collateral_lt?: InputMaybe; + readonly collateral_gte?: InputMaybe; + readonly collateral_lte?: InputMaybe; + readonly collateral_in?: InputMaybe>; + readonly collateral_not_in?: InputMaybe>; + readonly collateral_contains?: InputMaybe; + readonly collateral_contains_nocase?: InputMaybe; + readonly collateral_not_contains?: InputMaybe; + readonly collateral_not_contains_nocase?: InputMaybe; + readonly collateral_starts_with?: InputMaybe; + readonly collateral_starts_with_nocase?: InputMaybe; + readonly collateral_not_starts_with?: InputMaybe; + readonly collateral_not_starts_with_nocase?: InputMaybe; + readonly collateral_ends_with?: InputMaybe; + readonly collateral_ends_with_nocase?: InputMaybe; + readonly collateral_not_ends_with?: InputMaybe; + readonly collateral_not_ends_with_nocase?: InputMaybe; + readonly collateral_?: InputMaybe; + readonly name?: InputMaybe; + readonly name_not?: InputMaybe; + readonly name_gt?: InputMaybe; + readonly name_lt?: InputMaybe; + readonly name_gte?: InputMaybe; + readonly name_lte?: InputMaybe; + readonly name_in?: InputMaybe>; + readonly name_not_in?: InputMaybe>; + readonly name_contains?: InputMaybe; + readonly name_contains_nocase?: InputMaybe; + readonly name_not_contains?: InputMaybe; + readonly name_not_contains_nocase?: InputMaybe; + readonly name_starts_with?: InputMaybe; + readonly name_starts_with_nocase?: InputMaybe; + readonly name_not_starts_with?: InputMaybe; + readonly name_not_starts_with_nocase?: InputMaybe; + readonly name_ends_with?: InputMaybe; + readonly name_ends_with_nocase?: InputMaybe; + readonly name_not_ends_with?: InputMaybe; + readonly name_not_ends_with_nocase?: InputMaybe; + readonly symbol?: InputMaybe; + readonly symbol_not?: InputMaybe; + readonly symbol_gt?: InputMaybe; + readonly symbol_lt?: InputMaybe; + readonly symbol_gte?: InputMaybe; + readonly symbol_lte?: InputMaybe; + readonly symbol_in?: InputMaybe>; + readonly symbol_not_in?: InputMaybe>; + readonly symbol_contains?: InputMaybe; + readonly symbol_contains_nocase?: InputMaybe; + readonly symbol_not_contains?: InputMaybe; + readonly symbol_not_contains_nocase?: InputMaybe; + readonly symbol_starts_with?: InputMaybe; + readonly symbol_starts_with_nocase?: InputMaybe; + readonly symbol_not_starts_with?: InputMaybe; + readonly symbol_not_starts_with_nocase?: InputMaybe; + readonly symbol_ends_with?: InputMaybe; + readonly symbol_ends_with_nocase?: InputMaybe; + readonly symbol_not_ends_with?: InputMaybe; + readonly symbol_not_ends_with_nocase?: InputMaybe; + readonly decimals?: InputMaybe; + readonly decimals_not?: InputMaybe; + readonly decimals_gt?: InputMaybe; + readonly decimals_lt?: InputMaybe; + readonly decimals_gte?: InputMaybe; + readonly decimals_lte?: InputMaybe; + readonly decimals_in?: InputMaybe>; + readonly decimals_not_in?: InputMaybe>; + /** Filter for the block changed event. */ + readonly _change_block?: InputMaybe; + readonly and?: InputMaybe>>; + readonly or?: InputMaybe>>; +}; + +export type Token_orderBy = + | 'id' + | 'collateral' + | 'collateral__id' + | 'collateral__minCollRatio' + | 'collateral__totalDeposited' + | 'collateral__totalDebt' + | 'name' + | 'symbol' + | 'decimals'; + +export type Trove = { + readonly id: Scalars['ID']['output']; + readonly borrower: Scalars['Bytes']['output']; + readonly debt: Scalars['BigInt']['output']; + readonly deposit: Scalars['BigInt']['output']; + readonly stake: Scalars['BigInt']['output']; + readonly interestRate: Scalars['BigInt']['output']; + readonly createdAt: Scalars['BigInt']['output']; + readonly closedAt?: Maybe; + readonly collateral: Collateral; +}; + +export type Trove_filter = { + readonly id?: InputMaybe; + readonly id_not?: InputMaybe; + readonly id_gt?: InputMaybe; + readonly id_lt?: InputMaybe; + readonly id_gte?: InputMaybe; + readonly id_lte?: InputMaybe; + readonly id_in?: InputMaybe>; + readonly id_not_in?: InputMaybe>; + readonly borrower?: InputMaybe; + readonly borrower_not?: InputMaybe; + readonly borrower_gt?: InputMaybe; + readonly borrower_lt?: InputMaybe; + readonly borrower_gte?: InputMaybe; + readonly borrower_lte?: InputMaybe; + readonly borrower_in?: InputMaybe>; + readonly borrower_not_in?: InputMaybe>; + readonly borrower_contains?: InputMaybe; + readonly borrower_not_contains?: InputMaybe; + readonly debt?: InputMaybe; + readonly debt_not?: InputMaybe; + readonly debt_gt?: InputMaybe; + readonly debt_lt?: InputMaybe; + readonly debt_gte?: InputMaybe; + readonly debt_lte?: InputMaybe; + readonly debt_in?: InputMaybe>; + readonly debt_not_in?: InputMaybe>; + readonly deposit?: InputMaybe; + readonly deposit_not?: InputMaybe; + readonly deposit_gt?: InputMaybe; + readonly deposit_lt?: InputMaybe; + readonly deposit_gte?: InputMaybe; + readonly deposit_lte?: InputMaybe; + readonly deposit_in?: InputMaybe>; + readonly deposit_not_in?: InputMaybe>; + readonly stake?: InputMaybe; + readonly stake_not?: InputMaybe; + readonly stake_gt?: InputMaybe; + readonly stake_lt?: InputMaybe; + readonly stake_gte?: InputMaybe; + readonly stake_lte?: InputMaybe; + readonly stake_in?: InputMaybe>; + readonly stake_not_in?: InputMaybe>; + readonly interestRate?: InputMaybe; + readonly interestRate_not?: InputMaybe; + readonly interestRate_gt?: InputMaybe; + readonly interestRate_lt?: InputMaybe; + readonly interestRate_gte?: InputMaybe; + readonly interestRate_lte?: InputMaybe; + readonly interestRate_in?: InputMaybe>; + readonly interestRate_not_in?: InputMaybe>; + readonly createdAt?: InputMaybe; + readonly createdAt_not?: InputMaybe; + readonly createdAt_gt?: InputMaybe; + readonly createdAt_lt?: InputMaybe; + readonly createdAt_gte?: InputMaybe; + readonly createdAt_lte?: InputMaybe; + readonly createdAt_in?: InputMaybe>; + readonly createdAt_not_in?: InputMaybe>; + readonly closedAt?: InputMaybe; + readonly closedAt_not?: InputMaybe; + readonly closedAt_gt?: InputMaybe; + readonly closedAt_lt?: InputMaybe; + readonly closedAt_gte?: InputMaybe; + readonly closedAt_lte?: InputMaybe; + readonly closedAt_in?: InputMaybe>; + readonly closedAt_not_in?: InputMaybe>; + readonly collateral?: InputMaybe; + readonly collateral_not?: InputMaybe; + readonly collateral_gt?: InputMaybe; + readonly collateral_lt?: InputMaybe; + readonly collateral_gte?: InputMaybe; + readonly collateral_lte?: InputMaybe; + readonly collateral_in?: InputMaybe>; + readonly collateral_not_in?: InputMaybe>; + readonly collateral_contains?: InputMaybe; + readonly collateral_contains_nocase?: InputMaybe; + readonly collateral_not_contains?: InputMaybe; + readonly collateral_not_contains_nocase?: InputMaybe; + readonly collateral_starts_with?: InputMaybe; + readonly collateral_starts_with_nocase?: InputMaybe; + readonly collateral_not_starts_with?: InputMaybe; + readonly collateral_not_starts_with_nocase?: InputMaybe; + readonly collateral_ends_with?: InputMaybe; + readonly collateral_ends_with_nocase?: InputMaybe; + readonly collateral_not_ends_with?: InputMaybe; + readonly collateral_not_ends_with_nocase?: InputMaybe; + readonly collateral_?: InputMaybe; + /** Filter for the block changed event. */ + readonly _change_block?: InputMaybe; + readonly and?: InputMaybe>>; + readonly or?: InputMaybe>>; +}; + +export type Trove_orderBy = + | 'id' + | 'borrower' + | 'debt' + | 'deposit' + | 'stake' + | 'interestRate' + | 'createdAt' + | 'closedAt' + | 'collateral' + | 'collateral__id' + | 'collateral__minCollRatio' + | 'collateral__totalDeposited' + | 'collateral__totalDebt'; + +export type _Block_ = { + /** The hash of the block */ + readonly hash?: Maybe; + /** The block number */ + readonly number: Scalars['Int']['output']; + /** Integer representation of the timestamp stored in blocks for the chain */ + readonly timestamp?: Maybe; + /** The hash of the parent block */ + readonly parentHash?: Maybe; +}; + +/** The type for the top-level _meta field */ +export type _Meta_ = { + /** + * Information about a specific subgraph block. The hash of the block + * will be null if the _meta field has a block constraint that asks for + * a block number. It will be filled if the _meta field has no block constraint + * and therefore asks for the latest block + * + */ + readonly block: _Block_; + /** The deployment ID */ + readonly deployment: Scalars['String']['output']; + /** If `true`, the subgraph encountered indexing errors at some past block */ + readonly hasIndexingErrors: Scalars['Boolean']['output']; +}; + +export type _SubgraphErrorPolicy_ = + /** Data will be returned even if the subgraph has indexing errors */ + | 'allow' + /** If the subgraph has indexing errors, data will be omitted. The default. */ + | 'deny'; + +export type WithIndex = TObject & Record; +export type ResolversObject = WithIndex; + +export type ResolverTypeWrapper = Promise | T; + + +export type ResolverWithResolve = { + resolve: ResolverFn; +}; + +export type LegacyStitchingResolver = { + fragment: string; + resolve: ResolverFn; +}; + +export type NewStitchingResolver = { + selectionSet: string | ((fieldNode: FieldNode) => SelectionSetNode); + resolve: ResolverFn; +}; +export type StitchingResolver = LegacyStitchingResolver | NewStitchingResolver; +export type Resolver = + | ResolverFn + | ResolverWithResolve + | StitchingResolver; + +export type ResolverFn = ( + parent: TParent, + args: TArgs, + context: TContext, + info: GraphQLResolveInfo +) => Promise | TResult; + +export type SubscriptionSubscribeFn = ( + parent: TParent, + args: TArgs, + context: TContext, + info: GraphQLResolveInfo +) => AsyncIterable | Promise>; + +export type SubscriptionResolveFn = ( + parent: TParent, + args: TArgs, + context: TContext, + info: GraphQLResolveInfo +) => TResult | Promise; + +export interface SubscriptionSubscriberObject { + subscribe: SubscriptionSubscribeFn<{ [key in TKey]: TResult }, TParent, TContext, TArgs>; + resolve?: SubscriptionResolveFn; +} + +export interface SubscriptionResolverObject { + subscribe: SubscriptionSubscribeFn; + resolve: SubscriptionResolveFn; +} + +export type SubscriptionObject = + | SubscriptionSubscriberObject + | SubscriptionResolverObject; + +export type SubscriptionResolver = + | ((...args: any[]) => SubscriptionObject) + | SubscriptionObject; + +export type TypeResolveFn = ( + parent: TParent, + context: TContext, + info: GraphQLResolveInfo +) => Maybe | Promise>; + +export type IsTypeOfResolverFn = (obj: T, context: TContext, info: GraphQLResolveInfo) => boolean | Promise; + +export type NextResolverFn = () => Promise; + +export type DirectiveResolverFn = ( + next: NextResolverFn, + parent: TParent, + args: TArgs, + context: TContext, + info: GraphQLResolveInfo +) => TResult | Promise; + + + +/** Mapping between all available schema types and the resolvers types */ +export type ResolversTypes = ResolversObject<{ + Aggregation_interval: Aggregation_interval; + BigDecimal: ResolverTypeWrapper; + BigInt: ResolverTypeWrapper; + BlockChangedFilter: BlockChangedFilter; + Block_height: Block_height; + Boolean: ResolverTypeWrapper; + Bytes: ResolverTypeWrapper; + Collateral: ResolverTypeWrapper; + CollateralAddresses: ResolverTypeWrapper; + CollateralAddresses_filter: CollateralAddresses_filter; + CollateralAddresses_orderBy: CollateralAddresses_orderBy; + Collateral_filter: Collateral_filter; + Collateral_orderBy: Collateral_orderBy; + Float: ResolverTypeWrapper; + ID: ResolverTypeWrapper; + Int: ResolverTypeWrapper; + Int8: ResolverTypeWrapper; + InterestRateBracket: ResolverTypeWrapper; + InterestRateBracket_filter: InterestRateBracket_filter; + InterestRateBracket_orderBy: InterestRateBracket_orderBy; + OrderDirection: OrderDirection; + Query: ResolverTypeWrapper<{}>; + String: ResolverTypeWrapper; + Subscription: ResolverTypeWrapper<{}>; + Timestamp: ResolverTypeWrapper; + Token: ResolverTypeWrapper; + Token_filter: Token_filter; + Token_orderBy: Token_orderBy; + Trove: ResolverTypeWrapper; + Trove_filter: Trove_filter; + Trove_orderBy: Trove_orderBy; + _Block_: ResolverTypeWrapper<_Block_>; + _Meta_: ResolverTypeWrapper<_Meta_>; + _SubgraphErrorPolicy_: _SubgraphErrorPolicy_; +}>; + +/** Mapping between all available schema types and the resolvers parents */ +export type ResolversParentTypes = ResolversObject<{ + BigDecimal: Scalars['BigDecimal']['output']; + BigInt: Scalars['BigInt']['output']; + BlockChangedFilter: BlockChangedFilter; + Block_height: Block_height; + Boolean: Scalars['Boolean']['output']; + Bytes: Scalars['Bytes']['output']; + Collateral: Collateral; + CollateralAddresses: CollateralAddresses; + CollateralAddresses_filter: CollateralAddresses_filter; + Collateral_filter: Collateral_filter; + Float: Scalars['Float']['output']; + ID: Scalars['ID']['output']; + Int: Scalars['Int']['output']; + Int8: Scalars['Int8']['output']; + InterestRateBracket: InterestRateBracket; + InterestRateBracket_filter: InterestRateBracket_filter; + Query: {}; + String: Scalars['String']['output']; + Subscription: {}; + Timestamp: Scalars['Timestamp']['output']; + Token: Token; + Token_filter: Token_filter; + Trove: Trove; + Trove_filter: Trove_filter; + _Block_: _Block_; + _Meta_: _Meta_; +}>; + +export type entityDirectiveArgs = { }; + +export type entityDirectiveResolver = DirectiveResolverFn; + +export type subgraphIdDirectiveArgs = { + id: Scalars['String']['input']; +}; + +export type subgraphIdDirectiveResolver = DirectiveResolverFn; + +export type derivedFromDirectiveArgs = { + field: Scalars['String']['input']; +}; + +export type derivedFromDirectiveResolver = DirectiveResolverFn; + +export interface BigDecimalScalarConfig extends GraphQLScalarTypeConfig { + name: 'BigDecimal'; +} + +export interface BigIntScalarConfig extends GraphQLScalarTypeConfig { + name: 'BigInt'; +} + +export interface BytesScalarConfig extends GraphQLScalarTypeConfig { + name: 'Bytes'; +} + +export type CollateralResolvers = ResolversObject<{ + id?: Resolver; + token?: Resolver; + minCollRatio?: Resolver; + troves?: Resolver, ParentType, ContextType, RequireFields>; + addresses?: Resolver; + totalDeposited?: Resolver; + totalDebt?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type CollateralAddressesResolvers = ResolversObject<{ + id?: Resolver; + borrowerOperations?: Resolver; + collateral?: Resolver; + sortedTroves?: Resolver; + stabilityPool?: Resolver; + token?: Resolver; + troveManager?: Resolver; + troveNft?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export interface Int8ScalarConfig extends GraphQLScalarTypeConfig { + name: 'Int8'; +} + +export type InterestRateBracketResolvers = ResolversObject<{ + id?: Resolver; + rate?: Resolver; + totalDebt?: Resolver; + totalTroves?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type QueryResolvers = ResolversObject<{ + collateral?: Resolver, ParentType, ContextType, RequireFields>; + collaterals?: Resolver, ParentType, ContextType, RequireFields>; + token?: Resolver, ParentType, ContextType, RequireFields>; + tokens?: Resolver, ParentType, ContextType, RequireFields>; + collateralAddresses?: Resolver, ParentType, ContextType, RequireFields>; + collateralAddresses_collection?: Resolver, ParentType, ContextType, RequireFields>; + interestRateBracket?: Resolver, ParentType, ContextType, RequireFields>; + interestRateBrackets?: Resolver, ParentType, ContextType, RequireFields>; + trove?: Resolver, ParentType, ContextType, RequireFields>; + troves?: Resolver, ParentType, ContextType, RequireFields>; + _meta?: Resolver, ParentType, ContextType, Partial>; +}>; + +export type SubscriptionResolvers = ResolversObject<{ + collateral?: SubscriptionResolver, "collateral", ParentType, ContextType, RequireFields>; + collaterals?: SubscriptionResolver, "collaterals", ParentType, ContextType, RequireFields>; + token?: SubscriptionResolver, "token", ParentType, ContextType, RequireFields>; + tokens?: SubscriptionResolver, "tokens", ParentType, ContextType, RequireFields>; + collateralAddresses?: SubscriptionResolver, "collateralAddresses", ParentType, ContextType, RequireFields>; + collateralAddresses_collection?: SubscriptionResolver, "collateralAddresses_collection", ParentType, ContextType, RequireFields>; + interestRateBracket?: SubscriptionResolver, "interestRateBracket", ParentType, ContextType, RequireFields>; + interestRateBrackets?: SubscriptionResolver, "interestRateBrackets", ParentType, ContextType, RequireFields>; + trove?: SubscriptionResolver, "trove", ParentType, ContextType, RequireFields>; + troves?: SubscriptionResolver, "troves", ParentType, ContextType, RequireFields>; + _meta?: SubscriptionResolver, "_meta", ParentType, ContextType, Partial>; +}>; + +export interface TimestampScalarConfig extends GraphQLScalarTypeConfig { + name: 'Timestamp'; +} + +export type TokenResolvers = ResolversObject<{ + id?: Resolver; + collateral?: Resolver; + name?: Resolver; + symbol?: Resolver; + decimals?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type TroveResolvers = ResolversObject<{ + id?: Resolver; + borrower?: Resolver; + debt?: Resolver; + deposit?: Resolver; + stake?: Resolver; + interestRate?: Resolver; + createdAt?: Resolver; + closedAt?: Resolver, ParentType, ContextType>; + collateral?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type _Block_Resolvers = ResolversObject<{ + hash?: Resolver, ParentType, ContextType>; + number?: Resolver; + timestamp?: Resolver, ParentType, ContextType>; + parentHash?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type _Meta_Resolvers = ResolversObject<{ + block?: Resolver; + deployment?: Resolver; + hasIndexingErrors?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type Resolvers = ResolversObject<{ + BigDecimal?: GraphQLScalarType; + BigInt?: GraphQLScalarType; + Bytes?: GraphQLScalarType; + Collateral?: CollateralResolvers; + CollateralAddresses?: CollateralAddressesResolvers; + Int8?: GraphQLScalarType; + InterestRateBracket?: InterestRateBracketResolvers; + Query?: QueryResolvers; + Subscription?: SubscriptionResolvers; + Timestamp?: GraphQLScalarType; + Token?: TokenResolvers; + Trove?: TroveResolvers; + _Block_?: _Block_Resolvers; + _Meta_?: _Meta_Resolvers; +}>; + +export type DirectiveResolvers = ResolversObject<{ + entity?: entityDirectiveResolver; + subgraphId?: subgraphIdDirectiveResolver; + derivedFrom?: derivedFromDirectiveResolver; +}>; + +export type MeshContext = Liquity2Types.Context & BaseMeshContext; + + +import { fileURLToPath } from '@graphql-mesh/utils'; +const baseDir = pathModule.join(pathModule.dirname(fileURLToPath(import.meta.url)), '..'); + +const importFn: ImportFn = (moduleId: string) => { + const relativeModuleId = (pathModule.isAbsolute(moduleId) ? pathModule.relative(baseDir, moduleId) : moduleId).split('\\').join('/').replace(baseDir + '/', ''); + switch(relativeModuleId) { + case ".graphclient/sources/liquity2/introspectionSchema": + return Promise.resolve(importedModule$0) as T; + + default: + return Promise.reject(new Error(`Cannot find module '${relativeModuleId}'.`)); + } +}; + +const rootStore = new MeshStore('.graphclient', new FsStoreStorageAdapter({ + cwd: baseDir, + importFn, + fileType: "ts", +}), { + readonly: true, + validate: false +}); + +export const rawServeConfig: YamlConfig.Config['serve'] = undefined as any +export async function getMeshOptions(): Promise { +const pubsub = new PubSub(); +const sourcesStore = rootStore.child('sources'); +const logger = new DefaultLogger("GraphClient"); +const cache = new (MeshCache as any)({ + ...({} as any), + importFn, + store: rootStore.child('cache'), + pubsub, + logger, + } as any) + +const sources: MeshResolvedSource[] = []; +const transforms: MeshTransform[] = []; +const additionalEnvelopPlugins: MeshPlugin[] = []; +const liquity2Transforms = []; +const additionalTypeDefs = [] as any[]; +const liquity2Handler = new GraphqlHandler({ + name: "liquity2", + config: {"endpoint":"http://localhost:8000/subgraphs/name/liquity2/liquity2"}, + baseDir, + cache, + pubsub, + store: sourcesStore.child("liquity2"), + logger: logger.child("liquity2"), + importFn, + }); +sources[0] = { + name: 'liquity2', + handler: liquity2Handler, + transforms: liquity2Transforms + } +const additionalResolvers = [] as any[] +const merger = new(BareMerger as any)({ + cache, + pubsub, + logger: logger.child('bareMerger'), + store: rootStore.child('bareMerger') + }) +const documentHashMap = { + "45745732d955f1e9e56be85453b7766bb2b5d776bad265e1e6734958fbc111c8": TrovesByAccountDocument, +"45745732d955f1e9e56be85453b7766bb2b5d776bad265e1e6734958fbc111c8": TroveByIdDocument + } +additionalEnvelopPlugins.push(usePersistedOperations({ + getPersistedOperation(key) { + return documentHashMap[key]; + }, + ...{} + })) + + return { + sources, + transforms, + additionalTypeDefs, + additionalResolvers, + cache, + pubsub, + merger, + logger, + additionalEnvelopPlugins, + get documents() { + return [ + { + document: TrovesByAccountDocument, + get rawSDL() { + return printWithCache(TrovesByAccountDocument); + }, + location: 'TrovesByAccountDocument.graphql', + sha256Hash: '45745732d955f1e9e56be85453b7766bb2b5d776bad265e1e6734958fbc111c8' + },{ + document: TroveByIdDocument, + get rawSDL() { + return printWithCache(TroveByIdDocument); + }, + location: 'TroveByIdDocument.graphql', + sha256Hash: '45745732d955f1e9e56be85453b7766bb2b5d776bad265e1e6734958fbc111c8' + } + ]; + }, + fetchFn, + }; +} + +export function createBuiltMeshHTTPHandler(): MeshHTTPHandler { + return createMeshHTTPHandler({ + baseDir, + getBuiltMesh: getBuiltGraphClient, + rawServeConfig: undefined, + }) +} + + +let meshInstance$: Promise | undefined; + +export const pollingInterval = null; + +export function getBuiltGraphClient(): Promise { + if (meshInstance$ == null) { + if (pollingInterval) { + setInterval(() => { + getMeshOptions() + .then(meshOptions => getMesh(meshOptions)) + .then(newMesh => + meshInstance$.then(oldMesh => { + oldMesh.destroy() + meshInstance$ = Promise.resolve(newMesh) + }) + ).catch(err => { + console.error("Mesh polling failed so the existing version will be used:", err); + }); + }, pollingInterval) + } + meshInstance$ = getMeshOptions().then(meshOptions => getMesh(meshOptions)).then(mesh => { + const id = mesh.pubsub.subscribe('destroy', () => { + meshInstance$ = undefined; + mesh.pubsub.unsubscribe(id); + }); + return mesh; + }); + } + return meshInstance$; +} + +export const execute: ExecuteMeshFn = (...args) => getBuiltGraphClient().then(({ execute }) => execute(...args)); + +export const subscribe: SubscribeMeshFn = (...args) => getBuiltGraphClient().then(({ subscribe }) => subscribe(...args)); +export function getBuiltGraphSDK(globalContext?: TGlobalContext) { + const sdkRequester$ = getBuiltGraphClient().then(({ sdkRequesterFactory }) => sdkRequesterFactory(globalContext)); + return getSdk((...args) => sdkRequester$.then(sdkRequester => sdkRequester(...args))); +} +export type TrovesByAccountQueryVariables = Exact<{ + account: Scalars['Bytes']['input']; +}>; + + +export type TrovesByAccountQuery = { readonly troves: ReadonlyArray<( + Pick + & { readonly collateral: ( + Pick + & { readonly token: Pick } + ) } + )> }; + +export type TroveByIdQueryVariables = Exact<{ + id: Scalars['ID']['input']; +}>; + + +export type TroveByIdQuery = { readonly trove?: Maybe<( + Pick + & { readonly collateral: ( + Pick + & { readonly token: Pick } + ) } + )> }; + + +export const TrovesByAccountDocument = gql` + query TrovesByAccount($account: Bytes!) { + troves(where: {borrower: $account}) { + id + borrower + debt + deposit + stake + interestRate + createdAt + closedAt + collateral { + id + token { + symbol + name + } + minCollRatio + } + } +} + ` as unknown as DocumentNode; +export const TroveByIdDocument = gql` + query TroveById($id: ID!) { + trove(id: $id) { + id + borrower + debt + deposit + stake + interestRate + createdAt + closedAt + collateral { + id + token { + symbol + name + } + minCollRatio + } + } +} + ` as unknown as DocumentNode; + + + +export type Requester = (doc: DocumentNode, vars?: V, options?: C) => Promise | AsyncIterable +export function getSdk(requester: Requester) { + return { + TrovesByAccount(variables: TrovesByAccountQueryVariables, options?: C): Promise { + return requester(TrovesByAccountDocument, variables, options) as Promise; + }, + TroveById(variables: TroveByIdQueryVariables, options?: C): Promise { + return requester(TroveByIdDocument, variables, options) as Promise; + } + }; +} +export type Sdk = ReturnType; \ No newline at end of file diff --git a/frontend/app/.graphclient/persisted_operations.json b/frontend/app/.graphclient/persisted_operations.json new file mode 100644 index 00000000..5c0346b7 --- /dev/null +++ b/frontend/app/.graphclient/persisted_operations.json @@ -0,0 +1,3 @@ +{ + "45745732d955f1e9e56be85453b7766bb2b5d776bad265e1e6734958fbc111c8": "query TrovesByAccount($account: Bytes!) {\n troves(where: {borrower: $account}) {\n id\n borrower\n debt\n deposit\n stake\n interestRate\n createdAt\n closedAt\n collateral {\n id\n token {\n symbol\n name\n }\n minCollRatio\n }\n }\n}\n\nquery TroveById($id: ID!) {\n trove(id: $id) {\n id\n borrower\n debt\n deposit\n stake\n interestRate\n createdAt\n closedAt\n collateral {\n id\n token {\n symbol\n name\n }\n minCollRatio\n }\n }\n}" +} \ No newline at end of file diff --git a/frontend/app/.graphclient/schema.graphql b/frontend/app/.graphclient/schema.graphql new file mode 100644 index 00000000..d53c0294 --- /dev/null +++ b/frontend/app/.graphclient/schema.graphql @@ -0,0 +1,856 @@ +schema { + query: Query + subscription: Subscription +} + +""" +Marks the GraphQL type as indexable entity. Each type that should be an entity is required to be annotated with this directive. +""" +directive @entity on OBJECT + +"""Defined a Subgraph ID for an object type""" +directive @subgraphId(id: String!) on OBJECT + +""" +creates a virtual field on the entity that may be queried but cannot be set manually through the mappings API. +""" +directive @derivedFrom(field: String!) on FIELD_DEFINITION + +enum Aggregation_interval { + hour + day +} + +scalar BigDecimal + +scalar BigInt + +input BlockChangedFilter { + number_gte: Int! +} + +input Block_height { + hash: Bytes + number: Int + number_gte: Int +} + +scalar Bytes + +type Collateral { + id: ID! + token: Token! + minCollRatio: BigInt! + troves(skip: Int = 0, first: Int = 100, orderBy: Trove_orderBy, orderDirection: OrderDirection, where: Trove_filter): [Trove!]! + addresses: CollateralAddresses! + totalDeposited: BigInt! + totalDebt: BigInt! +} + +type CollateralAddresses { + id: ID! + borrowerOperations: Bytes! + collateral: Collateral! + sortedTroves: Bytes! + stabilityPool: Bytes! + token: Bytes! + troveManager: Bytes! + troveNft: Bytes! +} + +input CollateralAddresses_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + borrowerOperations: Bytes + borrowerOperations_not: Bytes + borrowerOperations_gt: Bytes + borrowerOperations_lt: Bytes + borrowerOperations_gte: Bytes + borrowerOperations_lte: Bytes + borrowerOperations_in: [Bytes!] + borrowerOperations_not_in: [Bytes!] + borrowerOperations_contains: Bytes + borrowerOperations_not_contains: Bytes + collateral: String + collateral_not: String + collateral_gt: String + collateral_lt: String + collateral_gte: String + collateral_lte: String + collateral_in: [String!] + collateral_not_in: [String!] + collateral_contains: String + collateral_contains_nocase: String + collateral_not_contains: String + collateral_not_contains_nocase: String + collateral_starts_with: String + collateral_starts_with_nocase: String + collateral_not_starts_with: String + collateral_not_starts_with_nocase: String + collateral_ends_with: String + collateral_ends_with_nocase: String + collateral_not_ends_with: String + collateral_not_ends_with_nocase: String + collateral_: Collateral_filter + sortedTroves: Bytes + sortedTroves_not: Bytes + sortedTroves_gt: Bytes + sortedTroves_lt: Bytes + sortedTroves_gte: Bytes + sortedTroves_lte: Bytes + sortedTroves_in: [Bytes!] + sortedTroves_not_in: [Bytes!] + sortedTroves_contains: Bytes + sortedTroves_not_contains: Bytes + stabilityPool: Bytes + stabilityPool_not: Bytes + stabilityPool_gt: Bytes + stabilityPool_lt: Bytes + stabilityPool_gte: Bytes + stabilityPool_lte: Bytes + stabilityPool_in: [Bytes!] + stabilityPool_not_in: [Bytes!] + stabilityPool_contains: Bytes + stabilityPool_not_contains: Bytes + token: Bytes + token_not: Bytes + token_gt: Bytes + token_lt: Bytes + token_gte: Bytes + token_lte: Bytes + token_in: [Bytes!] + token_not_in: [Bytes!] + token_contains: Bytes + token_not_contains: Bytes + troveManager: Bytes + troveManager_not: Bytes + troveManager_gt: Bytes + troveManager_lt: Bytes + troveManager_gte: Bytes + troveManager_lte: Bytes + troveManager_in: [Bytes!] + troveManager_not_in: [Bytes!] + troveManager_contains: Bytes + troveManager_not_contains: Bytes + troveNft: Bytes + troveNft_not: Bytes + troveNft_gt: Bytes + troveNft_lt: Bytes + troveNft_gte: Bytes + troveNft_lte: Bytes + troveNft_in: [Bytes!] + troveNft_not_in: [Bytes!] + troveNft_contains: Bytes + troveNft_not_contains: Bytes + """Filter for the block changed event.""" + _change_block: BlockChangedFilter + and: [CollateralAddresses_filter] + or: [CollateralAddresses_filter] +} + +enum CollateralAddresses_orderBy { + id + borrowerOperations + collateral + collateral__id + collateral__minCollRatio + collateral__totalDeposited + collateral__totalDebt + sortedTroves + stabilityPool + token + troveManager + troveNft +} + +input Collateral_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + token: String + token_not: String + token_gt: String + token_lt: String + token_gte: String + token_lte: String + token_in: [String!] + token_not_in: [String!] + token_contains: String + token_contains_nocase: String + token_not_contains: String + token_not_contains_nocase: String + token_starts_with: String + token_starts_with_nocase: String + token_not_starts_with: String + token_not_starts_with_nocase: String + token_ends_with: String + token_ends_with_nocase: String + token_not_ends_with: String + token_not_ends_with_nocase: String + token_: Token_filter + minCollRatio: BigInt + minCollRatio_not: BigInt + minCollRatio_gt: BigInt + minCollRatio_lt: BigInt + minCollRatio_gte: BigInt + minCollRatio_lte: BigInt + minCollRatio_in: [BigInt!] + minCollRatio_not_in: [BigInt!] + troves_: Trove_filter + addresses_: CollateralAddresses_filter + totalDeposited: BigInt + totalDeposited_not: BigInt + totalDeposited_gt: BigInt + totalDeposited_lt: BigInt + totalDeposited_gte: BigInt + totalDeposited_lte: BigInt + totalDeposited_in: [BigInt!] + totalDeposited_not_in: [BigInt!] + totalDebt: BigInt + totalDebt_not: BigInt + totalDebt_gt: BigInt + totalDebt_lt: BigInt + totalDebt_gte: BigInt + totalDebt_lte: BigInt + totalDebt_in: [BigInt!] + totalDebt_not_in: [BigInt!] + """Filter for the block changed event.""" + _change_block: BlockChangedFilter + and: [Collateral_filter] + or: [Collateral_filter] +} + +enum Collateral_orderBy { + id + token + token__id + token__name + token__symbol + token__decimals + minCollRatio + troves + addresses + addresses__id + addresses__borrowerOperations + addresses__sortedTroves + addresses__stabilityPool + addresses__token + addresses__troveManager + addresses__troveNft + totalDeposited + totalDebt +} + +""" +8 bytes signed integer + +""" +scalar Int8 + +type InterestRateBracket { + id: ID! + rate: BigInt! + totalDebt: BigInt! + totalTroves: Int! +} + +input InterestRateBracket_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + rate: BigInt + rate_not: BigInt + rate_gt: BigInt + rate_lt: BigInt + rate_gte: BigInt + rate_lte: BigInt + rate_in: [BigInt!] + rate_not_in: [BigInt!] + totalDebt: BigInt + totalDebt_not: BigInt + totalDebt_gt: BigInt + totalDebt_lt: BigInt + totalDebt_gte: BigInt + totalDebt_lte: BigInt + totalDebt_in: [BigInt!] + totalDebt_not_in: [BigInt!] + totalTroves: Int + totalTroves_not: Int + totalTroves_gt: Int + totalTroves_lt: Int + totalTroves_gte: Int + totalTroves_lte: Int + totalTroves_in: [Int!] + totalTroves_not_in: [Int!] + """Filter for the block changed event.""" + _change_block: BlockChangedFilter + and: [InterestRateBracket_filter] + or: [InterestRateBracket_filter] +} + +enum InterestRateBracket_orderBy { + id + rate + totalDebt + totalTroves +} + +"""Defines the order direction, either ascending or descending""" +enum OrderDirection { + asc + desc +} + +type Query { + collateral( + id: ID! + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): Collateral + collaterals( + skip: Int = 0 + first: Int = 100 + orderBy: Collateral_orderBy + orderDirection: OrderDirection + where: Collateral_filter + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): [Collateral!]! + token( + id: ID! + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): Token + tokens( + skip: Int = 0 + first: Int = 100 + orderBy: Token_orderBy + orderDirection: OrderDirection + where: Token_filter + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): [Token!]! + collateralAddresses( + id: ID! + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): CollateralAddresses + collateralAddresses_collection( + skip: Int = 0 + first: Int = 100 + orderBy: CollateralAddresses_orderBy + orderDirection: OrderDirection + where: CollateralAddresses_filter + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): [CollateralAddresses!]! + interestRateBracket( + id: ID! + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): InterestRateBracket + interestRateBrackets( + skip: Int = 0 + first: Int = 100 + orderBy: InterestRateBracket_orderBy + orderDirection: OrderDirection + where: InterestRateBracket_filter + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): [InterestRateBracket!]! + trove( + id: ID! + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): Trove + troves( + skip: Int = 0 + first: Int = 100 + orderBy: Trove_orderBy + orderDirection: OrderDirection + where: Trove_filter + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): [Trove!]! + """Access to subgraph metadata""" + _meta(block: Block_height): _Meta_ +} + +type Subscription { + collateral( + id: ID! + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): Collateral + collaterals( + skip: Int = 0 + first: Int = 100 + orderBy: Collateral_orderBy + orderDirection: OrderDirection + where: Collateral_filter + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): [Collateral!]! + token( + id: ID! + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): Token + tokens( + skip: Int = 0 + first: Int = 100 + orderBy: Token_orderBy + orderDirection: OrderDirection + where: Token_filter + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): [Token!]! + collateralAddresses( + id: ID! + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): CollateralAddresses + collateralAddresses_collection( + skip: Int = 0 + first: Int = 100 + orderBy: CollateralAddresses_orderBy + orderDirection: OrderDirection + where: CollateralAddresses_filter + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): [CollateralAddresses!]! + interestRateBracket( + id: ID! + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): InterestRateBracket + interestRateBrackets( + skip: Int = 0 + first: Int = 100 + orderBy: InterestRateBracket_orderBy + orderDirection: OrderDirection + where: InterestRateBracket_filter + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): [InterestRateBracket!]! + trove( + id: ID! + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): Trove + troves( + skip: Int = 0 + first: Int = 100 + orderBy: Trove_orderBy + orderDirection: OrderDirection + where: Trove_filter + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): [Trove!]! + """Access to subgraph metadata""" + _meta(block: Block_height): _Meta_ +} + +""" +A string representation of microseconds UNIX timestamp (16 digits) + +""" +scalar Timestamp + +type Token { + id: ID! + collateral: Collateral! + name: String! + symbol: String! + decimals: Int! +} + +input Token_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + collateral: String + collateral_not: String + collateral_gt: String + collateral_lt: String + collateral_gte: String + collateral_lte: String + collateral_in: [String!] + collateral_not_in: [String!] + collateral_contains: String + collateral_contains_nocase: String + collateral_not_contains: String + collateral_not_contains_nocase: String + collateral_starts_with: String + collateral_starts_with_nocase: String + collateral_not_starts_with: String + collateral_not_starts_with_nocase: String + collateral_ends_with: String + collateral_ends_with_nocase: String + collateral_not_ends_with: String + collateral_not_ends_with_nocase: String + collateral_: Collateral_filter + name: String + name_not: String + name_gt: String + name_lt: String + name_gte: String + name_lte: String + name_in: [String!] + name_not_in: [String!] + name_contains: String + name_contains_nocase: String + name_not_contains: String + name_not_contains_nocase: String + name_starts_with: String + name_starts_with_nocase: String + name_not_starts_with: String + name_not_starts_with_nocase: String + name_ends_with: String + name_ends_with_nocase: String + name_not_ends_with: String + name_not_ends_with_nocase: String + symbol: String + symbol_not: String + symbol_gt: String + symbol_lt: String + symbol_gte: String + symbol_lte: String + symbol_in: [String!] + symbol_not_in: [String!] + symbol_contains: String + symbol_contains_nocase: String + symbol_not_contains: String + symbol_not_contains_nocase: String + symbol_starts_with: String + symbol_starts_with_nocase: String + symbol_not_starts_with: String + symbol_not_starts_with_nocase: String + symbol_ends_with: String + symbol_ends_with_nocase: String + symbol_not_ends_with: String + symbol_not_ends_with_nocase: String + decimals: Int + decimals_not: Int + decimals_gt: Int + decimals_lt: Int + decimals_gte: Int + decimals_lte: Int + decimals_in: [Int!] + decimals_not_in: [Int!] + """Filter for the block changed event.""" + _change_block: BlockChangedFilter + and: [Token_filter] + or: [Token_filter] +} + +enum Token_orderBy { + id + collateral + collateral__id + collateral__minCollRatio + collateral__totalDeposited + collateral__totalDebt + name + symbol + decimals +} + +type Trove { + id: ID! + borrower: Bytes! + debt: BigInt! + deposit: BigInt! + stake: BigInt! + interestRate: BigInt! + createdAt: BigInt! + closedAt: BigInt + collateral: Collateral! +} + +input Trove_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + borrower: Bytes + borrower_not: Bytes + borrower_gt: Bytes + borrower_lt: Bytes + borrower_gte: Bytes + borrower_lte: Bytes + borrower_in: [Bytes!] + borrower_not_in: [Bytes!] + borrower_contains: Bytes + borrower_not_contains: Bytes + debt: BigInt + debt_not: BigInt + debt_gt: BigInt + debt_lt: BigInt + debt_gte: BigInt + debt_lte: BigInt + debt_in: [BigInt!] + debt_not_in: [BigInt!] + deposit: BigInt + deposit_not: BigInt + deposit_gt: BigInt + deposit_lt: BigInt + deposit_gte: BigInt + deposit_lte: BigInt + deposit_in: [BigInt!] + deposit_not_in: [BigInt!] + stake: BigInt + stake_not: BigInt + stake_gt: BigInt + stake_lt: BigInt + stake_gte: BigInt + stake_lte: BigInt + stake_in: [BigInt!] + stake_not_in: [BigInt!] + interestRate: BigInt + interestRate_not: BigInt + interestRate_gt: BigInt + interestRate_lt: BigInt + interestRate_gte: BigInt + interestRate_lte: BigInt + interestRate_in: [BigInt!] + interestRate_not_in: [BigInt!] + createdAt: BigInt + createdAt_not: BigInt + createdAt_gt: BigInt + createdAt_lt: BigInt + createdAt_gte: BigInt + createdAt_lte: BigInt + createdAt_in: [BigInt!] + createdAt_not_in: [BigInt!] + closedAt: BigInt + closedAt_not: BigInt + closedAt_gt: BigInt + closedAt_lt: BigInt + closedAt_gte: BigInt + closedAt_lte: BigInt + closedAt_in: [BigInt!] + closedAt_not_in: [BigInt!] + collateral: String + collateral_not: String + collateral_gt: String + collateral_lt: String + collateral_gte: String + collateral_lte: String + collateral_in: [String!] + collateral_not_in: [String!] + collateral_contains: String + collateral_contains_nocase: String + collateral_not_contains: String + collateral_not_contains_nocase: String + collateral_starts_with: String + collateral_starts_with_nocase: String + collateral_not_starts_with: String + collateral_not_starts_with_nocase: String + collateral_ends_with: String + collateral_ends_with_nocase: String + collateral_not_ends_with: String + collateral_not_ends_with_nocase: String + collateral_: Collateral_filter + """Filter for the block changed event.""" + _change_block: BlockChangedFilter + and: [Trove_filter] + or: [Trove_filter] +} + +enum Trove_orderBy { + id + borrower + debt + deposit + stake + interestRate + createdAt + closedAt + collateral + collateral__id + collateral__minCollRatio + collateral__totalDeposited + collateral__totalDebt +} + +type _Block_ { + """The hash of the block""" + hash: Bytes + """The block number""" + number: Int! + """Integer representation of the timestamp stored in blocks for the chain""" + timestamp: Int + """The hash of the parent block""" + parentHash: Bytes +} + +"""The type for the top-level _meta field""" +type _Meta_ { + """ + Information about a specific subgraph block. The hash of the block + will be null if the _meta field has a block constraint that asks for + a block number. It will be filled if the _meta field has no block constraint + and therefore asks for the latest block + + """ + block: _Block_! + """The deployment ID""" + deployment: String! + """If `true`, the subgraph encountered indexing errors at some past block""" + hasIndexingErrors: Boolean! +} + +enum _SubgraphErrorPolicy_ { + """Data will be returned even if the subgraph has indexing errors""" + allow + """ + If the subgraph has indexing errors, data will be omitted. The default. + """ + deny +} \ No newline at end of file diff --git a/frontend/app/.graphclient/sources/liquity2/introspectionSchema.ts b/frontend/app/.graphclient/sources/liquity2/introspectionSchema.ts new file mode 100644 index 00000000..4d3350be --- /dev/null +++ b/frontend/app/.graphclient/sources/liquity2/introspectionSchema.ts @@ -0,0 +1,10096 @@ +// @ts-nocheck +import { buildASTSchema } from 'graphql'; + +const schemaAST = { + "kind": "Document", + "definitions": [ + { + "kind": "SchemaDefinition", + "operationTypes": [ + { + "kind": "OperationTypeDefinition", + "operation": "query", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Query" + } + } + }, + { + "kind": "OperationTypeDefinition", + "operation": "subscription", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Subscription" + } + } + } + ], + "directives": [] + }, + { + "kind": "DirectiveDefinition", + "description": { + "kind": "StringValue", + "value": "Marks the GraphQL type as indexable entity. Each type that should be an entity is required to be annotated with this directive.", + "block": true + }, + "name": { + "kind": "Name", + "value": "entity" + }, + "arguments": [], + "repeatable": false, + "locations": [ + { + "kind": "Name", + "value": "OBJECT" + } + ] + }, + { + "kind": "DirectiveDefinition", + "description": { + "kind": "StringValue", + "value": "Defined a Subgraph ID for an object type", + "block": true + }, + "name": { + "kind": "Name", + "value": "subgraphId" + }, + "arguments": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + } + }, + "directives": [] + } + ], + "repeatable": false, + "locations": [ + { + "kind": "Name", + "value": "OBJECT" + } + ] + }, + { + "kind": "DirectiveDefinition", + "description": { + "kind": "StringValue", + "value": "creates a virtual field on the entity that may be queried but cannot be set manually through the mappings API.", + "block": true + }, + "name": { + "kind": "Name", + "value": "derivedFrom" + }, + "arguments": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "field" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + } + }, + "directives": [] + } + ], + "repeatable": false, + "locations": [ + { + "kind": "Name", + "value": "FIELD_DEFINITION" + } + ] + }, + { + "kind": "EnumTypeDefinition", + "name": { + "kind": "Name", + "value": "Aggregation_interval" + }, + "values": [ + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "hour" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "day" + }, + "directives": [] + } + ], + "directives": [] + }, + { + "kind": "ScalarTypeDefinition", + "name": { + "kind": "Name", + "value": "BigDecimal" + }, + "directives": [] + }, + { + "kind": "ScalarTypeDefinition", + "name": { + "kind": "Name", + "value": "BigInt" + }, + "directives": [] + }, + { + "kind": "InputObjectTypeDefinition", + "name": { + "kind": "Name", + "value": "BlockChangedFilter" + }, + "fields": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "number_gte" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + } + }, + "directives": [] + } + ], + "directives": [] + }, + { + "kind": "InputObjectTypeDefinition", + "name": { + "kind": "Name", + "value": "Block_height" + }, + "fields": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "hash" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "number" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "number_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "directives": [] + } + ], + "directives": [] + }, + { + "kind": "ScalarTypeDefinition", + "name": { + "kind": "Name", + "value": "Bytes" + }, + "directives": [] + }, + { + "kind": "ObjectTypeDefinition", + "name": { + "kind": "Name", + "value": "Collateral" + }, + "fields": [ + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "id" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "token" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Token" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "minCollRatio" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "troves" + }, + "arguments": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "skip" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "defaultValue": { + "kind": "IntValue", + "value": "0" + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "first" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "defaultValue": { + "kind": "IntValue", + "value": "100" + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "orderBy" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Trove_orderBy" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "orderDirection" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "OrderDirection" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "where" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Trove_filter" + } + }, + "directives": [] + } + ], + "type": { + "kind": "NonNullType", + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Trove" + } + } + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "addresses" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "CollateralAddresses" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "totalDeposited" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "totalDebt" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + }, + "directives": [] + } + ], + "interfaces": [], + "directives": [] + }, + { + "kind": "ObjectTypeDefinition", + "name": { + "kind": "Name", + "value": "CollateralAddresses" + }, + "fields": [ + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "id" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "borrowerOperations" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "collateral" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Collateral" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "sortedTroves" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "stabilityPool" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "token" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "troveManager" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "troveNft" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + } + }, + "directives": [] + } + ], + "interfaces": [], + "directives": [] + }, + { + "kind": "InputObjectTypeDefinition", + "name": { + "kind": "Name", + "value": "CollateralAddresses_filter" + }, + "fields": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "borrowerOperations" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "borrowerOperations_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "borrowerOperations_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "borrowerOperations_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "borrowerOperations_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "borrowerOperations_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "borrowerOperations_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "borrowerOperations_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "borrowerOperations_contains" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "borrowerOperations_not_contains" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_contains" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_contains_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_not_contains" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_not_contains_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_starts_with" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_starts_with_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_not_starts_with" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_not_starts_with_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_ends_with" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_ends_with_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_not_ends_with" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_not_ends_with_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Collateral_filter" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "sortedTroves" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "sortedTroves_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "sortedTroves_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "sortedTroves_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "sortedTroves_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "sortedTroves_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "sortedTroves_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "sortedTroves_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "sortedTroves_contains" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "sortedTroves_not_contains" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "stabilityPool" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "stabilityPool_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "stabilityPool_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "stabilityPool_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "stabilityPool_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "stabilityPool_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "stabilityPool_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "stabilityPool_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "stabilityPool_contains" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "stabilityPool_not_contains" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_contains" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_not_contains" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "troveManager" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "troveManager_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "troveManager_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "troveManager_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "troveManager_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "troveManager_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "troveManager_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "troveManager_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "troveManager_contains" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "troveManager_not_contains" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "troveNft" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "troveNft_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "troveNft_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "troveNft_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "troveNft_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "troveNft_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "troveNft_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "troveNft_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "troveNft_contains" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "troveNft_not_contains" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "Filter for the block changed event.", + "block": true + }, + "name": { + "kind": "Name", + "value": "_change_block" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BlockChangedFilter" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "and" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "CollateralAddresses_filter" + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "or" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "CollateralAddresses_filter" + } + } + }, + "directives": [] + } + ], + "directives": [] + }, + { + "kind": "EnumTypeDefinition", + "name": { + "kind": "Name", + "value": "CollateralAddresses_orderBy" + }, + "values": [ + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "id" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "borrowerOperations" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "collateral" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "collateral__id" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "collateral__minCollRatio" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "collateral__totalDeposited" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "collateral__totalDebt" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "sortedTroves" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "stabilityPool" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "token" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "troveManager" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "troveNft" + }, + "directives": [] + } + ], + "directives": [] + }, + { + "kind": "InputObjectTypeDefinition", + "name": { + "kind": "Name", + "value": "Collateral_filter" + }, + "fields": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_contains" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_contains_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_not_contains" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_not_contains_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_starts_with" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_starts_with_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_not_starts_with" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_not_starts_with_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_ends_with" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_ends_with_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_not_ends_with" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_not_ends_with_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "token_" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Token_filter" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "minCollRatio" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "minCollRatio_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "minCollRatio_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "minCollRatio_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "minCollRatio_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "minCollRatio_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "minCollRatio_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "minCollRatio_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "troves_" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Trove_filter" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "addresses_" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "CollateralAddresses_filter" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalDeposited" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalDeposited_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalDeposited_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalDeposited_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalDeposited_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalDeposited_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalDeposited_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalDeposited_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalDebt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalDebt_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalDebt_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalDebt_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalDebt_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalDebt_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalDebt_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalDebt_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "Filter for the block changed event.", + "block": true + }, + "name": { + "kind": "Name", + "value": "_change_block" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BlockChangedFilter" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "and" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Collateral_filter" + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "or" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Collateral_filter" + } + } + }, + "directives": [] + } + ], + "directives": [] + }, + { + "kind": "EnumTypeDefinition", + "name": { + "kind": "Name", + "value": "Collateral_orderBy" + }, + "values": [ + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "id" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "token" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "token__id" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "token__name" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "token__symbol" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "token__decimals" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "minCollRatio" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "troves" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "addresses" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "addresses__id" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "addresses__borrowerOperations" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "addresses__sortedTroves" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "addresses__stabilityPool" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "addresses__token" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "addresses__troveManager" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "addresses__troveNft" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "totalDeposited" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "totalDebt" + }, + "directives": [] + } + ], + "directives": [] + }, + { + "kind": "ScalarTypeDefinition", + "description": { + "kind": "StringValue", + "value": "8 bytes signed integer\n", + "block": true + }, + "name": { + "kind": "Name", + "value": "Int8" + }, + "directives": [] + }, + { + "kind": "ObjectTypeDefinition", + "name": { + "kind": "Name", + "value": "InterestRateBracket" + }, + "fields": [ + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "id" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "rate" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "totalDebt" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "totalTroves" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + } + }, + "directives": [] + } + ], + "interfaces": [], + "directives": [] + }, + { + "kind": "InputObjectTypeDefinition", + "name": { + "kind": "Name", + "value": "InterestRateBracket_filter" + }, + "fields": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "rate" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "rate_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "rate_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "rate_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "rate_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "rate_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "rate_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "rate_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalDebt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalDebt_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalDebt_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalDebt_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalDebt_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalDebt_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalDebt_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalDebt_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalTroves" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalTroves_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalTroves_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalTroves_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalTroves_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalTroves_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalTroves_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "totalTroves_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "Filter for the block changed event.", + "block": true + }, + "name": { + "kind": "Name", + "value": "_change_block" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BlockChangedFilter" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "and" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "InterestRateBracket_filter" + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "or" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "InterestRateBracket_filter" + } + } + }, + "directives": [] + } + ], + "directives": [] + }, + { + "kind": "EnumTypeDefinition", + "name": { + "kind": "Name", + "value": "InterestRateBracket_orderBy" + }, + "values": [ + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "id" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "rate" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "totalDebt" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "totalTroves" + }, + "directives": [] + } + ], + "directives": [] + }, + { + "kind": "EnumTypeDefinition", + "description": { + "kind": "StringValue", + "value": "Defines the order direction, either ascending or descending", + "block": true + }, + "name": { + "kind": "Name", + "value": "OrderDirection" + }, + "values": [ + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "asc" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "desc" + }, + "directives": [] + } + ], + "directives": [] + }, + { + "kind": "ObjectTypeDefinition", + "name": { + "kind": "Name", + "value": "Query" + }, + "fields": [ + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "collateral" + }, + "arguments": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", + "block": true + }, + "name": { + "kind": "Name", + "value": "block" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Block_height" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", + "block": true + }, + "name": { + "kind": "Name", + "value": "subgraphError" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "_SubgraphErrorPolicy_" + } + } + }, + "defaultValue": { + "kind": "EnumValue", + "value": "deny" + }, + "directives": [] + } + ], + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Collateral" + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "collaterals" + }, + "arguments": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "skip" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "defaultValue": { + "kind": "IntValue", + "value": "0" + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "first" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "defaultValue": { + "kind": "IntValue", + "value": "100" + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "orderBy" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Collateral_orderBy" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "orderDirection" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "OrderDirection" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "where" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Collateral_filter" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", + "block": true + }, + "name": { + "kind": "Name", + "value": "block" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Block_height" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", + "block": true + }, + "name": { + "kind": "Name", + "value": "subgraphError" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "_SubgraphErrorPolicy_" + } + } + }, + "defaultValue": { + "kind": "EnumValue", + "value": "deny" + }, + "directives": [] + } + ], + "type": { + "kind": "NonNullType", + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Collateral" + } + } + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "token" + }, + "arguments": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", + "block": true + }, + "name": { + "kind": "Name", + "value": "block" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Block_height" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", + "block": true + }, + "name": { + "kind": "Name", + "value": "subgraphError" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "_SubgraphErrorPolicy_" + } + } + }, + "defaultValue": { + "kind": "EnumValue", + "value": "deny" + }, + "directives": [] + } + ], + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Token" + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "tokens" + }, + "arguments": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "skip" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "defaultValue": { + "kind": "IntValue", + "value": "0" + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "first" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "defaultValue": { + "kind": "IntValue", + "value": "100" + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "orderBy" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Token_orderBy" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "orderDirection" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "OrderDirection" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "where" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Token_filter" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", + "block": true + }, + "name": { + "kind": "Name", + "value": "block" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Block_height" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", + "block": true + }, + "name": { + "kind": "Name", + "value": "subgraphError" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "_SubgraphErrorPolicy_" + } + } + }, + "defaultValue": { + "kind": "EnumValue", + "value": "deny" + }, + "directives": [] + } + ], + "type": { + "kind": "NonNullType", + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Token" + } + } + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "collateralAddresses" + }, + "arguments": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", + "block": true + }, + "name": { + "kind": "Name", + "value": "block" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Block_height" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", + "block": true + }, + "name": { + "kind": "Name", + "value": "subgraphError" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "_SubgraphErrorPolicy_" + } + } + }, + "defaultValue": { + "kind": "EnumValue", + "value": "deny" + }, + "directives": [] + } + ], + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "CollateralAddresses" + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "collateralAddresses_collection" + }, + "arguments": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "skip" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "defaultValue": { + "kind": "IntValue", + "value": "0" + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "first" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "defaultValue": { + "kind": "IntValue", + "value": "100" + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "orderBy" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "CollateralAddresses_orderBy" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "orderDirection" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "OrderDirection" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "where" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "CollateralAddresses_filter" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", + "block": true + }, + "name": { + "kind": "Name", + "value": "block" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Block_height" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", + "block": true + }, + "name": { + "kind": "Name", + "value": "subgraphError" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "_SubgraphErrorPolicy_" + } + } + }, + "defaultValue": { + "kind": "EnumValue", + "value": "deny" + }, + "directives": [] + } + ], + "type": { + "kind": "NonNullType", + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "CollateralAddresses" + } + } + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "interestRateBracket" + }, + "arguments": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", + "block": true + }, + "name": { + "kind": "Name", + "value": "block" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Block_height" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", + "block": true + }, + "name": { + "kind": "Name", + "value": "subgraphError" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "_SubgraphErrorPolicy_" + } + } + }, + "defaultValue": { + "kind": "EnumValue", + "value": "deny" + }, + "directives": [] + } + ], + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "InterestRateBracket" + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "interestRateBrackets" + }, + "arguments": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "skip" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "defaultValue": { + "kind": "IntValue", + "value": "0" + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "first" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "defaultValue": { + "kind": "IntValue", + "value": "100" + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "orderBy" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "InterestRateBracket_orderBy" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "orderDirection" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "OrderDirection" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "where" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "InterestRateBracket_filter" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", + "block": true + }, + "name": { + "kind": "Name", + "value": "block" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Block_height" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", + "block": true + }, + "name": { + "kind": "Name", + "value": "subgraphError" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "_SubgraphErrorPolicy_" + } + } + }, + "defaultValue": { + "kind": "EnumValue", + "value": "deny" + }, + "directives": [] + } + ], + "type": { + "kind": "NonNullType", + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "InterestRateBracket" + } + } + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "trove" + }, + "arguments": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", + "block": true + }, + "name": { + "kind": "Name", + "value": "block" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Block_height" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", + "block": true + }, + "name": { + "kind": "Name", + "value": "subgraphError" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "_SubgraphErrorPolicy_" + } + } + }, + "defaultValue": { + "kind": "EnumValue", + "value": "deny" + }, + "directives": [] + } + ], + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Trove" + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "troves" + }, + "arguments": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "skip" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "defaultValue": { + "kind": "IntValue", + "value": "0" + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "first" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "defaultValue": { + "kind": "IntValue", + "value": "100" + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "orderBy" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Trove_orderBy" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "orderDirection" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "OrderDirection" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "where" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Trove_filter" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", + "block": true + }, + "name": { + "kind": "Name", + "value": "block" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Block_height" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", + "block": true + }, + "name": { + "kind": "Name", + "value": "subgraphError" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "_SubgraphErrorPolicy_" + } + } + }, + "defaultValue": { + "kind": "EnumValue", + "value": "deny" + }, + "directives": [] + } + ], + "type": { + "kind": "NonNullType", + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Trove" + } + } + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "description": { + "kind": "StringValue", + "value": "Access to subgraph metadata", + "block": true + }, + "name": { + "kind": "Name", + "value": "_meta" + }, + "arguments": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "block" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Block_height" + } + }, + "directives": [] + } + ], + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "_Meta_" + } + }, + "directives": [] + } + ], + "interfaces": [], + "directives": [] + }, + { + "kind": "ObjectTypeDefinition", + "name": { + "kind": "Name", + "value": "Subscription" + }, + "fields": [ + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "collateral" + }, + "arguments": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", + "block": true + }, + "name": { + "kind": "Name", + "value": "block" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Block_height" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", + "block": true + }, + "name": { + "kind": "Name", + "value": "subgraphError" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "_SubgraphErrorPolicy_" + } + } + }, + "defaultValue": { + "kind": "EnumValue", + "value": "deny" + }, + "directives": [] + } + ], + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Collateral" + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "collaterals" + }, + "arguments": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "skip" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "defaultValue": { + "kind": "IntValue", + "value": "0" + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "first" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "defaultValue": { + "kind": "IntValue", + "value": "100" + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "orderBy" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Collateral_orderBy" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "orderDirection" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "OrderDirection" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "where" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Collateral_filter" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", + "block": true + }, + "name": { + "kind": "Name", + "value": "block" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Block_height" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", + "block": true + }, + "name": { + "kind": "Name", + "value": "subgraphError" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "_SubgraphErrorPolicy_" + } + } + }, + "defaultValue": { + "kind": "EnumValue", + "value": "deny" + }, + "directives": [] + } + ], + "type": { + "kind": "NonNullType", + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Collateral" + } + } + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "token" + }, + "arguments": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", + "block": true + }, + "name": { + "kind": "Name", + "value": "block" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Block_height" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", + "block": true + }, + "name": { + "kind": "Name", + "value": "subgraphError" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "_SubgraphErrorPolicy_" + } + } + }, + "defaultValue": { + "kind": "EnumValue", + "value": "deny" + }, + "directives": [] + } + ], + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Token" + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "tokens" + }, + "arguments": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "skip" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "defaultValue": { + "kind": "IntValue", + "value": "0" + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "first" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "defaultValue": { + "kind": "IntValue", + "value": "100" + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "orderBy" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Token_orderBy" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "orderDirection" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "OrderDirection" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "where" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Token_filter" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", + "block": true + }, + "name": { + "kind": "Name", + "value": "block" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Block_height" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", + "block": true + }, + "name": { + "kind": "Name", + "value": "subgraphError" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "_SubgraphErrorPolicy_" + } + } + }, + "defaultValue": { + "kind": "EnumValue", + "value": "deny" + }, + "directives": [] + } + ], + "type": { + "kind": "NonNullType", + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Token" + } + } + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "collateralAddresses" + }, + "arguments": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", + "block": true + }, + "name": { + "kind": "Name", + "value": "block" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Block_height" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", + "block": true + }, + "name": { + "kind": "Name", + "value": "subgraphError" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "_SubgraphErrorPolicy_" + } + } + }, + "defaultValue": { + "kind": "EnumValue", + "value": "deny" + }, + "directives": [] + } + ], + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "CollateralAddresses" + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "collateralAddresses_collection" + }, + "arguments": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "skip" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "defaultValue": { + "kind": "IntValue", + "value": "0" + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "first" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "defaultValue": { + "kind": "IntValue", + "value": "100" + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "orderBy" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "CollateralAddresses_orderBy" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "orderDirection" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "OrderDirection" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "where" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "CollateralAddresses_filter" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", + "block": true + }, + "name": { + "kind": "Name", + "value": "block" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Block_height" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", + "block": true + }, + "name": { + "kind": "Name", + "value": "subgraphError" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "_SubgraphErrorPolicy_" + } + } + }, + "defaultValue": { + "kind": "EnumValue", + "value": "deny" + }, + "directives": [] + } + ], + "type": { + "kind": "NonNullType", + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "CollateralAddresses" + } + } + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "interestRateBracket" + }, + "arguments": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", + "block": true + }, + "name": { + "kind": "Name", + "value": "block" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Block_height" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", + "block": true + }, + "name": { + "kind": "Name", + "value": "subgraphError" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "_SubgraphErrorPolicy_" + } + } + }, + "defaultValue": { + "kind": "EnumValue", + "value": "deny" + }, + "directives": [] + } + ], + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "InterestRateBracket" + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "interestRateBrackets" + }, + "arguments": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "skip" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "defaultValue": { + "kind": "IntValue", + "value": "0" + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "first" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "defaultValue": { + "kind": "IntValue", + "value": "100" + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "orderBy" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "InterestRateBracket_orderBy" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "orderDirection" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "OrderDirection" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "where" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "InterestRateBracket_filter" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", + "block": true + }, + "name": { + "kind": "Name", + "value": "block" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Block_height" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", + "block": true + }, + "name": { + "kind": "Name", + "value": "subgraphError" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "_SubgraphErrorPolicy_" + } + } + }, + "defaultValue": { + "kind": "EnumValue", + "value": "deny" + }, + "directives": [] + } + ], + "type": { + "kind": "NonNullType", + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "InterestRateBracket" + } + } + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "trove" + }, + "arguments": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", + "block": true + }, + "name": { + "kind": "Name", + "value": "block" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Block_height" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", + "block": true + }, + "name": { + "kind": "Name", + "value": "subgraphError" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "_SubgraphErrorPolicy_" + } + } + }, + "defaultValue": { + "kind": "EnumValue", + "value": "deny" + }, + "directives": [] + } + ], + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Trove" + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "troves" + }, + "arguments": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "skip" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "defaultValue": { + "kind": "IntValue", + "value": "0" + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "first" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "defaultValue": { + "kind": "IntValue", + "value": "100" + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "orderBy" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Trove_orderBy" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "orderDirection" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "OrderDirection" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "where" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Trove_filter" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.", + "block": true + }, + "name": { + "kind": "Name", + "value": "block" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Block_height" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.", + "block": true + }, + "name": { + "kind": "Name", + "value": "subgraphError" + }, + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "_SubgraphErrorPolicy_" + } + } + }, + "defaultValue": { + "kind": "EnumValue", + "value": "deny" + }, + "directives": [] + } + ], + "type": { + "kind": "NonNullType", + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Trove" + } + } + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "description": { + "kind": "StringValue", + "value": "Access to subgraph metadata", + "block": true + }, + "name": { + "kind": "Name", + "value": "_meta" + }, + "arguments": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "block" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Block_height" + } + }, + "directives": [] + } + ], + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "_Meta_" + } + }, + "directives": [] + } + ], + "interfaces": [], + "directives": [] + }, + { + "kind": "ScalarTypeDefinition", + "description": { + "kind": "StringValue", + "value": "A string representation of microseconds UNIX timestamp (16 digits)\n", + "block": true + }, + "name": { + "kind": "Name", + "value": "Timestamp" + }, + "directives": [] + }, + { + "kind": "ObjectTypeDefinition", + "name": { + "kind": "Name", + "value": "Token" + }, + "fields": [ + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "id" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "collateral" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Collateral" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "name" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "symbol" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "decimals" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + } + }, + "directives": [] + } + ], + "interfaces": [], + "directives": [] + }, + { + "kind": "InputObjectTypeDefinition", + "name": { + "kind": "Name", + "value": "Token_filter" + }, + "fields": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_contains" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_contains_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_not_contains" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_not_contains_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_starts_with" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_starts_with_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_not_starts_with" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_not_starts_with_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_ends_with" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_ends_with_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_not_ends_with" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_not_ends_with_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Collateral_filter" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "name" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "name_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "name_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "name_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "name_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "name_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "name_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "name_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "name_contains" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "name_contains_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "name_not_contains" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "name_not_contains_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "name_starts_with" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "name_starts_with_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "name_not_starts_with" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "name_not_starts_with_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "name_ends_with" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "name_ends_with_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "name_not_ends_with" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "name_not_ends_with_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "symbol" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "symbol_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "symbol_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "symbol_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "symbol_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "symbol_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "symbol_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "symbol_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "symbol_contains" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "symbol_contains_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "symbol_not_contains" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "symbol_not_contains_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "symbol_starts_with" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "symbol_starts_with_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "symbol_not_starts_with" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "symbol_not_starts_with_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "symbol_ends_with" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "symbol_ends_with_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "symbol_not_ends_with" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "symbol_not_ends_with_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "decimals" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "decimals_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "decimals_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "decimals_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "decimals_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "decimals_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "decimals_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "decimals_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "Filter for the block changed event.", + "block": true + }, + "name": { + "kind": "Name", + "value": "_change_block" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BlockChangedFilter" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "and" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Token_filter" + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "or" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Token_filter" + } + } + }, + "directives": [] + } + ], + "directives": [] + }, + { + "kind": "EnumTypeDefinition", + "name": { + "kind": "Name", + "value": "Token_orderBy" + }, + "values": [ + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "id" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "collateral" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "collateral__id" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "collateral__minCollRatio" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "collateral__totalDeposited" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "collateral__totalDebt" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "name" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "symbol" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "decimals" + }, + "directives": [] + } + ], + "directives": [] + }, + { + "kind": "ObjectTypeDefinition", + "name": { + "kind": "Name", + "value": "Trove" + }, + "fields": [ + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "id" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "borrower" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "debt" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "deposit" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "stake" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "interestRate" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "createdAt" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "closedAt" + }, + "arguments": [], + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "collateral" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Collateral" + } + } + }, + "directives": [] + } + ], + "interfaces": [], + "directives": [] + }, + { + "kind": "InputObjectTypeDefinition", + "name": { + "kind": "Name", + "value": "Trove_filter" + }, + "fields": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "id_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "ID" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "borrower" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "borrower_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "borrower_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "borrower_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "borrower_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "borrower_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "borrower_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "borrower_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "borrower_contains" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "borrower_not_contains" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "debt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "debt_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "debt_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "debt_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "debt_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "debt_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "debt_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "debt_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "deposit" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "deposit_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "deposit_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "deposit_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "deposit_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "deposit_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "deposit_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "deposit_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "stake" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "stake_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "stake_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "stake_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "stake_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "stake_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "stake_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "stake_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "interestRate" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "interestRate_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "interestRate_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "interestRate_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "interestRate_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "interestRate_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "interestRate_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "interestRate_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "createdAt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "createdAt_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "createdAt_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "createdAt_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "createdAt_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "createdAt_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "createdAt_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "createdAt_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "closedAt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "closedAt_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "closedAt_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "closedAt_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "closedAt_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "closedAt_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "closedAt_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "closedAt_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BigInt" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_not" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_gt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_lt" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_gte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_lte" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_not_in" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_contains" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_contains_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_not_contains" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_not_contains_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_starts_with" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_starts_with_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_not_starts_with" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_not_starts_with_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_ends_with" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_ends_with_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_not_ends_with" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_not_ends_with_nocase" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "collateral_" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Collateral_filter" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "description": { + "kind": "StringValue", + "value": "Filter for the block changed event.", + "block": true + }, + "name": { + "kind": "Name", + "value": "_change_block" + }, + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "BlockChangedFilter" + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "and" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Trove_filter" + } + } + }, + "directives": [] + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "or" + }, + "type": { + "kind": "ListType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Trove_filter" + } + } + }, + "directives": [] + } + ], + "directives": [] + }, + { + "kind": "EnumTypeDefinition", + "name": { + "kind": "Name", + "value": "Trove_orderBy" + }, + "values": [ + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "id" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "borrower" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "debt" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "deposit" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "stake" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "interestRate" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "createdAt" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "closedAt" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "collateral" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "collateral__id" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "collateral__minCollRatio" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "collateral__totalDeposited" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "name": { + "kind": "Name", + "value": "collateral__totalDebt" + }, + "directives": [] + } + ], + "directives": [] + }, + { + "kind": "ObjectTypeDefinition", + "name": { + "kind": "Name", + "value": "_Block_" + }, + "fields": [ + { + "kind": "FieldDefinition", + "description": { + "kind": "StringValue", + "value": "The hash of the block", + "block": true + }, + "name": { + "kind": "Name", + "value": "hash" + }, + "arguments": [], + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "description": { + "kind": "StringValue", + "value": "The block number", + "block": true + }, + "name": { + "kind": "Name", + "value": "number" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "description": { + "kind": "StringValue", + "value": "Integer representation of the timestamp stored in blocks for the chain", + "block": true + }, + "name": { + "kind": "Name", + "value": "timestamp" + }, + "arguments": [], + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Int" + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "description": { + "kind": "StringValue", + "value": "The hash of the parent block", + "block": true + }, + "name": { + "kind": "Name", + "value": "parentHash" + }, + "arguments": [], + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Bytes" + } + }, + "directives": [] + } + ], + "interfaces": [], + "directives": [] + }, + { + "kind": "ObjectTypeDefinition", + "description": { + "kind": "StringValue", + "value": "The type for the top-level _meta field", + "block": true + }, + "name": { + "kind": "Name", + "value": "_Meta_" + }, + "fields": [ + { + "kind": "FieldDefinition", + "description": { + "kind": "StringValue", + "value": "Information about a specific subgraph block. The hash of the block\nwill be null if the _meta field has a block constraint that asks for\na block number. It will be filled if the _meta field has no block constraint\nand therefore asks for the latest block\n", + "block": true + }, + "name": { + "kind": "Name", + "value": "block" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "_Block_" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "description": { + "kind": "StringValue", + "value": "The deployment ID", + "block": true + }, + "name": { + "kind": "Name", + "value": "deployment" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String" + } + } + }, + "directives": [] + }, + { + "kind": "FieldDefinition", + "description": { + "kind": "StringValue", + "value": "If `true`, the subgraph encountered indexing errors at some past block", + "block": true + }, + "name": { + "kind": "Name", + "value": "hasIndexingErrors" + }, + "arguments": [], + "type": { + "kind": "NonNullType", + "type": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Boolean" + } + } + }, + "directives": [] + } + ], + "interfaces": [], + "directives": [] + }, + { + "kind": "EnumTypeDefinition", + "name": { + "kind": "Name", + "value": "_SubgraphErrorPolicy_" + }, + "values": [ + { + "kind": "EnumValueDefinition", + "description": { + "kind": "StringValue", + "value": "Data will be returned even if the subgraph has indexing errors", + "block": true + }, + "name": { + "kind": "Name", + "value": "allow" + }, + "directives": [] + }, + { + "kind": "EnumValueDefinition", + "description": { + "kind": "StringValue", + "value": "If the subgraph has indexing errors, data will be omitted. The default.", + "block": true + }, + "name": { + "kind": "Name", + "value": "deny" + }, + "directives": [] + } + ], + "directives": [] + } + ] +}; + +export default buildASTSchema(schemaAST, { + assumeValid: true, + assumeValidSDL: true +}); \ No newline at end of file diff --git a/frontend/app/.graphclient/sources/liquity2/schema.graphql b/frontend/app/.graphclient/sources/liquity2/schema.graphql new file mode 100644 index 00000000..d53c0294 --- /dev/null +++ b/frontend/app/.graphclient/sources/liquity2/schema.graphql @@ -0,0 +1,856 @@ +schema { + query: Query + subscription: Subscription +} + +""" +Marks the GraphQL type as indexable entity. Each type that should be an entity is required to be annotated with this directive. +""" +directive @entity on OBJECT + +"""Defined a Subgraph ID for an object type""" +directive @subgraphId(id: String!) on OBJECT + +""" +creates a virtual field on the entity that may be queried but cannot be set manually through the mappings API. +""" +directive @derivedFrom(field: String!) on FIELD_DEFINITION + +enum Aggregation_interval { + hour + day +} + +scalar BigDecimal + +scalar BigInt + +input BlockChangedFilter { + number_gte: Int! +} + +input Block_height { + hash: Bytes + number: Int + number_gte: Int +} + +scalar Bytes + +type Collateral { + id: ID! + token: Token! + minCollRatio: BigInt! + troves(skip: Int = 0, first: Int = 100, orderBy: Trove_orderBy, orderDirection: OrderDirection, where: Trove_filter): [Trove!]! + addresses: CollateralAddresses! + totalDeposited: BigInt! + totalDebt: BigInt! +} + +type CollateralAddresses { + id: ID! + borrowerOperations: Bytes! + collateral: Collateral! + sortedTroves: Bytes! + stabilityPool: Bytes! + token: Bytes! + troveManager: Bytes! + troveNft: Bytes! +} + +input CollateralAddresses_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + borrowerOperations: Bytes + borrowerOperations_not: Bytes + borrowerOperations_gt: Bytes + borrowerOperations_lt: Bytes + borrowerOperations_gte: Bytes + borrowerOperations_lte: Bytes + borrowerOperations_in: [Bytes!] + borrowerOperations_not_in: [Bytes!] + borrowerOperations_contains: Bytes + borrowerOperations_not_contains: Bytes + collateral: String + collateral_not: String + collateral_gt: String + collateral_lt: String + collateral_gte: String + collateral_lte: String + collateral_in: [String!] + collateral_not_in: [String!] + collateral_contains: String + collateral_contains_nocase: String + collateral_not_contains: String + collateral_not_contains_nocase: String + collateral_starts_with: String + collateral_starts_with_nocase: String + collateral_not_starts_with: String + collateral_not_starts_with_nocase: String + collateral_ends_with: String + collateral_ends_with_nocase: String + collateral_not_ends_with: String + collateral_not_ends_with_nocase: String + collateral_: Collateral_filter + sortedTroves: Bytes + sortedTroves_not: Bytes + sortedTroves_gt: Bytes + sortedTroves_lt: Bytes + sortedTroves_gte: Bytes + sortedTroves_lte: Bytes + sortedTroves_in: [Bytes!] + sortedTroves_not_in: [Bytes!] + sortedTroves_contains: Bytes + sortedTroves_not_contains: Bytes + stabilityPool: Bytes + stabilityPool_not: Bytes + stabilityPool_gt: Bytes + stabilityPool_lt: Bytes + stabilityPool_gte: Bytes + stabilityPool_lte: Bytes + stabilityPool_in: [Bytes!] + stabilityPool_not_in: [Bytes!] + stabilityPool_contains: Bytes + stabilityPool_not_contains: Bytes + token: Bytes + token_not: Bytes + token_gt: Bytes + token_lt: Bytes + token_gte: Bytes + token_lte: Bytes + token_in: [Bytes!] + token_not_in: [Bytes!] + token_contains: Bytes + token_not_contains: Bytes + troveManager: Bytes + troveManager_not: Bytes + troveManager_gt: Bytes + troveManager_lt: Bytes + troveManager_gte: Bytes + troveManager_lte: Bytes + troveManager_in: [Bytes!] + troveManager_not_in: [Bytes!] + troveManager_contains: Bytes + troveManager_not_contains: Bytes + troveNft: Bytes + troveNft_not: Bytes + troveNft_gt: Bytes + troveNft_lt: Bytes + troveNft_gte: Bytes + troveNft_lte: Bytes + troveNft_in: [Bytes!] + troveNft_not_in: [Bytes!] + troveNft_contains: Bytes + troveNft_not_contains: Bytes + """Filter for the block changed event.""" + _change_block: BlockChangedFilter + and: [CollateralAddresses_filter] + or: [CollateralAddresses_filter] +} + +enum CollateralAddresses_orderBy { + id + borrowerOperations + collateral + collateral__id + collateral__minCollRatio + collateral__totalDeposited + collateral__totalDebt + sortedTroves + stabilityPool + token + troveManager + troveNft +} + +input Collateral_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + token: String + token_not: String + token_gt: String + token_lt: String + token_gte: String + token_lte: String + token_in: [String!] + token_not_in: [String!] + token_contains: String + token_contains_nocase: String + token_not_contains: String + token_not_contains_nocase: String + token_starts_with: String + token_starts_with_nocase: String + token_not_starts_with: String + token_not_starts_with_nocase: String + token_ends_with: String + token_ends_with_nocase: String + token_not_ends_with: String + token_not_ends_with_nocase: String + token_: Token_filter + minCollRatio: BigInt + minCollRatio_not: BigInt + minCollRatio_gt: BigInt + minCollRatio_lt: BigInt + minCollRatio_gte: BigInt + minCollRatio_lte: BigInt + minCollRatio_in: [BigInt!] + minCollRatio_not_in: [BigInt!] + troves_: Trove_filter + addresses_: CollateralAddresses_filter + totalDeposited: BigInt + totalDeposited_not: BigInt + totalDeposited_gt: BigInt + totalDeposited_lt: BigInt + totalDeposited_gte: BigInt + totalDeposited_lte: BigInt + totalDeposited_in: [BigInt!] + totalDeposited_not_in: [BigInt!] + totalDebt: BigInt + totalDebt_not: BigInt + totalDebt_gt: BigInt + totalDebt_lt: BigInt + totalDebt_gte: BigInt + totalDebt_lte: BigInt + totalDebt_in: [BigInt!] + totalDebt_not_in: [BigInt!] + """Filter for the block changed event.""" + _change_block: BlockChangedFilter + and: [Collateral_filter] + or: [Collateral_filter] +} + +enum Collateral_orderBy { + id + token + token__id + token__name + token__symbol + token__decimals + minCollRatio + troves + addresses + addresses__id + addresses__borrowerOperations + addresses__sortedTroves + addresses__stabilityPool + addresses__token + addresses__troveManager + addresses__troveNft + totalDeposited + totalDebt +} + +""" +8 bytes signed integer + +""" +scalar Int8 + +type InterestRateBracket { + id: ID! + rate: BigInt! + totalDebt: BigInt! + totalTroves: Int! +} + +input InterestRateBracket_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + rate: BigInt + rate_not: BigInt + rate_gt: BigInt + rate_lt: BigInt + rate_gte: BigInt + rate_lte: BigInt + rate_in: [BigInt!] + rate_not_in: [BigInt!] + totalDebt: BigInt + totalDebt_not: BigInt + totalDebt_gt: BigInt + totalDebt_lt: BigInt + totalDebt_gte: BigInt + totalDebt_lte: BigInt + totalDebt_in: [BigInt!] + totalDebt_not_in: [BigInt!] + totalTroves: Int + totalTroves_not: Int + totalTroves_gt: Int + totalTroves_lt: Int + totalTroves_gte: Int + totalTroves_lte: Int + totalTroves_in: [Int!] + totalTroves_not_in: [Int!] + """Filter for the block changed event.""" + _change_block: BlockChangedFilter + and: [InterestRateBracket_filter] + or: [InterestRateBracket_filter] +} + +enum InterestRateBracket_orderBy { + id + rate + totalDebt + totalTroves +} + +"""Defines the order direction, either ascending or descending""" +enum OrderDirection { + asc + desc +} + +type Query { + collateral( + id: ID! + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): Collateral + collaterals( + skip: Int = 0 + first: Int = 100 + orderBy: Collateral_orderBy + orderDirection: OrderDirection + where: Collateral_filter + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): [Collateral!]! + token( + id: ID! + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): Token + tokens( + skip: Int = 0 + first: Int = 100 + orderBy: Token_orderBy + orderDirection: OrderDirection + where: Token_filter + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): [Token!]! + collateralAddresses( + id: ID! + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): CollateralAddresses + collateralAddresses_collection( + skip: Int = 0 + first: Int = 100 + orderBy: CollateralAddresses_orderBy + orderDirection: OrderDirection + where: CollateralAddresses_filter + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): [CollateralAddresses!]! + interestRateBracket( + id: ID! + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): InterestRateBracket + interestRateBrackets( + skip: Int = 0 + first: Int = 100 + orderBy: InterestRateBracket_orderBy + orderDirection: OrderDirection + where: InterestRateBracket_filter + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): [InterestRateBracket!]! + trove( + id: ID! + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): Trove + troves( + skip: Int = 0 + first: Int = 100 + orderBy: Trove_orderBy + orderDirection: OrderDirection + where: Trove_filter + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): [Trove!]! + """Access to subgraph metadata""" + _meta(block: Block_height): _Meta_ +} + +type Subscription { + collateral( + id: ID! + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): Collateral + collaterals( + skip: Int = 0 + first: Int = 100 + orderBy: Collateral_orderBy + orderDirection: OrderDirection + where: Collateral_filter + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): [Collateral!]! + token( + id: ID! + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): Token + tokens( + skip: Int = 0 + first: Int = 100 + orderBy: Token_orderBy + orderDirection: OrderDirection + where: Token_filter + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): [Token!]! + collateralAddresses( + id: ID! + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): CollateralAddresses + collateralAddresses_collection( + skip: Int = 0 + first: Int = 100 + orderBy: CollateralAddresses_orderBy + orderDirection: OrderDirection + where: CollateralAddresses_filter + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): [CollateralAddresses!]! + interestRateBracket( + id: ID! + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): InterestRateBracket + interestRateBrackets( + skip: Int = 0 + first: Int = 100 + orderBy: InterestRateBracket_orderBy + orderDirection: OrderDirection + where: InterestRateBracket_filter + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): [InterestRateBracket!]! + trove( + id: ID! + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): Trove + troves( + skip: Int = 0 + first: Int = 100 + orderBy: Trove_orderBy + orderDirection: OrderDirection + where: Trove_filter + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): [Trove!]! + """Access to subgraph metadata""" + _meta(block: Block_height): _Meta_ +} + +""" +A string representation of microseconds UNIX timestamp (16 digits) + +""" +scalar Timestamp + +type Token { + id: ID! + collateral: Collateral! + name: String! + symbol: String! + decimals: Int! +} + +input Token_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + collateral: String + collateral_not: String + collateral_gt: String + collateral_lt: String + collateral_gte: String + collateral_lte: String + collateral_in: [String!] + collateral_not_in: [String!] + collateral_contains: String + collateral_contains_nocase: String + collateral_not_contains: String + collateral_not_contains_nocase: String + collateral_starts_with: String + collateral_starts_with_nocase: String + collateral_not_starts_with: String + collateral_not_starts_with_nocase: String + collateral_ends_with: String + collateral_ends_with_nocase: String + collateral_not_ends_with: String + collateral_not_ends_with_nocase: String + collateral_: Collateral_filter + name: String + name_not: String + name_gt: String + name_lt: String + name_gte: String + name_lte: String + name_in: [String!] + name_not_in: [String!] + name_contains: String + name_contains_nocase: String + name_not_contains: String + name_not_contains_nocase: String + name_starts_with: String + name_starts_with_nocase: String + name_not_starts_with: String + name_not_starts_with_nocase: String + name_ends_with: String + name_ends_with_nocase: String + name_not_ends_with: String + name_not_ends_with_nocase: String + symbol: String + symbol_not: String + symbol_gt: String + symbol_lt: String + symbol_gte: String + symbol_lte: String + symbol_in: [String!] + symbol_not_in: [String!] + symbol_contains: String + symbol_contains_nocase: String + symbol_not_contains: String + symbol_not_contains_nocase: String + symbol_starts_with: String + symbol_starts_with_nocase: String + symbol_not_starts_with: String + symbol_not_starts_with_nocase: String + symbol_ends_with: String + symbol_ends_with_nocase: String + symbol_not_ends_with: String + symbol_not_ends_with_nocase: String + decimals: Int + decimals_not: Int + decimals_gt: Int + decimals_lt: Int + decimals_gte: Int + decimals_lte: Int + decimals_in: [Int!] + decimals_not_in: [Int!] + """Filter for the block changed event.""" + _change_block: BlockChangedFilter + and: [Token_filter] + or: [Token_filter] +} + +enum Token_orderBy { + id + collateral + collateral__id + collateral__minCollRatio + collateral__totalDeposited + collateral__totalDebt + name + symbol + decimals +} + +type Trove { + id: ID! + borrower: Bytes! + debt: BigInt! + deposit: BigInt! + stake: BigInt! + interestRate: BigInt! + createdAt: BigInt! + closedAt: BigInt + collateral: Collateral! +} + +input Trove_filter { + id: ID + id_not: ID + id_gt: ID + id_lt: ID + id_gte: ID + id_lte: ID + id_in: [ID!] + id_not_in: [ID!] + borrower: Bytes + borrower_not: Bytes + borrower_gt: Bytes + borrower_lt: Bytes + borrower_gte: Bytes + borrower_lte: Bytes + borrower_in: [Bytes!] + borrower_not_in: [Bytes!] + borrower_contains: Bytes + borrower_not_contains: Bytes + debt: BigInt + debt_not: BigInt + debt_gt: BigInt + debt_lt: BigInt + debt_gte: BigInt + debt_lte: BigInt + debt_in: [BigInt!] + debt_not_in: [BigInt!] + deposit: BigInt + deposit_not: BigInt + deposit_gt: BigInt + deposit_lt: BigInt + deposit_gte: BigInt + deposit_lte: BigInt + deposit_in: [BigInt!] + deposit_not_in: [BigInt!] + stake: BigInt + stake_not: BigInt + stake_gt: BigInt + stake_lt: BigInt + stake_gte: BigInt + stake_lte: BigInt + stake_in: [BigInt!] + stake_not_in: [BigInt!] + interestRate: BigInt + interestRate_not: BigInt + interestRate_gt: BigInt + interestRate_lt: BigInt + interestRate_gte: BigInt + interestRate_lte: BigInt + interestRate_in: [BigInt!] + interestRate_not_in: [BigInt!] + createdAt: BigInt + createdAt_not: BigInt + createdAt_gt: BigInt + createdAt_lt: BigInt + createdAt_gte: BigInt + createdAt_lte: BigInt + createdAt_in: [BigInt!] + createdAt_not_in: [BigInt!] + closedAt: BigInt + closedAt_not: BigInt + closedAt_gt: BigInt + closedAt_lt: BigInt + closedAt_gte: BigInt + closedAt_lte: BigInt + closedAt_in: [BigInt!] + closedAt_not_in: [BigInt!] + collateral: String + collateral_not: String + collateral_gt: String + collateral_lt: String + collateral_gte: String + collateral_lte: String + collateral_in: [String!] + collateral_not_in: [String!] + collateral_contains: String + collateral_contains_nocase: String + collateral_not_contains: String + collateral_not_contains_nocase: String + collateral_starts_with: String + collateral_starts_with_nocase: String + collateral_not_starts_with: String + collateral_not_starts_with_nocase: String + collateral_ends_with: String + collateral_ends_with_nocase: String + collateral_not_ends_with: String + collateral_not_ends_with_nocase: String + collateral_: Collateral_filter + """Filter for the block changed event.""" + _change_block: BlockChangedFilter + and: [Trove_filter] + or: [Trove_filter] +} + +enum Trove_orderBy { + id + borrower + debt + deposit + stake + interestRate + createdAt + closedAt + collateral + collateral__id + collateral__minCollRatio + collateral__totalDeposited + collateral__totalDebt +} + +type _Block_ { + """The hash of the block""" + hash: Bytes + """The block number""" + number: Int! + """Integer representation of the timestamp stored in blocks for the chain""" + timestamp: Int + """The hash of the parent block""" + parentHash: Bytes +} + +"""The type for the top-level _meta field""" +type _Meta_ { + """ + Information about a specific subgraph block. The hash of the block + will be null if the _meta field has a block constraint that asks for + a block number. It will be filled if the _meta field has no block constraint + and therefore asks for the latest block + + """ + block: _Block_! + """The deployment ID""" + deployment: String! + """If `true`, the subgraph encountered indexing errors at some past block""" + hasIndexingErrors: Boolean! +} + +enum _SubgraphErrorPolicy_ { + """Data will be returned even if the subgraph has indexing errors""" + allow + """ + If the subgraph has indexing errors, data will be omitted. The default. + """ + deny +} \ No newline at end of file diff --git a/frontend/app/.graphclient/sources/liquity2/types.ts b/frontend/app/.graphclient/sources/liquity2/types.ts new file mode 100644 index 00000000..4852f8c1 --- /dev/null +++ b/frontend/app/.graphclient/sources/liquity2/types.ts @@ -0,0 +1,856 @@ +// @ts-nocheck + +import { InContextSdkMethod } from '@graphql-mesh/types'; +import { MeshContext } from '@graphql-mesh/runtime'; + +export namespace Liquity2Types { + export type Maybe = T | null; +export type InputMaybe = Maybe; +export type Exact = { [K in keyof T]: T[K] }; +export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; +export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; +export type MakeEmpty = { [_ in K]?: never }; +export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; +/** All built-in and custom scalars, mapped to their actual values */ +export type Scalars = { + ID: { input: string; output: string; } + String: { input: string; output: string; } + Boolean: { input: boolean; output: boolean; } + Int: { input: number; output: number; } + Float: { input: number; output: number; } + BigDecimal: { input: bigint; output: bigint; } + BigInt: { input: bigint; output: bigint; } + Bytes: { input: string; output: string; } + Int8: { input: number; output: number; } + Timestamp: { input: string; output: string; } +}; + +export type Aggregation_interval = + | 'hour' + | 'day'; + +export type BlockChangedFilter = { + readonly number_gte: Scalars['Int']['input']; +}; + +export type Block_height = { + readonly hash?: InputMaybe; + readonly number?: InputMaybe; + readonly number_gte?: InputMaybe; +}; + +export type Collateral = { + readonly id: Scalars['ID']['output']; + readonly token: Token; + readonly minCollRatio: Scalars['BigInt']['output']; + readonly troves: ReadonlyArray; + readonly addresses: CollateralAddresses; + readonly totalDeposited: Scalars['BigInt']['output']; + readonly totalDebt: Scalars['BigInt']['output']; +}; + + +export type CollateraltrovesArgs = { + skip?: InputMaybe; + first?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + where?: InputMaybe; +}; + +export type CollateralAddresses = { + readonly id: Scalars['ID']['output']; + readonly borrowerOperations: Scalars['Bytes']['output']; + readonly collateral: Collateral; + readonly sortedTroves: Scalars['Bytes']['output']; + readonly stabilityPool: Scalars['Bytes']['output']; + readonly token: Scalars['Bytes']['output']; + readonly troveManager: Scalars['Bytes']['output']; + readonly troveNft: Scalars['Bytes']['output']; +}; + +export type CollateralAddresses_filter = { + readonly id?: InputMaybe; + readonly id_not?: InputMaybe; + readonly id_gt?: InputMaybe; + readonly id_lt?: InputMaybe; + readonly id_gte?: InputMaybe; + readonly id_lte?: InputMaybe; + readonly id_in?: InputMaybe>; + readonly id_not_in?: InputMaybe>; + readonly borrowerOperations?: InputMaybe; + readonly borrowerOperations_not?: InputMaybe; + readonly borrowerOperations_gt?: InputMaybe; + readonly borrowerOperations_lt?: InputMaybe; + readonly borrowerOperations_gte?: InputMaybe; + readonly borrowerOperations_lte?: InputMaybe; + readonly borrowerOperations_in?: InputMaybe>; + readonly borrowerOperations_not_in?: InputMaybe>; + readonly borrowerOperations_contains?: InputMaybe; + readonly borrowerOperations_not_contains?: InputMaybe; + readonly collateral?: InputMaybe; + readonly collateral_not?: InputMaybe; + readonly collateral_gt?: InputMaybe; + readonly collateral_lt?: InputMaybe; + readonly collateral_gte?: InputMaybe; + readonly collateral_lte?: InputMaybe; + readonly collateral_in?: InputMaybe>; + readonly collateral_not_in?: InputMaybe>; + readonly collateral_contains?: InputMaybe; + readonly collateral_contains_nocase?: InputMaybe; + readonly collateral_not_contains?: InputMaybe; + readonly collateral_not_contains_nocase?: InputMaybe; + readonly collateral_starts_with?: InputMaybe; + readonly collateral_starts_with_nocase?: InputMaybe; + readonly collateral_not_starts_with?: InputMaybe; + readonly collateral_not_starts_with_nocase?: InputMaybe; + readonly collateral_ends_with?: InputMaybe; + readonly collateral_ends_with_nocase?: InputMaybe; + readonly collateral_not_ends_with?: InputMaybe; + readonly collateral_not_ends_with_nocase?: InputMaybe; + readonly collateral_?: InputMaybe; + readonly sortedTroves?: InputMaybe; + readonly sortedTroves_not?: InputMaybe; + readonly sortedTroves_gt?: InputMaybe; + readonly sortedTroves_lt?: InputMaybe; + readonly sortedTroves_gte?: InputMaybe; + readonly sortedTroves_lte?: InputMaybe; + readonly sortedTroves_in?: InputMaybe>; + readonly sortedTroves_not_in?: InputMaybe>; + readonly sortedTroves_contains?: InputMaybe; + readonly sortedTroves_not_contains?: InputMaybe; + readonly stabilityPool?: InputMaybe; + readonly stabilityPool_not?: InputMaybe; + readonly stabilityPool_gt?: InputMaybe; + readonly stabilityPool_lt?: InputMaybe; + readonly stabilityPool_gte?: InputMaybe; + readonly stabilityPool_lte?: InputMaybe; + readonly stabilityPool_in?: InputMaybe>; + readonly stabilityPool_not_in?: InputMaybe>; + readonly stabilityPool_contains?: InputMaybe; + readonly stabilityPool_not_contains?: InputMaybe; + readonly token?: InputMaybe; + readonly token_not?: InputMaybe; + readonly token_gt?: InputMaybe; + readonly token_lt?: InputMaybe; + readonly token_gte?: InputMaybe; + readonly token_lte?: InputMaybe; + readonly token_in?: InputMaybe>; + readonly token_not_in?: InputMaybe>; + readonly token_contains?: InputMaybe; + readonly token_not_contains?: InputMaybe; + readonly troveManager?: InputMaybe; + readonly troveManager_not?: InputMaybe; + readonly troveManager_gt?: InputMaybe; + readonly troveManager_lt?: InputMaybe; + readonly troveManager_gte?: InputMaybe; + readonly troveManager_lte?: InputMaybe; + readonly troveManager_in?: InputMaybe>; + readonly troveManager_not_in?: InputMaybe>; + readonly troveManager_contains?: InputMaybe; + readonly troveManager_not_contains?: InputMaybe; + readonly troveNft?: InputMaybe; + readonly troveNft_not?: InputMaybe; + readonly troveNft_gt?: InputMaybe; + readonly troveNft_lt?: InputMaybe; + readonly troveNft_gte?: InputMaybe; + readonly troveNft_lte?: InputMaybe; + readonly troveNft_in?: InputMaybe>; + readonly troveNft_not_in?: InputMaybe>; + readonly troveNft_contains?: InputMaybe; + readonly troveNft_not_contains?: InputMaybe; + /** Filter for the block changed event. */ + readonly _change_block?: InputMaybe; + readonly and?: InputMaybe>>; + readonly or?: InputMaybe>>; +}; + +export type CollateralAddresses_orderBy = + | 'id' + | 'borrowerOperations' + | 'collateral' + | 'collateral__id' + | 'collateral__minCollRatio' + | 'collateral__totalDeposited' + | 'collateral__totalDebt' + | 'sortedTroves' + | 'stabilityPool' + | 'token' + | 'troveManager' + | 'troveNft'; + +export type Collateral_filter = { + readonly id?: InputMaybe; + readonly id_not?: InputMaybe; + readonly id_gt?: InputMaybe; + readonly id_lt?: InputMaybe; + readonly id_gte?: InputMaybe; + readonly id_lte?: InputMaybe; + readonly id_in?: InputMaybe>; + readonly id_not_in?: InputMaybe>; + readonly token?: InputMaybe; + readonly token_not?: InputMaybe; + readonly token_gt?: InputMaybe; + readonly token_lt?: InputMaybe; + readonly token_gte?: InputMaybe; + readonly token_lte?: InputMaybe; + readonly token_in?: InputMaybe>; + readonly token_not_in?: InputMaybe>; + readonly token_contains?: InputMaybe; + readonly token_contains_nocase?: InputMaybe; + readonly token_not_contains?: InputMaybe; + readonly token_not_contains_nocase?: InputMaybe; + readonly token_starts_with?: InputMaybe; + readonly token_starts_with_nocase?: InputMaybe; + readonly token_not_starts_with?: InputMaybe; + readonly token_not_starts_with_nocase?: InputMaybe; + readonly token_ends_with?: InputMaybe; + readonly token_ends_with_nocase?: InputMaybe; + readonly token_not_ends_with?: InputMaybe; + readonly token_not_ends_with_nocase?: InputMaybe; + readonly token_?: InputMaybe; + readonly minCollRatio?: InputMaybe; + readonly minCollRatio_not?: InputMaybe; + readonly minCollRatio_gt?: InputMaybe; + readonly minCollRatio_lt?: InputMaybe; + readonly minCollRatio_gte?: InputMaybe; + readonly minCollRatio_lte?: InputMaybe; + readonly minCollRatio_in?: InputMaybe>; + readonly minCollRatio_not_in?: InputMaybe>; + readonly troves_?: InputMaybe; + readonly addresses_?: InputMaybe; + readonly totalDeposited?: InputMaybe; + readonly totalDeposited_not?: InputMaybe; + readonly totalDeposited_gt?: InputMaybe; + readonly totalDeposited_lt?: InputMaybe; + readonly totalDeposited_gte?: InputMaybe; + readonly totalDeposited_lte?: InputMaybe; + readonly totalDeposited_in?: InputMaybe>; + readonly totalDeposited_not_in?: InputMaybe>; + readonly totalDebt?: InputMaybe; + readonly totalDebt_not?: InputMaybe; + readonly totalDebt_gt?: InputMaybe; + readonly totalDebt_lt?: InputMaybe; + readonly totalDebt_gte?: InputMaybe; + readonly totalDebt_lte?: InputMaybe; + readonly totalDebt_in?: InputMaybe>; + readonly totalDebt_not_in?: InputMaybe>; + /** Filter for the block changed event. */ + readonly _change_block?: InputMaybe; + readonly and?: InputMaybe>>; + readonly or?: InputMaybe>>; +}; + +export type Collateral_orderBy = + | 'id' + | 'token' + | 'token__id' + | 'token__name' + | 'token__symbol' + | 'token__decimals' + | 'minCollRatio' + | 'troves' + | 'addresses' + | 'addresses__id' + | 'addresses__borrowerOperations' + | 'addresses__sortedTroves' + | 'addresses__stabilityPool' + | 'addresses__token' + | 'addresses__troveManager' + | 'addresses__troveNft' + | 'totalDeposited' + | 'totalDebt'; + +export type InterestRateBracket = { + readonly id: Scalars['ID']['output']; + readonly rate: Scalars['BigInt']['output']; + readonly totalDebt: Scalars['BigInt']['output']; + readonly totalTroves: Scalars['Int']['output']; +}; + +export type InterestRateBracket_filter = { + readonly id?: InputMaybe; + readonly id_not?: InputMaybe; + readonly id_gt?: InputMaybe; + readonly id_lt?: InputMaybe; + readonly id_gte?: InputMaybe; + readonly id_lte?: InputMaybe; + readonly id_in?: InputMaybe>; + readonly id_not_in?: InputMaybe>; + readonly rate?: InputMaybe; + readonly rate_not?: InputMaybe; + readonly rate_gt?: InputMaybe; + readonly rate_lt?: InputMaybe; + readonly rate_gte?: InputMaybe; + readonly rate_lte?: InputMaybe; + readonly rate_in?: InputMaybe>; + readonly rate_not_in?: InputMaybe>; + readonly totalDebt?: InputMaybe; + readonly totalDebt_not?: InputMaybe; + readonly totalDebt_gt?: InputMaybe; + readonly totalDebt_lt?: InputMaybe; + readonly totalDebt_gte?: InputMaybe; + readonly totalDebt_lte?: InputMaybe; + readonly totalDebt_in?: InputMaybe>; + readonly totalDebt_not_in?: InputMaybe>; + readonly totalTroves?: InputMaybe; + readonly totalTroves_not?: InputMaybe; + readonly totalTroves_gt?: InputMaybe; + readonly totalTroves_lt?: InputMaybe; + readonly totalTroves_gte?: InputMaybe; + readonly totalTroves_lte?: InputMaybe; + readonly totalTroves_in?: InputMaybe>; + readonly totalTroves_not_in?: InputMaybe>; + /** Filter for the block changed event. */ + readonly _change_block?: InputMaybe; + readonly and?: InputMaybe>>; + readonly or?: InputMaybe>>; +}; + +export type InterestRateBracket_orderBy = + | 'id' + | 'rate' + | 'totalDebt' + | 'totalTroves'; + +/** Defines the order direction, either ascending or descending */ +export type OrderDirection = + | 'asc' + | 'desc'; + +export type Query = { + readonly collateral?: Maybe; + readonly collaterals: ReadonlyArray; + readonly token?: Maybe; + readonly tokens: ReadonlyArray; + readonly collateralAddresses?: Maybe; + readonly collateralAddresses_collection: ReadonlyArray; + readonly interestRateBracket?: Maybe; + readonly interestRateBrackets: ReadonlyArray; + readonly trove?: Maybe; + readonly troves: ReadonlyArray; + /** Access to subgraph metadata */ + readonly _meta?: Maybe<_Meta_>; +}; + + +export type QuerycollateralArgs = { + id: Scalars['ID']['input']; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type QuerycollateralsArgs = { + skip?: InputMaybe; + first?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + where?: InputMaybe; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type QuerytokenArgs = { + id: Scalars['ID']['input']; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type QuerytokensArgs = { + skip?: InputMaybe; + first?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + where?: InputMaybe; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type QuerycollateralAddressesArgs = { + id: Scalars['ID']['input']; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type QuerycollateralAddresses_collectionArgs = { + skip?: InputMaybe; + first?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + where?: InputMaybe; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type QueryinterestRateBracketArgs = { + id: Scalars['ID']['input']; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type QueryinterestRateBracketsArgs = { + skip?: InputMaybe; + first?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + where?: InputMaybe; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type QuerytroveArgs = { + id: Scalars['ID']['input']; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type QuerytrovesArgs = { + skip?: InputMaybe; + first?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + where?: InputMaybe; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type Query_metaArgs = { + block?: InputMaybe; +}; + +export type Subscription = { + readonly collateral?: Maybe; + readonly collaterals: ReadonlyArray; + readonly token?: Maybe; + readonly tokens: ReadonlyArray; + readonly collateralAddresses?: Maybe; + readonly collateralAddresses_collection: ReadonlyArray; + readonly interestRateBracket?: Maybe; + readonly interestRateBrackets: ReadonlyArray; + readonly trove?: Maybe; + readonly troves: ReadonlyArray; + /** Access to subgraph metadata */ + readonly _meta?: Maybe<_Meta_>; +}; + + +export type SubscriptioncollateralArgs = { + id: Scalars['ID']['input']; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type SubscriptioncollateralsArgs = { + skip?: InputMaybe; + first?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + where?: InputMaybe; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type SubscriptiontokenArgs = { + id: Scalars['ID']['input']; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type SubscriptiontokensArgs = { + skip?: InputMaybe; + first?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + where?: InputMaybe; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type SubscriptioncollateralAddressesArgs = { + id: Scalars['ID']['input']; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type SubscriptioncollateralAddresses_collectionArgs = { + skip?: InputMaybe; + first?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + where?: InputMaybe; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type SubscriptioninterestRateBracketArgs = { + id: Scalars['ID']['input']; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type SubscriptioninterestRateBracketsArgs = { + skip?: InputMaybe; + first?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + where?: InputMaybe; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type SubscriptiontroveArgs = { + id: Scalars['ID']['input']; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type SubscriptiontrovesArgs = { + skip?: InputMaybe; + first?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + where?: InputMaybe; + block?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type Subscription_metaArgs = { + block?: InputMaybe; +}; + +export type Token = { + readonly id: Scalars['ID']['output']; + readonly collateral: Collateral; + readonly name: Scalars['String']['output']; + readonly symbol: Scalars['String']['output']; + readonly decimals: Scalars['Int']['output']; +}; + +export type Token_filter = { + readonly id?: InputMaybe; + readonly id_not?: InputMaybe; + readonly id_gt?: InputMaybe; + readonly id_lt?: InputMaybe; + readonly id_gte?: InputMaybe; + readonly id_lte?: InputMaybe; + readonly id_in?: InputMaybe>; + readonly id_not_in?: InputMaybe>; + readonly collateral?: InputMaybe; + readonly collateral_not?: InputMaybe; + readonly collateral_gt?: InputMaybe; + readonly collateral_lt?: InputMaybe; + readonly collateral_gte?: InputMaybe; + readonly collateral_lte?: InputMaybe; + readonly collateral_in?: InputMaybe>; + readonly collateral_not_in?: InputMaybe>; + readonly collateral_contains?: InputMaybe; + readonly collateral_contains_nocase?: InputMaybe; + readonly collateral_not_contains?: InputMaybe; + readonly collateral_not_contains_nocase?: InputMaybe; + readonly collateral_starts_with?: InputMaybe; + readonly collateral_starts_with_nocase?: InputMaybe; + readonly collateral_not_starts_with?: InputMaybe; + readonly collateral_not_starts_with_nocase?: InputMaybe; + readonly collateral_ends_with?: InputMaybe; + readonly collateral_ends_with_nocase?: InputMaybe; + readonly collateral_not_ends_with?: InputMaybe; + readonly collateral_not_ends_with_nocase?: InputMaybe; + readonly collateral_?: InputMaybe; + readonly name?: InputMaybe; + readonly name_not?: InputMaybe; + readonly name_gt?: InputMaybe; + readonly name_lt?: InputMaybe; + readonly name_gte?: InputMaybe; + readonly name_lte?: InputMaybe; + readonly name_in?: InputMaybe>; + readonly name_not_in?: InputMaybe>; + readonly name_contains?: InputMaybe; + readonly name_contains_nocase?: InputMaybe; + readonly name_not_contains?: InputMaybe; + readonly name_not_contains_nocase?: InputMaybe; + readonly name_starts_with?: InputMaybe; + readonly name_starts_with_nocase?: InputMaybe; + readonly name_not_starts_with?: InputMaybe; + readonly name_not_starts_with_nocase?: InputMaybe; + readonly name_ends_with?: InputMaybe; + readonly name_ends_with_nocase?: InputMaybe; + readonly name_not_ends_with?: InputMaybe; + readonly name_not_ends_with_nocase?: InputMaybe; + readonly symbol?: InputMaybe; + readonly symbol_not?: InputMaybe; + readonly symbol_gt?: InputMaybe; + readonly symbol_lt?: InputMaybe; + readonly symbol_gte?: InputMaybe; + readonly symbol_lte?: InputMaybe; + readonly symbol_in?: InputMaybe>; + readonly symbol_not_in?: InputMaybe>; + readonly symbol_contains?: InputMaybe; + readonly symbol_contains_nocase?: InputMaybe; + readonly symbol_not_contains?: InputMaybe; + readonly symbol_not_contains_nocase?: InputMaybe; + readonly symbol_starts_with?: InputMaybe; + readonly symbol_starts_with_nocase?: InputMaybe; + readonly symbol_not_starts_with?: InputMaybe; + readonly symbol_not_starts_with_nocase?: InputMaybe; + readonly symbol_ends_with?: InputMaybe; + readonly symbol_ends_with_nocase?: InputMaybe; + readonly symbol_not_ends_with?: InputMaybe; + readonly symbol_not_ends_with_nocase?: InputMaybe; + readonly decimals?: InputMaybe; + readonly decimals_not?: InputMaybe; + readonly decimals_gt?: InputMaybe; + readonly decimals_lt?: InputMaybe; + readonly decimals_gte?: InputMaybe; + readonly decimals_lte?: InputMaybe; + readonly decimals_in?: InputMaybe>; + readonly decimals_not_in?: InputMaybe>; + /** Filter for the block changed event. */ + readonly _change_block?: InputMaybe; + readonly and?: InputMaybe>>; + readonly or?: InputMaybe>>; +}; + +export type Token_orderBy = + | 'id' + | 'collateral' + | 'collateral__id' + | 'collateral__minCollRatio' + | 'collateral__totalDeposited' + | 'collateral__totalDebt' + | 'name' + | 'symbol' + | 'decimals'; + +export type Trove = { + readonly id: Scalars['ID']['output']; + readonly borrower: Scalars['Bytes']['output']; + readonly debt: Scalars['BigInt']['output']; + readonly deposit: Scalars['BigInt']['output']; + readonly stake: Scalars['BigInt']['output']; + readonly interestRate: Scalars['BigInt']['output']; + readonly createdAt: Scalars['BigInt']['output']; + readonly closedAt?: Maybe; + readonly collateral: Collateral; +}; + +export type Trove_filter = { + readonly id?: InputMaybe; + readonly id_not?: InputMaybe; + readonly id_gt?: InputMaybe; + readonly id_lt?: InputMaybe; + readonly id_gte?: InputMaybe; + readonly id_lte?: InputMaybe; + readonly id_in?: InputMaybe>; + readonly id_not_in?: InputMaybe>; + readonly borrower?: InputMaybe; + readonly borrower_not?: InputMaybe; + readonly borrower_gt?: InputMaybe; + readonly borrower_lt?: InputMaybe; + readonly borrower_gte?: InputMaybe; + readonly borrower_lte?: InputMaybe; + readonly borrower_in?: InputMaybe>; + readonly borrower_not_in?: InputMaybe>; + readonly borrower_contains?: InputMaybe; + readonly borrower_not_contains?: InputMaybe; + readonly debt?: InputMaybe; + readonly debt_not?: InputMaybe; + readonly debt_gt?: InputMaybe; + readonly debt_lt?: InputMaybe; + readonly debt_gte?: InputMaybe; + readonly debt_lte?: InputMaybe; + readonly debt_in?: InputMaybe>; + readonly debt_not_in?: InputMaybe>; + readonly deposit?: InputMaybe; + readonly deposit_not?: InputMaybe; + readonly deposit_gt?: InputMaybe; + readonly deposit_lt?: InputMaybe; + readonly deposit_gte?: InputMaybe; + readonly deposit_lte?: InputMaybe; + readonly deposit_in?: InputMaybe>; + readonly deposit_not_in?: InputMaybe>; + readonly stake?: InputMaybe; + readonly stake_not?: InputMaybe; + readonly stake_gt?: InputMaybe; + readonly stake_lt?: InputMaybe; + readonly stake_gte?: InputMaybe; + readonly stake_lte?: InputMaybe; + readonly stake_in?: InputMaybe>; + readonly stake_not_in?: InputMaybe>; + readonly interestRate?: InputMaybe; + readonly interestRate_not?: InputMaybe; + readonly interestRate_gt?: InputMaybe; + readonly interestRate_lt?: InputMaybe; + readonly interestRate_gte?: InputMaybe; + readonly interestRate_lte?: InputMaybe; + readonly interestRate_in?: InputMaybe>; + readonly interestRate_not_in?: InputMaybe>; + readonly createdAt?: InputMaybe; + readonly createdAt_not?: InputMaybe; + readonly createdAt_gt?: InputMaybe; + readonly createdAt_lt?: InputMaybe; + readonly createdAt_gte?: InputMaybe; + readonly createdAt_lte?: InputMaybe; + readonly createdAt_in?: InputMaybe>; + readonly createdAt_not_in?: InputMaybe>; + readonly closedAt?: InputMaybe; + readonly closedAt_not?: InputMaybe; + readonly closedAt_gt?: InputMaybe; + readonly closedAt_lt?: InputMaybe; + readonly closedAt_gte?: InputMaybe; + readonly closedAt_lte?: InputMaybe; + readonly closedAt_in?: InputMaybe>; + readonly closedAt_not_in?: InputMaybe>; + readonly collateral?: InputMaybe; + readonly collateral_not?: InputMaybe; + readonly collateral_gt?: InputMaybe; + readonly collateral_lt?: InputMaybe; + readonly collateral_gte?: InputMaybe; + readonly collateral_lte?: InputMaybe; + readonly collateral_in?: InputMaybe>; + readonly collateral_not_in?: InputMaybe>; + readonly collateral_contains?: InputMaybe; + readonly collateral_contains_nocase?: InputMaybe; + readonly collateral_not_contains?: InputMaybe; + readonly collateral_not_contains_nocase?: InputMaybe; + readonly collateral_starts_with?: InputMaybe; + readonly collateral_starts_with_nocase?: InputMaybe; + readonly collateral_not_starts_with?: InputMaybe; + readonly collateral_not_starts_with_nocase?: InputMaybe; + readonly collateral_ends_with?: InputMaybe; + readonly collateral_ends_with_nocase?: InputMaybe; + readonly collateral_not_ends_with?: InputMaybe; + readonly collateral_not_ends_with_nocase?: InputMaybe; + readonly collateral_?: InputMaybe; + /** Filter for the block changed event. */ + readonly _change_block?: InputMaybe; + readonly and?: InputMaybe>>; + readonly or?: InputMaybe>>; +}; + +export type Trove_orderBy = + | 'id' + | 'borrower' + | 'debt' + | 'deposit' + | 'stake' + | 'interestRate' + | 'createdAt' + | 'closedAt' + | 'collateral' + | 'collateral__id' + | 'collateral__minCollRatio' + | 'collateral__totalDeposited' + | 'collateral__totalDebt'; + +export type _Block_ = { + /** The hash of the block */ + readonly hash?: Maybe; + /** The block number */ + readonly number: Scalars['Int']['output']; + /** Integer representation of the timestamp stored in blocks for the chain */ + readonly timestamp?: Maybe; + /** The hash of the parent block */ + readonly parentHash?: Maybe; +}; + +/** The type for the top-level _meta field */ +export type _Meta_ = { + /** + * Information about a specific subgraph block. The hash of the block + * will be null if the _meta field has a block constraint that asks for + * a block number. It will be filled if the _meta field has no block constraint + * and therefore asks for the latest block + * + */ + readonly block: _Block_; + /** The deployment ID */ + readonly deployment: Scalars['String']['output']; + /** If `true`, the subgraph encountered indexing errors at some past block */ + readonly hasIndexingErrors: Scalars['Boolean']['output']; +}; + +export type _SubgraphErrorPolicy_ = + /** Data will be returned even if the subgraph has indexing errors */ + | 'allow' + /** If the subgraph has indexing errors, data will be omitted. The default. */ + | 'deny'; + + export type QuerySdk = { + /** null **/ + collateral: InContextSdkMethod, + /** null **/ + collaterals: InContextSdkMethod, + /** null **/ + token: InContextSdkMethod, + /** null **/ + tokens: InContextSdkMethod, + /** null **/ + collateralAddresses: InContextSdkMethod, + /** null **/ + collateralAddresses_collection: InContextSdkMethod, + /** null **/ + interestRateBracket: InContextSdkMethod, + /** null **/ + interestRateBrackets: InContextSdkMethod, + /** null **/ + trove: InContextSdkMethod, + /** null **/ + troves: InContextSdkMethod, + /** Access to subgraph metadata **/ + _meta: InContextSdkMethod + }; + + export type MutationSdk = { + + }; + + export type SubscriptionSdk = { + /** null **/ + collateral: InContextSdkMethod, + /** null **/ + collaterals: InContextSdkMethod, + /** null **/ + token: InContextSdkMethod, + /** null **/ + tokens: InContextSdkMethod, + /** null **/ + collateralAddresses: InContextSdkMethod, + /** null **/ + collateralAddresses_collection: InContextSdkMethod, + /** null **/ + interestRateBracket: InContextSdkMethod, + /** null **/ + interestRateBrackets: InContextSdkMethod, + /** null **/ + trove: InContextSdkMethod, + /** null **/ + troves: InContextSdkMethod, + /** Access to subgraph metadata **/ + _meta: InContextSdkMethod + }; + + export type Context = { + ["liquity2"]: { Query: QuerySdk, Mutation: MutationSdk, Subscription: SubscriptionSdk }, + + }; +} diff --git a/frontend/app/.graphclientrc.yml b/frontend/app/.graphclientrc.yml new file mode 100644 index 00000000..77649ff9 --- /dev/null +++ b/frontend/app/.graphclientrc.yml @@ -0,0 +1,20 @@ +sources: + - name: liquity2 + handler: + graphql: + endpoint: http://localhost:8000/subgraphs/name/liquity2/liquity2 + +codegen: + strictScalars: true + immutableTypes: true + useTypeImports: false # import name conflict if set to true + dedupeFragments: true + scalars: + BigDecimal: bigint + BigInt: bigint + Bytes: string + Int8: number + Timestamp: string + +documents: + - ./src/subgraph-queries.graphql diff --git a/frontend/app/package.json b/frontend/app/package.json index 2f3f4533..399b94c5 100644 --- a/frontend/app/package.json +++ b/frontend/app/package.json @@ -6,15 +6,17 @@ "scripts": { "build": "pnpm build-uikit && pnpm panda-codegen && next build", "build-uikit": "cd ../uikit && pnpm build && pnpm panda-codegen", + "coverage": "vitest run --coverage ./src", "dev": "rm -rf ./.next && next dev", "fmt": "dprint fmt **/*.{ts,tsx,js,json,html,md}", "lint": "pnpm oxlint ./src --import-plugin --nextjs-plugin --react-perf-plugin --jsx-a11y-plugin --allow pedantic", "panda-codegen": "panda codegen --silent", + "subgraph-codegen": "pnpm graphclient build", "test": "vitest", - "coverage": "vitest run --coverage ./src", "update-liquity-abis": "node --loader ts-node/esm ./scripts/update-liquity-abis.ts" }, "dependencies": { + "@graphprotocol/client-cli": "^3.0.7", "@liquity2/uikit": "workspace:*", "@rainbow-me/rainbowkit": "^2.1.3", "@react-spring/web": "^9.7.4", diff --git a/frontend/app/src/comps/AppLayout/AppLayout.tsx b/frontend/app/src/comps/AppLayout/AppLayout.tsx index 632de09d..790443d3 100644 --- a/frontend/app/src/comps/AppLayout/AppLayout.tsx +++ b/frontend/app/src/comps/AppLayout/AppLayout.tsx @@ -1,6 +1,7 @@ import type { ReactNode } from "react"; import { UpdatePrices } from "@/src/comps/Debug/UpdatePrices"; +import { ProtocolStats } from "@/src/comps/ProtocolStats/ProtocolStats"; import { TopBar } from "@/src/comps/TopBar/TopBar"; import { css } from "@/styled-system/css"; @@ -45,6 +46,14 @@ export function AppLayout({ })} > {children} +
+ +
diff --git a/frontend/app/src/comps/Debug/UpdatePrices.tsx b/frontend/app/src/comps/Debug/UpdatePrices.tsx index 20c2a7b2..a5b30a46 100644 --- a/frontend/app/src/comps/Debug/UpdatePrices.tsx +++ b/frontend/app/src/comps/Debug/UpdatePrices.tsx @@ -44,7 +44,7 @@ export function UpdatePrices() { color: "contentAlt", })} > - Simulate prices + simulate prices {" "}
void; -}) { - const position = ( - DEMO_MODE - ? ACCOUNT_POSITIONS.find((position) => ( - (position.type === "borrow" || position.type === "leverage") && position.troveId === troveId - )) - : undefined - ) as PositionLoan | undefined; - - const collateral = position && TOKENS_BY_SYMBOL[position.collateral]; - - const collPriceUsd = usePrice(collateral ? collateral.symbol : null); - - if (!position || !collPriceUsd || !collateral) { - return null; - } - - const { deposit, borrowed, interestRate } = position; - - const loanDetails = getLoanDetails( - deposit, - borrowed, - interestRate, - collateral.collateralRatio, - collPriceUsd, - ); - - const { - ltv, - depositPreLeverage, - leverageFactor, - redemptionRisk, - liquidationRisk, - } = loanDetails; - - const maxLtv = dn.div(dn.from(1, 18), collateral.collateralRatio); - - return ( -
-

-
-
- {leverageMode - ? - : } -
- {leverageMode ? "Leverage loan" : "BOLD loan"} -
-

-
-
- {leverageMode - ? ( -
-
{fmtnum(position.deposit)}
- -
-
- - {loanDetails.status === "underwater" || leverageFactor === null - ? INFINITY - : `${roundToDecimal(leverageFactor, 1)}x`} - -
- { - /*
- ${fmtnum(dn.mul(position.deposit, collPriceUsd), { digits: 2 })} -
*/ - } -
-
- ) - : ( -
- {fmtnum(position.borrowed)} - -
- )} -
-
-
-
- -
- {leverageMode - ? ( - - - {fmtnum(depositPreLeverage)} {TOKENS_BY_SYMBOL[position.collateral].name} - - - ) - : ( - -
- {fmtnum(position.deposit)} {TOKENS_BY_SYMBOL[position.collateral].name} -
-
- )} - - - ${fmtnum(loanDetails.liquidationPrice)} - - - - {fmtnum(dn.mul(position.interestRate, 100))}% - - -
- {ltv && fmtnum(dn.mul(ltv, 100))}% -
-
- - - - {formatRisk(liquidationRisk)} - - - {redemptionRisk && ( - - - - {formatRisk(redemptionRisk)} - - - )} -
-
- ); -} - -function GridItem({ - children, - label, -}: { - children: ReactNode; - label: string; -}) { - return ( -
-
- {label} -
-
- {children} -
-
- ); -} diff --git a/frontend/app/src/comps/Positions/Positions.tsx b/frontend/app/src/comps/Positions/Positions.tsx index 6b5c2190..b729804a 100644 --- a/frontend/app/src/comps/Positions/Positions.tsx +++ b/frontend/app/src/comps/Positions/Positions.tsx @@ -5,10 +5,12 @@ import { ActionCard } from "@/src/comps/ActionCard/ActionCard"; import { LQTY_SUPPLY } from "@/src/constants"; import content from "@/src/content"; import { ACCOUNT_POSITIONS } from "@/src/demo-mode"; +import { DEMO_MODE } from "@/src/env"; import { formatLiquidationRisk, formatRedemptionRisk } from "@/src/formatting"; import { getLiquidationRisk, getLtv, getRedemptionRisk } from "@/src/liquity-math"; import { useAccount } from "@/src/services/Ethereum"; import { usePrice } from "@/src/services/Prices"; +import { useLoansByAccount } from "@/src/subgraph-hooks"; import { riskLevelToStatusMode } from "@/src/uikit-utils"; import { css } from "@/styled-system/css"; import { @@ -26,12 +28,16 @@ import { import { a, useTransition } from "@react-spring/web"; import * as dn from "dnum"; import Link from "next/link"; +import { useState } from "react"; import { match } from "ts-pattern"; export function Positions() { const account = useAccount(); + const loans = useLoansByAccount(account.address); - const positionCards = ACCOUNT_POSITIONS.map((position, index) => ( + const positions = DEMO_MODE ? ACCOUNT_POSITIONS : loans.data ?? []; + + const positionCards = positions.map((position, index) => ( match(position) .with({ type: "borrow" }, ({ type, ...props }) => [index, ]) .with({ type: "earn" }, ({ type, ...props }) => [index, ]) @@ -40,7 +46,7 @@ export function Positions() { .exhaustive() )); - const mode = account.isConnected && positionCards.length > 0 ? "positions" : "actions"; + const mode = account.isConnected && (positionCards.length > 0 || loans.isLoading) ? "positions" : "actions"; const actionCards = [ , @@ -49,52 +55,152 @@ export function Positions() { , ].map((card, index) => [index, card]); - const positionTransitions = useTransition(mode === "positions" ? positionCards : actionCards, { - keys: ([index]) => `${index}${mode}`, - from: { opacity: 0, transform: "scale3d(0.95, 0.95, 1)" }, - enter: { opacity: 1, transform: "scale3d(1, 1, 1)" }, - leave: { display: "none", immediate: true }, - trail: 10, + const [increment, setIncrement] = useState(0); + + const positionTransitions = useTransition( + mode === "positions" ? positionCards : actionCards, + { + keys: ([index]) => `${index}${mode}${increment}`, + from: { opacity: 0, transform: "scale3d(0.95, 0.95, 1)" }, + enter: { opacity: 1, transform: "scale3d(1, 1, 1)" }, + leave: { display: "none", immediate: true }, + trail: 10, + config: { + mass: 1, + tension: 2800, + friction: 80, + }, + }, + ); + + const [forceLoading, setForceLoading] = useState(false); + + return ( + { + setForceLoading(true); + setTimeout(() => { + setForceLoading(false); + setIncrement((i) => i + 1); + }, 1000); + }} + > + {positionTransitions((style, [_, card]) => ( + + {card} + + ))} + + ); +} + +function PositionsGroup({ + children, + loading, + mode, + onTitleClick, +}: { + children: ReactNode; + loading?: boolean; + mode: "positions" | "actions"; + onTitleClick?: () => void; +}) { + const loadingTransition = useTransition(loading, { + from: { + opacity: 0, + transform: "scale3d(0.95, 0.95, 1)", + }, + enter: { + opacity: 1, + transform: "scale3d(1, 1, 1)", + }, + leave: { + opacity: 0, + transform: "scale3d(0.95, 0.95, 1)", + }, config: { mass: 1, - tension: 2800, + tension: 1800, friction: 80, }, }); - return (

{mode === "positions" ? content.home.myPositionsTitle : content.home.openPositionTitle}

- {positionTransitions((style, [_, card]) => ( - ( + loading && ( + +
+
+ Fetching positions… +
+ + ) + ))} + {!loading && ( +
- {card} - - ))} + {children} +
+ )}
); @@ -131,13 +237,13 @@ function PositionBorrow({ - {dn.format(dn.add(deposit, borrowed), 4)} + {dn.format(dn.add(deposit, borrowed), 2)} ), - label: "Total debt", + // label: "Total debt", + label: ( +
+ Backed by {deposit ? dn.format(deposit, 2) : "−"} {token.name} + +
+ ), }} secondary={ diff --git a/frontend/app/src/comps/ProtocolStats/ProtocolStats.tsx b/frontend/app/src/comps/ProtocolStats/ProtocolStats.tsx index b15eddc8..4dfb54dc 100644 --- a/frontend/app/src/comps/ProtocolStats/ProtocolStats.tsx +++ b/frontend/app/src/comps/ProtocolStats/ProtocolStats.tsx @@ -1,194 +1,66 @@ -import type { SpringValue } from "@react-spring/web"; -import type { Dnum } from "dnum"; -import type { ComponentProps } from "react"; +"use client"; import content from "@/src/content"; +import { BORROW_STATS } from "@/src/demo-mode"; +import { usePrice } from "@/src/services/Prices"; import { css } from "@/styled-system/css"; -import { TokenIcon } from "@liquity2/uikit"; -import { a, useTransition } from "@react-spring/web"; +import { HFlex, TokenIcon } from "@liquity2/uikit"; import * as dn from "dnum"; -import { useEffect, useState } from "react"; -import { stringify } from "viem"; - -type Stat = { - amount: Dnum | string; - label: string; - token?: ComponentProps["symbol"]; -}; export function ProtocolStats() { - const stats = useStats(); - - const transitions = useTransition(stats, { - keys: (stat) => stat.label, - from: { progress: 0 }, - initial: { progress: 0 }, - enter: { progress: 1 }, - leave: { progress: 0, immediate: true }, - config: { - mass: 1, - tension: 1800, - friction: 60, - }, - trail: 60, - }); + const prices = [ + ["LQTY", usePrice("LQTY")], + ["BOLD", usePrice("BOLD")], + ["ETH", usePrice("ETH")], + ] as const; - return ( -
-

{content.home.statsBar.label}

- {stats.length > 0 - ? ( -
- {transitions(({ progress }, item) => { - return ( - - ); - })} -
- ) - : ( -
- Loading… -
- )} -
+ const totalTvl = Object.values(BORROW_STATS).reduce( + (acc, { tvl }) => dn.add(acc, tvl), + dn.from(0, 18), ); -} -function AmountUsd({ - amount, - label, - tokenSymbol, - progress, -}: { - amount?: Dnum | string; - label: string; - tokenSymbol?: ComponentProps["symbol"]; - progress: SpringValue; -}) { return (
- {tokenSymbol && ( - `scale(${1.4 - v * 0.4})`), - }} - > - - - )} - {content.home.statsBar.label}
+ + + TVL{" "} + + ${dn.format(totalTvl, { compact: true })} + + + {prices.map(([symbol, price]) => { + return ( + + + + {symbol} + + ${price && dn.format(price, { + digits: 2, + trailingZeros: true, + })} + + + + ); })} - style={{ - opacity: progress, - transform: progress.to((v) => `scale(${1 - (1 - v) * 0.2})`), - }} - > -
{label}
- - {typeof amount === "string" ? amount : amount && dn.format(amount, { - digits: 2, - trailingZeros: true, - })} - - - {" $"} - - +
); } - -function formatMillions(amount: Dnum) { - return dn.gt(amount, 1_000_000) - ? `${dn.format(dn.div(amount, 1_000_000))}M` - : dn.format(amount, { compact: true }); -} - -function useStats() { - const [stats, setStats] = useState([]); - useEffect(() => { - const update = () => { - setStats([{ - amount: formatMillions([1_408_000_000n, 0]), - label: "TVL", - }, { - amount: [13_72n + BigInt(-100 + Math.round(Math.random() * 200)), 2], - label: "LQTY", - token: "LQTY", - }, { - amount: [1_01n + BigInt(-10 + Math.round(Math.random() * 20)), 2], - label: "BOLD", - token: "BOLD", - }, { - amount: [3421_55n, 2], - label: "ETH", - token: "ETH", - }]); - }; - - update(); - - const timer = setInterval(update, 30_000); - - return () => { - clearInterval(timer); - }; - }, []); - - return stats; -} diff --git a/frontend/app/src/demo-mode/demo-data.ts b/frontend/app/src/demo-mode/demo-data.ts index 23db0b4a..3fb9d64f 100644 --- a/frontend/app/src/demo-mode/demo-data.ts +++ b/frontend/app/src/demo-mode/demo-data.ts @@ -7,7 +7,7 @@ import * as dn from "dnum"; export const PRICE_UPDATE_INTERVAL = 15_000; export const PRICE_UPDATE_VARIATION = 0.003; -export const PRICE_UPDATE_MANUAL = true; +export const PRICE_UPDATE_MANUAL = false; export const LQTY_PRICE = dn.from(0.64832, 18); export const ETH_PRICE = dn.from(2_580.293872, 18); @@ -38,7 +38,7 @@ export const ACCOUNT_POSITIONS: Position[] = [ collateral: "RETH", deposit: dn.from(5.5, 18), interestRate: dn.from(0.067, 18), - troveId: 1n, + troveId: "0x01", }, { type: "leverage", @@ -46,7 +46,7 @@ export const ACCOUNT_POSITIONS: Position[] = [ collateral: "ETH", deposit: dn.from(19.20, 18), // 8 ETH @ 2.4 leverage interestRate: dn.from(0.045, 18), - troveId: 2n, + troveId: "0x02", }, { type: "earn", diff --git a/frontend/app/src/dnum-utils.ts b/frontend/app/src/dnum-utils.ts index 87deb50c..a5d3dcab 100644 --- a/frontend/app/src/dnum-utils.ts +++ b/frontend/app/src/dnum-utils.ts @@ -2,6 +2,10 @@ import type { Dnum } from "dnum"; import * as dn from "dnum"; +export function dnum18(value: string | bigint | number): Dnum { + return [BigInt(value), 18]; +} + export function formatAmountCompact(value: Dnum, digits: number = 2) { const valueAbs = dn.abs(value); if (dn.eq(valueAbs, 1e9) || dn.gt(valueAbs, 1e9)) { diff --git a/frontend/app/src/liquity-utils.ts b/frontend/app/src/liquity-utils.ts index 0645c4c2..9143adcf 100644 --- a/frontend/app/src/liquity-utils.ts +++ b/frontend/app/src/liquity-utils.ts @@ -1,5 +1,5 @@ import type { TroveId } from "@/src/types"; -import type { Address } from "@liquity2/uikit"; +import type { Address, CollateralSymbol } from "@liquity2/uikit"; import type { Dnum } from "dnum"; import { useCollateralContract, useProtocolContract } from "@/src/contracts"; @@ -34,6 +34,12 @@ type Rewards = { bold: Dnum; }; +export function shortenTroveId(troveId: TroveId, chars = 4) { + return troveId.length < chars * 2 + 2 + ? troveId + : troveId.slice(0, chars + 2) + "…" + troveId.slice(-chars); +} + function troveStatusFromNumber(value: number): TroveStatus { return match(value) .with(0, () => "nonExistent") @@ -333,6 +339,21 @@ export function getTroveId(owner: Address, ownerIndex: bigint | number) { ))); } +export function getCollateralFromTroveSymbol(symbol: string): null | CollateralSymbol { + symbol = symbol.toUpperCase(); + if (symbol === "ETH" || symbol === "WETH") { + return "ETH"; + } + // this is to handle symbols used for testing, like stETH1, stETH2, etc. + if (symbol.startsWith("RETH")) { + return "RETH"; + } + if (symbol.startsWith("STETH")) { + return "STETH"; + } + return null; +} + export function useCollTokenAllowance() { const account = useAccount(); diff --git a/frontend/app/src/screens/BorrowScreen/BorrowScreen.tsx b/frontend/app/src/screens/BorrowScreen/BorrowScreen.tsx index 30662d3c..988c6e85 100644 --- a/frontend/app/src/screens/BorrowScreen/BorrowScreen.tsx +++ b/frontend/app/src/screens/BorrowScreen/BorrowScreen.tsx @@ -24,6 +24,7 @@ import { IconSuggestion, InfoTooltip, InputField, + isCollateralSymbol, PillButton, TextButton, TokenIcon, @@ -35,11 +36,6 @@ import { match, P } from "ts-pattern"; const collateralSymbols = COLLATERALS.map(({ symbol }) => symbol); -function isCollateralSymbol(symbol: string): symbol is typeof collateralSymbols[number] { - const c: string[] = collateralSymbols; - return c.includes(symbol); -} - export function BorrowScreen() { const account = useAccount(); diff --git a/frontend/app/src/screens/EarnPoolScreen/EarnPoolScreen.tsx b/frontend/app/src/screens/EarnPoolScreen/EarnPoolScreen.tsx index a7fa0e6c..33ef2231 100644 --- a/frontend/app/src/screens/EarnPoolScreen/EarnPoolScreen.tsx +++ b/frontend/app/src/screens/EarnPoolScreen/EarnPoolScreen.tsx @@ -11,7 +11,15 @@ import { ACCOUNT_BALANCES, ACCOUNT_POSITIONS, EARN_POOLS } from "@/src/demo-mode import { useAccount } from "@/src/services/Ethereum"; import { infoTooltipProps } from "@/src/uikit-utils"; import { css } from "@/styled-system/css"; -import { COLLATERALS, HFlex, InfoTooltip, Tabs, TokenIcon, TokenIconGroup, TOKENS_BY_SYMBOL } from "@liquity2/uikit"; +import { + HFlex, + InfoTooltip, + isCollateralSymbol, + Tabs, + TokenIcon, + TokenIconGroup, + TOKENS_BY_SYMBOL, +} from "@liquity2/uikit"; import * as dn from "dnum"; import { useParams, useRouter } from "next/navigation"; import { DepositPanel } from "./DepositPanel"; @@ -24,13 +32,6 @@ const TABS = [ { action: "claim", label: content.earnScreen.tabs.claim }, ] as const; -const collateralSymbols = COLLATERALS.map(({ symbol }) => symbol); -function isCollateralSymbol(symbol: string): symbol is typeof collateralSymbols[number] { - console.log(symbol, collateralSymbols); - const c: string[] = collateralSymbols; - return c.includes(symbol); -} - export function EarnPoolScreen() { const account = useAccount(); const router = useRouter(); diff --git a/frontend/app/src/screens/HomeScreen/HomeProtocolStats.tsx b/frontend/app/src/screens/HomeScreen/HomeProtocolStats.tsx index b83141f4..e69de29b 100644 --- a/frontend/app/src/screens/HomeScreen/HomeProtocolStats.tsx +++ b/frontend/app/src/screens/HomeScreen/HomeProtocolStats.tsx @@ -1,63 +0,0 @@ -import content from "@/src/content"; -import { BORROW_STATS } from "@/src/demo-mode"; -import { usePrice } from "@/src/services/Prices"; -import { css } from "@/styled-system/css"; -import { HFlex, TokenIcon } from "@liquity2/uikit"; -import * as dn from "dnum"; - -export function HomeProtocolStats() { - const prices = [ - ["LQTY", usePrice("LQTY")], - ["BOLD", usePrice("BOLD")], - ["ETH", usePrice("ETH")], - ] as const; - - const totalTvl = Object.values(BORROW_STATS).reduce( - (acc, { tvl }) => dn.add(acc, tvl), - dn.from(0, 18), - ); - - return ( -
-
{content.home.statsBar.label}
- - - TVL{" "} - - ${dn.format(totalTvl, { compact: true })} - - - {prices.map(([symbol, price]) => { - return ( - - - - {symbol} - - ${price && dn.format(price, { - digits: 2, - trailingZeros: true, - })} - - - - ); - })} - -
- ); -} diff --git a/frontend/app/src/screens/HomeScreen/HomeScreen.tsx b/frontend/app/src/screens/HomeScreen/HomeScreen.tsx index 24734982..92907da4 100644 --- a/frontend/app/src/screens/HomeScreen/HomeScreen.tsx +++ b/frontend/app/src/screens/HomeScreen/HomeScreen.tsx @@ -6,7 +6,6 @@ import { css } from "@/styled-system/css"; import { AnchorTextButton, COLLATERALS, IconBorrow, IconEarn, TokenIcon } from "@liquity2/uikit"; import * as dn from "dnum"; import Link from "next/link"; -import { HomeProtocolStats } from "./HomeProtocolStats"; import { HomeTable } from "./HomeTable"; export function HomeScreen() { @@ -152,13 +151,6 @@ export function HomeScreen() { })} />
-
- -
); } diff --git a/frontend/app/src/screens/LeverageScreen/LeverageScreen.tsx b/frontend/app/src/screens/LeverageScreen/LeverageScreen.tsx index d8c4cdae..1406f188 100644 --- a/frontend/app/src/screens/LeverageScreen/LeverageScreen.tsx +++ b/frontend/app/src/screens/LeverageScreen/LeverageScreen.tsx @@ -23,6 +23,7 @@ import { IconSuggestion, InfoTooltip, InputField, + isCollateralSymbol, TextButton, TokenIcon, VFlex, @@ -33,11 +34,6 @@ import { useEffect, useState } from "react"; const collateralSymbols = COLLATERALS.map(({ symbol }) => symbol); -function isCollateralSymbol(symbol: string): symbol is typeof collateralSymbols[number] { - const c: string[] = collateralSymbols; - return c.includes(symbol); -} - export function LeverageScreen() { const account = useAccount(); const router = useRouter(); diff --git a/frontend/app/src/screens/LoanScreen/LoanCard.tsx b/frontend/app/src/screens/LoanScreen/LoanCard.tsx new file mode 100644 index 00000000..5d25be80 --- /dev/null +++ b/frontend/app/src/screens/LoanScreen/LoanCard.tsx @@ -0,0 +1,513 @@ +import type { PositionLoan, TroveId } from "@/src/types"; +import type { ReactNode } from "react"; +import type { LoanLoadingState } from "./LoanScreen"; + +import { INFINITY } from "@/src/characters"; +import { Value } from "@/src/comps/Value/Value"; +import { formatRisk } from "@/src/formatting"; +import { fmtnum } from "@/src/formatting"; +import { getLoanDetails } from "@/src/liquity-math"; +import { shortenTroveId } from "@/src/liquity-utils"; +import { usePrice } from "@/src/services/Prices"; +import { riskLevelToStatusMode } from "@/src/uikit-utils"; +import { roundToDecimal } from "@/src/utils"; +import { css } from "@/styled-system/css"; +import { token } from "@/styled-system/tokens"; +import { Button, HFlex, IconBorrow, IconLeverage, StatusDot, TokenIcon, TOKENS_BY_SYMBOL } from "@liquity2/uikit"; +import { a, useSpring } from "@react-spring/web"; +import * as dn from "dnum"; +import { match, P } from "ts-pattern"; + +const LOAN_CARD_HEIGHT = 246; + +export function LoanCard({ + leverageMode, + loadingState, + loan, + onLeverageModeChange, + onRetry, + troveId, +}: { + leverageMode: boolean; + loadingState: LoanLoadingState; + loan: PositionLoan | null; + onLeverageModeChange: (leverageMode: boolean) => void; + onRetry: () => void; + troveId: TroveId; +}) { + const collateral = loan && TOKENS_BY_SYMBOL[loan.collateral]; + const collPriceUsd = usePrice(collateral ? collateral.symbol : null); + + const loanDetails = loan && collateral && getLoanDetails( + loan.deposit, + loan.borrowed, + loan.interestRate, + collateral.collateralRatio, + collPriceUsd, + ); + + const { + ltv, + depositPreLeverage, + leverageFactor, + redemptionRisk, + liquidationRisk, + } = loanDetails || {}; + + const maxLtv = collateral && dn.div( + dn.from(1, 18), + collateral.collateralRatio, + ); + + return ( + + {loan + && loanDetails + && collateral + && typeof leverageFactor === "number" + && depositPreLeverage + && maxLtv + && liquidationRisk + && ( + <> +
+
+ {leverageMode + ? ( +
+
{fmtnum(loan.deposit)}
+ +
+
+ + {loanDetails.status === "underwater" || leverageFactor === null + ? INFINITY + : `${roundToDecimal(leverageFactor, 1)}x`} + +
+
+
+ ) + : ( +
+ {fmtnum(loan.borrowed)} + +
+ )} +
+
+
+
+
+ {leverageMode + ? ( + + + {fmtnum(depositPreLeverage)} {collateral.name} + + + ) + : ( + +
+ {fmtnum(loan.deposit)} {collateral.name} +
+
+ )} + + + ${fmtnum(loanDetails.liquidationPrice)} + + + + {fmtnum(dn.mul(loan.interestRate, 100))}% + + +
+ {ltv && fmtnum(dn.mul(ltv, 100))}% +
+
+ + + + {formatRisk(liquidationRisk)} + + + {redemptionRisk && ( + + + + {formatRisk(redemptionRisk)} + + + )} +
+ + )} +
+ ); +} + +function LoadingCard({ + children, + leverage, + loadingState, + loan, + onRetry, + troveId, +}: { + children: ReactNode; + leverage: boolean; + loadingState: LoanLoadingState; + loan: PositionLoan | null; + onRetry: () => void; + troveId: TroveId; +}) { + const title = leverage ? "Leverage loan" : "BOLD loan"; + const titleFull = loan && `${title}: ${troveId}`; + + const spring = useSpring({ + to: match(loadingState) + .with( + P.union( + "loading", + "error", + "awaiting-confirmation", + "not-found", + ), + (s) => ({ + cardtransform: "scale3d(0.95, 0.95, 1)", + containerHeight: ( + window.innerHeight + - 120 // top bar + - 24 * 2 // padding + - 48 // bottom bar 1 + - 40 + // - 40 // bottom bar 2 + ), + cardHeight: s === "error" || s === "not-found" ? 180 : 120, + cardBackground: token("colors.blue:50"), + cardColor: token("colors.blue:950"), + }), + ) + .otherwise(() => ({ + cardtransform: "scale3d(1, 1, 1)", + containerHeight: LOAN_CARD_HEIGHT, + cardHeight: LOAN_CARD_HEIGHT, + cardBackground: token("colors.blue:950"), + cardColor: token("colors.white"), + })), + config: { + mass: 1, + tension: 2000, + friction: 120, + }, + }); + + return ( + + +

+
+
+ {leverage + ? + : } +
+ {title} +
+

+ {match(loadingState) + .with(P.union("loading", "awaiting-confirmation"), () => ( +
+ Fetching loan + + {shortenTroveId(troveId)}… + + +
+ )) + .with("error", () => ( +
+
+ Error fetching loan{" "} + + {shortenTroveId(troveId)} + . +
+
+ )) + .with("not-found", () => ( +
+
+ Loan{" "} + + {shortenTroveId(troveId)} + {" "} + not found. +
+
+ )) + .otherwise(() => ( +
+ {children} +
+ ))} +
+
+ ); +} + +function Spinner({ + size = 24, +}: { + size?: number; +}) { + const spring = useSpring({ + from: { rotate: 0 }, + to: { rotate: 360 }, + loop: true, + config: { + duration: 1000, + }, + }); + return ( + `rotate(${r}deg)`), + }} + > + + + ); +} + +function GridItem({ + children, + label, +}: { + children: ReactNode; + label: string; +}) { + return ( +
+
+ {label} +
+
+ {children} +
+
+ ); +} diff --git a/frontend/app/src/screens/LoanScreen/LoanScreen.tsx b/frontend/app/src/screens/LoanScreen/LoanScreen.tsx index b1abcc4b..17367871 100644 --- a/frontend/app/src/screens/LoanScreen/LoanScreen.tsx +++ b/frontend/app/src/screens/LoanScreen/LoanScreen.tsx @@ -1,14 +1,15 @@ "use client"; -import type { PositionLoan } from "@/src/types"; - -import { Position } from "@/src/comps/Position/Position"; import { Screen } from "@/src/comps/Screen/Screen"; -import { ACCOUNT_POSITIONS } from "@/src/demo-mode"; +import { useLoanById } from "@/src/subgraph-hooks"; +import { isTroveId } from "@/src/types"; import { css } from "@/styled-system/css"; -import { IconSettings, Tabs, VFlex } from "@liquity2/uikit"; +import { Button, IconSettings, Tabs, VFlex } from "@liquity2/uikit"; +import { a, useTransition } from "@react-spring/web"; import { notFound, useRouter, useSearchParams, useSelectedLayoutSegment } from "next/navigation"; -import { useMemo, useState } from "react"; +import { useState } from "react"; +import { match, P } from "ts-pattern"; +import { LoanCard } from "./LoanCard"; import { PanelClosePosition } from "./PanelClosePosition"; import { PanelUpdateBorrowPosition } from "./PanelUpdateBorrowPosition"; import { PanelUpdateLeveragePosition } from "./PanelUpdateLeveragePosition"; @@ -20,89 +21,161 @@ const TABS = [ { label: "Close position", id: "close" }, ]; +export type LoanLoadingState = + | "awaiting-confirmation" + | "error" + | "loading" + | "not-found" + | "success"; + +export const LOAN_STATES: LoanLoadingState[] = [ + "success", + "loading", + "awaiting-confirmation", + "error", + "not-found", +]; + export function LoanScreen() { const router = useRouter(); const action = useSelectedLayoutSegment() ?? "colldebt"; const searchParams = useSearchParams(); - const trove = useTrove(searchParams.get("id")); + const paramId = searchParams.get("id"); + const troveId = isTroveId(paramId) ? paramId : null; - const [leverageMode, setLeverageMode] = useState(trove?.type === "leverage"); - - if (!trove) { + const loan = useLoanById(troveId); + if (loan.isLoadingError || !troveId) { notFound(); } const tab = TABS.findIndex(({ id }) => id === action); + const [leverageMode, setLeverageMode] = useState(false); + + const [forcedLoadingState, setForcedLoadingState] = useState(null); + const loadingState = forcedLoadingState ?? match(loan) + .returnType() + .with({ status: "error" }, () => "error") + .with({ status: "pending" }, () => "loading") + .with({ data: null }, () => "not-found") + .with({ data: P.nonNullable }, () => "success") + .otherwise(() => "error"); + + const setLoadingstate = (state: LoanLoadingState) => { + setForcedLoadingState(state); + }; + // const [loadingState, setLoadingstate] = useState("loading"); + + const tabsTransition = useTransition(loadingState, { + from: { opacity: 0 }, + enter: { opacity: 1 }, + leave: { opacity: 0 }, + config: { + mass: 1, + tension: 2000, + friction: 120, + }, + }); return ( +
+ loan state: {LOAN_STATES.map((s) => ( +
- { + setLoadingstate("loading"); + loan.refetch(); + }} + troveId={troveId} /> -
-
Manage your position
-
- -
-
- - ({ - label, - panelId: `p-${id}`, - tabId: `t-${id}`, - }))} - selected={tab} - onSelect={(index) => { - router.push(`/loan/${TABS[index].id}?id=${trove.troveId}`, { scroll: false }); - }} - /> - {action === "colldebt" && ( - leverageMode - ? - : - )} - {action === "rate" && } - {action === "close" && } - + {tabsTransition((style, item) => ( + item === "success" && loan.data && ( + +
+
Manage your position
+
+ +
+
+ + ({ + label, + panelId: `p-${id}`, + tabId: `t-${id}`, + }))} + selected={tab} + onSelect={(index) => { + router.push( + `/loan/${TABS[index].id}?id=${loan.data?.troveId}`, + { scroll: false }, + ); + }} + /> + {action === "colldebt" && ( + leverageMode + ? + : + )} + {action === "rate" && } + {action === "close" && } + +
+ ) + ))}
); } - -function useTrove(troveId: string | null) { - return useMemo(() => { - if (troveId === null) { - return null; - } - let troveIdInt: bigint; - try { - troveIdInt = BigInt(troveId); - } catch { - return null; - } - const position = ACCOUNT_POSITIONS.find((position) => (( - position.type === "borrow" || position.type === "leverage" - ) && position.troveId === troveIdInt)) ?? null; - return position as PositionLoan | null; - }, [troveId]); -} diff --git a/frontend/app/src/services/Prices.tsx b/frontend/app/src/services/Prices.tsx index 5943c694..9288901c 100644 --- a/frontend/app/src/services/Prices.tsx +++ b/frontend/app/src/services/Prices.tsx @@ -65,7 +65,8 @@ let useWatchPrices = function useWatchPrices(callback: (prices: Prices) => void) ]); }; -if (DEMO_MODE) { +// if (DEMO_MODE) { +if (true) { // TODO: fix useWatchPrices above so we only use this if DEMO_MODE=true // in demo mode, simulate a variation of the prices useWatchPrices = (callback) => { useEffect(() => { diff --git a/frontend/app/src/subgraph-hooks.ts b/frontend/app/src/subgraph-hooks.ts new file mode 100644 index 00000000..42ebe0ae --- /dev/null +++ b/frontend/app/src/subgraph-hooks.ts @@ -0,0 +1,94 @@ +import type { Address, PositionLoan, TroveId } from "@/src/types"; + +import { getBuiltGraphSDK } from "@/.graphclient"; +import { ACCOUNT_POSITIONS } from "@/src/demo-mode"; +import { dnum18 } from "@/src/dnum-utils"; +import { DEMO_MODE } from "@/src/env"; +import { getCollateralFromTroveSymbol } from "@/src/liquity-utils"; +import { isPositionLoan, isTroveId } from "@/src/types"; +import { sleep } from "@/src/utils"; +import { useQuery } from "@tanstack/react-query"; + +const graphSdk = getBuiltGraphSDK(); + +function subgraphTroveToLoan( + trove: Awaited>["troves"][0], +): PositionLoan { + if (!isTroveId(trove.id)) { + throw new Error(`Invalid trove ID: ${trove.id}`); + } + const collSymbol = getCollateralFromTroveSymbol(trove.collateral.token.symbol); + if (!collSymbol) { + throw new Error(`Invalid collateral symbol: ${collSymbol}`); + } + return { + type: "borrow", + borrowed: dnum18(trove.debt), + collateral: collSymbol, + deposit: dnum18(trove.deposit), + interestRate: dnum18(trove.interestRate), + troveId: trove.id, + }; +} + +export let useLoansByAccount = (account?: Address) => { + return useQuery({ + queryKey: ["TrovesByAccount", account], + queryFn: async () => { + if (!account) { + return null; + } + const { troves } = await graphSdk.TrovesByAccount({ account }); + return troves.map(subgraphTroveToLoan); + }, + }); +}; + +if (DEMO_MODE) { + useLoansByAccount = (account?: Address) => { + return useQuery({ + queryKey: ["TrovesByAccount", account], + queryFn: async () => { + if (!account) { + return []; + } + return ACCOUNT_POSITIONS.filter(isPositionLoan); + }, + }); + }; +} + +export let useLoanById = (troveId?: TroveId | null) => { + return useQuery({ + queryKey: ["TroveById", troveId], + queryFn: async () => { + if (!troveId || !isTroveId(troveId)) { + return null; + } + await sleep(500); + const { trove } = await graphSdk.TroveById({ id: troveId }); + return trove && isTroveId(trove.id) + ? subgraphTroveToLoan(trove) + : null; + }, + }); +}; + +if (DEMO_MODE) { + useLoanById = (troveId?: TroveId | null) => { + return useQuery({ + queryKey: ["TroveById", troveId], + queryFn: async () => { + if (!troveId || !isTroveId(troveId)) { + return null; + } + for (const position of ACCOUNT_POSITIONS) { + if (isPositionLoan(position) && position.troveId === troveId) { + return position; + } + } + return null; + }, + }); + }; +} diff --git a/frontend/app/src/subgraph-queries.graphql b/frontend/app/src/subgraph-queries.graphql new file mode 100644 index 00000000..44a43cad --- /dev/null +++ b/frontend/app/src/subgraph-queries.graphql @@ -0,0 +1,41 @@ +query TrovesByAccount($account: Bytes!) { + troves(where: { borrower: $account }) { + id + borrower + debt + deposit + stake + interestRate + createdAt + closedAt + collateral { + id + token { + symbol + name + } + minCollRatio + } + } +} + +query TroveById($id: ID!) { + trove(id: $id) { + id + borrower + debt + deposit + stake + interestRate + createdAt + closedAt + collateral { + id + token { + symbol + name + } + minCollRatio + } + } +} diff --git a/frontend/app/src/types.ts b/frontend/app/src/types.ts index 1e403354..d004bc6d 100644 --- a/frontend/app/src/types.ts +++ b/frontend/app/src/types.ts @@ -6,7 +6,11 @@ export type { Address, CollateralSymbol, Dnum, Token }; export type RiskLevel = "low" | "medium" | "high"; -export type TroveId = bigint; +export type TroveId = `0x${string}`; + +export function isTroveId(value: unknown): value is TroveId { + return typeof value === "string" && /^0x[0-9a-f]+$/.test(value); +} // Utility type to get type-safe entries of an object, // to be used like this: Object.entries(o) as Entries) @@ -34,6 +38,10 @@ export type PositionLoan = { troveId: TroveId; }; +export function isPositionLoan(position: Position): position is PositionLoan { + return position.type === "borrow" || position.type === "leverage"; +} + export type PositionEarn = { type: "earn"; apr: Dnum; diff --git a/frontend/uikit/src/tokens.ts b/frontend/uikit/src/tokens.ts index f63990de..6003bced 100644 --- a/frontend/uikit/src/tokens.ts +++ b/frontend/uikit/src/tokens.ts @@ -9,6 +9,10 @@ import tokenSteth from "./token-icons/wsteth.svg"; export type CollateralSymbol = "ETH" | "RETH" | "STETH"; +export function isCollateralSymbol(symbol: string): symbol is CollateralSymbol { + return symbol === "ETH" || symbol === "RETH" || symbol === "STETH"; +} + export type CollateralToken = Token & { collateralRatio: number; symbol: CollateralSymbol;