Skip to content

Commit

Permalink
dispenser progression
Browse files Browse the repository at this point in the history
  • Loading branch information
YouStillAlive committed Mar 20, 2024
1 parent 19fa9ee commit 4811a7a
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 25 deletions.
13 changes: 7 additions & 6 deletions contracts/DispenserProvider.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ pragma solidity ^0.8.0;

import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/interfaces/IERC20.sol";
import "hardhat/console.sol";
import "./DispenserView.sol";

contract DispenserProvider is DispenserView {
Expand Down Expand Up @@ -69,8 +68,9 @@ contract DispenserProvider is DispenserView {
Builder[] calldata data,
bytes memory signature
) external validProviderId(poolId) {
require(msg.sender == owner || lockDealNFT.getApproved(poolId) == msg.sender, "DispenserProvider: Not approved");
require(
lockDealNFT.isApprovedForAll(owner, address(this)),
lockDealNFT.isApprovedForAll(owner, address(this)),
"DispenserProvider: Owner has not approved the DispenserProvider"
);
require(
Expand All @@ -95,7 +95,7 @@ contract DispenserProvider is DispenserView {
Builder[] calldata builder
) internal pure returns (bytes memory data) {
for (uint256 i = 0; i < builder.length; ++i) {
data = abi.encodePacked(data, abi.encode(builder));
data = abi.encodePacked(data, address(builder[i].simpleProvider), builder[i].params);
}
}

Expand All @@ -108,17 +108,18 @@ contract DispenserProvider is DispenserView {
uint256 poolId = lockDealNFT.mintForProvider(owner, data[i].simpleProvider);
data[i].simpleProvider.registerPool(poolId, data[i].params);
lockDealNFT.cloneVaultId(poolId, tokenPoolId);
_withdrawIfAvaliable(data[i].simpleProvider, poolId, owner);
leftAmount[tokenPoolId] -= data[i].params[0];
_withdrawIfAvailable(data[i].simpleProvider, poolId, owner);
}
}

function _withdrawIfAvaliable(
function _withdrawIfAvailable(
ISimpleProvider provider,
uint256 poolId,
address owner
) internal {
if (provider.getWithdrawableAmount(poolId) > 0) {
lockDealNFT.safeTransferFrom(address(this), owner, poolId);
lockDealNFT.safeTransferFrom(owner, address(lockDealNFT), poolId);
}
}

Expand Down
29 changes: 28 additions & 1 deletion contracts/mock/MockVaultManager.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,31 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@poolzfinance/lockdeal-nft/contracts/mock/MockVaultManager.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract MockVaultManager {
mapping(address => uint) public tokenToVaultId;
mapping(uint256 => address) vaultIdtoToken;
bool public transfers = true;
uint256 public Id = 0;

function safeDeposit(address _tokenAddress, uint _amount, address from, bytes memory signature) external returns (uint vaultId) {
require(keccak256(abi.encodePacked(signature)) == keccak256(abi.encodePacked("signature")), "wrong signature");
IERC20(_tokenAddress).transferFrom(from, address(this), _amount);
vaultId = _depositByToken(_tokenAddress);
}

function _depositByToken(address _tokenAddress) internal returns (uint vaultId) {
vaultId = ++Id;
vaultIdtoToken[vaultId] = _tokenAddress;
tokenToVaultId[_tokenAddress] = vaultId;
}

function withdrawByVaultId(uint _vaultId, address _to, uint _amount) external {
IERC20(vaultIdtoToken[_vaultId]).transfer(_to, _amount);
}

function vaultIdToTokenAddress(uint _vaultId) external view returns (address) {
return vaultIdtoToken[_vaultId];
}
}
45 changes: 27 additions & 18 deletions test/DispenserProvider.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,34 @@
import { DispenserProvider } from "../typechain-types/contracts/DispenserProvider"
import { LockDealNFT } from "../typechain-types/@poolzfinance/lockdeal-nft/contracts/LockDealNFT/LockDealNFT"
import { DealProvider } from "../typechain-types/@poolzfinance/lockdeal-nft/contracts/SimpleProviders/DealProvider/DealProvider"
import { MockVaultManager as VaultManager } from "../typechain-types/@poolzfinance/lockdeal-nft/contracts/mock/MockVaultManager"
import { MockVaultManager as VaultManager } from "../typechain-types/contracts/mock/MockVaultManager"
import { LockDealProvider } from "../typechain-types/@poolzfinance/lockdeal-nft/contracts/SimpleProviders/LockProvider/LockDealProvider"
import { ERC20Token } from "../typechain-types/@poolzfinance/poolz-helper-v2/contracts/token/ERC20Token"
import { TimedDealProvider } from "../typechain-types/@poolzfinance/lockdeal-nft/contracts/SimpleProviders/TimedDealProvider/TimedDealProvider"
import { DispenserState } from "../typechain-types/contracts/DispenserProvider"
import { time } from "@nomicfoundation/hardhat-network-helpers"
import { expect } from "chai"
import { Bytes, constants } from "ethers"
import { createSignature } from "./helper"
import { Bytes, constants, BigNumber } from "ethers"
import { ethers } from "hardhat"
import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers"

describe("DispenserProvider", function () {
describe("Dispenser Provider tests", function () {
let owner: SignerWithAddress
let user: SignerWithAddress
let signer: SignerWithAddress
let dispenserProvider: DispenserProvider
let token: ERC20Token
let lockDealNFT: LockDealNFT
let dealProvider: DealProvider
let userData: DispenserState.BuilderStruct[]
let userData: DispenserState.BuilderStruct
let usersData: DispenserState.BuilderStruct[]
let lockProvider: LockDealProvider
let timedProvider: TimedDealProvider
let vaultManager: VaultManager
let packedData: string
let poolId: number
let validTime: BigNumber
const builderType = ["uint256", "uint256", "address", "tuple(address,uint256[])[]"]
const creationSignature: Bytes = ethers.utils.toUtf8Bytes("signature")
const amount = ethers.utils.parseUnits("10", 18)
Expand All @@ -45,7 +48,6 @@ describe("DispenserProvider", function () {
lockProvider = await LockDealProvider.deploy(lockDealNFT.address, dealProvider.address)
const TimedDealProvider = await ethers.getContractFactory("TimedDealProvider")
timedProvider = await TimedDealProvider.deploy(lockDealNFT.address, lockProvider.address)

await lockDealNFT.setApprovedContract(dealProvider.address, true)
await lockDealNFT.setApprovedContract(lockProvider.address, true)
await lockDealNFT.setApprovedContract(timedProvider.address, true)
Expand All @@ -57,8 +59,9 @@ describe("DispenserProvider", function () {
const ERC20Token = await ethers.getContractFactory("ERC20Token")
token = await ERC20Token.deploy("Test", "TST")
poolId = (await lockDealNFT.totalSupply()).toNumber()
await token.approve(vaultManager.address, amount)
await dispenserProvider.connect(owner).deposit(signer.address, token.address, amount, creationSignature)
const validTime = ethers.BigNumber.from((await time.latest()) + ONE_DAY)
validTime = ethers.BigNumber.from((await time.latest()) + ONE_DAY)
packedData = ethers.utils.defaultAbiCoder.encode(builderType, [
poolId,
validTime,
Expand All @@ -67,11 +70,6 @@ describe("DispenserProvider", function () {
])
})

async function createSignature(signer: SignerWithAddress, data: string[]) {
const packedData = ethers.utils.defaultAbiCoder.encode(builderType, data)
return await signer.signMessage(ethers.utils.arrayify(packedData))
}

it("should return name of contract", async () => {
expect(await dispenserProvider.name()).to.equal("DispenserProvider")
})
Expand All @@ -80,13 +78,24 @@ describe("DispenserProvider", function () {
expect(await dispenserProvider.leftAmount(poolId)).to.equal(amount)
})

it("should transfer dealProvider nft", async () => {
const validTime = ethers.BigNumber.from((await time.latest()) + ONE_DAY)
userData = [{ simpleProvider: dealProvider.address, params: [amount] }]
const builderData = [[dealProvider.address, [amount]]]
const data = [poolId, validTime, user.address, builderData]
const signature = await createSignature(signer, data)
//await dispenserProvider.connect(user).createLock(poolId, validTime, user.address, userData, signature)
it("should deacrease leftAmount after lock", async () => {
userData = { simpleProvider: lockProvider.address, params: [amount.div(2), validTime] }
usersData = [{ simpleProvider: lockProvider.address, params: [amount.div(2), validTime] }]
const signatureData = [poolId, validTime, user.address, userData]
const signature = await createSignature(signer, signatureData)
await dispenserProvider.connect(user).createLock(poolId, validTime, user.address, usersData, signature)
expect(await dispenserProvider.leftAmount(poolId)).to.equal(amount.div(2))
})

it("should transfer if available", async () => {
userData = { simpleProvider: dealProvider.address, params: [amount] }
usersData = [{ simpleProvider: dealProvider.address, params: [amount] }]
const signatureData = [poolId, validTime, user.address, userData]
const signature = await createSignature(signer, signatureData)
const beforeBalance = await token.balanceOf(user.address)
await dispenserProvider.connect(user).createLock(poolId, validTime, user.address, usersData, signature)
// check if user has tokens after the transfer
expect(await token.balanceOf(user.address)).to.equal(beforeBalance.add(amount))
})

it("should revert invalid signer address", async () => {
Expand Down
26 changes: 26 additions & 0 deletions test/helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers"
import { ethers } from "hardhat"

export async function createSignature(signer: SignerWithAddress, data: any[]): Promise<string> {
const types: string[] = []
const values: any[] = []
for (const element of data) {
if (typeof element === "string") {
types.push("address")
values.push(element)
} else if (typeof element === "object" && Array.isArray(element)) {
types.push("uint256[]")
values.push(element)
} else if (typeof element === "number" || ethers.BigNumber.isBigNumber(element)) {
types.push("uint256")
values.push(element)
} else if (typeof element === "object" && !Array.isArray(element)) {
types.push("address")
values.push(element.simpleProvider)
types.push("uint256[]")
values.push(element.params)
}
}
const packedData = ethers.utils.solidityKeccak256(types, values)
return signer.signMessage(ethers.utils.arrayify(packedData))
}

0 comments on commit 4811a7a

Please sign in to comment.