Compare commits

...

2 Commits

Author SHA1 Message Date
hueso 4a4a18121c expired bond goes to seller 2024-03-04 13:37:51 -03:00
hueso 9b6617a702 bond to override lock limit 2024-03-03 21:58:41 -03:00
7 changed files with 92 additions and 10 deletions

View File

@ -44,4 +44,5 @@ abstract contract Constants {
uint256 constant MAXBALANCE_UPPERBOUND = 1e8 ether;
uint256 constant REPUTATION_LOWERBOUND = 1e2 ether;
uint256 constant LOCKAMOUNT_UPPERBOUND = 1e6 ether;
uint256 constant BOND_DIVISOR = 4; // 6,25%
}

View File

@ -13,6 +13,7 @@ library DataTypes {
ERC20 token;
address buyerAddress;
address seller;
bool bond;
}
// prettier-ignore

View File

@ -135,7 +135,8 @@ contract P2PIX is BaseUtils {
ERC20 token,
uint80 amount,
bytes32[] calldata merkleProof,
uint256[] calldata expiredLocks
uint256[] calldata expiredLocks,
bool bond
) public nonReentrant returns (uint256 lockID) {
unlockExpired(expiredLocks);
@ -154,10 +155,17 @@ contract P2PIX is BaseUtils {
bytes32 _pixTarget = getPixTarget(seller, token);
// transaction forwarding must leave `merkleProof` empty;
// otherwise, the trustedForwarder must be previously added
// to a seller whitelist.
if (merkleProof.length != 0) {
if (bond){
SafeTransferLib.safeTransferFrom(
token,
_msgSender(),
address(this),
amount >> BOND_DIVISOR
);
} else if (merkleProof.length != 0) {
// transaction forwarding must leave `merkleProof` empty;
// otherwise, the trustedForwarder must be previously added
// to a seller whitelist.
_merkleVerify( merkleProof, sellerAllowList(seller), _msgSender());
} else if ( amount > REPUTATION_LOWERBOUND && msg.sender == _msgSender() ) {
@ -178,7 +186,8 @@ contract P2PIX is BaseUtils {
amount,
token,
_msgSender(),
seller
seller,
bond
);
_addLock(bal, l);
@ -237,7 +246,7 @@ contract P2PIX is BaseUtils {
SafeTransferLib.safeTransfer(
t,
l.buyerAddress,
lockAmount
l.bond ? lockAmount + lockAmount >> BOND_DIVISOR : lockAmount
);
emit LockReleased(l.buyerAddress, lockID, lockAmount);
@ -266,7 +275,7 @@ contract P2PIX is BaseUtils {
if ((_sellerBalance + l.amount) > MAXBALANCE_UPPERBOUND)
revert MaxBalExceeded();
_addSellerBalance(l.seller, l.token, l.amount);
_addSellerBalance(l.seller, l.token, l.bond ? l.amount + l.amount >> BOND_DIVISOR : l.amount);
l.amount = 0;

View File

@ -94,3 +94,9 @@ uint256 REPUTATION_LOWERBOUND
uint256 LOCKAMOUNT_UPPERBOUND
```
### BOND_DIVISOR
```solidity
uint256 BOND_DIVISOR
```

View File

@ -13,6 +13,7 @@ struct Lock {
contract ERC20 token;
address buyerAddress;
address seller;
bool bond;
}
```

View File

@ -67,7 +67,7 @@ _Function sighash: 0x6d82d9e0_
### lock
```solidity
function lock(address seller, contract ERC20 token, uint80 amount, bytes32[] merkleProof, uint256[] expiredLocks) public returns (uint256 lockID)
function lock(address seller, contract ERC20 token, uint80 amount, bytes32[] merkleProof, uint256[] expiredLocks, bool bond) public returns (uint256 lockID)
```
Public method designed to lock an remaining amount of
@ -78,7 +78,7 @@ to a seller whitelist.
This method can be performed either by:
- An user allowed via the seller's allowlist;
- An user with enough userRecord to lock the wished amount;
There can only exist a lock per each `_amount` partitioned
There can only exist a lock per each `amount` partitioned
from the total `remaining` value.
Locks can only be performed in valid orders.
@ -93,6 +93,7 @@ _Function sighash: 0xdc43221c_
| amount | uint80 | The deposit's remaining amount wished to be locked. |
| merkleProof | bytes32[] | Provided as a pass if the `msg.sender` is in the seller's allowlist; Left empty otherwise; |
| expiredLocks | uint256[] | An array of identifiers to be provided so to unexpire locks using this transaction gas push. |
| bond | bool | |
#### Return Values

View File

@ -622,6 +622,7 @@ describe("P2PIX", () => {
price,
[],
[],
false,
);
const fail2 = p2pix.lock(
zero,
@ -629,6 +630,7 @@ describe("P2PIX", () => {
price,
[],
[],
false,
);
await expect(fail).to.be.revertedWithCustomError(
@ -658,6 +660,7 @@ describe("P2PIX", () => {
price.mul(ethers.BigNumber.from(2)),
[],
[],
false,
);
await expect(fail).to.be.revertedWithCustomError(
@ -683,6 +686,7 @@ describe("P2PIX", () => {
ethers.BigNumber.from(1000),
[ethers.utils.keccak256(ethers.utils.toUtf8Bytes("wrong"))],
[],
false,
);
await expect(fail).to.be.revertedWithCustomError(
@ -710,6 +714,7 @@ describe("P2PIX", () => {
price.mul(2),
[],
[],
false,
);
await expect(fail).to.be.revertedWithCustomError(
@ -717,6 +722,42 @@ describe("P2PIX", () => {
P2PixErrors.AmountNotAllowed,
);
});
it("should override spend limit if buyer pays the bond", async () => {
await erc20.approve(
p2pix.address,
price.mul(3),
);
await p2pix.deposit(
"1",
merkleRoot,
erc20.address,
price.mul(3),
true,
);
await erc20
.transfer(
acc02.address,
price,
);
await erc20
.connect(acc02)
.approve(
p2pix.address,
price.mul(30000),
);
const bond = p2pix
.connect(acc02)
.lock(
owner.address,
erc20.address,
price.mul(2),
[],
[],
true,
);
await expect(bond).to.be.ok;
});
it("should create a lock, update storage and emit events via the allowlist path", async () => {
const target = "333";
await erc20.approve(p2pix.address, price);
@ -735,6 +776,7 @@ describe("P2PIX", () => {
price,
proof,
[],
false,
);
const storage: Lock = await p2pix.callStatic.mapLocks(
1,
@ -779,6 +821,7 @@ describe("P2PIX", () => {
price,
[],
[],
false,
);
const storage: Lock = await p2pix.callStatic.mapLocks(
1,
@ -840,6 +883,7 @@ describe("P2PIX", () => {
price,
[],
[],
false,
);
await p2pix
.connect(acc01)
@ -856,6 +900,7 @@ describe("P2PIX", () => {
price.add(ethers.constants.One),
[],
[],
false,
);
const storage: Lock = await p2pix.callStatic.mapLocks(
2,
@ -906,6 +951,7 @@ describe("P2PIX", () => {
newPrice,
proof,
[],
false,
);
const storage1: Lock = await p2pix.callStatic.mapLocks(
1,
@ -922,6 +968,7 @@ describe("P2PIX", () => {
ethers.BigNumber.from(100),
[],
[],
false,
);
const storage2: Lock = await p2pix.callStatic.mapLocks(
2,
@ -938,6 +985,7 @@ describe("P2PIX", () => {
ethers.BigNumber.from(100),
[],
[],
false,
);
const storage3: Lock = await p2pix.callStatic.mapLocks(
3,
@ -1214,6 +1262,7 @@ describe("P2PIX", () => {
ethers.BigNumber.from(100),
[],
[],
false,
);
const lockID = ethers.constants.One;
await mine(13);
@ -1255,6 +1304,7 @@ describe("P2PIX", () => {
ethers.BigNumber.from(100),
[],
[],
false,
);
const lockID = ethers.constants.One;
await p2pix.release(
@ -1299,6 +1349,7 @@ describe("P2PIX", () => {
ethers.BigNumber.from(100),
[],
[],
false,
);
await p2pix
@ -1316,6 +1367,7 @@ describe("P2PIX", () => {
ethers.BigNumber.from(100),
[],
[],
false,
);
const fail = p2pix
.connect(acc01)
@ -1357,6 +1409,7 @@ describe("P2PIX", () => {
ethers.BigNumber.from(100),
[],
[],
false,
);
const fail = p2pix
.connect(acc01)
@ -1413,6 +1466,7 @@ describe("P2PIX", () => {
ethers.BigNumber.from(100),
[],
[],
false,
);
const acc01Key = await p2pix.callStatic._castAddrToKey(
acc01.address,
@ -1577,6 +1631,7 @@ describe("P2PIX", () => {
ethers.BigNumber.from(100),
[],
[],
false,
);
await p2pix
.connect(acc03)
@ -1586,6 +1641,7 @@ describe("P2PIX", () => {
ethers.BigNumber.from(50),
[],
[],
false,
);
await p2pix
.connect(acc03)
@ -1595,6 +1651,7 @@ describe("P2PIX", () => {
ethers.BigNumber.from(25),
[],
[],
false,
);
const lockStatus1 =
@ -1764,6 +1821,7 @@ describe("P2PIX", () => {
ethers.constants.One,
[],
[],
false,
);
const lockID = ethers.constants.One;
const fail = p2pix.unlockExpired([lockID]);
@ -1802,6 +1860,7 @@ describe("P2PIX", () => {
ethers.constants.One,
[],
[],
false,
);
const lockID = ethers.constants.One;
// await mine(10);
@ -1835,6 +1894,7 @@ describe("P2PIX", () => {
ethers.constants.One,
[],
[],
false,
);
const lockID = ethers.constants.One;
await mine(11);
@ -1898,6 +1958,7 @@ describe("P2PIX", () => {
price,
proof,
[],
false,
);
// as return values of non view functions can't be accessed
// outside the evm, we fetch the lockID from the emitted event.
@ -1937,6 +1998,7 @@ describe("P2PIX", () => {
ethers.BigNumber.from(100),
[],
[lockID],
false
);
const remaining = await p2pix.callStatic.getBalance(
owner.address,
@ -1970,6 +2032,7 @@ describe("P2PIX", () => {
price,
proof,
[],
false,
);
const lockID = ethers.constants.One;
// mine blocks to expire lock