bond to override lock limit

This commit is contained in:
hueso 2024-03-03 21:58:41 -03:00
parent e57428525b
commit b2198306e6
7 changed files with 91 additions and 9 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -67,7 +67,7 @@ _Function sighash: 0x6d82d9e0_
### lock ### lock
```solidity ```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 Public method designed to lock an remaining amount of
@ -78,7 +78,7 @@ to a seller whitelist.
This method can be performed either by: This method can be performed either by:
- An user allowed via the seller's allowlist; - An user allowed via the seller's allowlist;
- An user with enough userRecord to lock the wished amount; - 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. from the total `remaining` value.
Locks can only be performed in valid orders. 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. | | 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; | | 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. | | expiredLocks | uint256[] | An array of identifiers to be provided so to unexpire locks using this transaction gas push. |
| bond | bool | |
#### Return Values #### Return Values

View File

@ -615,6 +615,7 @@ describe("P2PIX", () => {
price, price,
[], [],
[], [],
false,
); );
const fail2 = p2pix.lock( const fail2 = p2pix.lock(
zero, zero,
@ -622,6 +623,7 @@ describe("P2PIX", () => {
price, price,
[], [],
[], [],
false,
); );
expect(fail).to.be.revertedWithCustomError( expect(fail).to.be.revertedWithCustomError(
@ -651,6 +653,7 @@ describe("P2PIX", () => {
price * 2n, price * 2n,
[], [],
[], [],
false,
); );
await expect(fail).to.be.revertedWithCustomError( await expect(fail).to.be.revertedWithCustomError(
@ -676,6 +679,7 @@ describe("P2PIX", () => {
1000n, 1000n,
[ethers.keccak256(ethers.toUtf8Bytes("wrong"))], [ethers.keccak256(ethers.toUtf8Bytes("wrong"))],
[], [],
false,
); );
await expect(fail).to.be.revertedWithCustomError( await expect(fail).to.be.revertedWithCustomError(
@ -703,6 +707,7 @@ describe("P2PIX", () => {
price * 2n, price * 2n,
[], [],
[], [],
false,
); );
await expect(fail).to.be.revertedWithCustomError( await expect(fail).to.be.revertedWithCustomError(
@ -710,6 +715,42 @@ describe("P2PIX", () => {
P2PixErrors.AmountNotAllowed, 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 () => { it("should create a lock, update storage and emit events via the allowlist path", async () => {
const target = "333"; const target = "333";
await erc20.approve(p2pix.target, price); await erc20.approve(p2pix.target, price);
@ -728,6 +769,7 @@ describe("P2PIX", () => {
price, price,
proof, proof,
[], [],
false,
); );
const storage: Lock = await p2pix.mapLocks.staticCall( const storage: Lock = await p2pix.mapLocks.staticCall(
1, 1,
@ -772,6 +814,7 @@ describe("P2PIX", () => {
price, price,
[], [],
[], [],
false,
); );
const storage: Lock = await p2pix.mapLocks.staticCall( const storage: Lock = await p2pix.mapLocks.staticCall(
1, 1,
@ -831,6 +874,7 @@ describe("P2PIX", () => {
price, price,
[], [],
[], [],
false,
); );
await p2pix await p2pix
.connect(acc01) .connect(acc01)
@ -847,6 +891,7 @@ describe("P2PIX", () => {
price + 1n, price + 1n,
[], [],
[], [],
false,
); );
const storage: Lock = await p2pix.mapLocks.staticCall( const storage: Lock = await p2pix.mapLocks.staticCall(
2, 2,
@ -897,6 +942,7 @@ describe("P2PIX", () => {
newPrice, newPrice,
proof, proof,
[], [],
false,
); );
const storage1: Lock = await p2pix.mapLocks.staticCall( const storage1: Lock = await p2pix.mapLocks.staticCall(
1, 1,
@ -913,6 +959,7 @@ describe("P2PIX", () => {
BigInt(100), BigInt(100),
[], [],
[], [],
false,
); );
const storage2: Lock = await p2pix.mapLocks.staticCall( const storage2: Lock = await p2pix.mapLocks.staticCall(
2, 2,
@ -929,6 +976,7 @@ describe("P2PIX", () => {
BigInt(100), BigInt(100),
[], [],
[], [],
false,
); );
const storage3: Lock = await p2pix.mapLocks.staticCall( const storage3: Lock = await p2pix.mapLocks.staticCall(
3, 3,
@ -1205,6 +1253,7 @@ describe("P2PIX", () => {
BigInt(100), BigInt(100),
[], [],
[], [],
false,
); );
const lockID = BigInt(1); const lockID = BigInt(1);
await mine(13); await mine(13);
@ -1246,6 +1295,7 @@ describe("P2PIX", () => {
BigInt(100), BigInt(100),
[], [],
[], [],
false,
); );
const lockID = BigInt(1); const lockID = BigInt(1);
await p2pix.release( await p2pix.release(
@ -1290,6 +1340,7 @@ describe("P2PIX", () => {
BigInt(100), BigInt(100),
[], [],
[], [],
false,
); );
await p2pix await p2pix
@ -1307,6 +1358,7 @@ describe("P2PIX", () => {
BigInt(100), BigInt(100),
[], [],
[], [],
false,
); );
const fail = p2pix const fail = p2pix
.connect(acc01) .connect(acc01)
@ -1348,6 +1400,7 @@ describe("P2PIX", () => {
BigInt(100), BigInt(100),
[], [],
[], [],
false,
); );
const fail = p2pix const fail = p2pix
.connect(acc01) .connect(acc01)
@ -1404,6 +1457,7 @@ describe("P2PIX", () => {
BigInt(100), BigInt(100),
[], [],
[], [],
false,
); );
const acc01Key = await p2pix._castAddrToKey.staticCall( const acc01Key = await p2pix._castAddrToKey.staticCall(
acc01.address, acc01.address,
@ -1568,6 +1622,7 @@ describe("P2PIX", () => {
BigInt(100), BigInt(100),
[], [],
[], [],
false,
); );
await p2pix await p2pix
.connect(acc03) .connect(acc03)
@ -1577,6 +1632,7 @@ describe("P2PIX", () => {
BigInt(50), BigInt(50),
[], [],
[], [],
false,
); );
await p2pix await p2pix
.connect(acc03) .connect(acc03)
@ -1586,6 +1642,7 @@ describe("P2PIX", () => {
BigInt(25), BigInt(25),
[], [],
[], [],
false,
); );
const lockStatus1 = const lockStatus1 =
@ -1755,6 +1812,7 @@ describe("P2PIX", () => {
BigInt(1), BigInt(1),
[], [],
[], [],
false,
); );
const lockID = BigInt(1); const lockID = BigInt(1);
const fail = p2pix.unlockExpired([lockID]); const fail = p2pix.unlockExpired([lockID]);
@ -1793,6 +1851,7 @@ describe("P2PIX", () => {
BigInt(1), BigInt(1),
[], [],
[], [],
false,
); );
const lockID = BigInt(1); const lockID = BigInt(1);
// await mine(10); // await mine(10);
@ -1826,6 +1885,7 @@ describe("P2PIX", () => {
BigInt(1), BigInt(1),
[], [],
[], [],
false,
); );
const lockID = BigInt(1); const lockID = BigInt(1);
await mine(11); await mine(11);
@ -1889,6 +1949,7 @@ describe("P2PIX", () => {
price, price,
proof, proof,
[], [],
false,
); );
// as return values of non view functions can't be accessed // as return values of non view functions can't be accessed
// outside the evm, we fetch the lockID from the emitted event. // outside the evm, we fetch the lockID from the emitted event.
@ -1928,6 +1989,7 @@ describe("P2PIX", () => {
BigInt(100), BigInt(100),
[], [],
[lockID], [lockID],
false
); );
const remaining = await p2pix.getBalance.staticCall( const remaining = await p2pix.getBalance.staticCall(
owner.address, owner.address,
@ -1961,6 +2023,7 @@ describe("P2PIX", () => {
price, price,
proof, proof,
[], [],
false,
); );
const lockID = BigInt(1); const lockID = BigInt(1);
// mine blocks to expire lock // mine blocks to expire lock