Skip to content

Commit ec42a26

Browse files
authored
New tests (#316)
* add new tests
1 parent 6e0c8a2 commit ec42a26

File tree

1 file changed

+317
-4
lines changed

1 file changed

+317
-4
lines changed

test/SuperfluidFactoringTest.js

Lines changed: 317 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -464,9 +464,9 @@ describe("Superfluid Factoring", function () {
464464
// `payer ${payer.address} usdcx balance: ${await usdcx.balanceOf(payer.address)}`
465465
// );
466466

467-
streamAmount = 2000;
468-
streamDays = 10;
469-
streamDuration = 10 * 24 * 60 * 60;
467+
streamAmount = 6000;
468+
streamDays = 30;
469+
streamDuration = streamDays * 24 * 60 * 60;
470470

471471
let flowrate = toDefaultToken(streamAmount).div(BN.from(streamDuration));
472472
await createFlow(usdcx, payer, borrower, flowrate);
@@ -475,7 +475,7 @@ describe("Superfluid Factoring", function () {
475475
await authorizeFlow(usdcx, payer, nftContract);
476476

477477
// console.log(`mint TradableStream...`);
478-
collateralAmount = 500;
478+
collateralAmount = 1500;
479479
flowrate = toDefaultToken(collateralAmount).div(BN.from(streamDuration)).add(BN.from(1));
480480
await nftContract
481481
.connect(borrower)
@@ -4182,4 +4182,317 @@ describe("Superfluid Factoring", function () {
41824182
// printRecord(cr, crs);
41834183
// });
41844184
});
4185+
4186+
describe("Use front loading fee instead of interest apr", function () {
4187+
beforeEach(async function () {
4188+
const frontLoadingFeeBps = 100;
4189+
await feeManagerContract.connect(poolOwner).setFees(0, frontLoadingFeeBps, 0, 0, 0);
4190+
let result = await feeManagerContract.getFees();
4191+
// console.log("fees: " + result);
4192+
4193+
await poolContract
4194+
.connect(eaServiceAccount)
4195+
["approveCredit(address,uint256,uint256,uint256,uint256,address,uint256,uint256)"](
4196+
borrower.address,
4197+
toUSDC(streamAmount),
4198+
streamDays,
4199+
1,
4200+
0,
4201+
nftContract.address,
4202+
ethers.utils.solidityKeccak256(
4203+
["address", "address", "address"],
4204+
[usdcx.address, payer.address, borrower.address]
4205+
),
4206+
toUSDC(streamAmount)
4207+
);
4208+
await usdc.connect(borrower).approve(poolProcessorContract.address, toUSDC(10_000));
4209+
4210+
const beforeAmount = await usdc.balanceOf(borrower.address);
4211+
4212+
let flowrate = toDefaultToken(collateralAmount)
4213+
.div(BN.from(streamDuration))
4214+
.add(BN.from(1));
4215+
loanAmount = flowrate.mul(BN.from(streamDuration));
4216+
const nonce = await nftContract.nonces(borrower.address);
4217+
const expiry = Math.ceil(Date.now() / 1000) + 300;
4218+
const signatureData = await borrower._signTypedData(
4219+
{
4220+
name: "TradableStream",
4221+
version: nftVersion,
4222+
chainId: HARDHAT_CHAIN_ID,
4223+
verifyingContract: nftContract.address,
4224+
},
4225+
{
4226+
MintToWithAuthorization: [
4227+
{name: "receiver", type: "address"},
4228+
{name: "token", type: "address"},
4229+
{name: "origin", type: "address"},
4230+
{name: "owner", type: "address"},
4231+
{name: "flowrate", type: "int96"},
4232+
{name: "durationInSeconds", type: "uint256"},
4233+
{name: "nonce", type: "uint256"},
4234+
{name: "expiry", type: "uint256"},
4235+
],
4236+
},
4237+
{
4238+
receiver: borrower.address,
4239+
token: usdcx.address,
4240+
origin: payer.address,
4241+
owner: poolProcessorContract.address,
4242+
flowrate: flowrate,
4243+
durationInSeconds: streamDuration,
4244+
nonce: nonce,
4245+
expiry: expiry,
4246+
}
4247+
);
4248+
const signature = ethers.utils.splitSignature(signatureData);
4249+
const calldata = ethers.utils.defaultAbiCoder.encode(
4250+
[
4251+
"address",
4252+
"address",
4253+
"address",
4254+
"int96",
4255+
"uint256",
4256+
"uint256",
4257+
"uint8",
4258+
"bytes32",
4259+
"bytes32",
4260+
],
4261+
[
4262+
borrower.address,
4263+
usdcx.address,
4264+
payer.address,
4265+
flowrate,
4266+
streamDuration,
4267+
expiry,
4268+
signature.v,
4269+
signature.r,
4270+
signature.s,
4271+
]
4272+
);
4273+
await poolProcessorContract.mintAndDrawdown(
4274+
borrower.address,
4275+
loanAmount,
4276+
nftContract.address,
4277+
calldata
4278+
);
4279+
4280+
const afterAmount = await usdc.balanceOf(borrower.address);
4281+
const receivedAmount = afterAmount.sub(beforeAmount);
4282+
const fee = loanAmount.mul(BN.from(frontLoadingFeeBps)).div(BN.from(10000));
4283+
4284+
expect(receivedAmount).to.equal(loanAmount.sub(fee));
4285+
});
4286+
4287+
it("Should pay off correctly", async function () {
4288+
let cr = await poolContract.creditRecordMapping(borrower.address);
4289+
let crs = await poolContract.creditRecordStaticMapping(borrower.address);
4290+
// printRecord(cr, crs);
4291+
4292+
const expiration = 10000;
4293+
const nts = cr.dueDate.toNumber() + expiration;
4294+
let block = await ethers.provider.getBlock();
4295+
const beforeBorrowerFlowrate = await cfa.getNetFlow(usdcx.address, borrower.address);
4296+
const beforeReceivedAmount = BN.from(nts)
4297+
.sub(block.timestamp)
4298+
.mul(beforeBorrowerFlowrate);
4299+
await setNextBlockTimestamp(nts);
4300+
const streamId = 1;
4301+
let res = await nftContract.getTradableStreamData(streamId);
4302+
const flowrate = res[6];
4303+
const si = await poolProcessorContract.streamInfoMapping(streamId);
4304+
const beforeBorrowAmount = await usdc.balanceOf(borrower.address);
4305+
const beforePoolAmount = await usdc.balanceOf(poolContract.address);
4306+
const beforeBorrowXAmount = await usdcx.balanceOf(borrower.address);
4307+
const beforeProcessorFlowrate = await cfa.getNetFlow(
4308+
usdcx.address,
4309+
poolProcessorContract.address
4310+
);
4311+
await expect(poolProcessorContract.settlement(nftContract.address, streamId))
4312+
.to.emit(poolProcessorContract, "SettlementMade")
4313+
.withArgs(
4314+
poolContract.address,
4315+
borrower.address,
4316+
si.flowKey,
4317+
nftContract.address,
4318+
streamId
4319+
);
4320+
const afterBorrowAmount = await usdc.balanceOf(borrower.address);
4321+
const afterPoolAmount = await usdc.balanceOf(poolContract.address);
4322+
const afterBorrowXAmount = await usdcx.balanceOf(borrower.address);
4323+
const afterProcessorFlowrate = await cfa.getNetFlow(
4324+
usdcx.address,
4325+
poolProcessorContract.address
4326+
);
4327+
const afterBorrowerFlowrate = await cfa.getNetFlow(usdcx.address, borrower.address);
4328+
// console.log(
4329+
// `afterBorrowAmount: ${afterBorrowAmount}, beforeBorrowAmount: ${beforeBorrowAmount}`
4330+
// );
4331+
expect(afterBorrowAmount.sub(beforeBorrowAmount)).to.equal(0);
4332+
expect(afterPoolAmount.sub(beforePoolAmount)).to.equal(loanAmount);
4333+
expect(beforeProcessorFlowrate.sub(afterProcessorFlowrate)).to.equal(
4334+
afterBorrowerFlowrate.sub(beforeBorrowerFlowrate)
4335+
);
4336+
expect(afterBorrowerFlowrate.sub(beforeBorrowerFlowrate)).to.equal(flowrate);
4337+
await expect(nftContract.ownerOf(streamId)).to.be.revertedWith(
4338+
"ERC721: invalid token ID"
4339+
);
4340+
expect(afterBorrowXAmount.sub(beforeBorrowXAmount).sub(beforeReceivedAmount)).to.equal(
4341+
si.flowrate.mul(BN.from(expiration))
4342+
);
4343+
cr = await poolContract.creditRecordMapping(borrower.address);
4344+
crs = await poolContract.creditRecordStaticMapping(borrower.address);
4345+
// printRecord(cr, crs);
4346+
checkRecord(
4347+
cr,
4348+
crs,
4349+
toUSDC(streamAmount),
4350+
0,
4351+
"SKIP",
4352+
"SKIP",
4353+
0,
4354+
0,
4355+
0,
4356+
0,
4357+
0,
4358+
streamDays,
4359+
0,
4360+
0
4361+
);
4362+
checkResults(await poolContract.receivableInfoMapping(borrower.address), [
4363+
ethers.constants.AddressZero,
4364+
0,
4365+
0,
4366+
]);
4367+
checkResults(await poolProcessorContract.streamInfoMapping(streamId), [
4368+
ethers.constants.AddressZero,
4369+
0,
4370+
0,
4371+
0,
4372+
0,
4373+
ethers.constants.HashZero,
4374+
]);
4375+
4376+
const flowId = ethers.utils.keccak256(
4377+
ethers.utils.defaultAbiCoder.encode(
4378+
["address", "address"],
4379+
[payer.address, poolProcessorContract.address]
4380+
)
4381+
);
4382+
const flowKey = ethers.utils.solidityKeccak256(
4383+
["address", "bytes32"],
4384+
[usdcx.address, flowId]
4385+
);
4386+
expect(await poolProcessorContract.flowEndMapping(flowKey)).to.equal(0);
4387+
});
4388+
4389+
it("Should pay off correctly if the flow was terminated", async function () {
4390+
await sfRegisterContract.register(poolProcessorContract.address);
4391+
4392+
let balance = await usdc.balanceOf(borrower.address);
4393+
let remainingBal = toUSDC(10);
4394+
if (balance.gt(remainingBal)) {
4395+
await usdc
4396+
.connect(borrower)
4397+
.transfer(defaultDeployer.address, balance.sub(remainingBal));
4398+
} else {
4399+
remainingBal = balance;
4400+
}
4401+
4402+
let cr = await poolContract.creditRecordMapping(borrower.address);
4403+
const remainingTime = 3600 * 24 * 7;
4404+
let nts = cr.dueDate.toNumber() - remainingTime;
4405+
await setNextBlockTimestamp(nts);
4406+
4407+
await deleteFlow(usdcx, payer, poolProcessorContract);
4408+
4409+
const streamId = 1;
4410+
const flowId = ethers.utils.keccak256(
4411+
ethers.utils.defaultAbiCoder.encode(
4412+
["address", "address"],
4413+
[payer.address, poolProcessorContract.address]
4414+
)
4415+
);
4416+
const flowKey = ethers.utils.solidityKeccak256(
4417+
["address", "bytes32"],
4418+
[usdcx.address, flowId]
4419+
);
4420+
let beforeSI = await poolProcessorContract.streamInfoMapping(streamId);
4421+
let beforeBorrowerBal = await usdc.balanceOf(borrower.address);
4422+
let beforePoolBal = await usdc.balanceOf(poolContract.address);
4423+
await poolProcessorContract.onTerminatedFlow(flowKey, streamId);
4424+
let afterBorrowerBal = await usdc.balanceOf(borrower.address);
4425+
let afterPoolBal = await usdc.balanceOf(poolContract.address);
4426+
let afterSI = await poolProcessorContract.streamInfoMapping(streamId);
4427+
4428+
expect(beforeBorrowerBal.sub(afterBorrowerBal)).to.equal(remainingBal);
4429+
expect(afterPoolBal.sub(beforePoolBal)).to.equal(remainingBal);
4430+
expect(afterSI.lastStartTime).to.equal(nts);
4431+
expect(afterSI.flowrate).to.equal(0);
4432+
expect(afterSI.endTime).to.equal(beforeSI.endTime);
4433+
expect(afterSI.receivedFlowAmount).to.equal(
4434+
BN.from(nts).sub(beforeSI.lastStartTime).mul(beforeSI.flowrate)
4435+
);
4436+
4437+
cr = await poolContract.creditRecordMapping(borrower.address);
4438+
crs = await poolContract.creditRecordStaticMapping(borrower.address);
4439+
let block = await ethers.provider.getBlock();
4440+
let correction = calcCorrection(cr, crs, block.timestamp, remainingBal);
4441+
// console.log("correction: " + correction);
4442+
checkRecord(
4443+
cr,
4444+
crs,
4445+
toUSDC(streamAmount),
4446+
0,
4447+
"SKIP",
4448+
correction,
4449+
loanAmount.sub(remainingBal),
4450+
0,
4451+
0,
4452+
0,
4453+
0,
4454+
streamDays,
4455+
3,
4456+
0
4457+
);
4458+
4459+
await mint(borrower.address, toUSDC(streamAmount));
4460+
4461+
const expiration = 1000;
4462+
nts = cr.dueDate.toNumber() + expiration;
4463+
await setNextBlockTimestamp(nts);
4464+
4465+
beforeBorrowerBal = await usdc.balanceOf(borrower.address);
4466+
beforePoolBal = await usdc.balanceOf(poolContract.address);
4467+
await poolProcessorContract.settlement(nftContract.address, streamId);
4468+
afterBorrowerBal = await usdc.balanceOf(borrower.address);
4469+
afterPoolBal = await usdc.balanceOf(poolContract.address);
4470+
4471+
expect(afterPoolBal.sub(beforePoolBal)).to.equal(
4472+
loanAmount.sub(remainingBal).add(correction)
4473+
);
4474+
expect(beforeBorrowerBal.sub(afterBorrowerBal)).to.equal(
4475+
loanAmount.sub(remainingBal).sub(afterSI.receivedFlowAmount).add(correction)
4476+
);
4477+
4478+
cr = await poolContract.creditRecordMapping(borrower.address);
4479+
crs = await poolContract.creditRecordStaticMapping(borrower.address);
4480+
checkRecord(
4481+
cr,
4482+
crs,
4483+
toUSDC(streamAmount),
4484+
0,
4485+
"SKIP",
4486+
0,
4487+
0,
4488+
0,
4489+
0,
4490+
0,
4491+
0,
4492+
streamDays,
4493+
0,
4494+
0
4495+
);
4496+
});
4497+
});
41854498
});

0 commit comments

Comments
 (0)