diff --git a/packages/ethereum-contracts/CHANGELOG.md b/packages/ethereum-contracts/CHANGELOG.md index 12b657a635..97cbdbe186 100644 --- a/packages/ethereum-contracts/CHANGELOG.md +++ b/packages/ethereum-contracts/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to the ethereum-contracts will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [UNRELEASED] + +### Added + +- `SuperTokenV1Library` + - overloaded `claimAll` for the msg.sender to claim for themselves + - added `flowWithCtx` and `flowFromWithCtx` + ## [v1.12.0] ### Added diff --git a/packages/ethereum-contracts/contracts/agreements/ConstantFlowAgreementV1.sol b/packages/ethereum-contracts/contracts/agreements/ConstantFlowAgreementV1.sol index bf225b729b..5ec427a356 100644 --- a/packages/ethereum-contracts/contracts/agreements/ConstantFlowAgreementV1.sol +++ b/packages/ethereum-contracts/contracts/agreements/ConstantFlowAgreementV1.sol @@ -1348,8 +1348,7 @@ contract ConstantFlowAgreementV1 is // do not enforce balance checks during callbacks for the appCreditToken if (currentContext.callType != ContextDefinitions.CALL_INFO_CALL_TYPE_APP_CALLBACK || currentContext.appCreditToken != token) { - (int256 availableBalance,,) = token.realtimeBalanceOf(flowSender, currentContext.timestamp); - if (availableBalance < 0) { + if (! token.hasRealtimeBalanceOfAtLeast(flowSender, currentContext.timestamp, 0)) { revert CFA_INSUFFICIENT_BALANCE(); } } diff --git a/packages/ethereum-contracts/contracts/agreements/gdav1/GeneralDistributionAgreementV1.sol b/packages/ethereum-contracts/contracts/agreements/gdav1/GeneralDistributionAgreementV1.sol index 0583c2b7ed..a9892a3782 100644 --- a/packages/ethereum-contracts/contracts/agreements/gdav1/GeneralDistributionAgreementV1.sol +++ b/packages/ethereum-contracts/contracts/agreements/gdav1/GeneralDistributionAgreementV1.sol @@ -150,6 +150,38 @@ contract GeneralDistributionAgreementV1 is AgreementBase, TokenMonad, IGeneralDi owedBuffer = 0; } + function hasRealtimeBalanceOfAtLeast(ISuperfluidToken token, address account, uint256 time, int256 minBalance) + public view override returns (bool) + { + UniversalIndexData memory universalIndexData = _getUIndexData(abi.encode(token), account); + + int256 balance; + if (_isPool(token, account)) { + balance = ISuperfluidPool(account).getDisconnectedBalance(uint32(time)); + } else { + // this is outflow and can only be negative or 0 + balance = Value.unwrap(_getBasicParticleFromUIndex(universalIndexData).rtb(Time.wrap(uint32(time)))); + } + // subtract buffer + balance -= universalIndexData.totalBuffer.toInt256(); + + { + if (balance >= minBalance) { + return true; // it can only increase from here, so we can stop calculating + } + (uint32[] memory slotIds, bytes32[] memory pidList) = _listPoolConnectionIds(token, account); + for (uint256 i = 0; i < slotIds.length; ++i) { + address pool = address(uint160(uint256(pidList[i]))); + (bool exist, PoolMemberData memory poolMemberData) = + _getPoolMemberData(token, account, ISuperfluidPool(pool)); + assert(exist); + assert(poolMemberData.pool == pool); + balance += ISuperfluidPool(pool).getClaimable(account, uint32(time)); + } + } + return balance >= minBalance; + } + /// @dev ISuperAgreement.realtimeBalanceOf implementation function realtimeBalanceOfNow(ISuperfluidToken token, address account) external diff --git a/packages/ethereum-contracts/contracts/apps/SuperTokenV1Library.sol b/packages/ethereum-contracts/contracts/apps/SuperTokenV1Library.sol index b44fd86b2c..b5de253f4a 100644 --- a/packages/ethereum-contracts/contracts/apps/SuperTokenV1Library.sol +++ b/packages/ethereum-contracts/contracts/apps/SuperTokenV1Library.sol @@ -264,6 +264,7 @@ library SuperTokenV1Library { } // else no change, do nothing return true; } else { + // can't set negative flowrate revert IConstantFlowAgreementV1.CFA_INVALID_FLOW_RATE(); } } @@ -430,8 +431,8 @@ library SuperTokenV1Library { * @param token The token used in flow * @param flowOperator The address given flow permissions * @param allowCreate creation permissions - * @param allowCreate update permissions - * @param allowCreate deletion permissions + * @param allowUpdate update permissions + * @param allowDelete deletion permissions * @param flowRateAllowance The allowance provided to flowOperator */ function setFlowPermissions( @@ -802,7 +803,78 @@ library SuperTokenV1Library { /** CFA With CTX FUNCTIONS ************************************* */ /** - * @dev Create flow with context and userData + * @dev Set CFA flowrate with context + * @param token Super token address + * @param receiver The receiver of the flow + * @param flowRate The wanted flowrate in wad/second. Only positive values are valid here. + * @param ctx Context bytes (see ISuperfluid.sol for Context struct) + * @return newCtx The updated context after the execution of the agreement function + */ + function flowWithCtx( + ISuperToken token, + address receiver, + int96 flowRate, + bytes memory ctx + ) internal returns (bytes memory newCtx) { + // note: from the lib's perspective, the caller is "this", NOT "msg.sender" + address sender = address(this); + int96 prevFlowRate = getCFAFlowRate(token, sender, receiver); + + if (flowRate > 0) { + if (prevFlowRate == 0) { + return createFlowWithCtx(token, receiver, flowRate, ctx); + } else if (prevFlowRate != flowRate) { + return updateFlowWithCtx(token, receiver, flowRate, ctx); + } // else no change, do nothing + return ctx; + } else if (flowRate == 0) { + if (prevFlowRate > 0) { + return deleteFlowWithCtx(token, sender, receiver, ctx); + } // else no change, do nothing + return ctx; + } else { + // can't set negative flowrate + revert IConstantFlowAgreementV1.CFA_INVALID_FLOW_RATE(); + } + } + + /** + * @notice Like `flowFrom`, with context + * @param token Super token address + * @param sender The sender of the flow + * @param receiver The receiver of the flow + * @param flowRate The wanted flowRate in wad/second. Only positive values are valid here. + * @param ctx Context bytes (see ISuperfluid.sol for Context struct) + * @return newCtx The updated context after the execution of the agreement function + */ + function flowFromWithCtx( + ISuperToken token, + address sender, + address receiver, + int96 flowRate, + bytes memory ctx + ) internal returns (bytes memory newCtx) { + int96 prevFlowRate = getCFAFlowRate(token, sender, receiver); + + if (flowRate > 0) { + if (prevFlowRate == 0) { + return createFlowFromWithCtx(token, sender, receiver, flowRate, ctx); + } else if (prevFlowRate != flowRate) { + return updateFlowFromWithCtx(token, sender, receiver, flowRate, ctx); + } // else no change, do nothing + return ctx; + } else if (flowRate == 0) { + if (prevFlowRate > 0) { + return deleteFlowFromWithCtx(token, sender, receiver, ctx); + } // else no change, do nothing + return ctx; + } else { + revert IConstantFlowAgreementV1.CFA_INVALID_FLOW_RATE(); + } + } + + /** + * @dev Create flow with context * @param token The token to flow * @param receiver The receiver of the flow * @param flowRate The desired flowRate @@ -1221,6 +1293,16 @@ library SuperTokenV1Library { return createPool(token, address(this)); } + /** + * @dev Claims all tokens from the pool for the msg.sender + * @param token The Super Token address. + * @param pool The Superfluid Pool to claim from. + * @return A boolean value indicating whether the claim was successful. + */ + function claimAll(ISuperToken token, ISuperfluidPool pool) internal returns (bool) { + return claimAll(token, pool, address(this), new bytes(0)); + } + /** * @dev Claims all tokens from the pool. * @param token The Super Token address. @@ -1368,6 +1450,8 @@ library SuperTokenV1Library { /** * @dev Tries to distribute flow at `requestedFlowRate` of `token` from `from` to `pool`. + * Note: the "actual" flowrate set can also be less than `requestedFlowRate, depending on the + * current total pool units. In order to know beforehand, use `estimateDistributionActualAmount`. * NOTE: The ability to set the `from` argument is needed only when liquidating a GDA flow. * The GDA currently doesn't have ACL support. * @param token The Super Token address. diff --git a/packages/ethereum-contracts/contracts/interfaces/agreements/gdav1/IGeneralDistributionAgreementV1.sol b/packages/ethereum-contracts/contracts/interfaces/agreements/gdav1/IGeneralDistributionAgreementV1.sol index e8f9c63159..21fce6b4d1 100644 --- a/packages/ethereum-contracts/contracts/interfaces/agreements/gdav1/IGeneralDistributionAgreementV1.sol +++ b/packages/ethereum-contracts/contracts/interfaces/agreements/gdav1/IGeneralDistributionAgreementV1.sol @@ -277,4 +277,17 @@ abstract contract IGeneralDistributionAgreementV1 is ISuperAgreement { view virtual returns (bool); + + + function hasRealtimeBalanceOfAtLeast( + ISuperfluidToken token, + address account, + uint256 time, + int256 minAmount + ) + external + view + virtual + returns (bool); + } diff --git a/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperAgreement.sol b/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperAgreement.sol index 4a865603d5..b1ed169a46 100644 --- a/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperAgreement.sol +++ b/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperAgreement.sol @@ -34,5 +34,4 @@ interface ISuperAgreement { uint256 deposit, uint256 owedDeposit ); - } diff --git a/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluidToken.sol b/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluidToken.sol index 36e06fa123..eab86a1014 100644 --- a/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluidToken.sol +++ b/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluidToken.sol @@ -31,7 +31,7 @@ interface ISuperfluidToken { /** * @dev Encoded liquidation type data mainly used for handling stack to deep errors * - * @custom:note + * @custom:note * - version: 1 * - liquidationType key: * - 0 = reward account receives reward (PIC period) @@ -83,6 +83,10 @@ interface ISuperfluidToken { uint256 owedDeposit, uint256 timestamp); + function hasRealtimeBalanceOfAtLeast(address account, uint256 timestamp, int256 minBalance) + external view + returns (bool); + /** * @notice Check if account is critical * @dev A critical account is when availableBalance < 0 @@ -231,7 +235,7 @@ interface ISuperfluidToken { * @dev Update agreement state slot * @param account Account to be updated * - * @custom:note + * @custom:note * - To clear the storage out, provide zero-ed array of intended length */ function updateAgreementStateSlot( @@ -274,7 +278,7 @@ interface ISuperfluidToken { * @param account Account to query. * @param delta Amount of balance delta to be settled * - * @custom:modifiers + * @custom:modifiers * - onlyAgreement */ function settleBalance( @@ -293,7 +297,7 @@ interface ISuperfluidToken { * @param rewardAmount The amount the rewarded account will receive * @param targetAccountBalanceDelta The delta amount the target account balance should change by * - * @custom:note + * @custom:note * - If a bailout is required (bailoutAmount > 0) * - the actual reward (single deposit) goes to the executor, * - while the reward account becomes the bailout account @@ -303,7 +307,7 @@ interface ISuperfluidToken { * - the targetAccount will pay the rewardAmount * - the liquidator (reward account in PIC period) will receive the rewardAmount * - * @custom:modifiers + * @custom:modifiers * - onlyAgreement */ function makeLiquidationPayoutsV2 @@ -327,7 +331,7 @@ interface ISuperfluidToken { * @param targetAccountBalanceDelta The amount the sender account balance should change by * @param liquidationTypeData The encoded liquidation type data including the version (how to decode) * - * @custom:note + * @custom:note * Reward account rule: * - if the agreement is liquidated during the PIC period * - the rewardAmountReceiver will get the rewardAmount (remaining deposit), regardless of the liquidatorAccount @@ -412,7 +416,7 @@ interface ISuperfluidToken { * * @custom:deprecated Use AgreementLiquidatedV2 instead * - * @custom:note + * @custom:note * Reward account rule: * - if bailout is equal to 0, then * - the bondAccount will get the rewardAmount, diff --git a/packages/ethereum-contracts/contracts/superfluid/SuperfluidToken.sol b/packages/ethereum-contracts/contracts/superfluid/SuperfluidToken.sol index cb5218676e..e2e4f40941 100644 --- a/packages/ethereum-contracts/contracts/superfluid/SuperfluidToken.sol +++ b/packages/ethereum-contracts/contracts/superfluid/SuperfluidToken.sol @@ -7,7 +7,8 @@ import { ISuperfluid, ISuperAgreement, ISuperfluidGovernance, - ISuperfluidToken + ISuperfluidToken, + IGeneralDistributionAgreementV1 } from "../interfaces/superfluid/ISuperfluid.sol"; import { FixedSizeData } from "../libs/FixedSizeData.sol"; @@ -105,6 +106,49 @@ abstract contract SuperfluidToken is ISuperfluidToken } } + function hasRealtimeBalanceOfAtLeast( + address account, + uint256 timestamp, + int256 minBalance + ) + public view virtual override + returns (bool) + { + int256 availableBalance = _sharedSettledBalances[account]; + ISuperAgreement[] memory activeAgreements = getAccountActiveAgreements(account); + IGeneralDistributionAgreementV1 gda; + for (uint256 i = 0; i < activeAgreements.length; ++i) { + if (activeAgreements[i].agreementType() == + keccak256("org.superfluid-finance.agreements.GeneralDistributionAgreement.v1")) + { + gda = IGeneralDistributionAgreementV1(address(activeAgreements[i])); + continue; + } else { + ( + int256 agreementDynamicBalance, + uint256 agreementDeposit, + uint256 agreementOwedDeposit) = activeAgreements[i] + .realtimeBalanceOf( + this, + account, + timestamp + ); + + availableBalance = availableBalance + + agreementDynamicBalance + - ( + agreementDeposit > agreementOwedDeposit ? + (agreementDeposit - agreementOwedDeposit) : 0 + ).toInt256(); + } + } + if (address(gda) != address(0)) { + return gda.hasRealtimeBalanceOfAtLeast(this, account, timestamp, minBalance - availableBalance); + } + + return availableBalance >= minBalance; + } + /// @dev ISuperfluidToken.realtimeBalanceOfNow implementation function realtimeBalanceOfNow( address account @@ -211,8 +255,7 @@ abstract contract SuperfluidToken is ISuperfluidToken ) internal { - (int256 availableBalance,,) = realtimeBalanceOf(from, _host.getNow()); - if (availableBalance < amount) { + if (! hasRealtimeBalanceOfAtLeast(from, _host.getNow(), amount)) { revert SF_TOKEN_MOVE_INSUFFICIENT_BALANCE(); } _sharedSettledBalances[from] = _sharedSettledBalances[from] - amount; diff --git a/packages/ethereum-contracts/test/foundry/apps/SuperTokenV1Library.t.sol b/packages/ethereum-contracts/test/foundry/apps/SuperTokenV1Library.t.sol index c5bb7209df..3a33bfa9cd 100644 --- a/packages/ethereum-contracts/test/foundry/apps/SuperTokenV1Library.t.sol +++ b/packages/ethereum-contracts/test/foundry/apps/SuperTokenV1Library.t.sol @@ -1,9 +1,11 @@ // SPDX-License-Identifier: AGPLv3 pragma solidity ^0.8.23; -import { IConstantFlowAgreementV1 } from "../../../contracts/interfaces/agreements/IConstantFlowAgreementV1.sol"; -import { FoundrySuperfluidTester, ISuperToken, SuperTokenV1Library, ISuperfluidPool } - from "../FoundrySuperfluidTester.t.sol"; +import { IConstantFlowAgreementV1, ISuperfluid, ISuperToken, ISuperfluidPool, ISuperApp } + from "../../../contracts/interfaces/superfluid/ISuperfluid.sol"; +import { CFASuperAppBase } from "../../../contracts/apps/CFASuperAppBase.sol"; +import { SuperTokenV1Library } from "../../../contracts/apps/SuperTokenV1Library.sol"; +import { FoundrySuperfluidTester } from "../FoundrySuperfluidTester.t.sol"; /* * Note: since libs are used by contracts, not EOAs, do NOT try to use @@ -119,6 +121,26 @@ contract SuperTokenV1LibraryTest is FoundrySuperfluidTester { assertEq(superToken.balanceOf(bob) - bobBalBefore, DEFAULT_AMOUNT, "distribute unexpected result"); } + function testClaimAllToMsgSender() external { + superToken.transfer(alice, DEFAULT_AMOUNT); + + uint256 balBefore = superToken.balanceOf(address(this)); + ISuperfluidPool pool = superToken.createPool(); + pool.updateMemberUnits(address(this), 1); + + vm.startPrank(alice); + // using callAgreement here because prank won't work as expected with the lib function + sf.host.callAgreement( + sf.gda, + abi.encodeCall(sf.gda.distribute, (superToken, alice, pool, DEFAULT_AMOUNT, new bytes(0))), + new bytes(0) // userData + ); + vm.stopPrank(); + + superToken.claimAll(pool); + assertEq(superToken.balanceOf(address(this)) - balBefore, DEFAULT_AMOUNT, "distribute unexpected result"); + } + function testCreatePool() external { ISuperfluidPool pool = superToken.createPool(); assertEq(pool.admin(), address(this)); @@ -294,15 +316,60 @@ contract SuperTokenV1LibraryTest is FoundrySuperfluidTester { assert(lastUpdated2 > lastUpdated1); } + function testFlowWithCtx(bool useACL) external { + SuperAppMock superApp = new SuperAppMock(sf.host); + superApp.selfRegister(true, true, true); + address superAppAddr = address(superApp); + + address flowSender = superAppAddr; + address flowReceiver = address(this); + + if (useACL) { + vm.startPrank(alice); + superApp.setACLFlowSender(); + sf.host.callAgreement( + sf.cfa, + abi.encodeCall(sf.cfa.authorizeFlowOperatorWithFullControl, (superToken, superAppAddr, new bytes(0))), + new bytes(0) // userData + ); + vm.stopPrank(); + flowSender = alice; + } + + // initial createFlow + superToken.flow(superAppAddr, DEFAULT_FLOWRATE); + assertEq(_getCFAFlowRate(flowSender, flowReceiver), DEFAULT_FLOWRATE, "createFlow unexpected result"); + + // double it -> updateFlow + superToken.flow(superAppAddr, DEFAULT_FLOWRATE * 2); + assertEq(_getCFAFlowRate(flowSender, flowReceiver), DEFAULT_FLOWRATE * 2, "updateFlow unexpected result"); + + if (! useACL) { + // delete the mirrored flow (check if remains sticky) + superToken.deleteFlow(superAppAddr, address(this)); + assertEq(_getCFAFlowRate(flowSender, flowReceiver), DEFAULT_FLOWRATE * 2, "flow not sticky"); + } + + // set to 0 -> deleteFlow + superToken.flow(superAppAddr, 0); + assertEq(_getCFAFlowRate(flowSender, flowReceiver), 0, "deleteFlow unexpected result"); + + // invalid flowrate + vm.expectRevert(IConstantFlowAgreementV1.CFA_INVALID_FLOW_RATE.selector); + this.__externalflow(flowSender, superAppAddr, -1); + + assertFalse(sf.host.isAppJailed(ISuperApp(superAppAddr)), "superApp is jailed"); + } + // HELPER FUNCTIONS ======================================================================================== - // direct use of the agreement for assertions - function _getCFAFlowRate(address sender, address receiver) public view returns (int96 flowRate) { + // direct use of the agreement for assertions + function _getCFAFlowRate(address sender, address receiver) internal view returns (int96 flowRate) { (,flowRate,,) = sf.cfa.getFlow(superToken, sender, receiver); } // Note: this is without adjustmentFR - function _getGDAFlowRate(address sender, ISuperfluidPool pool) public view returns (int96 flowRate) { + function _getGDAFlowRate(address sender, ISuperfluidPool pool) internal view returns (int96 flowRate) { return sf.gda.getFlowRate(superToken, sender, pool); } @@ -324,4 +391,66 @@ contract SuperTokenV1LibraryTest is FoundrySuperfluidTester { superToken.flowFrom(sender, receiver, flowRate); vm.stopPrank(); } +} + +// SuperApp for testing withCtx methods. +// mirrors (default mode) or matches (ACL mode) the incoming flow +contract SuperAppMock is CFASuperAppBase { + using SuperTokenV1Library for ISuperToken; + + // if not set (0), the SuperApp itself is the flowSender + address aclFlowSender; + + constructor(ISuperfluid host) CFASuperAppBase(host) { } + + // enable ACL mode by setting a sender + function setACLFlowSender() external { + aclFlowSender = msg.sender; + } + + function onFlowCreated( + ISuperToken superToken, + address sender, + bytes calldata ctx + ) internal virtual override returns (bytes memory /*newCtx*/) { + return _mirrorOrMatchIncomingFlow(superToken, sender, ctx); + } + + function onFlowUpdated( + ISuperToken superToken, + address sender, + int96 /*previousFlowRate*/, + uint256 /*lastUpdated*/, + bytes calldata ctx + ) internal virtual override returns (bytes memory /*newCtx*/) { + return _mirrorOrMatchIncomingFlow(superToken, sender, ctx); + } + + function onFlowDeleted( + ISuperToken superToken, + address sender, + address receiver, + int96 previousFlowRate, + uint256 /*lastUpdated*/, + bytes calldata ctx + ) internal virtual override returns (bytes memory /*newCtx*/) { + if (receiver == address(this)) { + return _mirrorOrMatchIncomingFlow(superToken, sender, ctx); + } else { + // outflow was deleted by the sender we mirror to, + // we make it "sticky" by simply restoring it. + return superToken.flowWithCtx(receiver, previousFlowRate, ctx); + } + } + + function _mirrorOrMatchIncomingFlow(ISuperToken superToken, address senderAndReceiver, bytes memory ctx) + internal returns (bytes memory newCtx) + { + int96 flowRate = superToken.getFlowRate(senderAndReceiver, address(this)); + if (aclFlowSender == address(0)) { + return superToken.flowWithCtx(senderAndReceiver, flowRate, ctx); + } else { + return superToken.flowFromWithCtx(aclFlowSender, senderAndReceiver, flowRate, ctx); + } + } } \ No newline at end of file diff --git a/packages/metadata/main/networks/list.cjs b/packages/metadata/main/networks/list.cjs index 08e00d319a..14502f7735 100644 --- a/packages/metadata/main/networks/list.cjs +++ b/packages/metadata/main/networks/list.cjs @@ -280,7 +280,7 @@ module.exports = "shortName": "matic", "uppercaseName": "POLYGON_MAINNET", "humanReadableName": "Polygon", - "nativeTokenSymbol": "MATIC", + "nativeTokenSymbol": "POL", "nativeTokenWrapper": "0x3aD736904E9e65189c3000c7DD2c8AC8bB7cD4e3", "duneName": "polygon", "contractsV1": { @@ -763,7 +763,8 @@ module.exports = "name": "protocol-v1-scroll-mainnet", "hostedEndpoint": "https://subgraph-endpoints.superfluid.dev/scroll-mainnet/protocol-v1" }, - "publicRPCs": ["https://rpc.scroll.io"] + "publicRPCs": ["https://rpc.scroll.io"], + "coinGeckoId": "scroll" }, { "name": "degenchain", @@ -799,6 +800,7 @@ module.exports = "name": "protocol-v1-degenchain", "hostedEndpoint": "https://subgraph-endpoints.superfluid.dev/degenchain/protocol-v1" }, - "publicRPCs": ["https://rpc.degen.tips"] + "publicRPCs": ["https://rpc.degen.tips"], + "coinGeckoId": "degen" } ] diff --git a/packages/metadata/module/networks/list.js b/packages/metadata/module/networks/list.js index 050bea99e8..068a70c1b9 100644 --- a/packages/metadata/module/networks/list.js +++ b/packages/metadata/module/networks/list.js @@ -280,7 +280,7 @@ export default "shortName": "matic", "uppercaseName": "POLYGON_MAINNET", "humanReadableName": "Polygon", - "nativeTokenSymbol": "MATIC", + "nativeTokenSymbol": "POL", "nativeTokenWrapper": "0x3aD736904E9e65189c3000c7DD2c8AC8bB7cD4e3", "duneName": "polygon", "contractsV1": { @@ -763,7 +763,8 @@ export default "name": "protocol-v1-scroll-mainnet", "hostedEndpoint": "https://subgraph-endpoints.superfluid.dev/scroll-mainnet/protocol-v1" }, - "publicRPCs": ["https://rpc.scroll.io"] + "publicRPCs": ["https://rpc.scroll.io"], + "coinGeckoId": "scroll" }, { "name": "degenchain", @@ -799,6 +800,7 @@ export default "name": "protocol-v1-degenchain", "hostedEndpoint": "https://subgraph-endpoints.superfluid.dev/degenchain/protocol-v1" }, - "publicRPCs": ["https://rpc.degen.tips"] + "publicRPCs": ["https://rpc.degen.tips"], + "coinGeckoId": "degen" } ] diff --git a/packages/metadata/networks.json b/packages/metadata/networks.json index d4576df194..48c97f4dbd 100644 --- a/packages/metadata/networks.json +++ b/packages/metadata/networks.json @@ -278,7 +278,7 @@ "shortName": "matic", "uppercaseName": "POLYGON_MAINNET", "humanReadableName": "Polygon", - "nativeTokenSymbol": "MATIC", + "nativeTokenSymbol": "POL", "nativeTokenWrapper": "0x3aD736904E9e65189c3000c7DD2c8AC8bB7cD4e3", "duneName": "polygon", "contractsV1": { @@ -761,7 +761,8 @@ "name": "protocol-v1-scroll-mainnet", "hostedEndpoint": "https://subgraph-endpoints.superfluid.dev/scroll-mainnet/protocol-v1" }, - "publicRPCs": ["https://rpc.scroll.io"] + "publicRPCs": ["https://rpc.scroll.io"], + "coinGeckoId": "scroll" }, { "name": "degenchain", @@ -797,6 +798,7 @@ "name": "protocol-v1-degenchain", "hostedEndpoint": "https://subgraph-endpoints.superfluid.dev/degenchain/protocol-v1" }, - "publicRPCs": ["https://rpc.degen.tips"] + "publicRPCs": ["https://rpc.degen.tips"], + "coinGeckoId": "degen" } ]