Skip to content

Commit

Permalink
fix pure supertoken issue
Browse files Browse the repository at this point in the history
  • Loading branch information
0xdavinchee committed Sep 28, 2023
1 parent ae7f923 commit c82fd03
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 10 deletions.
24 changes: 15 additions & 9 deletions packages/ethereum-contracts/contracts/superfluid/SuperToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -733,20 +733,26 @@ contract SuperToken is
bytes memory userData,
bytes memory operatorData
) internal {
if (address(_underlyingToken) == address(0)) revert SUPER_TOKEN_NO_UNDERLYING_TOKEN();
bool hasNoUnderlying = address(_underlyingToken) == address(0);

(uint256 underlyingAmount, uint256 adjustedAmount) = _toUnderlyingAmount(amount);

// _burn will check the (actual) amount availability again
_burn(operator, account, adjustedAmount, userData.length != 0, userData, operatorData);
adjustedAmount = hasNoUnderlying ? amount : adjustedAmount;

uint256 amountBefore = _underlyingToken.balanceOf(address(this));
_underlyingToken.safeTransfer(to, underlyingAmount);
uint256 amountAfter = _underlyingToken.balanceOf(address(this));
uint256 actualDowngradedAmount = amountBefore - amountAfter;
if (underlyingAmount != actualDowngradedAmount) revert SUPER_TOKEN_INFLATIONARY_DEFLATIONARY_NOT_SUPPORTED();
// _burn will check the (actual) amount availability again
_burn(operator, account, adjustedAmount, userData.length != 0, userData, operatorData);

emit TokenDowngraded(account, adjustedAmount);
if (!hasNoUnderlying) {
uint256 amountBefore = _underlyingToken.balanceOf(address(this));
_underlyingToken.safeTransfer(to, underlyingAmount);
uint256 amountAfter = _underlyingToken.balanceOf(address(this));
uint256 actualDowngradedAmount = amountBefore - amountAfter;
if (underlyingAmount != actualDowngradedAmount) {
revert SUPER_TOKEN_INFLATIONARY_DEFLATIONARY_NOT_SUPPORTED();
}

emit TokenDowngraded(account, adjustedAmount);
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,7 @@ describe("SuperToken's Non Standard Functions", function () {
await expectCustomError(
customToken.downgrade(100),
customToken,
reason
"SF_TOKEN_BURN_INSUFFICIENT_BALANCE"
);
await web3tx(customToken.initialize, "customToken.initialize")(
ZERO_ADDRESS,
Expand Down
111 changes: 111 additions & 0 deletions packages/ethereum-contracts/test/foundry/superfluid/SuperToken.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { UUPSProxiable } from "../../../contracts/upgradability/UUPSProxiable.so
import { IERC20, ISuperToken, SuperToken } from "../../../contracts/superfluid/SuperToken.sol";
import { ConstantOutflowNFT, IConstantOutflowNFT } from "../../../contracts/superfluid/ConstantOutflowNFT.sol";
import { ConstantInflowNFT, IConstantInflowNFT } from "../../../contracts/superfluid/ConstantInflowNFT.sol";
import { IPureSuperToken } from "../../../contracts/interfaces/tokens/IPureSuperToken.sol";
import { FoundrySuperfluidTester } from "../FoundrySuperfluidTester.sol";
import { TestToken } from "../../../contracts/utils/TestToken.sol";
import { TokenDeployerLibrary } from "../../../contracts/utils/SuperfluidFrameworkDeploymentSteps.sol";
Expand Down Expand Up @@ -234,4 +235,114 @@ contract SuperTokenIntegrationTest is FoundrySuperfluidTester {
UUPSProxiable(address(localSuperToken)).updateCode(address(newSuperTokenLogic));
vm.stopPrank();
}

function testPureSuperTokenDowngrade(address holder, int256 initialSupply, int256 downgradeAmount) public {
_assumeValidPureSuperTokenBurnConditions(holder, initialSupply, downgradeAmount);

vm.startPrank(holder);
(IPureSuperToken pureSuperToken) = sfDeployer.deployPureSuperToken("Mr. Token", "MR", uint256(initialSupply));
uint256 initialTotalSupply = pureSuperToken.totalSupply();
pureSuperToken.downgrade(uint256(downgradeAmount));
vm.stopPrank();

assertEq(
pureSuperToken.totalSupply(),
initialTotalSupply - uint256(downgradeAmount),
"testPureSuperTokenDowngrade: total supply not updated correctly"
);
}

function testPureSuperTokenDowngradeTo(address holder, address to, int256 initialSupply, int256 downgradeAmount)
public
{
_assumeValidPureSuperTokenBurnConditions(holder, initialSupply, downgradeAmount);

vm.startPrank(holder);
(IPureSuperToken pureSuperToken) = sfDeployer.deployPureSuperToken("Mr. Token", "MR", uint256(initialSupply));
uint256 initialTotalSupply = pureSuperToken.totalSupply();
// @note this function doesn't do anything except for burning the tokens
// that is, `to` receives nothing
pureSuperToken.downgradeTo(to, uint256(downgradeAmount));
vm.stopPrank();

assertEq(
pureSuperToken.totalSupply(),
initialTotalSupply - uint256(downgradeAmount),
"testPureSuperTokenDowngradeTo: total supply not updated correctly"
);
}

function testPureSuperTokenBurn(address holder, int256 initialSupply, int256 downgradeAmount) public {
_assumeValidPureSuperTokenBurnConditions(holder, initialSupply, downgradeAmount);

vm.startPrank(holder);
(IPureSuperToken pureSuperToken) = sfDeployer.deployPureSuperToken("Mr. Token", "MR", uint256(initialSupply));
uint256 initialTotalSupply = pureSuperToken.totalSupply();
pureSuperToken.burn(uint256(downgradeAmount), "");
vm.stopPrank();

assertEq(
pureSuperToken.totalSupply(),
initialTotalSupply - uint256(downgradeAmount),
"testPureSuperTokenBurn: total supply not updated correctly"
);
}

function testPureSuperTokenOperatorBurn(
address operator,
address holder,
int256 initialSupply,
int256 downgradeAmount
) public {
_assumeValidPureSuperTokenBurnConditions(holder, initialSupply, downgradeAmount);

vm.startPrank(holder);
(IPureSuperToken pureSuperToken) = sfDeployer.deployPureSuperToken("Mr. Token", "MR", uint256(initialSupply));
pureSuperToken.authorizeOperator(operator);
vm.stopPrank();

assertTrue(
pureSuperToken.isOperatorFor(operator, holder), "testPureSuperTokenOperatorBurn: operator not authorized"
);
uint256 initialTotalSupply = pureSuperToken.totalSupply();

vm.startPrank(operator);
pureSuperToken.operatorBurn(holder, uint256(downgradeAmount), "", "");
vm.stopPrank();

assertEq(
pureSuperToken.totalSupply(),
initialTotalSupply - uint256(downgradeAmount),
"testPureSuperTokenOperatorBurn: total supply not updated correctly"
);
}

function testPureSuperTokenOperationDowngrade(address holder, int256 initialSupply, int256 downgradeAmount)
public
{
_assumeValidPureSuperTokenBurnConditions(holder, initialSupply, downgradeAmount);

vm.startPrank(holder);
(IPureSuperToken pureSuperToken) = sfDeployer.deployPureSuperToken("Mr. Token", "MR", uint256(initialSupply));
uint256 initialTotalSupply = pureSuperToken.totalSupply();
vm.stopPrank();
vm.startPrank(address(sf.host));
pureSuperToken.operationDowngrade(holder, uint256(downgradeAmount));
vm.stopPrank();

assertEq(
pureSuperToken.totalSupply(),
initialTotalSupply - uint256(downgradeAmount),
"testPureSuperTokenOperatorBurn: total supply not updated correctly"
);
}

function _assumeValidPureSuperTokenBurnConditions(address holder, int256 initialSupply, int256 downgradeAmount)
internal
{
vm.assume(initialSupply > downgradeAmount);
vm.assume(initialSupply > 0);
vm.assume(downgradeAmount > 0);
vm.assume(holder != address(0));
}
}

0 comments on commit c82fd03

Please sign in to comment.