From 4ba021066ee7311e8ad74b7176f41dc10de8cc5e Mon Sep 17 00:00:00 2001 From: #Mae Date: Mon, 17 Jul 2023 09:50:37 -0700 Subject: [PATCH 1/5] feat: create tsx for cow zap transaction --- .../dapp/components/ubiquity-pool/cow-zap.tsx | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 packages/dapp/components/ubiquity-pool/cow-zap.tsx diff --git a/packages/dapp/components/ubiquity-pool/cow-zap.tsx b/packages/dapp/components/ubiquity-pool/cow-zap.tsx new file mode 100644 index 000000000..ae821d617 --- /dev/null +++ b/packages/dapp/components/ubiquity-pool/cow-zap.tsx @@ -0,0 +1,46 @@ +import { ethers } from "ethers"; +import useWeb3 from "../lib/hooks/use-web-3"; + +const { provider, walletAddress, signer } = useWeb3(); + +const LUSD = new ethers.Contract( + "0x5f98805A4E8be255a32880FDeC7F6728C6568bA0", + [ + "function decimals() view returns (uint8)", + "function name() view returns (string)", + "function version() view returns (string)", + "function nonces(address owner) view returns (string)", + `function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + )`, + ], + signer +); + +const cowZap = (sellToken: string) => { + const Token = new ethers.Contract( + sellToken, + [ + "function decimals() view returns (uint8)", + "function name() view returns (string)", + "function version() view returns (string)", + "function nonces(address owner) view returns (string)", + `function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + )`, + ], + signer + ); +}; From 27ec4a84d1585a675763b3c61fb7b8bca2bbc69e Mon Sep 17 00:00:00 2001 From: #Mae Date: Tue, 18 Jul 2023 13:24:45 -0700 Subject: [PATCH 2/5] feat: zap ubiquity pool --- .../src/dollar/cow-minter/Minter.sol | 127 +++++++++++ .../src/dollar/facets/UbiquityPoolFacet.sol | 2 + .../src/dollar/interfaces/IUbiquityPool.sol | 1 + .../src/dollar/libraries/LibUbiquityPool.sol | 9 +- .../diamond/facets/UbiquityPoolFacet.t.sol | 29 ++- .../dapp/components/ubiquity-pool/cow-zap.jsx | 198 ++++++++++++++++++ .../dapp/components/ubiquity-pool/cow-zap.tsx | 46 ---- 7 files changed, 359 insertions(+), 53 deletions(-) create mode 100644 packages/contracts/src/dollar/cow-minter/Minter.sol create mode 100644 packages/dapp/components/ubiquity-pool/cow-zap.jsx delete mode 100644 packages/dapp/components/ubiquity-pool/cow-zap.tsx diff --git a/packages/contracts/src/dollar/cow-minter/Minter.sol b/packages/contracts/src/dollar/cow-minter/Minter.sol new file mode 100644 index 000000000..4b6df4d1e --- /dev/null +++ b/packages/contracts/src/dollar/cow-minter/Minter.sol @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol"; + +contract Minter { + address public immutable ubiquityPool; + + constructor(address ubiquityPool_) { + ubiquityPool = ubiquityPool_; + } + + function getAccountAddress(address user) external view returns (address) { + return _getAccountAddress(user); + } + + function getAccountBalance( + address user, + IERC20 token + ) public view returns (uint256) { + return token.balanceOf(_getAccountAddress(user)); + } + + function ensureAccount(address user) public returns (MintAccount) { + address accountAddress = _getAccountAddress(user); + uint256 codeSize; + assembly { + codeSize := extcodesize(accountAddress) + } + + if (codeSize > 0) { + return MintAccount(accountAddress); + } else { + MintAccount newAccount = new MintAccount{salt: bytes32(0)}( + user, + ubiquityPool + ); + require( + accountAddress == address(newAccount), + "account does not expected deployment address" + ); + + return newAccount; + } + } + + function mint( + address user, + address token, + uint256 amountIn, + uint256 dollarMin + ) public { + ensureAccount(user).mintDollar(token, amountIn, dollarMin); + } + + function mintAll(address user, address token, uint256 dollarMin) external { + mint(user, token, getAccountBalance(user, IERC20(token)), dollarMin); + } + + function withdraw(address user, address token, uint256 amount) public { + ensureAccount(user).withdraw(token, amount); + } + + function withdrawAll(address user, address token) external { + withdraw(user, token, getAccountBalance(user, IERC20(token))); + } + + function _getAccountAddress(address user) internal view returns (address) { + return + address( + uint160( + uint256( + keccak256( + abi.encodePacked( + bytes1(0xff), + address(this), + bytes32(0), + keccak256( + abi.encodePacked( + type(MintAccount).creationCode, + abi.encode(user, ubiquityPool) + ) + ) + ) + ) + ) + ) + ); + } +} + +contract MintAccount { + address public immutable user; + address public immutable ubiquityPool; + + constructor(address user_, address ubiquityPool_) { + user = user_; + ubiquityPool = ubiquityPool_; + } + + function mintDollar( + address token, + uint256 amountIn, + uint256 amountOutMin + ) external { + IERC20(token).approve(ubiquityPool, amountIn); + IUbiquityPool(ubiquityPool).mintDollar( + user, + token, + amountIn, + amountOutMin + ); + } + + function withdraw(address token, uint256 amount) external { + IERC20(token).transfer(user, amount); + } +} + +interface IUbiquityPool { + function mintDollar( + address user, + address collateralAddress, + uint256 collateralAmount, + uint256 dollarOutMin + ) external; +} diff --git a/packages/contracts/src/dollar/facets/UbiquityPoolFacet.sol b/packages/contracts/src/dollar/facets/UbiquityPoolFacet.sol index 032b6624b..0ded9bb5c 100644 --- a/packages/contracts/src/dollar/facets/UbiquityPoolFacet.sol +++ b/packages/contracts/src/dollar/facets/UbiquityPoolFacet.sol @@ -15,11 +15,13 @@ contract UbiquityPoolFacet is Modifiers, IUbiquityPool { /// @param collateralAmount amount of collateral tokens being deposited /// @param dollarOutMin minimum amount of UbiquityDollarToken that'll be minted, used to set acceptable slippage function mintDollar( + address user, address collateralAddress, uint256 collateralAmount, uint256 dollarOutMin ) external { LibUbiquityPool.mintDollar( + user, collateralAddress, collateralAmount, dollarOutMin diff --git a/packages/contracts/src/dollar/interfaces/IUbiquityPool.sol b/packages/contracts/src/dollar/interfaces/IUbiquityPool.sol index 0f969ec65..b092c3661 100644 --- a/packages/contracts/src/dollar/interfaces/IUbiquityPool.sol +++ b/packages/contracts/src/dollar/interfaces/IUbiquityPool.sol @@ -5,6 +5,7 @@ import {IMetaPool} from "./IMetaPool.sol"; interface IUbiquityPool { function mintDollar( + address user, address collateralAddress, uint256 collateralAmount, uint256 dollarOutMin diff --git a/packages/contracts/src/dollar/libraries/LibUbiquityPool.sol b/packages/contracts/src/dollar/libraries/LibUbiquityPool.sol index 3e72ca2dd..21a728802 100644 --- a/packages/contracts/src/dollar/libraries/LibUbiquityPool.sol +++ b/packages/contracts/src/dollar/libraries/LibUbiquityPool.sol @@ -21,7 +21,9 @@ library LibUbiquityPool { using SafeERC20 for IERC20; bytes32 constant UBIQUITY_POOL_STORAGE_POSITION = - bytes32(uint256(keccak256("ubiquity.contracts.ubiquity.pool.storage")) - 1); + bytes32( + uint256(keccak256("ubiquity.contracts.ubiquity.pool.storage")) - 1 + ); function ubiquityPoolStorage() internal @@ -74,6 +76,7 @@ library LibUbiquityPool { /// User Functions /// function mintDollar( + address user, address collateralAddress, uint256 collateralAmount, uint256 dollarOutMin @@ -103,7 +106,7 @@ library LibUbiquityPool { dollarAmountD18 = dollarAmountD18.sub(poolStorage.mintingFee); require(dollarOutMin <= dollarAmountD18, "Slippage limit reached"); IERC20(collateralAddress).safeTransferFrom( - msg.sender, + user, address(this), collateralAmount ); @@ -115,7 +118,7 @@ library LibUbiquityPool { IERC20Ubiquity ubiquityDollarToken = IERC20Ubiquity( LibAppStorage.appStorage().dollarTokenAddress ); - ubiquityDollarToken.mint(msg.sender, dollarAmountD18); + ubiquityDollarToken.mint(user, dollarAmountD18); } function redeemDollar( diff --git a/packages/contracts/test/diamond/facets/UbiquityPoolFacet.t.sol b/packages/contracts/test/diamond/facets/UbiquityPoolFacet.t.sol index 5a94e6872..a22d9b53e 100644 --- a/packages/contracts/test/diamond/facets/UbiquityPoolFacet.t.sol +++ b/packages/contracts/test/diamond/facets/UbiquityPoolFacet.t.sol @@ -209,6 +209,7 @@ contract UbiquityPoolFacetTest is DiamondSetup { collateral.approve(address(IUbiquityPoolFacet), type(uint256).max); vm.expectRevert("Slippage limit reached"); IUbiquityPoolFacet.mintDollar( + fourthAccount, address(collateral), 10 ether, 10000 ether @@ -228,7 +229,12 @@ contract UbiquityPoolFacetTest is DiamondSetup { collateral.approve(address(IUbiquityPoolFacet), type(uint256).max); uint256 balanceBefore = IDollar.balanceOf(fourthAccount); - IUbiquityPoolFacet.mintDollar(address(collateral), 1 ether, 0 ether); + IUbiquityPoolFacet.mintDollar( + fourthAccount, + address(collateral), + 1 ether, + 0 ether + ); assertGt(IDollar.balanceOf(fourthAccount), balanceBefore); vm.stopPrank(); } @@ -245,7 +251,12 @@ contract UbiquityPoolFacetTest is DiamondSetup { collateral.approve(address(IUbiquityPoolFacet), type(uint256).max); uint256 balanceBefore = IDollar.balanceOf(fourthAccount); - IUbiquityPoolFacet.mintDollar(address(collateral), 1 ether, 0 ether); + IUbiquityPoolFacet.mintDollar( + fourthAccount, + address(collateral), + 1 ether, + 0 ether + ); assertGt(IDollar.balanceOf(fourthAccount), balanceBefore); vm.stopPrank(); @@ -270,7 +281,12 @@ contract UbiquityPoolFacetTest is DiamondSetup { vm.startPrank(fourthAccount); collateral.approve(address(IUbiquityPoolFacet), type(uint256).max); - IUbiquityPoolFacet.mintDollar(address(collateral), 10 ether, 0 ether); + IUbiquityPoolFacet.mintDollar( + fourthAccount, + address(collateral), + 10 ether, + 0 ether + ); uint256 balanceBefore = IDollar.balanceOf(fourthAccount); vm.stopPrank(); MockMetaPool mock = MockMetaPool(IManager.stableSwapMetaPoolAddress()); @@ -309,7 +325,12 @@ contract UbiquityPoolFacetTest is DiamondSetup { vm.startPrank(fourthAccount); collateral.approve(address(IUbiquityPoolFacet), type(uint256).max); - IUbiquityPoolFacet.mintDollar(address(collateral), 10 ether, 0 ether); + IUbiquityPoolFacet.mintDollar( + fourthAccount, + address(collateral), + 10 ether, + 0 ether + ); uint256 balanceBefore = IDollar.balanceOf(fourthAccount); uint256 balanceCollateralBefore = collateral.balanceOf(fourthAccount); vm.stopPrank(); diff --git a/packages/dapp/components/ubiquity-pool/cow-zap.jsx b/packages/dapp/components/ubiquity-pool/cow-zap.jsx new file mode 100644 index 000000000..89a7ff7df --- /dev/null +++ b/packages/dapp/components/ubiquity-pool/cow-zap.jsx @@ -0,0 +1,198 @@ +import { ethers } from "ethers"; +import useWeb3 from "../lib/hooks/use-web-3"; + +const { walletAddress, signer } = useWeb3(); + +const LUSD = new ethers.Contract( + "0x5f98805A4E8be255a32880FDeC7F6728C6568bA0", + [ + "function decimals() view returns (uint8)", + "function name() view returns (string)", + "function version() view returns (string)", + "function nonces(address owner) view returns (string)", + `function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + )`, + ], + signer +); + +const SETTLEMENT = new ethers.Contract("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", [], signer); + +const VAULT_RELAYER = new ethers.Contract("0xC92E8bdf79f0507f65a392b0ab4667716BFE0110", [], signer); + +const chainId = await signer?.getChainId(); + +async function cowZap(sellToken, sellAmount, minterAddress) { + const Token = new ethers.Contract( + sellToken, + [ + "function decimals() view returns (uint8)", + "function name() view returns (string)", + "function version() view returns (string)", + "function nonces(address owner) view returns (string)", + `function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + )`, + ], + signer + ); + + const MINTER = new ethers.Contract( + minterAddress, + [`function getAccountAddress(address user) view returns (address)`, `function mintAll(address user view returns (address))`], + signer + ); + + const orderConfig = { + sellToken: Token.address, + buyToken: LUSD.address, + sellAmount: sellAmount, + type: "sell", + partiallyFillable: false, + sellTokenBalance: "erc20", + buyTokenBalance: "erc20", + receiver: "", + appData: JSON.stringify({ + backend: { + hooks: { + pre: [permitHook], + post: [bridgeHook], + }, + }, + }), + }; + + const permit = { + owner: walletAddress, + spender: VAULT_RELAYER.address, + value: orderConfig.sellAmount, + nonce: await Token.nonces(walletAddress), + deadline: ethers.constants.MaxUint256, + }; + + const permitSignature = ethers.utils.splitSignature( + await signer?._signTypedData( + { + name: await Token.name(), + version: await Token.version(), + chainId, + verifyingContract: Token.address, + }, + { + Permit: [ + { name: "owner", type: "address" }, + { name: "spender", type: "address" }, + { name: "value", type: "uint256" }, + { name: "nonce", type: "uint256" }, + { name: "deadline", type: "uint256" }, + ], + }, + permit + ) + ); + + const permitParams = [permit.owner, permit.spender, permit.value, permit.deadline, permitSignature.v, permitSignature.r, permitSignature.s]; + const permitHook = { + target: Token.address, + callData: Token.interface.encodeFunctionData("permit", permitParams), + gasLimit: `${await Token.estimateGas.permit(...permitParams)}`, + }; + + orderConfig.receiver = await MINTER.getAccountAddress(walletAddress); + const bridgeHook = { + target: MINTER.address, + callData: MINTER.interface.encodeFunctionData("mintAll", [walletAddress, LUSD.address]), + // Approximate gas limit determined with Tenderly. + gasLimit: "228533", + }; + console.log("bridge hook:", bridgeHook); + + /*** Order Creation ***/ + + orderConfig.appData = JSON.stringify({ + backend: { + hooks: { + pre: [permitHook], + post: [bridgeHook], + }, + }, + }); + const { id: quoteId, quote } = await fetch("https://barn.api.cow.fi/mainnet/api/v1/quote", { + method: "POST", + headers: { + "content-type": "application/json", + }, + body: JSON.stringify({ + from: walletAddress, + sellAmountBeforeFee: orderConfig.sellAmount, + ...orderConfig, + }), + }).then((response) => response.json()); + console.log("quote:", quoteId, quote); + + const orderData = { + ...orderConfig, + sellAmount: quote.sellAmount, + buyAmount: `${ethers.BigNumber.from(quote.buyAmount).mul(99).div(100)}`, + validTo: quote.validTo, + appData: ethers.utils.id(orderConfig.appData), + feeAmount: quote.feeAmount, + }; + const orderSignature = await signer._signTypedData( + { + name: "Gnosis Protocol", + version: "v2", + chainId, + verifyingContract: SETTLEMENT.address, + }, + { + Order: [ + { name: "sellToken", type: "address" }, + { name: "buyToken", type: "address" }, + { name: "receiver", type: "address" }, + { name: "sellAmount", type: "uint256" }, + { name: "buyAmount", type: "uint256" }, + { name: "validTo", type: "uint32" }, + { name: "appData", type: "bytes32" }, + { name: "feeAmount", type: "uint256" }, + { name: "kind", type: "string" }, + { name: "partiallyFillable", type: "bool" }, + { name: "sellTokenBalance", type: "string" }, + { name: "buyTokenBalance", type: "string" }, + ], + }, + orderData + ); + + const orderUid = await fetch("https://barn.api.cow.fi/mainnet/api/v1/orders", { + method: "POST", + headers: { + "content-type": "application/json", + }, + body: JSON.stringify({ + ...orderData, + from: walletAddress, + appData: orderConfig.appData, + appDataHash: orderData.appData, + signingScheme: "eip712", + signature: orderSignature, + quoteId, + }), + }).then((response) => response.json()); + console.log("order:", orderUid); +} + +export default cowZap; diff --git a/packages/dapp/components/ubiquity-pool/cow-zap.tsx b/packages/dapp/components/ubiquity-pool/cow-zap.tsx deleted file mode 100644 index ae821d617..000000000 --- a/packages/dapp/components/ubiquity-pool/cow-zap.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { ethers } from "ethers"; -import useWeb3 from "../lib/hooks/use-web-3"; - -const { provider, walletAddress, signer } = useWeb3(); - -const LUSD = new ethers.Contract( - "0x5f98805A4E8be255a32880FDeC7F6728C6568bA0", - [ - "function decimals() view returns (uint8)", - "function name() view returns (string)", - "function version() view returns (string)", - "function nonces(address owner) view returns (string)", - `function permit( - address owner, - address spender, - uint256 value, - uint256 deadline, - uint8 v, - bytes32 r, - bytes32 s - )`, - ], - signer -); - -const cowZap = (sellToken: string) => { - const Token = new ethers.Contract( - sellToken, - [ - "function decimals() view returns (uint8)", - "function name() view returns (string)", - "function version() view returns (string)", - "function nonces(address owner) view returns (string)", - `function permit( - address owner, - address spender, - uint256 value, - uint256 deadline, - uint8 v, - bytes32 r, - bytes32 s - )`, - ], - signer - ); -}; From b31a8ed29368fc4c004487a6f1587570f40d818b Mon Sep 17 00:00:00 2001 From: #Mae Date: Tue, 18 Jul 2023 14:06:52 -0700 Subject: [PATCH 3/5] fix: slither --- .../contracts/src/dollar/cow-minter/Minter.sol | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/packages/contracts/src/dollar/cow-minter/Minter.sol b/packages/contracts/src/dollar/cow-minter/Minter.sol index 4b6df4d1e..697e63e3d 100644 --- a/packages/contracts/src/dollar/cow-minter/Minter.sol +++ b/packages/contracts/src/dollar/cow-minter/Minter.sol @@ -2,6 +2,7 @@ pragma solidity 0.8.19; import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol"; +import {IUbiquityPool} from "../interfaces/IUbiquityPool.sol"; contract Minter { address public immutable ubiquityPool; @@ -112,16 +113,7 @@ contract MintAccount { ); } - function withdraw(address token, uint256 amount) external { - IERC20(token).transfer(user, amount); + function withdraw(address token, uint256 amount) external returns (bool) { + return IERC20(token).transfer(user, amount); } } - -interface IUbiquityPool { - function mintDollar( - address user, - address collateralAddress, - uint256 collateralAmount, - uint256 dollarOutMin - ) external; -} From 9c9b25622937e4683f6217d23d5a34acdd0db957 Mon Sep 17 00:00:00 2001 From: #Mae Date: Mon, 31 Jul 2023 12:41:47 -0700 Subject: [PATCH 4/5] feat: tests --- .../diamond/facets/UbiquityPoolFacet.t.sol | 2 +- packages/contracts/test/dollar/Minter.t.sol | 50 +++++++++++++++++++ .../{cow-zap.jsx => cow-zap.tsx} | 35 ++++++------- packages/dapp/tsconfig.json | 2 +- 4 files changed, 70 insertions(+), 19 deletions(-) create mode 100644 packages/contracts/test/dollar/Minter.t.sol rename packages/dapp/components/ubiquity-pool/{cow-zap.jsx => cow-zap.tsx} (97%) diff --git a/packages/contracts/test/diamond/facets/UbiquityPoolFacet.t.sol b/packages/contracts/test/diamond/facets/UbiquityPoolFacet.t.sol index a22d9b53e..de12fc3c3 100644 --- a/packages/contracts/test/diamond/facets/UbiquityPoolFacet.t.sol +++ b/packages/contracts/test/diamond/facets/UbiquityPoolFacet.t.sol @@ -33,7 +33,7 @@ contract UbiquityPoolFacetTest is DiamondSetup { StakingShare stakingShare; BondingShare stakingShareV1; - function setUp() public override { + function setUp() public virtual override { super.setUp(); crvToken = new MockERC20("3 CRV", "3CRV", 18); curve3CrvToken = address(crvToken); diff --git a/packages/contracts/test/dollar/Minter.t.sol b/packages/contracts/test/dollar/Minter.t.sol new file mode 100644 index 000000000..27aa0456f --- /dev/null +++ b/packages/contracts/test/dollar/Minter.t.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {Minter, MintAccount} from "../../src/dollar/cow-minter/Minter.sol"; +import {UbiquityPoolFacetTest} from "../diamond/facets/UbiquityPoolFacet.t.sol"; +import {MockERC20} from "../../src/dollar/mocks/MockERC20.sol"; + +contract MinterTest is UbiquityPoolFacetTest { + Minter public minter; + MintAccount public mintAccount; + MockERC20 public collateral; + + function setUp() public override { + super.setUp(); + minter = new Minter(address(diamond)); + + collateral = new MockERC20("collateral", "collateral", 18); + collateral.mint(secondAccount, 10 ether); + vm.prank(admin); + IUbiquityPoolFacet.addToken(address(collateral), (metapool)); + vm.prank(admin); + IUbiquityPoolFacet.setMintActive(address(collateral), true); + } + + function test_createAccountIfNoneExists() public { + address accountAddress = minter.getAccountAddress(secondAccount); + uint256 codeSize; + assembly { + codeSize := extcodesize(accountAddress) + } + assertEq(codeSize, 0); + + MintAccount mintAccount_ = minter.ensureAccount(secondAccount); + uint256 codeSize_; + assembly { + codeSize_ := extcodesize(mintAccount_) + } + assertGt(codeSize, 0); + } + + function test_MintFunction() public { + uint256 preBal = IDollar.balanceOf(secondAccount); + vm.startPrank(secondAccount); + mintAccount = minter.ensureAccount(secondAccount); + collateral.transfer(address(mintAccount), 5 ether); + minter.mintAll(secondAccount, address(collateral), 0); + minter.withdrawAll(secondAccount, address(IDollar)); + assertGt(IDollar.balanceOf(secondAccount), preBal); + } +} diff --git a/packages/dapp/components/ubiquity-pool/cow-zap.jsx b/packages/dapp/components/ubiquity-pool/cow-zap.tsx similarity index 97% rename from packages/dapp/components/ubiquity-pool/cow-zap.jsx rename to packages/dapp/components/ubiquity-pool/cow-zap.tsx index 89a7ff7df..384d857d9 100644 --- a/packages/dapp/components/ubiquity-pool/cow-zap.jsx +++ b/packages/dapp/components/ubiquity-pool/cow-zap.tsx @@ -29,7 +29,7 @@ const VAULT_RELAYER = new ethers.Contract("0xC92E8bdf79f0507f65a392b0ab4667716BF const chainId = await signer?.getChainId(); -async function cowZap(sellToken, sellAmount, minterAddress) { +async function cowZap(sellToken: string, sellAmount: number, minterAddress: string) { const Token = new ethers.Contract( sellToken, [ @@ -56,6 +56,22 @@ async function cowZap(sellToken, sellAmount, minterAddress) { signer ); + const permit = { + owner: walletAddress, + spender: VAULT_RELAYER.address, + value: orderConfig.sellAmount, + nonce: await Token.nonces(walletAddress), + deadline: ethers.constants.MaxUint256, + }; + + const permitParams = [permit.owner, permit.spender, permit.value, permit.deadline, permitSignature.v, permitSignature.r, permitSignature.s]; + + const permitHook = { + target: Token.address, + callData: Token.interface.encodeFunctionData("permit", permitParams), + gasLimit: `${await Token.estimateGas.permit(...permitParams)}`, + }; + const orderConfig = { sellToken: Token.address, buyToken: LUSD.address, @@ -75,16 +91,8 @@ async function cowZap(sellToken, sellAmount, minterAddress) { }), }; - const permit = { - owner: walletAddress, - spender: VAULT_RELAYER.address, - value: orderConfig.sellAmount, - nonce: await Token.nonces(walletAddress), - deadline: ethers.constants.MaxUint256, - }; - const permitSignature = ethers.utils.splitSignature( - await signer?._signTypedData( + await signer!._signTypedData( { name: await Token.name(), version: await Token.version(), @@ -104,13 +112,6 @@ async function cowZap(sellToken, sellAmount, minterAddress) { ) ); - const permitParams = [permit.owner, permit.spender, permit.value, permit.deadline, permitSignature.v, permitSignature.r, permitSignature.s]; - const permitHook = { - target: Token.address, - callData: Token.interface.encodeFunctionData("permit", permitParams), - gasLimit: `${await Token.estimateGas.permit(...permitParams)}`, - }; - orderConfig.receiver = await MINTER.getAccountAddress(walletAddress); const bridgeHook = { target: MINTER.address, diff --git a/packages/dapp/tsconfig.json b/packages/dapp/tsconfig.json index 402fdf90f..ea473f258 100644 --- a/packages/dapp/tsconfig.json +++ b/packages/dapp/tsconfig.json @@ -26,6 +26,6 @@ "@/types/contracts": ["types/contracts"] } }, - "include": ["global.d.ts", "next-env.d.ts", "**/*.ts", "**/*.tsx"], + "include": ["global.d.ts", "next-env.d.ts", "**/*.ts", "**/*.tsx", "components/ubiquity-pool/cow-zap.tsx"], "exclude": ["node_modules"] } From 855fb8bb53d1adfe694adc8f4707d9f397537f02 Mon Sep 17 00:00:00 2001 From: #Mae Date: Mon, 31 Jul 2023 13:08:25 -0700 Subject: [PATCH 5/5] fix: tests --- .../src/dollar/cow-minter/Minter.sol | 7 +---- .../src/dollar/facets/UbiquityPoolFacet.sol | 2 -- .../src/dollar/interfaces/IUbiquityPool.sol | 1 - .../src/dollar/libraries/LibUbiquityPool.sol | 5 ++-- .../diamond/facets/UbiquityPoolFacet.t.sol | 29 +++---------------- packages/contracts/test/dollar/Minter.t.sol | 6 ++-- 6 files changed, 11 insertions(+), 39 deletions(-) diff --git a/packages/contracts/src/dollar/cow-minter/Minter.sol b/packages/contracts/src/dollar/cow-minter/Minter.sol index 697e63e3d..2ef47467e 100644 --- a/packages/contracts/src/dollar/cow-minter/Minter.sol +++ b/packages/contracts/src/dollar/cow-minter/Minter.sol @@ -105,12 +105,7 @@ contract MintAccount { uint256 amountOutMin ) external { IERC20(token).approve(ubiquityPool, amountIn); - IUbiquityPool(ubiquityPool).mintDollar( - user, - token, - amountIn, - amountOutMin - ); + IUbiquityPool(ubiquityPool).mintDollar(token, amountIn, amountOutMin); } function withdraw(address token, uint256 amount) external returns (bool) { diff --git a/packages/contracts/src/dollar/facets/UbiquityPoolFacet.sol b/packages/contracts/src/dollar/facets/UbiquityPoolFacet.sol index 0ded9bb5c..032b6624b 100644 --- a/packages/contracts/src/dollar/facets/UbiquityPoolFacet.sol +++ b/packages/contracts/src/dollar/facets/UbiquityPoolFacet.sol @@ -15,13 +15,11 @@ contract UbiquityPoolFacet is Modifiers, IUbiquityPool { /// @param collateralAmount amount of collateral tokens being deposited /// @param dollarOutMin minimum amount of UbiquityDollarToken that'll be minted, used to set acceptable slippage function mintDollar( - address user, address collateralAddress, uint256 collateralAmount, uint256 dollarOutMin ) external { LibUbiquityPool.mintDollar( - user, collateralAddress, collateralAmount, dollarOutMin diff --git a/packages/contracts/src/dollar/interfaces/IUbiquityPool.sol b/packages/contracts/src/dollar/interfaces/IUbiquityPool.sol index b092c3661..0f969ec65 100644 --- a/packages/contracts/src/dollar/interfaces/IUbiquityPool.sol +++ b/packages/contracts/src/dollar/interfaces/IUbiquityPool.sol @@ -5,7 +5,6 @@ import {IMetaPool} from "./IMetaPool.sol"; interface IUbiquityPool { function mintDollar( - address user, address collateralAddress, uint256 collateralAmount, uint256 dollarOutMin diff --git a/packages/contracts/src/dollar/libraries/LibUbiquityPool.sol b/packages/contracts/src/dollar/libraries/LibUbiquityPool.sol index 21a728802..2c38fe76d 100644 --- a/packages/contracts/src/dollar/libraries/LibUbiquityPool.sol +++ b/packages/contracts/src/dollar/libraries/LibUbiquityPool.sol @@ -76,7 +76,6 @@ library LibUbiquityPool { /// User Functions /// function mintDollar( - address user, address collateralAddress, uint256 collateralAmount, uint256 dollarOutMin @@ -106,7 +105,7 @@ library LibUbiquityPool { dollarAmountD18 = dollarAmountD18.sub(poolStorage.mintingFee); require(dollarOutMin <= dollarAmountD18, "Slippage limit reached"); IERC20(collateralAddress).safeTransferFrom( - user, + msg.sender, address(this), collateralAmount ); @@ -118,7 +117,7 @@ library LibUbiquityPool { IERC20Ubiquity ubiquityDollarToken = IERC20Ubiquity( LibAppStorage.appStorage().dollarTokenAddress ); - ubiquityDollarToken.mint(user, dollarAmountD18); + ubiquityDollarToken.mint(msg.sender, dollarAmountD18); } function redeemDollar( diff --git a/packages/contracts/test/diamond/facets/UbiquityPoolFacet.t.sol b/packages/contracts/test/diamond/facets/UbiquityPoolFacet.t.sol index de12fc3c3..e79bced0f 100644 --- a/packages/contracts/test/diamond/facets/UbiquityPoolFacet.t.sol +++ b/packages/contracts/test/diamond/facets/UbiquityPoolFacet.t.sol @@ -209,7 +209,6 @@ contract UbiquityPoolFacetTest is DiamondSetup { collateral.approve(address(IUbiquityPoolFacet), type(uint256).max); vm.expectRevert("Slippage limit reached"); IUbiquityPoolFacet.mintDollar( - fourthAccount, address(collateral), 10 ether, 10000 ether @@ -229,12 +228,7 @@ contract UbiquityPoolFacetTest is DiamondSetup { collateral.approve(address(IUbiquityPoolFacet), type(uint256).max); uint256 balanceBefore = IDollar.balanceOf(fourthAccount); - IUbiquityPoolFacet.mintDollar( - fourthAccount, - address(collateral), - 1 ether, - 0 ether - ); + IUbiquityPoolFacet.mintDollar(address(collateral), 1 ether, 0 ether); assertGt(IDollar.balanceOf(fourthAccount), balanceBefore); vm.stopPrank(); } @@ -251,12 +245,7 @@ contract UbiquityPoolFacetTest is DiamondSetup { collateral.approve(address(IUbiquityPoolFacet), type(uint256).max); uint256 balanceBefore = IDollar.balanceOf(fourthAccount); - IUbiquityPoolFacet.mintDollar( - fourthAccount, - address(collateral), - 1 ether, - 0 ether - ); + IUbiquityPoolFacet.mintDollar(address(collateral), 1 ether, 0 ether); assertGt(IDollar.balanceOf(fourthAccount), balanceBefore); vm.stopPrank(); @@ -281,12 +270,7 @@ contract UbiquityPoolFacetTest is DiamondSetup { vm.startPrank(fourthAccount); collateral.approve(address(IUbiquityPoolFacet), type(uint256).max); - IUbiquityPoolFacet.mintDollar( - fourthAccount, - address(collateral), - 10 ether, - 0 ether - ); + IUbiquityPoolFacet.mintDollar(address(collateral), 10 ether, 0 ether); uint256 balanceBefore = IDollar.balanceOf(fourthAccount); vm.stopPrank(); MockMetaPool mock = MockMetaPool(IManager.stableSwapMetaPoolAddress()); @@ -325,12 +309,7 @@ contract UbiquityPoolFacetTest is DiamondSetup { vm.startPrank(fourthAccount); collateral.approve(address(IUbiquityPoolFacet), type(uint256).max); - IUbiquityPoolFacet.mintDollar( - fourthAccount, - address(collateral), - 10 ether, - 0 ether - ); + IUbiquityPoolFacet.mintDollar(address(collateral), 10 ether, 0 ether); uint256 balanceBefore = IDollar.balanceOf(fourthAccount); uint256 balanceCollateralBefore = collateral.balanceOf(fourthAccount); vm.stopPrank(); diff --git a/packages/contracts/test/dollar/Minter.t.sol b/packages/contracts/test/dollar/Minter.t.sol index 27aa0456f..eda6ffe45 100644 --- a/packages/contracts/test/dollar/Minter.t.sol +++ b/packages/contracts/test/dollar/Minter.t.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.19; import {Minter, MintAccount} from "../../src/dollar/cow-minter/Minter.sol"; import {UbiquityPoolFacetTest} from "../diamond/facets/UbiquityPoolFacet.t.sol"; import {MockERC20} from "../../src/dollar/mocks/MockERC20.sol"; +import "forge-std/console.sol"; contract MinterTest is UbiquityPoolFacetTest { Minter public minter; @@ -35,7 +36,7 @@ contract MinterTest is UbiquityPoolFacetTest { assembly { codeSize_ := extcodesize(mintAccount_) } - assertGt(codeSize, 0); + assertGt(codeSize_, 0); } function test_MintFunction() public { @@ -45,6 +46,7 @@ contract MinterTest is UbiquityPoolFacetTest { collateral.transfer(address(mintAccount), 5 ether); minter.mintAll(secondAccount, address(collateral), 0); minter.withdrawAll(secondAccount, address(IDollar)); - assertGt(IDollar.balanceOf(secondAccount), preBal); + uint256 postBal = IDollar.balanceOf(secondAccount); + assertGt(postBal, preBal); } }