Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ETHEREUM-CONTRACTS] update SuperTokenV1Library #2048

Open
wants to merge 7 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion packages/ethereum-contracts/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

### Added
- Superfluid Pools now implement `IERC20Metadata`, thus going forward have a name, symbol and decimals
- `ISuperfluidPool.createPoolWithCustomERC20Metadata` for creating pools with custom ERC20 metadata
- `IGeneralDistributionAgreementV1.createPoolWithCustomERC20Metadata` and `SuperTokenV1Library.createPoolWithCustomERC20Metadata` for creating pools with custom ERC20 metadata
- `SuperTokenV1Library`
- overloaded `claimAll` for the msg.sender to claim for themselves
- added `flowWithCtx` and `flowFromWithCtx`

### Changed
- Fixed deployment of SimpleForwarder (solved an issue which caused batch operation `OPERATION_TYPE_SIMPLE_FORWARD_CALL` to always revert)
- `SuperTokenV1Library.distributeFlow`: return `actualFlowRate`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it could be breaking change for some; I think I might have a few places doing assert(whateverreturningbool)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but that's an okay breaking change, since it's not at ABI level, and code will not compile for the new function signature if they relying on returning bool.

- `SuperTokenV1Library.distribute`: return `actualAmount`

## [v1.12.0]

Expand Down
157 changes: 133 additions & 24 deletions packages/ethereum-contracts/contracts/apps/SuperTokenV1Library.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import {
IConstantFlowAgreementV1,
IGeneralDistributionAgreementV1,
ISuperfluidPool,
PoolConfig
PoolConfig,
PoolERC20Metadata
} from "../interfaces/superfluid/ISuperfluid.sol";


Expand Down Expand Up @@ -37,15 +38,15 @@ library SuperTokenV1Library {
* @param token Super token address
* @param receiverOrPool The receiver (account) or pool
* @param flowRate the flowRate to be set.
* @return A boolean value indicating whether the operation was successful.
* @return newFlowRate The new flow rate after the operation.
* Note that all the specifics of the underlying agreement used still apply.
* E.g. if the GDA is used, the effective flowRate may differ from the selected one.
*/
function flowX(
ISuperToken token,
address receiverOrPool,
int96 flowRate
) internal returns(bool) {
) internal returns(int96 newFlowRate) {
address sender = address(this);

(, IGeneralDistributionAgreementV1 gda) = _getAndCacheHostAndGDA(token);
Expand All @@ -57,7 +58,8 @@ library SuperTokenV1Library {
flowRate
);
} else {
return flow(token, receiverOrPool, flowRate);
flow(token, receiverOrPool, flowRate);
return flowRate;
}
}

Expand All @@ -66,14 +68,14 @@ library SuperTokenV1Library {
* @param token Super token address
* @param receiverOrPool The receiver (account) or pool
* @param amount the amount to be transferred/distributed
* @return A boolean value indicating whether the operation was successful.
* @return distributedAmount The amount actually transferred/distributed
* Note in case of distribution, the effective amount may be smaller than requested.
*/
function transferX(
ISuperToken token,
address receiverOrPool,
uint256 amount
) internal returns(bool) {
) internal returns(uint256 distributedAmount) {
address sender = address(this);

(, IGeneralDistributionAgreementV1 gda) = _getAndCacheHostAndGDA(token);
Expand All @@ -85,7 +87,8 @@ library SuperTokenV1Library {
amount
);
} else {
return token.transfer(receiverOrPool, amount);
token.transfer(receiverOrPool, amount);
return amount;
}
}

Expand Down Expand Up @@ -264,6 +267,7 @@ library SuperTokenV1Library {
} // else no change, do nothing
return true;
} else {
// can't set negative flowrate
revert IConstantFlowAgreementV1.CFA_INVALID_FLOW_RATE();
}
}
Expand Down Expand Up @@ -430,8 +434,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(
Expand Down Expand Up @@ -802,7 +806,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
Expand Down Expand Up @@ -1213,6 +1288,7 @@ library SuperTokenV1Library {

/**
* @dev Creates a new Superfluid Pool with default PoolConfig and the caller set as admin
* @param token The Super Token address.
* @return pool The address of the deployed Superfluid Pool
*/
function createPool(ISuperToken token) internal returns (ISuperfluidPool pool) {
Expand All @@ -1221,6 +1297,34 @@ library SuperTokenV1Library {
return createPool(token, address(this));
}

/**
* @dev Creates a new Superfluid Pool with custom ERC20 metadata.
* @param token The Super Token address.
* @param admin The pool admin address.
* @param poolConfig The pool configuration (see PoolConfig in IGeneralDistributionAgreementV1.sol)
* @param poolERC20Metadata The pool ERC20 metadata (see PoolERC20Metadata in IGeneralDistributionAgreementV1.sol)
* @return pool The pool address
*/
function createPoolWithCustomERC20Metadata(
ISuperToken token,
address admin,
PoolConfig memory poolConfig,
PoolERC20Metadata memory poolERC20Metadata
) internal returns (ISuperfluidPool pool) {
(, IGeneralDistributionAgreementV1 gda) = _getAndCacheHostAndGDA(token);
pool = gda.createPoolWithCustomERC20Metadata(token, admin, poolConfig, poolERC20Metadata);
}

/**
* @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.
Expand Down Expand Up @@ -1303,11 +1407,11 @@ library SuperTokenV1Library {
* @param token The Super Token address.
* @param pool The Superfluid Pool address.
* @param requestedAmount The amount of tokens to distribute.
* @return A boolean value indicating whether the distribution was successful.
* @return actualAmount The amount actually distributed, which is equal or smaller than `requestedAmount`
*/
function distribute(ISuperToken token, ISuperfluidPool pool, uint256 requestedAmount)
internal
returns (bool)
returns (uint256 actualAmount)
{
return distribute(token, address(this), pool, requestedAmount, new bytes(0));
}
Expand All @@ -1320,11 +1424,11 @@ library SuperTokenV1Library {
* @param from The address from which to distribute tokens.
* @param pool The Superfluid Pool address.
* @param requestedAmount The amount of tokens to distribute.
* @return A boolean value indicating whether the distribution was successful.
* @return actualAmount The amount actually distributed, which is equal or smaller than `requestedAmount`
*/
function distribute(ISuperToken token, address from, ISuperfluidPool pool, uint256 requestedAmount)
internal
returns (bool)
returns (uint256 actualAmount)
{
return distribute(token, from, pool, requestedAmount, new bytes(0));
}
Expand All @@ -1336,49 +1440,53 @@ library SuperTokenV1Library {
* @param pool The Superfluid Pool address.
* @param requestedAmount The amount of tokens to distribute.
* @param userData User-specific data.
* @return A boolean value indicating whether the distribution was successful.
* @return actualAmount The amount actually distributed, which is equal or smaller than `requestedAmount`
*/
function distribute(
ISuperToken token,
address from,
ISuperfluidPool pool,
uint256 requestedAmount,
bytes memory userData
) internal returns (bool) {
) internal returns (uint256 actualAmount) {
(ISuperfluid host, IGeneralDistributionAgreementV1 gda) = _getAndCacheHostAndGDA(token);
host.callAgreement(
gda, abi.encodeCall(gda.distribute, (token, from, pool, requestedAmount, new bytes(0))), userData
);
return true;
return gda.estimateDistributionActualAmount(token, from, pool, requestedAmount);
}

/**
* @dev Tries to distribute flow at `requestedFlowRate` of `token` from `from` to `pool`.
* @param token The Super Token address.
* @param pool The Superfluid Pool address.
* @param requestedFlowRate The flow rate of tokens to distribute.
* @return A boolean value indicating whether the distribution was successful.
* @return actualFlowRate The flowrate actually set, which is equal or smaller than `requestedFlowRate`,
* depending on pool state - see IGeneralDistributionAgreement.estimateFlowDistributionActualFlowRate().
*/
function distributeFlow(ISuperToken token, ISuperfluidPool pool, int96 requestedFlowRate)
internal
returns (bool)
returns (int96 actualFlowRate)
{
return distributeFlow(token, address(this), pool, requestedFlowRate, new bytes(0));
}

/**
* @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.
* @param from The address from which to distribute tokens.
* @param pool The Superfluid Pool address.
* @param requestedFlowRate The flow rate of tokens to distribute.
* @return A boolean value indicating whether the distribution was successful.
* @return actualFlowRate The flowrate actually set, which is equal or smaller than `requestedFlowRate`,
* depending on pool state - see IGeneralDistributionAgreementV1.estimateFlowDistributionActualFlowRate().
*/
function distributeFlow(ISuperToken token, address from, ISuperfluidPool pool, int96 requestedFlowRate)
internal
returns (bool)
returns (int96 actualFlowRate)
{
return distributeFlow(token, from, pool, requestedFlowRate, new bytes(0));
}
Expand All @@ -1390,20 +1498,21 @@ library SuperTokenV1Library {
* @param pool The Superfluid Pool address.
* @param requestedFlowRate The flow rate of tokens to distribute.
* @param userData User-specific data.
* @return A boolean value indicating whether the distribution was successful.
* @return actualFlowRate The flowrate actually set, which is equal or smaller than `requestedFlowRate`,
* depending on pool state - see IGeneralDistributionAgreementV1.estimateFlowDistributionActualFlowRate().
*/
function distributeFlow(
ISuperToken token,
address from,
ISuperfluidPool pool,
int96 requestedFlowRate,
bytes memory userData
) internal returns (bool) {
) internal returns (int96 actualFlowRate) {
(ISuperfluid host, IGeneralDistributionAgreementV1 gda) = _getAndCacheHostAndGDA(token);
host.callAgreement(
gda, abi.encodeCall(gda.distributeFlow, (token, from, pool, requestedFlowRate, new bytes(0))), userData
);
return true;
return gda.getFlowRate(token, from, pool);
}

/** GDA WITH CTX FUNCTIONS ************************************* */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -803,7 +803,7 @@ module.exports = eval(`(${S.toString()})({skipArgv: true})`)(async function (
return ZERO_ADDRESS;
});

{
if (prevAddr !== ZERO_ADDRESS) {
// TEMPORARY FIX - can be removed after applied
// we found a previous deployment. Now verify it has the host as owner.
// the first mainnet deployment didn't have this for SimpleForwarder, thus needs a redeployment.
Expand Down
Loading
Loading