Compare commits
2 Commits
dev
...
feature_bo
Author | SHA1 | Date |
---|---|---|
hueso | 4a4a18121c | |
hueso | 9b6617a702 |
|
@ -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%
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ library DataTypes {
|
||||||
ERC20 token;
|
ERC20 token;
|
||||||
address buyerAddress;
|
address buyerAddress;
|
||||||
address seller;
|
address seller;
|
||||||
|
bool bond;
|
||||||
}
|
}
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
|
|
|
@ -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);
|
||||||
|
@ -266,7 +275,7 @@ contract P2PIX is BaseUtils {
|
||||||
if ((_sellerBalance + l.amount) > MAXBALANCE_UPPERBOUND)
|
if ((_sellerBalance + l.amount) > MAXBALANCE_UPPERBOUND)
|
||||||
revert MaxBalExceeded();
|
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;
|
l.amount = 0;
|
||||||
|
|
||||||
|
|
|
@ -94,3 +94,9 @@ uint256 REPUTATION_LOWERBOUND
|
||||||
uint256 LOCKAMOUNT_UPPERBOUND
|
uint256 LOCKAMOUNT_UPPERBOUND
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### BOND_DIVISOR
|
||||||
|
|
||||||
|
```solidity
|
||||||
|
uint256 BOND_DIVISOR
|
||||||
|
```
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ struct Lock {
|
||||||
contract ERC20 token;
|
contract ERC20 token;
|
||||||
address buyerAddress;
|
address buyerAddress;
|
||||||
address seller;
|
address seller;
|
||||||
|
bool bond;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -622,6 +622,7 @@ describe("P2PIX", () => {
|
||||||
price,
|
price,
|
||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
const fail2 = p2pix.lock(
|
const fail2 = p2pix.lock(
|
||||||
zero,
|
zero,
|
||||||
|
@ -629,6 +630,7 @@ describe("P2PIX", () => {
|
||||||
price,
|
price,
|
||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
await expect(fail).to.be.revertedWithCustomError(
|
await expect(fail).to.be.revertedWithCustomError(
|
||||||
|
@ -658,6 +660,7 @@ describe("P2PIX", () => {
|
||||||
price.mul(ethers.BigNumber.from(2)),
|
price.mul(ethers.BigNumber.from(2)),
|
||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
await expect(fail).to.be.revertedWithCustomError(
|
await expect(fail).to.be.revertedWithCustomError(
|
||||||
|
@ -683,6 +686,7 @@ describe("P2PIX", () => {
|
||||||
ethers.BigNumber.from(1000),
|
ethers.BigNumber.from(1000),
|
||||||
[ethers.utils.keccak256(ethers.utils.toUtf8Bytes("wrong"))],
|
[ethers.utils.keccak256(ethers.utils.toUtf8Bytes("wrong"))],
|
||||||
[],
|
[],
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
await expect(fail).to.be.revertedWithCustomError(
|
await expect(fail).to.be.revertedWithCustomError(
|
||||||
|
@ -710,6 +714,7 @@ describe("P2PIX", () => {
|
||||||
price.mul(2),
|
price.mul(2),
|
||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
await expect(fail).to.be.revertedWithCustomError(
|
await expect(fail).to.be.revertedWithCustomError(
|
||||||
|
@ -717,6 +722,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.address, price);
|
await erc20.approve(p2pix.address, price);
|
||||||
|
@ -735,6 +776,7 @@ describe("P2PIX", () => {
|
||||||
price,
|
price,
|
||||||
proof,
|
proof,
|
||||||
[],
|
[],
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
const storage: Lock = await p2pix.callStatic.mapLocks(
|
const storage: Lock = await p2pix.callStatic.mapLocks(
|
||||||
1,
|
1,
|
||||||
|
@ -779,6 +821,7 @@ describe("P2PIX", () => {
|
||||||
price,
|
price,
|
||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
const storage: Lock = await p2pix.callStatic.mapLocks(
|
const storage: Lock = await p2pix.callStatic.mapLocks(
|
||||||
1,
|
1,
|
||||||
|
@ -840,6 +883,7 @@ describe("P2PIX", () => {
|
||||||
price,
|
price,
|
||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
await p2pix
|
await p2pix
|
||||||
.connect(acc01)
|
.connect(acc01)
|
||||||
|
@ -856,6 +900,7 @@ describe("P2PIX", () => {
|
||||||
price.add(ethers.constants.One),
|
price.add(ethers.constants.One),
|
||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
const storage: Lock = await p2pix.callStatic.mapLocks(
|
const storage: Lock = await p2pix.callStatic.mapLocks(
|
||||||
2,
|
2,
|
||||||
|
@ -906,6 +951,7 @@ describe("P2PIX", () => {
|
||||||
newPrice,
|
newPrice,
|
||||||
proof,
|
proof,
|
||||||
[],
|
[],
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
const storage1: Lock = await p2pix.callStatic.mapLocks(
|
const storage1: Lock = await p2pix.callStatic.mapLocks(
|
||||||
1,
|
1,
|
||||||
|
@ -922,6 +968,7 @@ describe("P2PIX", () => {
|
||||||
ethers.BigNumber.from(100),
|
ethers.BigNumber.from(100),
|
||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
const storage2: Lock = await p2pix.callStatic.mapLocks(
|
const storage2: Lock = await p2pix.callStatic.mapLocks(
|
||||||
2,
|
2,
|
||||||
|
@ -938,6 +985,7 @@ describe("P2PIX", () => {
|
||||||
ethers.BigNumber.from(100),
|
ethers.BigNumber.from(100),
|
||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
const storage3: Lock = await p2pix.callStatic.mapLocks(
|
const storage3: Lock = await p2pix.callStatic.mapLocks(
|
||||||
3,
|
3,
|
||||||
|
@ -1214,6 +1262,7 @@ describe("P2PIX", () => {
|
||||||
ethers.BigNumber.from(100),
|
ethers.BigNumber.from(100),
|
||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
const lockID = ethers.constants.One;
|
const lockID = ethers.constants.One;
|
||||||
await mine(13);
|
await mine(13);
|
||||||
|
@ -1255,6 +1304,7 @@ describe("P2PIX", () => {
|
||||||
ethers.BigNumber.from(100),
|
ethers.BigNumber.from(100),
|
||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
const lockID = ethers.constants.One;
|
const lockID = ethers.constants.One;
|
||||||
await p2pix.release(
|
await p2pix.release(
|
||||||
|
@ -1299,6 +1349,7 @@ describe("P2PIX", () => {
|
||||||
ethers.BigNumber.from(100),
|
ethers.BigNumber.from(100),
|
||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
await p2pix
|
await p2pix
|
||||||
|
@ -1316,6 +1367,7 @@ describe("P2PIX", () => {
|
||||||
ethers.BigNumber.from(100),
|
ethers.BigNumber.from(100),
|
||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
const fail = p2pix
|
const fail = p2pix
|
||||||
.connect(acc01)
|
.connect(acc01)
|
||||||
|
@ -1357,6 +1409,7 @@ describe("P2PIX", () => {
|
||||||
ethers.BigNumber.from(100),
|
ethers.BigNumber.from(100),
|
||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
const fail = p2pix
|
const fail = p2pix
|
||||||
.connect(acc01)
|
.connect(acc01)
|
||||||
|
@ -1413,6 +1466,7 @@ describe("P2PIX", () => {
|
||||||
ethers.BigNumber.from(100),
|
ethers.BigNumber.from(100),
|
||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
const acc01Key = await p2pix.callStatic._castAddrToKey(
|
const acc01Key = await p2pix.callStatic._castAddrToKey(
|
||||||
acc01.address,
|
acc01.address,
|
||||||
|
@ -1577,6 +1631,7 @@ describe("P2PIX", () => {
|
||||||
ethers.BigNumber.from(100),
|
ethers.BigNumber.from(100),
|
||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
await p2pix
|
await p2pix
|
||||||
.connect(acc03)
|
.connect(acc03)
|
||||||
|
@ -1586,6 +1641,7 @@ describe("P2PIX", () => {
|
||||||
ethers.BigNumber.from(50),
|
ethers.BigNumber.from(50),
|
||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
await p2pix
|
await p2pix
|
||||||
.connect(acc03)
|
.connect(acc03)
|
||||||
|
@ -1595,6 +1651,7 @@ describe("P2PIX", () => {
|
||||||
ethers.BigNumber.from(25),
|
ethers.BigNumber.from(25),
|
||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
const lockStatus1 =
|
const lockStatus1 =
|
||||||
|
@ -1764,6 +1821,7 @@ describe("P2PIX", () => {
|
||||||
ethers.constants.One,
|
ethers.constants.One,
|
||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
const lockID = ethers.constants.One;
|
const lockID = ethers.constants.One;
|
||||||
const fail = p2pix.unlockExpired([lockID]);
|
const fail = p2pix.unlockExpired([lockID]);
|
||||||
|
@ -1802,6 +1860,7 @@ describe("P2PIX", () => {
|
||||||
ethers.constants.One,
|
ethers.constants.One,
|
||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
const lockID = ethers.constants.One;
|
const lockID = ethers.constants.One;
|
||||||
// await mine(10);
|
// await mine(10);
|
||||||
|
@ -1835,6 +1894,7 @@ describe("P2PIX", () => {
|
||||||
ethers.constants.One,
|
ethers.constants.One,
|
||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
const lockID = ethers.constants.One;
|
const lockID = ethers.constants.One;
|
||||||
await mine(11);
|
await mine(11);
|
||||||
|
@ -1898,6 +1958,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.
|
||||||
|
@ -1937,6 +1998,7 @@ describe("P2PIX", () => {
|
||||||
ethers.BigNumber.from(100),
|
ethers.BigNumber.from(100),
|
||||||
[],
|
[],
|
||||||
[lockID],
|
[lockID],
|
||||||
|
false
|
||||||
);
|
);
|
||||||
const remaining = await p2pix.callStatic.getBalance(
|
const remaining = await p2pix.callStatic.getBalance(
|
||||||
owner.address,
|
owner.address,
|
||||||
|
@ -1970,6 +2032,7 @@ describe("P2PIX", () => {
|
||||||
price,
|
price,
|
||||||
proof,
|
proof,
|
||||||
[],
|
[],
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
const lockID = ethers.constants.One;
|
const lockID = ethers.constants.One;
|
||||||
// mine blocks to expire lock
|
// mine blocks to expire lock
|
||||||
|
|
Loading…
Reference in New Issue