Merge pull request #9 from doiim/dev

Merge dev branch updates to main.
This commit is contained in:
PedroCailleret 2023-02-14 20:26:54 -03:00 committed by GitHub
commit 4568cad8f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 1539 additions and 592 deletions

View File

@ -19,3 +19,5 @@ coverage.json
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
contracts/p2pix.sol

View File

@ -32,8 +32,9 @@
## Current Deployment addresses ## Current Deployment addresses
### V1 ### V1
| Testnet | Token Address | P2pix Address | | Testnet | Token Address | P2pix Address |
|--------- |-------------------------------------------- |-------------------------------------------- | | ------- | ------------------------------------------ | ------------------------------------------ |
| Goerli | 0x294003F602c321627152c6b7DED3EAb5bEa853Ee | 0x5f3EFA9A90532914545CEf527C530658af87e196 | | Goerli | 0x294003F602c321627152c6b7DED3EAb5bEa853Ee | 0x5f3EFA9A90532914545CEf527C530658af87e196 |
| Mumbai | 0x294003F602c321627152c6b7DED3EAb5bEa853Ee | 0x5f3EFA9A90532914545CEf527C530658af87e196 | | Mumbai | 0x294003F602c321627152c6b7DED3EAb5bEa853Ee | 0x5f3EFA9A90532914545CEf527C530658af87e196 |
@ -48,19 +49,22 @@
<!-- https://mumbai.polygonscan.com/address/0x5f3EFA9A90532914545CEf527C530658af87e196#code --> <!-- https://mumbai.polygonscan.com/address/0x5f3EFA9A90532914545CEf527C530658af87e196#code -->
### V2 ### V2
| Testnet | Token Address | P2pix Address | Reputation Address |
|--------- |-------------------------------------------- |-------------------------------------------- |-------------------------------------------- | | Testnet | Token Address | P2pix Address | Reputation Address | Multicall Address |
| Goerli | 0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00 | 0xefa5cE4351cda51192509cf8De7d8881ADAE95DD | 0x939d3c357dc7017cDbDE681BF8e552b54595318A | | ------- | ------------------------------------------ | ------------------------------------------ | ------------------------------------------ | ------------------------------------------ |
| Mumbai | 0xC86042E9F2977C62Da8c9dDF7F9c40fde4796A29 | 0xA9258eBb157E4cf5e756b77FDD0DF09C2F73240b | 0x1fd30b94f20d2f73e9630261342ba68f244da92b | | Goerli | 0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00 | 0x2414817FF64A114d91eCFA16a834d3fCf69103d4 | 0x2CFD9354Ec7614fEf036EFd6A730dA1d5fC2762A | 0x8FE009992d96A86c7f0Bccdaf1eC3471E302a8a6 |
| Mumbai | 0xC86042E9F2977C62Da8c9dDF7F9c40fde4796A29 | 0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00 | 0x570445E3eF413bCDb5De79ed27B1c3840683e385 | 0x718B2C4DE4F9654E1349F610ff561249bfe1c418 |
<!-- All contracts deployed by 0x8dC06F985C131166570825F52447E8c88d64aE20 --> <!-- All contracts deployed by 0x8dC06F985C131166570825F52447E8c88d64aE20 -->
<!-- https://goerli.etherscan.io/address/0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00#code --> <!-- https://goerli.etherscan.io/address/0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00#code -->
<!-- https://goerli.etherscan.io/address/0xefa5cE4351cda51192509cf8De7d8881ADAE95DD#code --> <!-- https://goerli.etherscan.io/address/0x2414817FF64A114d91eCFA16a834d3fCf69103d4#code -->
<!-- https://goerli.etherscan.io/address/0x939d3c357dc7017cDbDE681BF8e552b54595318A#code --> <!-- https://goerli.etherscan.io/address/0x2CFD9354Ec7614fEf036EFd6A730dA1d5fC2762A#code -->
<!-- https://goerli.etherscan.io/address/0x8FE009992d96A86c7f0Bccdaf1eC3471E302a8a6#code -->
<!-- https://mumbai.polygonscan.com/address/0xC86042E9F2977C62Da8c9dDF7F9c40fde4796A29#code --> <!-- https://mumbai.polygonscan.com/address/0xC86042E9F2977C62Da8c9dDF7F9c40fde4796A29#code -->
<!-- https://mumbai.polygonscan.com/address/0xA9258eBb157E4cf5e756b77FDD0DF09C2F73240b#code --> <!-- https://mumbai.polygonscan.com/address/0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00#code -->
<!-- https://mumbai.polygonscan.com/address/0x1fd30b94f20d2f73e9630261342ba68f244da92b#code --> <!-- https://mumbai.polygonscan.com/address/0x570445e3ef413bcdb5de79ed27b1c3840683e385#code -->
<!-- https://mumbai.polygonscan.com/address/0x718B2C4DE4F9654E1349F610ff561249bfe1c418#code -->
## Usage ## Usage
@ -136,7 +140,6 @@ yarn deploy2:localhost
**_NOTE_:** The second script transfers 2M tokens to the first wallet of the node. **_NOTE_:** The second script transfers 2M tokens to the first wallet of the node.
To use the P2Pix smart contract first transfer some of the tokens to other wallets. To use the P2Pix smart contract first transfer some of the tokens to other wallets.
## Deploying to testnets ## Deploying to testnets
Deploy to Ethereum's Goerli testnet: Deploy to Ethereum's Goerli testnet:

View File

@ -1,4 +1,4 @@
{ {
"_format": "hh-sol-dbg-1", "_format": "hh-sol-dbg-1",
"buildInfo": "../../build-info/6e32e8b8339868a5a7b642cfedb2d144.json" "buildInfo": "../../build-info/901b067f80b6616939e558d795c555e5.json"
} }

View File

@ -1,4 +1,4 @@
{ {
"_format": "hh-sol-dbg-1", "_format": "hh-sol-dbg-1",
"buildInfo": "../../build-info/6e32e8b8339868a5a7b642cfedb2d144.json" "buildInfo": "../../build-info/901b067f80b6616939e558d795c555e5.json"
} }

View File

@ -1,4 +1,4 @@
{ {
"_format": "hh-sol-dbg-1", "_format": "hh-sol-dbg-1",
"buildInfo": "../../build-info/6e32e8b8339868a5a7b642cfedb2d144.json" "buildInfo": "../../build-info/901b067f80b6616939e558d795c555e5.json"
} }

View File

@ -1,4 +1,4 @@
{ {
"_format": "hh-sol-dbg-1", "_format": "hh-sol-dbg-1",
"buildInfo": "../../../../build-info/6e32e8b8339868a5a7b642cfedb2d144.json" "buildInfo": "../../../../build-info/901b067f80b6616939e558d795c555e5.json"
} }

View File

@ -1,4 +1,4 @@
{ {
"_format": "hh-sol-dbg-1", "_format": "hh-sol-dbg-1",
"buildInfo": "../../../../build-info/6e32e8b8339868a5a7b642cfedb2d144.json" "buildInfo": "../../../../build-info/901b067f80b6616939e558d795c555e5.json"
} }

View File

@ -1,4 +1,4 @@
{ {
"_format": "hh-sol-dbg-1", "_format": "hh-sol-dbg-1",
"buildInfo": "../../../../build-info/6e32e8b8339868a5a7b642cfedb2d144.json" "buildInfo": "../../../../build-info/901b067f80b6616939e558d795c555e5.json"
} }

View File

@ -1,4 +1,4 @@
{ {
"_format": "hh-sol-dbg-1", "_format": "hh-sol-dbg-1",
"buildInfo": "../../../../build-info/6e32e8b8339868a5a7b642cfedb2d144.json" "buildInfo": "../../../../build-info/901b067f80b6616939e558d795c555e5.json"
} }

View File

@ -1,4 +1,4 @@
{ {
"_format": "hh-sol-dbg-1", "_format": "hh-sol-dbg-1",
"buildInfo": "../../../../build-info/6e32e8b8339868a5a7b642cfedb2d144.json" "buildInfo": "../../../../build-info/901b067f80b6616939e558d795c555e5.json"
} }

View File

@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../../../build-info/901b067f80b6616939e558d795c555e5.json"
}

View File

@ -0,0 +1,116 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "Multicall",
"sourceName": "contracts/lib/utils/Multicall.sol",
"abi": [
{
"inputs": [],
"stateMutability": "payable",
"type": "constructor"
},
{
"inputs": [
{
"internalType": "string",
"name": "reason",
"type": "string"
}
],
"name": "CallFailed",
"type": "error"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "target",
"type": "address"
},
{
"internalType": "bytes",
"name": "callData",
"type": "bytes"
}
],
"internalType": "struct Multicall.Call[]",
"name": "calls",
"type": "tuple[]"
}
],
"name": "mtc1",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
},
{
"internalType": "bytes[]",
"name": "",
"type": "bytes[]"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "target",
"type": "address"
},
{
"internalType": "bytes",
"name": "callData",
"type": "bytes"
}
],
"internalType": "struct Multicall.Call[]",
"name": "calls",
"type": "tuple[]"
}
],
"name": "mtc2",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
},
{
"components": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
},
{
"internalType": "bytes",
"name": "returnData",
"type": "bytes"
}
],
"internalType": "struct Multicall.Result[]",
"name": "",
"type": "tuple[]"
}
],
"stateMutability": "nonpayable",
"type": "function"
}
],
"bytecode": "0x60806040526108ec806100136000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80631b57b72f1461003b57806386575ee914610066575b600080fd5b61004e610049366004610438565b610087565b60405161005d93929190610527565b60405180910390f35b610079610074366004610438565b610227565b60405161005d9291906105cb565b600080606043804085848167ffffffffffffffff8111156100aa576100aa610653565b6040519080825280602002602001820160405280156100f057816020015b6040805180820190915260008152606060208201528152602001906001900390816100c85790505b50905060005b82811015610217576000808b8b8481811061011357610113610682565b905060200281019061012591906106b1565b6101339060208101906106ef565b73ffffffffffffffffffffffffffffffffffffffff168c8c8581811061015b5761015b610682565b905060200281019061016d91906106b1565b61017b90602081019061072c565b604051610189929190610791565b6000604051808303816000865af19150503d80600081146101c6576040519150601f19603f3d011682016040523d82523d6000602084013e6101cb565b606091505b509150915060405180604001604052808315158152602001828152508484815181106101f9576101f9610682565b60200260200101819052508261020e906107a1565b925050506100f6565b5092989197509195509350505050565b600060604383838167ffffffffffffffff81111561024757610247610653565b60405190808252806020026020018201604052801561027a57816020015b60608152602001906001900390816102655790505b50905060005b828110156104285760008089898481811061029d5761029d610682565b90506020028101906102af91906106b1565b6102bd9060208101906106ef565b73ffffffffffffffffffffffffffffffffffffffff168a8a858181106102e5576102e5610682565b90506020028101906102f791906106b1565b61030590602081019061072c565b604051610313929190610791565b6000604051808303816000865af19150503d8060008114610350576040519150601f19603f3d011682016040523d82523d6000602084013e610355565b606091505b5091509150816103f7576044815110156103aa576040517fb5e1dc2d00000000000000000000000000000000000000000000000000000000815260206004820152600060248201526044015b60405180910390fd5b600481019050808060200190518101906103c49190610801565b6040517fb5e1dc2d0000000000000000000000000000000000000000000000000000000081526004016103a191906108cc565b8084848151811061040a5761040a610682565b60200260200101819052508261041f906107a1565b92505050610280565b50919350909150505b9250929050565b6000806020838503121561044b57600080fd5b823567ffffffffffffffff8082111561046357600080fd5b818501915085601f83011261047757600080fd5b81358181111561048657600080fd5b8660208260051b850101111561049b57600080fd5b60209290920196919550909350505050565b60005b838110156104c85781810151838201526020016104b0565b838111156104d7576000848401525b50505050565b600081518084526104f58160208601602086016104ad565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60006060820185835260208581850152604060608186015282865180855260808701915060808160051b880101945083880160005b828110156105bb578887037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8001845281518051151588528601518688018690526105a8868901826104dd565b975050928501929085019060010161055c565b50949a9950505050505050505050565b600060408201848352602060408185015281855180845260608601915060608160051b870101935082870160005b82811015610645577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08887030184526106338683516104dd565b955092840192908401906001016105f9565b509398975050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18336030181126106e557600080fd5b9190910192915050565b60006020828403121561070157600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461072557600080fd5b9392505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261076157600080fd5b83018035915067ffffffffffffffff82111561077c57600080fd5b60200191503681900382131561043157600080fd5b8183823760009101908152919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156107fa577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b60006020828403121561081357600080fd5b815167ffffffffffffffff8082111561082b57600080fd5b818401915084601f83011261083f57600080fd5b81518181111561085157610851610653565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561089757610897610653565b816040528281528760208487010111156108b057600080fd5b6108c18360208301602088016104ad565b979650505050505050565b60208152600061072560208301846104dd56fea164736f6c6343000809000a",
"deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c80631b57b72f1461003b57806386575ee914610066575b600080fd5b61004e610049366004610438565b610087565b60405161005d93929190610527565b60405180910390f35b610079610074366004610438565b610227565b60405161005d9291906105cb565b600080606043804085848167ffffffffffffffff8111156100aa576100aa610653565b6040519080825280602002602001820160405280156100f057816020015b6040805180820190915260008152606060208201528152602001906001900390816100c85790505b50905060005b82811015610217576000808b8b8481811061011357610113610682565b905060200281019061012591906106b1565b6101339060208101906106ef565b73ffffffffffffffffffffffffffffffffffffffff168c8c8581811061015b5761015b610682565b905060200281019061016d91906106b1565b61017b90602081019061072c565b604051610189929190610791565b6000604051808303816000865af19150503d80600081146101c6576040519150601f19603f3d011682016040523d82523d6000602084013e6101cb565b606091505b509150915060405180604001604052808315158152602001828152508484815181106101f9576101f9610682565b60200260200101819052508261020e906107a1565b925050506100f6565b5092989197509195509350505050565b600060604383838167ffffffffffffffff81111561024757610247610653565b60405190808252806020026020018201604052801561027a57816020015b60608152602001906001900390816102655790505b50905060005b828110156104285760008089898481811061029d5761029d610682565b90506020028101906102af91906106b1565b6102bd9060208101906106ef565b73ffffffffffffffffffffffffffffffffffffffff168a8a858181106102e5576102e5610682565b90506020028101906102f791906106b1565b61030590602081019061072c565b604051610313929190610791565b6000604051808303816000865af19150503d8060008114610350576040519150601f19603f3d011682016040523d82523d6000602084013e610355565b606091505b5091509150816103f7576044815110156103aa576040517fb5e1dc2d00000000000000000000000000000000000000000000000000000000815260206004820152600060248201526044015b60405180910390fd5b600481019050808060200190518101906103c49190610801565b6040517fb5e1dc2d0000000000000000000000000000000000000000000000000000000081526004016103a191906108cc565b8084848151811061040a5761040a610682565b60200260200101819052508261041f906107a1565b92505050610280565b50919350909150505b9250929050565b6000806020838503121561044b57600080fd5b823567ffffffffffffffff8082111561046357600080fd5b818501915085601f83011261047757600080fd5b81358181111561048657600080fd5b8660208260051b850101111561049b57600080fd5b60209290920196919550909350505050565b60005b838110156104c85781810151838201526020016104b0565b838111156104d7576000848401525b50505050565b600081518084526104f58160208601602086016104ad565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60006060820185835260208581850152604060608186015282865180855260808701915060808160051b880101945083880160005b828110156105bb578887037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8001845281518051151588528601518688018690526105a8868901826104dd565b975050928501929085019060010161055c565b50949a9950505050505050505050565b600060408201848352602060408185015281855180845260608601915060608160051b870101935082870160005b82811015610645577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08887030184526106338683516104dd565b955092840192908401906001016105f9565b509398975050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18336030181126106e557600080fd5b9190910192915050565b60006020828403121561070157600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461072557600080fd5b9392505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261076157600080fd5b83018035915067ffffffffffffffff82111561077c57600080fd5b60200191503681900382131561043157600080fd5b8183823760009101908152919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156107fa577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b60006020828403121561081357600080fd5b815167ffffffffffffffff8082111561082b57600080fd5b818401915084601f83011261083f57600080fd5b81518181111561085157610851610653565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561089757610897610653565b816040528281528760208487010111156108b057600080fd5b6108c18360208301602088016104ad565b979650505050505050565b60208152600061072560208301846104dd56fea164736f6c6343000809000a",
"linkReferences": {},
"deployedLinkReferences": {}
}

View File

@ -1,4 +1,4 @@
{ {
"_format": "hh-sol-dbg-1", "_format": "hh-sol-dbg-1",
"buildInfo": "../../../../build-info/6e32e8b8339868a5a7b642cfedb2d144.json" "buildInfo": "../../../../build-info/901b067f80b6616939e558d795c555e5.json"
} }

View File

@ -1,4 +1,4 @@
{ {
"_format": "hh-sol-dbg-1", "_format": "hh-sol-dbg-1",
"buildInfo": "../../../../build-info/6e32e8b8339868a5a7b642cfedb2d144.json" "buildInfo": "../../../../build-info/901b067f80b6616939e558d795c555e5.json"
} }

View File

@ -1,4 +1,4 @@
{ {
"_format": "hh-sol-dbg-1", "_format": "hh-sol-dbg-1",
"buildInfo": "../../build-info/6e32e8b8339868a5a7b642cfedb2d144.json" "buildInfo": "../../build-info/901b067f80b6616939e558d795c555e5.json"
} }

File diff suppressed because one or more lines are too long

View File

@ -2,18 +2,6 @@
pragma solidity 0.8.9; pragma solidity 0.8.9;
library DataTypes { library DataTypes {
// struct Deposit {
// /// @dev Remaining tokens available.
// uint256 remaining;
// /// @dev The PIX account for the seller receive transactions.
// string pixTarget;
// address seller;
// /// @dev ERC20 stable token address.
// address token;
// /// @dev Could be invalidated by the seller.
// bool valid;
// }
struct Lock { struct Lock {
uint256 sellerKey; uint256 sellerKey;
uint256 counter; uint256 counter;
@ -33,4 +21,12 @@ library DataTypes {
address relayerAddress; address relayerAddress;
address token; address token;
} }
// prettier-ignore
enum LockStatus {
Inexistent, // 0 := Uninitialized Lock.
Active, // 1 := Valid Lock.
Expired, // 2 := Expired Lock.
Released // 3 := Already released Lock.
}
} }

View File

@ -0,0 +1,80 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
/// @title Multicall.
/// @notice Contract that batches view function calls and aggregates their results.
/// @author Adapted from Makerdao's Multicall2 (https://github.com/makerdao/multicall/blob/master/src/Multicall2.sol).
contract Multicall {
/// @dev 0x
error CallFailed(string reason);
struct Call {
address target;
bytes callData;
}
struct Result {
bool success;
bytes returnData;
}
//prettier-ignore
constructor(/* */) payable {/* */}
function mtc1(Call[] calldata calls)
external
returns (uint256, bytes[] memory)
{
uint256 bn = block.number;
uint256 len = calls.length;
bytes[] memory res = new bytes[](len);
uint256 j;
while (j < len) {
(bool success, bytes memory ret) = calls[j]
.target
.call(calls[j].callData);
if (!success) {
if (ret.length < 0x44) revert CallFailed("");
assembly {
ret := add(ret, 0x04)
}
revert CallFailed({
reason: abi.decode(ret, (string))
});
}
res[j] = ret;
++j;
}
return (bn, res);
}
function mtc2(Call[] calldata calls)
external
returns (
uint256,
bytes32,
Result[] memory
)
{
uint256 bn = block.number;
// µ 0 s [0] P(IHp , µs [0], 0) P is the hash of a block of a particular number, up to a maximum age.
// 0 is left on the stack if the looked for `block.number` is >= to the current `block.number` or more than 256
// blocks behind the current block (Yellow Paper, p. 33, https://ethereum.github.io/yellowpaper/paper.pdf).
bytes32 bh = blockhash(
bn /* - 1 */
);
uint256 len = calls.length;
Result[] memory res = new Result[](len);
uint256 i;
for (i; i < len; ) {
(bool success, bytes memory ret) = calls[i]
.target
.call(calls[i].callData);
res[i] = Result(success, ret);
++i;
}
return (bn, bh, res);
}
}

View File

@ -114,46 +114,4 @@ library SafeTransferLib {
require(success, "TRANSFER_FAILED"); require(success, "TRANSFER_FAILED");
} }
function safeApprove(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
assembly {
// We'll write our calldata to this slot below, but restore it later.
let memPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(
0,
0x095ea7b300000000000000000000000000000000000000000000000000000000
)
mstore(4, to) // Append the "to" argument.
mstore(36, amount) // Append the "amount" argument.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(
and(
eq(mload(0), 1),
gt(returndatasize(), 31)
),
iszero(returndatasize())
),
// We use 68 because that's the total length of our calldata (4 + 32 * 2)
// Counterintuitively, this call() must be positioned after the or() in the
// surrounding and() because and() evaluates its arguments from right to left.
call(gas(), token, 0, 0, 68, 0, 32)
)
mstore(0x60, 0) // Restore the zero slot to zero.
mstore(0x40, memPointer) // Restore the memPointer.
}
require(success, "APPROVE_FAILED");
}
} }

View File

@ -26,6 +26,7 @@ contract P2PIX is
// solhint-disable no-empty-blocks // solhint-disable no-empty-blocks
using DT for DT.Lock; using DT for DT.Lock;
using DT for DT.LockStatus;
/// Constants /// Constants
@ -43,7 +44,6 @@ contract P2PIX is
/// Storage /// Storage
IReputation public reputation; IReputation public reputation;
// Counters.Counter public depositCount;
/// @dev Default blocks that lock will hold tokens. /// @dev Default blocks that lock will hold tokens.
uint256 public defaultLockBlocks; uint256 public defaultLockBlocks;
@ -106,15 +106,11 @@ contract P2PIX is
ERC20 t = ERC20(_token); ERC20 t = ERC20(_token);
uint256 k = _castAddrToKey(msg.sender); uint256 k = _castAddrToKey(msg.sender);
if (_pixTarget == 0) if (_pixTarget == 0) revert EmptyPixTarget();
revert EmptyPixTarget(); if (!allowedERC20s[t]) revert TokenDenied();
if (!allowedERC20s[t]) uint256 _sellerBalance = sellerBalance[k][t];
revert TokenDenied();
uint256 _sellerBalance =
sellerBalance[k][t];
uint256 currBal = uint256 currBal = _sellerBalance & BITMASK_SB_ENTRY;
_sellerBalance & BITMASK_SB_ENTRY;
if ((currBal + _amount) > 1e8 ether) if ((currBal + _amount) > 1e8 ether)
revert MaxBalExceeded(); revert MaxBalExceeded();
@ -131,11 +127,7 @@ contract P2PIX is
amountCasted, amountCasted,
pixTargetCasted, pixTargetCasted,
validCasted validCasted
) = _castToUint( ) = _castToUint(_amount, _pixTarget, _valid);
_amount,
_pixTarget,
_valid
);
sellerBalance[k][t] = sellerBalance[k][t] =
(currBal + amountCasted) | (currBal + amountCasted) |
@ -151,11 +143,7 @@ contract P2PIX is
clearReentrancyGuard(); clearReentrancyGuard();
emit DepositAdded( emit DepositAdded(msg.sender, _token, _amount);
msg.sender,
_token,
_amount
);
} }
/// @notice Enables seller to invalidate future /// @notice Enables seller to invalidate future
@ -163,29 +151,23 @@ contract P2PIX is
/// @dev This function does not affect any ongoing active locks. /// @dev This function does not affect any ongoing active locks.
/// @dev Function sighash: 0x72fada5c. /// @dev Function sighash: 0x72fada5c.
function setValidState(ERC20 token, bool state) public { function setValidState(ERC20 token, bool state) public {
uint256 key = uint256 key = _castAddrToKey(msg.sender);
_castAddrToKey(msg.sender); uint256 _sellerBalance = sellerBalance[key][token];
uint256 _sellerBalance =
sellerBalance[key][token];
if (_sellerBalance != 0) { if (_sellerBalance != 0) {
uint256 _valid; uint256 _valid;
assembly { _valid := state } assembly {
_valid := state
}
_sellerBalance = _sellerBalance =
(_sellerBalance & BITMASK_VALID) | (_sellerBalance & BITMASK_VALID) |
(_valid << BITPOS_VALID); (_valid << BITPOS_VALID);
sellerBalance[key][token] = sellerBalance[key][token] = _sellerBalance;
_sellerBalance;
emit ValidSet( emit ValidSet(msg.sender, address(token), state);
msg.sender, } else revert NotInitialized();
address(token),
state
);
} else
revert NotInitialized();
} }
/// @notice Public method designed to lock an remaining amount of /// @notice Public method designed to lock an remaining amount of
@ -220,33 +202,26 @@ contract P2PIX is
unlockExpired(expiredLocks); unlockExpired(expiredLocks);
ERC20 t = ERC20(_token); ERC20 t = ERC20(_token);
if (!getValid(_seller, t)) if (!getValid(_seller, t)) revert InvalidDeposit();
revert InvalidDeposit();
uint256 bal = uint256 bal = getBalance(_seller, t);
getBalance(_seller, t); if (bal < _amount) revert NotEnoughTokens();
if (bal < _amount)
revert NotEnoughTokens();
uint256 k = uint256 k = _castAddrToKey(_seller);
_castAddrToKey(_seller);
uint256 cCounter = uint256 cCounter = lockCounter + 1;
lockCounter + 1;
if (mapLocks[cCounter].expirationBlock if (
>= block.number) mapLocks[cCounter].expirationBlock >= block.number
revert NotExpired(); ) revert NotExpired();
DT.Lock memory l = DT.Lock( DT.Lock memory l = DT.Lock(
k, k,
cCounter, cCounter,
_relayerPremium, _relayerPremium,
_amount, _amount,
(block.number + (block.number + defaultLockBlocks),
defaultLockBlocks), uint160(sellerBalance[k][t] >> BITPOS_PIXTARGET),
uint160(sellerBalance[k][t]
>> BITPOS_PIXTARGET),
_buyerAddress, _buyerAddress,
_relayerTarget, _relayerTarget,
msg.sender, msg.sender,
@ -260,58 +235,34 @@ contract P2PIX is
msg.sender msg.sender
); );
_addLock( _addLock(bal, _amount, cCounter, l, t, k);
bal,
_amount,
cCounter,
l,
t,
k
);
lockCounter++; lockCounter++;
// Halt execution and output `lockID`. // Halt execution and output `lockID`.
return cCounter; return cCounter;
} else { } else {
if (l.amount <= 1e2 ether) { if (l.amount <= 1e2 ether) {
_addLock( _addLock(bal, _amount, cCounter, l, t, k);
bal,
_amount,
cCounter,
l,
t,
k
);
lockCounter++; lockCounter++;
// Halt execution and output `lockID`. // Halt execution and output `lockID`.
return cCounter; return cCounter;
} else { } else {
uint256 userCredit = userRecord[ uint256 userCredit = userRecord[
_castAddrToKey(msg.sender) _castAddrToKey(msg.sender)
]; ];
uint256 spendLimit; uint256 spendLimit;
(spendLimit) = (spendLimit) = _limiter(userCredit / WAD);
_limiter(userCredit / WAD);
if ( if (
l.amount > (spendLimit * WAD) || l.amount > (spendLimit * WAD) ||
l.amount > 1e6 ether l.amount > 1e6 ether
) revert AmountNotAllowed(); ) revert AmountNotAllowed();
_addLock( _addLock(bal, _amount, cCounter, l, t, k);
bal,
_amount,
cCounter,
l,
t,
k
);
lockCounter++; lockCounter++;
@ -375,25 +326,22 @@ contract P2PIX is
ERC20 t = ERC20(l.token); ERC20 t = ERC20(l.token);
// We cache values before zeroing them out. // We cache values before zeroing them out.
uint256 lockAmount = uint256 lockAmount = l.amount;
l.amount; uint256 totalAmount = (lockAmount - l.relayerPremium);
uint256 totalAmount =
(lockAmount - l.relayerPremium);
l.amount = 0; l.amount = 0;
l.expirationBlock = 0; l.expirationBlock = 0;
usedTransactions[message] = true; usedTransactions[message] = true;
if (msg.sender != l.relayerAddress) { if (msg.sender != l.relayerAddress) {
userRecord[ userRecord[_castAddrToKey(msg.sender)] += l
_castAddrToKey(msg.sender) .relayerPremium;
] += l.relayerPremium;
userRecord[ userRecord[
_castAddrToKey(l.relayerAddress) _castAddrToKey(l.relayerAddress)
] += lockAmount; ] += lockAmount;
} else { } else {
userRecord[_castAddrToKey(msg.sender)] userRecord[_castAddrToKey(msg.sender)] += (l
+= (l.relayerPremium + lockAmount); .relayerPremium + lockAmount);
} }
SafeTransferLib.safeTransfer( SafeTransferLib.safeTransfer(
@ -424,11 +372,7 @@ contract P2PIX is
} }
} }
emit LockReleased( emit LockReleased(l.buyerAddress, lockID, lockAmount);
l.buyerAddress,
lockID,
lockAmount
);
} }
/// @notice Unlocks expired locks. /// @notice Unlocks expired locks.
@ -444,42 +388,34 @@ contract P2PIX is
uint256 locksSize = lockIDs.length; uint256 locksSize = lockIDs.length;
for (i; i < locksSize; ) { for (i; i < locksSize; ) {
DT.Lock storage l = DT.Lock storage l = mapLocks[lockIDs[i]];
mapLocks[lockIDs[i]];
_notExpired(l); _notExpired(l);
uint256 _sellerBalance = uint256 _sellerBalance = sellerBalance[
sellerBalance[ l.sellerKey
l.sellerKey][ERC20(l.token) ][ERC20(l.token)] & BITMASK_SB_ENTRY;
] & BITMASK_SB_ENTRY;
if ( if ((_sellerBalance + l.amount) > 1e8 ether)
(_sellerBalance + l.amount)
> 1e8 ether
)
revert MaxBalExceeded(); revert MaxBalExceeded();
sellerBalance[ sellerBalance[l.sellerKey][ERC20(l.token)] += l
l.sellerKey][ERC20(l.token) .amount;
] += l.amount;
l.amount = 0; l.amount = 0;
uint256 userKey = uint256 userKey = _castAddrToKey(
_castAddrToKey(l.relayerAddress); l.relayerAddress
uint256 _newUserRecord = );
(userRecord[userKey] >> 1); uint256 _newUserRecord = (userRecord[userKey] >>
1);
if (_newUserRecord <= 1e2 ether) { if (_newUserRecord <= 1e2 ether) {
userRecord[userKey] = 1e2 ether; userRecord[userKey] = 1e2 ether;
} else { } else {
userRecord[userKey] = _newUserRecord; userRecord[userKey] = _newUserRecord;
} }
emit LockReturned( emit LockReturned(l.buyerAddress, lockIDs[i]);
l.buyerAddress,
lockIDs[i]
);
unchecked { unchecked {
++i; ++i;
@ -503,23 +439,16 @@ contract P2PIX is
ERC20 token, ERC20 token,
uint256 amount, uint256 amount,
uint256[] calldata expiredLocks uint256[] calldata expiredLocks
) ) public nonReentrant {
public
nonReentrant
{
unlockExpired(expiredLocks); unlockExpired(expiredLocks);
if (getValid(msg.sender, token) if (getValid(msg.sender, token) == true) {
== true
) {
setValidState(token, false); setValidState(token, false);
} }
uint256 key = uint256 key = _castAddrToKey(msg.sender);
_castAddrToKey(msg.sender);
_decBal( _decBal(
(sellerBalance[key][token] (sellerBalance[key][token] & BITMASK_SB_ENTRY),
& BITMASK_SB_ENTRY),
amount, amount,
token, token,
key key
@ -785,7 +714,11 @@ contract P2PIX is
// sellerBalance[_castAddrToKey(seller)][token] & // sellerBalance[_castAddrToKey(seller)][token] &
// BITMASK_SB_ENTRY; // BITMASK_SB_ENTRY;
assembly { assembly {
for {/* */} iszero(0x0) {/* */} { for {
/* */
} iszero(0x0) {
/* */
} {
mstore(0x00, shl(0xC, seller)) mstore(0x00, shl(0xC, seller))
mstore(0x20, sellerBalance.slot) mstore(0x20, sellerBalance.slot)
let sbkslot := keccak256(0x00, 0x40) let sbkslot := keccak256(0x00, 0x40)
@ -793,9 +726,11 @@ contract P2PIX is
mstore(0x20, sbkslot) mstore(0x20, sbkslot)
bal := and( bal := and(
BITMASK_SB_ENTRY, BITMASK_SB_ENTRY,
sload(keccak256(0x00,0x40) sload(keccak256(0x00, 0x40))
)) break )
}} break
}
}
} }
function getValid(address seller, ERC20 token) function getValid(address seller, ERC20 token)
@ -808,7 +743,11 @@ contract P2PIX is
// ][token]; // ][token];
// ] >> BITPOS_VALID) & BITMASK_SB_ENTRY; // ] >> BITPOS_VALID) & BITMASK_SB_ENTRY;
assembly { assembly {
for {/* */} iszero(0x0) {/* */} { for {
/* */
} iszero(0x0) {
/* */
} {
mstore(0x00, shl(0xC, seller)) mstore(0x00, shl(0xC, seller))
mstore(0x20, sellerBalance.slot) mstore(0x20, sellerBalance.slot)
let sbkslot := keccak256(0x00, 0x40) let sbkslot := keccak256(0x00, 0x40)
@ -818,9 +757,12 @@ contract P2PIX is
BITMASK_SB_ENTRY, BITMASK_SB_ENTRY,
shr( shr(
BITPOS_VALID, BITPOS_VALID,
sload(keccak256(0x00,0x40) sload(keccak256(0x00, 0x40))
))) break )
}} )
break
}
}
} }
function getPixTarget(address seller, ERC20 token) function getPixTarget(address seller, ERC20 token)
@ -833,7 +775,11 @@ contract P2PIX is
// BITPOS_PIXTARGET // BITPOS_PIXTARGET
// ); // );
assembly { assembly {
for {/* */} iszero(0) {/* */} { for {
/* */
} iszero(0) {
/* */
} {
mstore(0, shl(12, seller)) mstore(0, shl(12, seller))
mstore(32, sellerBalance.slot) mstore(32, sellerBalance.slot)
let sbkslot := keccak256(0, 64) let sbkslot := keccak256(0, 64)
@ -841,37 +787,80 @@ contract P2PIX is
mstore(32, sbkslot) mstore(32, sbkslot)
pixTarget := shr( pixTarget := shr(
BITPOS_PIXTARGET, BITPOS_PIXTARGET,
sload(keccak256(0,64) sload(keccak256(0, 64))
)) break )
}} break
}
}
} }
function getBalances( function getBalances(
address[] memory sellers, address[] memory sellers,
ERC20 token ERC20 token
) ) external view returns (uint256[] memory) {
external
view
returns(uint256[] memory)
{
uint256 j; uint256 j;
uint256 len = uint256 len = sellers.length;
sellers.length; uint256[] memory balances = new uint256[](len);
uint256[] memory balances =
new uint256[](len);
while (j < len) { while (j < len) {
uint256 bal = uint256 bal = getBalance(sellers[j], token);
getBalance(
sellers[j],
token
);
balances[j] = bal; balances[j] = bal;
unchecked { ++j; } unchecked {
++j;
}
} }
return balances; return balances;
} }
/// @notice External getter that returns the status of a lockIDs array.
/// @dev Call will not revert if provided with an empty array as parameter.
/// @dev Function sighash: 0x49ef8448
function getLocksStatus(uint256[] memory ids)
external
view
returns (uint256[] memory, DT.LockStatus[] memory)
{
if (ids.length == 0) {
uint256[] memory null1 = new uint256[](0);
DT.LockStatus[]
memory null2 = new DT.LockStatus[](0);
return (null1, null2);
}
uint256 c;
uint256 len = ids.length;
uint256[] memory sortedIDs = new uint256[](len);
DT.LockStatus[] memory status = new DT.LockStatus[](
len
);
unchecked {
for (c; c < len; ) {
if (mapLocks[ids[c]].sellerKey == 0x0) {
sortedIDs[c] = ids[c];
status[c] = type(DT.LockStatus).min;
++c;
} else if (mapLocks[ids[c]].amount == 0x0) {
sortedIDs[c] = ids[c];
status[c] = type(DT.LockStatus).max;
++c;
} else if (
mapLocks[ids[c]].expirationBlock <
block.number
) {
sortedIDs[c] = ids[c];
status[c] = DT.LockStatus.Expired;
++c;
} else {
sortedIDs[c] = ids[c];
status[c] = DT.LockStatus.Active;
++c;
}
}
}
return (sortedIDs, status);
}
/// @notice Public method that handles `address` /// @notice Public method that handles `address`
/// to `uint256` safe type casting. /// to `uint256` safe type casting.
/// @dev Function sighash: 0x4b2ae980. /// @dev Function sighash: 0x4b2ae980.

View File

@ -3,6 +3,6 @@
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
"0x70997970C51812dc3A010C7d01b50e0d17dc79C8" "0x70997970C51812dc3A010C7d01b50e0d17dc79C8"
], ],
"p2pix": "0xefa5cE4351cda51192509cf8De7d8881ADAE95DD", "p2pix": "0x2414817FF64A114d91eCFA16a834d3fCf69103d4",
"token": "0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00" "token": "0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00"
} }

View File

@ -3,6 +3,6 @@
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
"0x70997970C51812dc3A010C7d01b50e0d17dc79C8" "0x70997970C51812dc3A010C7d01b50e0d17dc79C8"
], ],
"p2pix": "0xA9258eBb157E4cf5e756b77FDD0DF09C2F73240b", "p2pix": "0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00",
"token": "0xC86042E9F2977C62Da8c9dDF7F9c40fde4796A29" "token": "0xC86042E9F2977C62Da8c9dDF7F9c40fde4796A29"
} }

View File

@ -44,7 +44,9 @@ function getChainConfig(
let jsonRpcUrl: string; let jsonRpcUrl: string;
switch (chain) { switch (chain) {
case "polygon-mumbai": case "polygon-mumbai":
jsonRpcUrl = "https://polygon-mumbai.g.alchemy.com/v2/" + alchemyApiKey; jsonRpcUrl =
"https://polygon-mumbai.g.alchemy.com/v2/" +
alchemyApiKey;
break; break;
default: default:
jsonRpcUrl = jsonRpcUrl =

View File

@ -64,7 +64,7 @@
"fs-extra": "^10.1.0", "fs-extra": "^10.1.0",
"hardhat": "^2.12.2", "hardhat": "^2.12.2",
"hardhat-gas-reporter": "^1.0.9", "hardhat-gas-reporter": "^1.0.9",
"hardhat-tracer": "^1.2.0", "hardhat-tracer": "beta",
"husky": "^8.0.1", "husky": "^8.0.1",
"keccak256": "^1.0.6", "keccak256": "^1.0.6",
"lint-staged": "^13.0.3", "lint-staged": "^13.0.3",

View File

@ -3,11 +3,10 @@ import "@nomiclabs/hardhat-etherscan";
import { BigNumber } from "ethers"; import { BigNumber } from "ethers";
import * as fs from "fs"; import * as fs from "fs";
import { ethers, network } from "hardhat"; import { ethers, network } from "hardhat";
import hre from "hardhat";
import { Deploys } from "../test/utils/fixtures"; import { Deploys } from "../test/utils/fixtures";
import hre from "hardhat";
let deploysJson: Deploys; let deploysJson: Deploys;
const supply: BigNumber = ethers.utils.parseEther("20000000"); const supply: BigNumber = ethers.utils.parseEther("20000000");

View File

@ -2,11 +2,10 @@ import "@nomiclabs/hardhat-ethers";
import "@nomiclabs/hardhat-etherscan"; import "@nomiclabs/hardhat-etherscan";
import * as fs from "fs"; import * as fs from "fs";
import { ethers, network } from "hardhat"; import { ethers, network } from "hardhat";
import hre from "hardhat";
import { Deploys } from "../test/utils/fixtures"; import { Deploys } from "../test/utils/fixtures";
import hre from "hardhat";
let deploysJson: Deploys; let deploysJson: Deploys;
const main = async () => { const main = async () => {
@ -27,8 +26,13 @@ const main = async () => {
const Reputation = await ethers.getContractFactory( const Reputation = await ethers.getContractFactory(
"Reputation", "Reputation",
); );
const Multicall = await ethers.getContractFactory(
"Multicall",
);
const reputation = await Reputation.deploy(); const reputation = await Reputation.deploy();
await reputation.deployed(); await reputation.deployed();
const mutlicall = await Multicall.deploy();
await mutlicall.deployed();
const P2PIX = await ethers.getContractFactory("P2PIX"); const P2PIX = await ethers.getContractFactory("P2PIX");
const p2pix = await P2PIX.deploy( const p2pix = await P2PIX.deploy(
@ -42,6 +46,8 @@ const main = async () => {
deploysJson.p2pix = p2pix.address; deploysJson.p2pix = p2pix.address;
console.log("🚀 P2PIX Deployed:", p2pix.address); console.log("🚀 P2PIX Deployed:", p2pix.address);
console.log("🌠 Reputation Deployed:", reputation.address);
console.log("🛰 Multicall Deployed:", mutlicall.address);
await p2pix.deployTransaction.wait(6); await p2pix.deployTransaction.wait(6);
fs.writeFileSync( fs.writeFileSync(
@ -53,8 +59,7 @@ const main = async () => {
//verify //verify
await hre.run("verify:verify", { await hre.run("verify:verify", {
address: p2pix.address, address: p2pix.address,
constructorArguments: constructorArguments: [
[
10, 10,
deploysJson.signers, deploysJson.signers,
reputation.address, reputation.address,
@ -66,6 +71,10 @@ const main = async () => {
address: reputation.address, address: reputation.address,
constructorArguments: [], constructorArguments: [],
}); });
await hre.run("verify:verify", {
address: mutlicall.address,
constructorArguments: [],
});
}; };
main() main()

View File

@ -263,12 +263,6 @@ const _abi = [
name: "amount", name: "amount",
type: "uint256", type: "uint256",
}, },
{
indexed: false,
internalType: "uint256",
name: "amount",
type: "uint256",
},
], ],
name: "LockReleased", name: "LockReleased",
type: "event", type: "event",

View File

@ -0,0 +1,174 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import {
Signer,
utils,
Contract,
ContractFactory,
PayableOverrides,
} from "ethers";
import type { Provider, TransactionRequest } from "@ethersproject/providers";
import type { PromiseOrValue } from "../../../common";
import type {
Multicall,
MulticallInterface,
} from "../../../lib/utils/Multicall";
const _abi = [
{
inputs: [],
stateMutability: "payable",
type: "constructor",
},
{
inputs: [
{
internalType: "string",
name: "reason",
type: "string",
},
],
name: "CallFailed",
type: "error",
},
{
inputs: [
{
components: [
{
internalType: "address",
name: "target",
type: "address",
},
{
internalType: "bytes",
name: "callData",
type: "bytes",
},
],
internalType: "struct Multicall.Call[]",
name: "calls",
type: "tuple[]",
},
],
name: "mtc1",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
{
internalType: "bytes[]",
name: "",
type: "bytes[]",
},
],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
components: [
{
internalType: "address",
name: "target",
type: "address",
},
{
internalType: "bytes",
name: "callData",
type: "bytes",
},
],
internalType: "struct Multicall.Call[]",
name: "calls",
type: "tuple[]",
},
],
name: "mtc2",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
{
internalType: "bytes32",
name: "",
type: "bytes32",
},
{
components: [
{
internalType: "bool",
name: "success",
type: "bool",
},
{
internalType: "bytes",
name: "returnData",
type: "bytes",
},
],
internalType: "struct Multicall.Result[]",
name: "",
type: "tuple[]",
},
],
stateMutability: "nonpayable",
type: "function",
},
];
const _bytecode =
"0x60806040526108ec806100136000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80631b57b72f1461003b57806386575ee914610066575b600080fd5b61004e610049366004610438565b610087565b60405161005d93929190610527565b60405180910390f35b610079610074366004610438565b610227565b60405161005d9291906105cb565b600080606043804085848167ffffffffffffffff8111156100aa576100aa610653565b6040519080825280602002602001820160405280156100f057816020015b6040805180820190915260008152606060208201528152602001906001900390816100c85790505b50905060005b82811015610217576000808b8b8481811061011357610113610682565b905060200281019061012591906106b1565b6101339060208101906106ef565b73ffffffffffffffffffffffffffffffffffffffff168c8c8581811061015b5761015b610682565b905060200281019061016d91906106b1565b61017b90602081019061072c565b604051610189929190610791565b6000604051808303816000865af19150503d80600081146101c6576040519150601f19603f3d011682016040523d82523d6000602084013e6101cb565b606091505b509150915060405180604001604052808315158152602001828152508484815181106101f9576101f9610682565b60200260200101819052508261020e906107a1565b925050506100f6565b5092989197509195509350505050565b600060604383838167ffffffffffffffff81111561024757610247610653565b60405190808252806020026020018201604052801561027a57816020015b60608152602001906001900390816102655790505b50905060005b828110156104285760008089898481811061029d5761029d610682565b90506020028101906102af91906106b1565b6102bd9060208101906106ef565b73ffffffffffffffffffffffffffffffffffffffff168a8a858181106102e5576102e5610682565b90506020028101906102f791906106b1565b61030590602081019061072c565b604051610313929190610791565b6000604051808303816000865af19150503d8060008114610350576040519150601f19603f3d011682016040523d82523d6000602084013e610355565b606091505b5091509150816103f7576044815110156103aa576040517fb5e1dc2d00000000000000000000000000000000000000000000000000000000815260206004820152600060248201526044015b60405180910390fd5b600481019050808060200190518101906103c49190610801565b6040517fb5e1dc2d0000000000000000000000000000000000000000000000000000000081526004016103a191906108cc565b8084848151811061040a5761040a610682565b60200260200101819052508261041f906107a1565b92505050610280565b50919350909150505b9250929050565b6000806020838503121561044b57600080fd5b823567ffffffffffffffff8082111561046357600080fd5b818501915085601f83011261047757600080fd5b81358181111561048657600080fd5b8660208260051b850101111561049b57600080fd5b60209290920196919550909350505050565b60005b838110156104c85781810151838201526020016104b0565b838111156104d7576000848401525b50505050565b600081518084526104f58160208601602086016104ad565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60006060820185835260208581850152604060608186015282865180855260808701915060808160051b880101945083880160005b828110156105bb578887037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8001845281518051151588528601518688018690526105a8868901826104dd565b975050928501929085019060010161055c565b50949a9950505050505050505050565b600060408201848352602060408185015281855180845260608601915060608160051b870101935082870160005b82811015610645577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08887030184526106338683516104dd565b955092840192908401906001016105f9565b509398975050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18336030181126106e557600080fd5b9190910192915050565b60006020828403121561070157600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461072557600080fd5b9392505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261076157600080fd5b83018035915067ffffffffffffffff82111561077c57600080fd5b60200191503681900382131561043157600080fd5b8183823760009101908152919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156107fa577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b60006020828403121561081357600080fd5b815167ffffffffffffffff8082111561082b57600080fd5b818401915084601f83011261083f57600080fd5b81518181111561085157610851610653565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561089757610897610653565b816040528281528760208487010111156108b057600080fd5b6108c18360208301602088016104ad565b979650505050505050565b60208152600061072560208301846104dd56fea164736f6c6343000809000a";
type MulticallConstructorParams =
| [signer?: Signer]
| ConstructorParameters<typeof ContractFactory>;
const isSuperArgs = (
xs: MulticallConstructorParams
): xs is ConstructorParameters<typeof ContractFactory> => xs.length > 1;
export class Multicall__factory extends ContractFactory {
constructor(...args: MulticallConstructorParams) {
if (isSuperArgs(args)) {
super(...args);
} else {
super(_abi, _bytecode, args[0]);
}
}
override deploy(
overrides?: PayableOverrides & { from?: PromiseOrValue<string> }
): Promise<Multicall> {
return super.deploy(overrides || {}) as Promise<Multicall>;
}
override getDeployTransaction(
overrides?: PayableOverrides & { from?: PromiseOrValue<string> }
): TransactionRequest {
return super.getDeployTransaction(overrides || {});
}
override attach(address: string): Multicall {
return super.attach(address) as Multicall;
}
override connect(signer: Signer): Multicall__factory {
return super.connect(signer) as Multicall__factory;
}
static readonly bytecode = _bytecode;
static readonly abi = _abi;
static createInterface(): MulticallInterface {
return new utils.Interface(_abi) as MulticallInterface;
}
static connect(
address: string,
signerOrProvider: Signer | Provider
): Multicall {
return new Contract(address, _abi, signerOrProvider) as Multicall;
}
}

View File

@ -1,4 +1,5 @@
/* Autogenerated file. Do not edit manually. */ /* Autogenerated file. Do not edit manually. */
/* tslint:disable */ /* tslint:disable */
/* eslint-disable */ /* eslint-disable */
export { Multicall__factory } from "./Multicall__factory";
export { ReentrancyGuard__factory } from "./ReentrancyGuard__factory"; export { ReentrancyGuard__factory } from "./ReentrancyGuard__factory";

File diff suppressed because one or more lines are too long

View File

@ -32,6 +32,10 @@ declare module "hardhat/types/runtime" {
name: "ERC20", name: "ERC20",
signerOrOptions?: ethers.Signer | FactoryOptions signerOrOptions?: ethers.Signer | FactoryOptions
): Promise<Contracts.ERC20__factory>; ): Promise<Contracts.ERC20__factory>;
getContractFactory(
name: "Multicall",
signerOrOptions?: ethers.Signer | FactoryOptions
): Promise<Contracts.Multicall__factory>;
getContractFactory( getContractFactory(
name: "ReentrancyGuard", name: "ReentrancyGuard",
signerOrOptions?: ethers.Signer | FactoryOptions signerOrOptions?: ethers.Signer | FactoryOptions
@ -70,6 +74,11 @@ declare module "hardhat/types/runtime" {
address: string, address: string,
signer?: ethers.Signer signer?: ethers.Signer
): Promise<Contracts.ERC20>; ): Promise<Contracts.ERC20>;
getContractAt(
name: "Multicall",
address: string,
signer?: ethers.Signer
): Promise<Contracts.Multicall>;
getContractAt( getContractAt(
name: "ReentrancyGuard", name: "ReentrancyGuard",
address: string, address: string,

View File

@ -17,6 +17,8 @@ export type { MockToken } from "./lib/mock/mockToken.sol/MockToken";
export { MockToken__factory } from "./factories/lib/mock/mockToken.sol/MockToken__factory"; export { MockToken__factory } from "./factories/lib/mock/mockToken.sol/MockToken__factory";
export type { ERC20 } from "./lib/tokens/ERC20"; export type { ERC20 } from "./lib/tokens/ERC20";
export { ERC20__factory } from "./factories/lib/tokens/ERC20__factory"; export { ERC20__factory } from "./factories/lib/tokens/ERC20__factory";
export type { Multicall } from "./lib/utils/Multicall";
export { Multicall__factory } from "./factories/lib/utils/Multicall__factory";
export type { ReentrancyGuard } from "./lib/utils/ReentrancyGuard"; export type { ReentrancyGuard } from "./lib/utils/ReentrancyGuard";
export { ReentrancyGuard__factory } from "./factories/lib/utils/ReentrancyGuard__factory"; export { ReentrancyGuard__factory } from "./factories/lib/utils/ReentrancyGuard__factory";
export type { P2PIX } from "./p2pix.sol/P2PIX"; export type { P2PIX } from "./p2pix.sol/P2PIX";

View File

@ -0,0 +1,155 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type {
BaseContract,
BigNumber,
BytesLike,
CallOverrides,
ContractTransaction,
Overrides,
PopulatedTransaction,
Signer,
utils,
} from "ethers";
import type { FunctionFragment, Result } from "@ethersproject/abi";
import type { Listener, Provider } from "@ethersproject/providers";
import type {
TypedEventFilter,
TypedEvent,
TypedListener,
OnEvent,
PromiseOrValue,
} from "../../common";
export declare namespace Multicall {
export type CallStruct = {
target: PromiseOrValue<string>;
callData: PromiseOrValue<BytesLike>;
};
export type CallStructOutput = [string, string] & {
target: string;
callData: string;
};
export type ResultStruct = {
success: PromiseOrValue<boolean>;
returnData: PromiseOrValue<BytesLike>;
};
export type ResultStructOutput = [boolean, string] & {
success: boolean;
returnData: string;
};
}
export interface MulticallInterface extends utils.Interface {
functions: {
"mtc1((address,bytes)[])": FunctionFragment;
"mtc2((address,bytes)[])": FunctionFragment;
};
getFunction(nameOrSignatureOrTopic: "mtc1" | "mtc2"): FunctionFragment;
encodeFunctionData(
functionFragment: "mtc1",
values: [Multicall.CallStruct[]]
): string;
encodeFunctionData(
functionFragment: "mtc2",
values: [Multicall.CallStruct[]]
): string;
decodeFunctionResult(functionFragment: "mtc1", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "mtc2", data: BytesLike): Result;
events: {};
}
export interface Multicall extends BaseContract {
connect(signerOrProvider: Signer | Provider | string): this;
attach(addressOrName: string): this;
deployed(): Promise<this>;
interface: MulticallInterface;
queryFilter<TEvent extends TypedEvent>(
event: TypedEventFilter<TEvent>,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TEvent>>;
listeners<TEvent extends TypedEvent>(
eventFilter?: TypedEventFilter<TEvent>
): Array<TypedListener<TEvent>>;
listeners(eventName?: string): Array<Listener>;
removeAllListeners<TEvent extends TypedEvent>(
eventFilter: TypedEventFilter<TEvent>
): this;
removeAllListeners(eventName?: string): this;
off: OnEvent<this>;
on: OnEvent<this>;
once: OnEvent<this>;
removeListener: OnEvent<this>;
functions: {
mtc1(
calls: Multicall.CallStruct[],
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<ContractTransaction>;
mtc2(
calls: Multicall.CallStruct[],
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<ContractTransaction>;
};
mtc1(
calls: Multicall.CallStruct[],
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<ContractTransaction>;
mtc2(
calls: Multicall.CallStruct[],
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<ContractTransaction>;
callStatic: {
mtc1(
calls: Multicall.CallStruct[],
overrides?: CallOverrides
): Promise<[BigNumber, string[]]>;
mtc2(
calls: Multicall.CallStruct[],
overrides?: CallOverrides
): Promise<[BigNumber, string, Multicall.ResultStructOutput[]]>;
};
filters: {};
estimateGas: {
mtc1(
calls: Multicall.CallStruct[],
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<BigNumber>;
mtc2(
calls: Multicall.CallStruct[],
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<BigNumber>;
};
populateTransaction: {
mtc1(
calls: Multicall.CallStruct[],
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<PopulatedTransaction>;
mtc2(
calls: Multicall.CallStruct[],
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<PopulatedTransaction>;
};
}

View File

@ -1,4 +1,5 @@
/* Autogenerated file. Do not edit manually. */ /* Autogenerated file. Do not edit manually. */
/* tslint:disable */ /* tslint:disable */
/* eslint-disable */ /* eslint-disable */
export type { Multicall } from "./Multicall";
export type { ReentrancyGuard } from "./ReentrancyGuard"; export type { ReentrancyGuard } from "./ReentrancyGuard";

View File

@ -37,6 +37,7 @@ export interface P2PIXInterface extends utils.Interface {
"deposit(address,uint96,uint160,bool,bytes32)": FunctionFragment; "deposit(address,uint96,uint160,bool,bytes32)": FunctionFragment;
"getBalance(address,address)": FunctionFragment; "getBalance(address,address)": FunctionFragment;
"getBalances(address[],address)": FunctionFragment; "getBalances(address[],address)": FunctionFragment;
"getLocksStatus(uint256[])": FunctionFragment;
"getPixTarget(address,address)": FunctionFragment; "getPixTarget(address,address)": FunctionFragment;
"getValid(address,address)": FunctionFragment; "getValid(address,address)": FunctionFragment;
"lock(address,address,address,address,uint256,uint256,bytes32[],uint256[])": FunctionFragment; "lock(address,address,address,address,uint256,uint256,bytes32[],uint256[])": FunctionFragment;
@ -72,6 +73,7 @@ export interface P2PIXInterface extends utils.Interface {
| "deposit" | "deposit"
| "getBalance" | "getBalance"
| "getBalances" | "getBalances"
| "getLocksStatus"
| "getPixTarget" | "getPixTarget"
| "getValid" | "getValid"
| "lock" | "lock"
@ -132,6 +134,10 @@ export interface P2PIXInterface extends utils.Interface {
functionFragment: "getBalances", functionFragment: "getBalances",
values: [PromiseOrValue<string>[], PromiseOrValue<string>] values: [PromiseOrValue<string>[], PromiseOrValue<string>]
): string; ): string;
encodeFunctionData(
functionFragment: "getLocksStatus",
values: [PromiseOrValue<BigNumberish>[]]
): string;
encodeFunctionData( encodeFunctionData(
functionFragment: "getPixTarget", functionFragment: "getPixTarget",
values: [PromiseOrValue<string>, PromiseOrValue<string>] values: [PromiseOrValue<string>, PromiseOrValue<string>]
@ -265,6 +271,10 @@ export interface P2PIXInterface extends utils.Interface {
functionFragment: "getBalances", functionFragment: "getBalances",
data: BytesLike data: BytesLike
): Result; ): Result;
decodeFunctionResult(
functionFragment: "getLocksStatus",
data: BytesLike
): Result;
decodeFunctionResult( decodeFunctionResult(
functionFragment: "getPixTarget", functionFragment: "getPixTarget",
data: BytesLike data: BytesLike
@ -577,6 +587,11 @@ export interface P2PIX extends BaseContract {
overrides?: CallOverrides overrides?: CallOverrides
): Promise<[BigNumber[]]>; ): Promise<[BigNumber[]]>;
getLocksStatus(
ids: PromiseOrValue<BigNumberish>[],
overrides?: CallOverrides
): Promise<[BigNumber[], number[]]>;
getPixTarget( getPixTarget(
seller: PromiseOrValue<string>, seller: PromiseOrValue<string>,
token: PromiseOrValue<string>, token: PromiseOrValue<string>,
@ -767,6 +782,11 @@ export interface P2PIX extends BaseContract {
overrides?: CallOverrides overrides?: CallOverrides
): Promise<BigNumber[]>; ): Promise<BigNumber[]>;
getLocksStatus(
ids: PromiseOrValue<BigNumberish>[],
overrides?: CallOverrides
): Promise<[BigNumber[], number[]]>;
getPixTarget( getPixTarget(
seller: PromiseOrValue<string>, seller: PromiseOrValue<string>,
token: PromiseOrValue<string>, token: PromiseOrValue<string>,
@ -957,6 +977,11 @@ export interface P2PIX extends BaseContract {
overrides?: CallOverrides overrides?: CallOverrides
): Promise<BigNumber[]>; ): Promise<BigNumber[]>;
getLocksStatus(
ids: PromiseOrValue<BigNumberish>[],
overrides?: CallOverrides
): Promise<[BigNumber[], number[]]>;
getPixTarget( getPixTarget(
seller: PromiseOrValue<string>, seller: PromiseOrValue<string>,
token: PromiseOrValue<string>, token: PromiseOrValue<string>,
@ -1257,6 +1282,11 @@ export interface P2PIX extends BaseContract {
overrides?: CallOverrides overrides?: CallOverrides
): Promise<BigNumber>; ): Promise<BigNumber>;
getLocksStatus(
ids: PromiseOrValue<BigNumberish>[],
overrides?: CallOverrides
): Promise<BigNumber>;
getPixTarget( getPixTarget(
seller: PromiseOrValue<string>, seller: PromiseOrValue<string>,
token: PromiseOrValue<string>, token: PromiseOrValue<string>,
@ -1424,6 +1454,11 @@ export interface P2PIX extends BaseContract {
overrides?: CallOverrides overrides?: CallOverrides
): Promise<PopulatedTransaction>; ): Promise<PopulatedTransaction>;
getLocksStatus(
ids: PromiseOrValue<BigNumberish>[],
overrides?: CallOverrides
): Promise<PopulatedTransaction>;
getPixTarget( getPixTarget(
seller: PromiseOrValue<string>, seller: PromiseOrValue<string>,
token: PromiseOrValue<string>, token: PromiseOrValue<string>,

View File

@ -23,19 +23,73 @@ describe("Reputation", () => {
({ reputation } = await loadFixture(repFixture)); ({ reputation } = await loadFixture(repFixture));
}); });
// describe("Limiter", async () => {
// it("Curve reliability", async () => {
// const tx1 = await reputation.connect(owner).limiter(0);
// const tx2 = await reputation.limiter(500);
// const tx3 = await reputation
// .connect(owner)
// .limiter(444444);
// const tx4 = await reputation.limiter(988700);
// expect(tx1).to.eq(curve(0));
// expect(tx2).to.eq(curve(500));
// expect(tx3).to.eq(curve(444444));
// expect(tx4).to.eq(curve(988700));
// });
// });
describe("Limiter", async () => { describe("Limiter", async () => {
it("Curve reliability", async () => { it("Curve reliability", async () => {
const tx1 = await reputation.connect(owner).limiter(0); const testCases = [
const tx2 = await reputation.limiter(500); {
const tx3 = await reputation x: 0,
.connect(owner) expected: curve(0),
.limiter(444444); },
const tx4 = await reputation.limiter(988700); {
x: 500,
expected: curve(500),
},
{
x: 444444,
expected: curve(444444),
},
{
x: 988700,
expected: curve(988700),
},
{
x: Number.MAX_SAFE_INTEGER,
shouldRevert: "overflow",
},
{
x: Number.POSITIVE_INFINITY,
shouldRevert: "overflow",
},
{
x: Number.NEGATIVE_INFINITY,
shouldRevert: "overflow",
},
{
x: -1,
shouldRevert: "value out-of-bounds",
},
{
x: Number.NaN,
shouldRevert: "invalid BigNumber string",
},
];
expect(tx1).to.eq(curve(0)); for (const testCase of testCases) {
expect(tx2).to.eq(curve(500)); if (testCase.shouldRevert != undefined) {
expect(tx3).to.eq(curve(444444)); await expect(reputation.limiter(testCase.x)).to.be
expect(tx4).to.eq(curve(988700)); .rejected;
} else {
const result = await reputation.limiter(testCase.x);
expect(result).to.eq(testCase.expected).and.to.be
.ok;
}
}
}); });
}); });
}); });

View File

@ -7,6 +7,7 @@ import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
import { expect } from "chai"; import { expect } from "chai";
import { import {
BigNumber, BigNumber,
BytesLike,
ContractReceipt, ContractReceipt,
ContractTransaction, ContractTransaction,
Wallet, Wallet,
@ -17,12 +18,19 @@ import {
/* tracer */ /* tracer */
} from "hardhat"; } from "hardhat";
// import keccak256 from "keccak256"; import {
import { MockToken, P2PIX, Reputation } from "../src/types"; MockToken,
Multicall,
P2PIX,
Reputation,
} from "../src/types";
import { P2PixErrors } from "./utils/errors"; import { P2PixErrors } from "./utils/errors";
import { import {
// Deposit, Call,
Lock, Lock,
Result,
getBnFrom,
getLockData,
getSignerAddrs, getSignerAddrs,
p2pixFixture, p2pixFixture,
randomSigners, randomSigners,
@ -45,6 +53,7 @@ describe("P2PIX", () => {
let p2pix: P2PIX; // Contract instance let p2pix: P2PIX; // Contract instance
let erc20: MockToken; // Token instance let erc20: MockToken; // Token instance
let reputation: Reputation; // Reputation Interface instance let reputation: Reputation; // Reputation Interface instance
let multicall: Multicall; // Multicall contract instance
let merkleRoot: string; // MerkleRoot from seller's allowlist let merkleRoot: string; // MerkleRoot from seller's allowlist
let proof: string[]; // Owner's proof as whitelisted address let proof: string[]; // Owner's proof as whitelisted address
@ -62,8 +71,14 @@ describe("P2PIX", () => {
await network.provider.send("hardhat_reset"); await network.provider.send("hardhat_reset");
}); });
beforeEach("Load deployment fixtures", async () => { beforeEach("Load deployment fixtures", async () => {
({ erc20, p2pix, reputation, merkleRoot, proof } = ({
await loadFixture(p2pixFixture)); erc20,
p2pix,
reputation,
multicall,
merkleRoot,
proof,
} = await loadFixture(p2pixFixture));
}); });
describe("Init", async () => { describe("Init", async () => {
@ -234,11 +249,22 @@ describe("P2PIX", () => {
await p2pix.callStatic.allowedERC20s(erc20.address); await p2pix.callStatic.allowedERC20s(erc20.address);
const newTokenState2 = const newTokenState2 =
await p2pix.callStatic.allowedERC20s(owner.address); await p2pix.callStatic.allowedERC20s(owner.address);
const funcSig = "0xd6e8b973";
const args = ethers.utils.defaultAbiCoder.encode(
["address[]", "bool[]"],
[[acc01.address], [false]],
);
const cd = funcSig + args.substring(2);
const callStruct: Call = {
target: p2pix.address,
callData: cd,
};
const fail = p2pix const fail = p2pix
.connect(acc01) .connect(acc01)
.tokenSettings([acc01.address], [false]); .tokenSettings([acc01.address], [false]);
const fail2 = p2pix.tokenSettings([], [true, false]); const fail2 = p2pix.tokenSettings([], [true, false]);
const fail3 = p2pix.tokenSettings([zero], [true, true]); const fail3 = p2pix.tokenSettings([zero], [true, true]);
const mtcFail = multicall.mtc1([callStruct]);
expect(tx).to.be.ok; expect(tx).to.be.ok;
await expect(tx) await expect(tx)
@ -262,6 +288,12 @@ describe("P2PIX", () => {
p2pix, p2pix,
P2PixErrors.LengthMismatch, P2PixErrors.LengthMismatch,
); );
await expect(mtcFail)
.to.be.revertedWithCustomError(
multicall,
P2PixErrors.CallFailed,
)
.withArgs(P2PixErrors.UNAUTHORIZED);
}); });
}); });
describe("Deposit", async () => { describe("Deposit", async () => {
@ -330,9 +362,18 @@ describe("P2PIX", () => {
true, true,
root, root,
); );
const storage = await p2pix.callStatic.getBalance(owner.address, erc20.address); const storage = await p2pix.callStatic.getBalance(
const pixTarget = await p2pix.callStatic.getPixTarget(owner.address,erc20.address); owner.address,
const valid = await p2pix.callStatic.getValid(owner.address,erc20.address); erc20.address,
);
const pixTarget = await p2pix.callStatic.getPixTarget(
owner.address,
erc20.address,
);
const valid = await p2pix.callStatic.getValid(
owner.address,
erc20.address,
);
const ownerKey = await p2pix.callStatic._castAddrToKey( const ownerKey = await p2pix.callStatic._castAddrToKey(
owner.address, owner.address,
); );
@ -385,7 +426,12 @@ describe("P2PIX", () => {
const price2 = price.mul(ethers.BigNumber.from(2)); const price2 = price.mul(ethers.BigNumber.from(2));
const price3 = price.mul(ethers.BigNumber.from(3)); const price3 = price.mul(ethers.BigNumber.from(3));
const price4 = price.mul(ethers.BigNumber.from(4)); const price4 = price.mul(ethers.BigNumber.from(4));
const prices:BigNumber[] = [price, price2, price3, price4]; const prices: BigNumber[] = [
price,
price2,
price3,
price4,
];
await erc20.mint( await erc20.mint(
getSignerAddrs(4, await ethers.getSigners()), getSignerAddrs(4, await ethers.getSigners()),
price4, price4,
@ -408,31 +454,86 @@ describe("P2PIX", () => {
.deposit(erc20.address, price, pTarget, true, root); .deposit(erc20.address, price, pTarget, true, root);
const tx2 = await p2pix const tx2 = await p2pix
.connect(acc01) .connect(acc01)
.deposit(erc20.address, price2, pTarget2, false, nullRoot); .deposit(
erc20.address,
price2,
pTarget2,
false,
nullRoot,
);
const tx3 = await p2pix const tx3 = await p2pix
.connect(acc02) .connect(acc02)
.deposit(erc20.address, price3, pTarget3, true, root); .deposit(erc20.address, price3, pTarget3, true, root);
const tx4 = await p2pix const tx4 = await p2pix
.connect(acc03) .connect(acc03)
.deposit(erc20.address, price4, pTarget, false, nullRoot); .deposit(
erc20.address,
price4,
pTarget,
false,
nullRoot,
);
const balances = await p2pix.callStatic.getBalances( const balances = await p2pix.callStatic.getBalances(
[owner.address, acc01.address, acc02.address, acc03.address], erc20.address); [
owner.address,
acc01.address,
acc02.address,
acc03.address,
],
erc20.address,
);
const storage1 = await p2pix.callStatic.getBalance(owner.address, erc20.address); const storage1 = await p2pix.callStatic.getBalance(
const storage2 = await p2pix.callStatic.getBalance(acc01.address, erc20.address); owner.address,
const storage3 = await p2pix.callStatic.getBalance(acc02.address, erc20.address); erc20.address,
const storage4 = await p2pix.callStatic.getBalance(acc03.address, erc20.address); );
const storage2 = await p2pix.callStatic.getBalance(
acc01.address,
erc20.address,
);
const storage3 = await p2pix.callStatic.getBalance(
acc02.address,
erc20.address,
);
const storage4 = await p2pix.callStatic.getBalance(
acc03.address,
erc20.address,
);
const pixTarget1 = await p2pix.callStatic.getPixTarget(owner.address, erc20.address); const pixTarget1 = await p2pix.callStatic.getPixTarget(
const pixTarget2 = await p2pix.callStatic.getPixTarget(acc01.address, erc20.address); owner.address,
const pixTarget3 = await p2pix.callStatic.getPixTarget(acc02.address, erc20.address); erc20.address,
const pixTarget4 = await p2pix.callStatic.getPixTarget(acc03.address, erc20.address); );
const pixTarget2 = await p2pix.callStatic.getPixTarget(
acc01.address,
erc20.address,
);
const pixTarget3 = await p2pix.callStatic.getPixTarget(
acc02.address,
erc20.address,
);
const pixTarget4 = await p2pix.callStatic.getPixTarget(
acc03.address,
erc20.address,
);
const valid1 = await p2pix.callStatic.getValid(owner.address, erc20.address); const valid1 = await p2pix.callStatic.getValid(
const valid2 = await p2pix.callStatic.getValid(acc01.address, erc20.address); owner.address,
const valid3 = await p2pix.callStatic.getValid(acc02.address, erc20.address); erc20.address,
const valid4 = await p2pix.callStatic.getValid(acc03.address, erc20.address); );
const valid2 = await p2pix.callStatic.getValid(
acc01.address,
erc20.address,
);
const valid3 = await p2pix.callStatic.getValid(
acc02.address,
erc20.address,
);
const valid4 = await p2pix.callStatic.getValid(
acc03.address,
erc20.address,
);
const allowList1 = await p2pix.sellerAllowList( const allowList1 = await p2pix.sellerAllowList(
ownerKey, ownerKey,
@ -452,41 +553,30 @@ describe("P2PIX", () => {
expect(tx3).to.be.ok; expect(tx3).to.be.ok;
expect(tx4).to.be.ok; expect(tx4).to.be.ok;
const transactions = [tx, tx2, tx3, tx4];
const addresses = [
owner.address,
acc01.address,
acc02.address,
acc03.address,
];
const depositPrices = [price, price2, price3, price4];
for (let i = 0; i < transactions.length; i++) {
const tx = transactions[i];
const addr = addresses[i];
const depositPrice = depositPrices[i];
const amount = `-${(i + 1) * 100000000000000000000}`;
await expect(tx) await expect(tx)
.to.emit(p2pix, "DepositAdded") .to.emit(p2pix, "DepositAdded")
.withArgs(owner.address, erc20.address, price); .withArgs(addr, erc20.address, depositPrice);
await expect(tx).to.changeTokenBalances( await expect(tx).to.changeTokenBalances(
erc20, erc20,
[owner.address, p2pix.address], [addr, p2pix.address],
["-100000000000000000000", price], [amount, depositPrice],
);
await expect(tx2)
.to.emit(p2pix, "DepositAdded")
.withArgs(acc01.address, erc20.address, price2);
await expect(tx2).to.changeTokenBalances(
erc20,
[acc01.address, p2pix.address],
["-200000000000000000000", price2],
);
await expect(tx3)
.to.emit(p2pix, "DepositAdded")
.withArgs(acc02.address, erc20.address, price3);
await expect(tx3).to.changeTokenBalances(
erc20,
[acc02.address, p2pix.address],
["-300000000000000000000", price3],
);
await expect(tx4)
.to.emit(p2pix, "DepositAdded")
.withArgs(acc03.address, erc20.address, price4);
await expect(tx4).to.changeTokenBalances(
erc20,
[acc03.address, p2pix.address],
["-400000000000000000000", price4],
); );
}
expect(prices[0]).to.eq(balances[0]); expect(prices[0]).to.eq(balances[0]);
expect(prices[1]).to.eq(balances[1]); expect(prices[1]).to.eq(balances[1]);
@ -586,36 +676,7 @@ describe("P2PIX", () => {
P2PixErrors.NotEnoughTokens, P2PixErrors.NotEnoughTokens,
); );
}); });
// test invalid since lockID has been replaced by a counter.
// it.only("should revert if a non expired lock has the same ID encoded", async () => {
// const pTarget = ethers.BigNumber.from(1337);
// await erc20.approve(p2pix.address, price);
// await p2pix.deposit(
// erc20.address,
// price,
// pTarget,
// true,
// ethers.constants.HashZero,
// );
// await p2pix
// .connect(acc03)
// .lock(
// owner.address,
// erc20.address,
// acc02.address,
// acc03.address,
// 0, 1, [], []);
// console.log(await p2pix.callStatic.getValid(owner.address,erc20.address))
// const fail = p2pix
// .connect(acc03)
// .lock(owner.address, erc20.address, acc02.address, acc03.address, 0, 1, [], []);
// await expect(fail).to.be.revertedWithCustomError(
// p2pix,
// P2PixErrors.NotExpired,
// );
// });
it("should revert if an invalid allowlist merkleproof is provided", async () => { it("should revert if an invalid allowlist merkleproof is provided", async () => {
await erc20.approve(p2pix.address, price); await erc20.approve(p2pix.address, price);
await p2pix.deposit( await p2pix.deposit(
@ -699,11 +760,15 @@ describe("P2PIX", () => {
proof, proof,
[], [],
); );
const storage: Lock = await p2pix.callStatic.mapLocks(1); const storage: Lock = await p2pix.callStatic.mapLocks(
1,
);
const rc: ContractReceipt = await tx.wait(); const rc: ContractReceipt = await tx.wait();
const expiration = rc.blockNumber + 10; const expiration = rc.blockNumber + 10;
const key = await p2pix.callStatic._castAddrToKey(owner.address); const key = await p2pix.callStatic._castAddrToKey(
owner.address,
);
await expect(tx) await expect(tx)
.to.emit(p2pix, "LockAdded") .to.emit(p2pix, "LockAdded")
@ -750,12 +815,18 @@ describe("P2PIX", () => {
[], [],
[], [],
); );
const storage: Lock = await p2pix.callStatic.mapLocks(1); const storage: Lock = await p2pix.callStatic.mapLocks(
1,
);
const rc: ContractReceipt = await tx.wait(); const rc: ContractReceipt = await tx.wait();
const expiration = rc.blockNumber + 10; const expiration = rc.blockNumber + 10;
const key = await p2pix.callStatic._castAddrToKey(owner.address); const key = await p2pix.callStatic._castAddrToKey(
const castBack = await p2pix.callStatic._castKeyToAddr(key); owner.address,
);
const castBack = await p2pix.callStatic._castKeyToAddr(
key,
);
expect(tx).to.be.ok; expect(tx).to.be.ok;
expect(castBack).to.eq(owner.address); expect(castBack).to.eq(owner.address);
@ -774,16 +845,13 @@ describe("P2PIX", () => {
await expect(tx) await expect(tx)
.to.emit(p2pix, "LockAdded") .to.emit(p2pix, "LockAdded")
.withArgs( .withArgs(acc02.address, 1, key, storage.amount);
acc02.address,
1,
key,
storage.amount,
);
}); });
it("should create a lock, update storage and emit events via the reputation path 2", async () => { it("should create a lock, update storage and emit events via the reputation path 2", async () => {
const root = ethers.constants.HashZero; const root = ethers.constants.HashZero;
const newPrice = price.mul(ethers.constants.Two).add(ethers.constants.One); const newPrice = price
.mul(ethers.constants.Two)
.add(ethers.constants.One);
const endtoendID = ethers.constants.HashZero; const endtoendID = ethers.constants.HashZero;
const target = ethers.BigNumber.from(101); const target = ethers.BigNumber.from(101);
const messageToSign = ethers.utils.solidityKeccak256( const messageToSign = ethers.utils.solidityKeccak256(
@ -838,12 +906,18 @@ describe("P2PIX", () => {
[], [],
[], [],
); );
const storage: Lock = await p2pix.callStatic.mapLocks(2); const storage: Lock = await p2pix.callStatic.mapLocks(
2,
);
const rc: ContractReceipt = await tx.wait(); const rc: ContractReceipt = await tx.wait();
const expiration = rc.blockNumber + 10; const expiration = rc.blockNumber + 10;
const key = await p2pix.callStatic._castAddrToKey(owner.address); const key = await p2pix.callStatic._castAddrToKey(
const castBack = await p2pix.callStatic._castKeyToAddr(key); owner.address,
);
const castBack = await p2pix.callStatic._castKeyToAddr(
key,
);
expect(tx).to.be.ok; expect(tx).to.be.ok;
expect(castBack).to.eq(owner.address); expect(castBack).to.eq(owner.address);
@ -852,7 +926,9 @@ describe("P2PIX", () => {
expect(storage.relayerPremium).to.eq( expect(storage.relayerPremium).to.eq(
ethers.constants.Zero, ethers.constants.Zero,
); );
expect(storage.amount).to.eq(price.add(ethers.constants.One)); expect(storage.amount).to.eq(
price.add(ethers.constants.One),
);
expect(storage.expirationBlock).to.eq(expiration); expect(storage.expirationBlock).to.eq(expiration);
expect(storage.pixTarget).to.eq(target); expect(storage.pixTarget).to.eq(target);
expect(storage.buyerAddress).to.eq(acc02.address); expect(storage.buyerAddress).to.eq(acc02.address);
@ -862,12 +938,7 @@ describe("P2PIX", () => {
await expect(tx) await expect(tx)
.to.emit(p2pix, "LockAdded") .to.emit(p2pix, "LockAdded")
.withArgs( .withArgs(acc02.address, 2, key, storage.amount);
acc02.address,
2,
key,
storage.amount,
);
}); });
// edge case test // edge case test
it("should create multiple locks", async () => { it("should create multiple locks", async () => {
@ -912,7 +983,9 @@ describe("P2PIX", () => {
[], [],
[], [],
); );
const storage2: Lock = await p2pix.callStatic.mapLocks(2); const storage2: Lock = await p2pix.callStatic.mapLocks(
2,
);
const rc2: ContractReceipt = await tx2.wait(); const rc2: ContractReceipt = await tx2.wait();
const expiration2 = rc2.blockNumber + 10; const expiration2 = rc2.blockNumber + 10;
@ -929,17 +1002,81 @@ describe("P2PIX", () => {
[], [],
[], [],
); );
const storage3: Lock = await p2pix.callStatic.mapLocks(3); const storage3: Lock = await p2pix.callStatic.mapLocks(
3,
);
const rc3: ContractReceipt = await tx3.wait(); const rc3: ContractReceipt = await tx3.wait();
const expiration3 = rc3.blockNumber + 10; const expiration3 = rc3.blockNumber + 10;
const key = await p2pix.callStatic._castAddrToKey(owner.address); const key = await p2pix.callStatic._castAddrToKey(
owner.address,
);
// const lockStatus1 = await p2pix.callStatic.getLocksStatus([1,7,7,2,3,4,5,5,2,3]);
// const lockStatus2 = await p2pix.callStatic.getLocksStatus([0,1,2,3]);
// const lockStatus3 = await p2pix.callStatic.getLocksStatus([7,7,333,14,777]);
// const lockStatus4 = await p2pix.callStatic.getLocksStatus([]);
// All getLocksStatus calls were batched via the Multicall contract.
const ls1: [BigNumber[], BigNumber[]] = [
getBnFrom([1, 7, 7, 2, 3, 4, 5, 5, 2, 3]),
getBnFrom([1, 0, 0, 1, 1, 0, 0, 0, 1, 1]),
];
const ls2: [BigNumber[], BigNumber[]] = [
getBnFrom([0, 1, 2, 3]),
getBnFrom([0, 1, 1, 1]),
];
const ls3: [BigNumber[], BigNumber[]] = [
getBnFrom([7, 7, 333, 14, 777]),
getBnFrom([0, 0, 0, 0, 0]),
];
const ls4 = [[], []];
const batchedLocks: Array<BigNumber[]> = [
ls1,
ls2,
ls3,
ls4,
].map(arr => arr[0]);
const cData: Call[] = getLockData(
p2pix.address,
batchedLocks,
);
const batchCall = await multicall.callStatic.mtc1(
cData,
);
const blockNumber = batchCall[0];
const result: Array<BytesLike> = batchCall[1].slice(
0,
4,
);
const decodedData = result.map(r =>
ethers.utils.defaultAbiCoder.decode(
["uint256[]", "uint8[]"],
r,
),
);
const [ls1Res, ls2Res, ls3Res, ls4Res] = decodedData;
expect(tx1).to.be.ok; expect(tx1).to.be.ok;
expect(tx2).to.be.ok; expect(tx2).to.be.ok;
expect(tx3).to.be.ok; expect(tx3).to.be.ok;
expect(blockNumber).to.eq(9);
expect(ls1Res).to.deep.equal(ls1);
expect(ls2Res).to.deep.equal(ls2);
expect(ls3Res).to.deep.equal(ls3);
expect(ls4Res).to.deep.equal(ls4);
expect(key) expect(key)
.to.eq(storage1.sellerKey) .to.eq(storage1.sellerKey)
.and.to.eq(storage2.sellerKey) .and.to.eq(storage2.sellerKey)
@ -990,28 +1127,13 @@ describe("P2PIX", () => {
await expect(tx1) await expect(tx1)
.to.emit(p2pix, "LockAdded") .to.emit(p2pix, "LockAdded")
.withArgs( .withArgs(acc02.address, 1, key, storage1.amount);
acc02.address,
1,
key,
storage1.amount,
);
await expect(tx2) await expect(tx2)
.to.emit(p2pix, "LockAdded") .to.emit(p2pix, "LockAdded")
.withArgs( .withArgs(acc02.address, 2, key, storage2.amount);
acc02.address,
2,
key,
storage2.amount,
);
await expect(tx3) await expect(tx3)
.to.emit(p2pix, "LockAdded") .to.emit(p2pix, "LockAdded")
.withArgs( .withArgs(acc03.address, 3, key, storage3.amount);
acc03.address,
3,
key,
storage3.amount,
);
}); });
}); });
describe("Set sellerBalance Valid State", async () => { describe("Set sellerBalance Valid State", async () => {
@ -1032,11 +1154,18 @@ describe("P2PIX", () => {
true, true,
merkleRoot, merkleRoot,
); );
const state1 = const state1 = await p2pix.callStatic.getValid(
await p2pix.callStatic.getValid(owner.address,erc20.address); owner.address,
const tx = await p2pix.setValidState(erc20.address,false); erc20.address,
const state2 = );
await p2pix.callStatic.getValid(owner.address,erc20.address); const tx = await p2pix.setValidState(
erc20.address,
false,
);
const state2 = await p2pix.callStatic.getValid(
owner.address,
erc20.address,
);
expect(tx).to.be.ok; expect(tx).to.be.ok;
await expect(tx) await expect(tx)
@ -1057,37 +1186,64 @@ describe("P2PIX", () => {
true, true,
hashZero, hashZero,
); );
await erc20.connect(acc01).approve(p2pix.address, price); await erc20
await p2pix.connect(acc01).deposit( .connect(acc01)
.approve(p2pix.address, price);
await p2pix
.connect(acc01)
.deposit(
erc20.address, erc20.address,
price, price,
target, target,
false, false,
hashZero, hashZero,
); );
await erc20.connect(acc02).approve(p2pix.address, price); await erc20
await p2pix.connect(acc02).deposit( .connect(acc02)
.approve(p2pix.address, price);
await p2pix
.connect(acc02)
.deposit(
erc20.address, erc20.address,
price, price,
target, target,
true, true,
hashZero, hashZero,
); );
const oldState1 = const oldState1 = await p2pix.callStatic.getValid(
await p2pix.callStatic.getValid(owner.address,erc20.address); owner.address,
const oldState2 = erc20.address,
await p2pix.callStatic.getValid(acc01.address,erc20.address); );
const oldState3 = const oldState2 = await p2pix.callStatic.getValid(
await p2pix.callStatic.getValid(acc02.address,erc20.address); acc01.address,
const tx1 = await p2pix.setValidState(erc20.address,false); erc20.address,
const tx2 = await p2pix.connect(acc01).setValidState(erc20.address,true); );
const tx3 = await p2pix.connect(acc02).setValidState(erc20.address,true); const oldState3 = await p2pix.callStatic.getValid(
const newState1 = acc02.address,
await p2pix.callStatic.getValid(owner.address,erc20.address); erc20.address,
const newState2 = );
await p2pix.callStatic.getValid(acc01.address,erc20.address); const tx1 = await p2pix.setValidState(
const newState3 = erc20.address,
await p2pix.callStatic.getValid(acc02.address,erc20.address); false,
);
const tx2 = await p2pix
.connect(acc01)
.setValidState(erc20.address, true);
const tx3 = await p2pix
.connect(acc02)
.setValidState(erc20.address, true);
const newState1 = await p2pix.callStatic.getValid(
owner.address,
erc20.address,
);
const newState2 = await p2pix.callStatic.getValid(
acc01.address,
erc20.address,
);
const newState3 = await p2pix.callStatic.getValid(
acc02.address,
erc20.address,
);
expect(tx1).to.be.ok; expect(tx1).to.be.ok;
expect(tx2).to.be.ok; expect(tx2).to.be.ok;
@ -1384,7 +1540,9 @@ describe("P2PIX", () => {
const userRecord1 = await p2pix.callStatic.userRecord( const userRecord1 = await p2pix.callStatic.userRecord(
acc03Key, acc03Key,
); );
const storage1: Lock = await p2pix.callStatic.mapLocks(1); const storage1: Lock = await p2pix.callStatic.mapLocks(
1,
);
const tx = await p2pix const tx = await p2pix
.connect(acc01) .connect(acc01)
.release( .release(
@ -1395,7 +1553,41 @@ describe("P2PIX", () => {
sig.s, sig.s,
sig.v, sig.v,
); );
const storage2: Lock = await p2pix.callStatic.mapLocks(1);
const lockStatus1 =
await p2pix.callStatic.getLocksStatus([1]);
const ls1: [BigNumber[], number[]] = [
[ethers.constants.One],
[3],
];
const funcSig = "0xd6e8b973";
const args = ethers.utils.defaultAbiCoder.encode(
["address[]", "bool[]"],
[[acc01.address], [false]],
);
const cd1 = funcSig + args.substring(2);
const cd2: Call[] = getLockData(p2pix.address, [
ls1[0],
]);
const mtcCalls = [
{ target: p2pix.address, callData: cd1 },
];
mtcCalls.push(cd2[0]);
const mtc2 = await multicall.callStatic.mtc2(mtcCalls);
const blockNumber: BigNumber = mtc2[0];
const blockhash: BytesLike = mtc2[1];
const result = mtc2.slice(2).flat(1) as Result[];
const res1: BytesLike[] = [result[1].returnData];
const decodedLockData = res1.map(r =>
ethers.utils.defaultAbiCoder.decode(
["uint256[]", "uint8[]"],
r,
),
);
const storage2: Lock = await p2pix.callStatic.mapLocks(
1,
);
const userRecordB = await p2pix.callStatic.userRecord( const userRecordB = await p2pix.callStatic.userRecord(
acc01Key, acc01Key,
); );
@ -1408,13 +1600,30 @@ describe("P2PIX", () => {
expect(tx).to.be.ok; expect(tx).to.be.ok;
await expect(tx) await expect(tx)
.to.emit(p2pix, "LockReleased") .to.emit(p2pix, "LockReleased")
.withArgs(acc02.address, ethers.constants.One, storage1.amount); .withArgs(
acc02.address,
ethers.constants.One,
storage1.amount,
);
expect(storage1.expirationBlock).to.eq( expect(storage1.expirationBlock).to.eq(
ethers.BigNumber.from(16), ethers.BigNumber.from(17),
); );
expect(storage1.amount).to.eq( expect(storage1.amount).to.eq(
ethers.BigNumber.from(100), ethers.BigNumber.from(100),
); );
expect(lockStatus1[0].toString()).to.equal(
ls1[0].toString(),
);
expect(lockStatus1[1].toString()).to.equal(
ls1[1].toString(),
);
expect(blockNumber).to.eq(8);
expect(blockhash).to.deep.equal(
ethers.constants.HashZero,
);
expect(result[0].success).to.eq(false);
expect(result[1].success).to.eq(true);
expect(decodedLockData.flat(1)).to.deep.eq(ls1);
expect(storage2.expirationBlock).to.eq(zero); expect(storage2.expirationBlock).to.eq(zero);
expect(storage2.amount).to.eq(zero); expect(storage2.amount).to.eq(zero);
expect(used).to.eq(true); expect(used).to.eq(true);
@ -1501,7 +1710,7 @@ describe("P2PIX", () => {
6, 6,
50, 50,
[], [],
[] [],
); );
await p2pix await p2pix
.connect(acc03) .connect(acc03)
@ -1515,12 +1724,31 @@ describe("P2PIX", () => {
[], [],
[], [],
); );
const lockStatus1 =
await p2pix.callStatic.getLocksStatus([1, 2, 3, 44]);
const ls1: [BigNumber[], BigNumber[]] = [
[
ethers.constants.One,
ethers.constants.Two,
ethers.BigNumber.from(3),
ethers.BigNumber.from(44),
],
getBnFrom([1, 1, 1, 0]),
];
const lockID = ethers.constants.One; const lockID = ethers.constants.One;
const lockID2 = ethers.constants.Two; const lockID2 = ethers.constants.Two;
const lockID3 = ethers.BigNumber.from(3); const lockID3 = ethers.BigNumber.from(3);
const storage1: Lock = await p2pix.callStatic.mapLocks(lockID); const storage1: Lock = await p2pix.callStatic.mapLocks(
const storage2: Lock = await p2pix.callStatic.mapLocks(lockID2); lockID,
const storage3: Lock = await p2pix.callStatic.mapLocks(lockID3); );
const storage2: Lock = await p2pix.callStatic.mapLocks(
lockID2,
);
const storage3: Lock = await p2pix.callStatic.mapLocks(
lockID3,
);
// relayerPremium == 0 // relayerPremium == 0
const tx = await p2pix const tx = await p2pix
.connect(acc01) .connect(acc01)
@ -1572,6 +1800,27 @@ describe("P2PIX", () => {
acc03Key, acc03Key,
); );
const lockStatus2 =
await p2pix.callStatic.getLocksStatus([1, 2, 3, 44]);
const ls2: [BigNumber[], BigNumber[]] = [
[
ethers.constants.One,
ethers.constants.Two,
ethers.BigNumber.from(3),
ethers.BigNumber.from(44),
],
getBnFrom([3, 3, 3, 0]),
];
const batchedLocks: Array<BigNumber[]> = [
ls1.slice(0, 1)[0],
ls2.slice(0, 1)[0],
];
const cData: Call[] = getLockData(
erc20.address,
batchedLocks,
);
expect(tx).to.be.ok; expect(tx).to.be.ok;
expect(tx1).to.be.ok; expect(tx1).to.be.ok;
expect(tx2).to.be.ok; expect(tx2).to.be.ok;
@ -1590,35 +1839,46 @@ describe("P2PIX", () => {
expect(0).to.eq(acc01Record1).and.to.eq(acc03Record1); expect(0).to.eq(acc01Record1).and.to.eq(acc03Record1);
expect(acc01Record2).to.eq(6); // 0 + 6 expect(acc01Record2).to.eq(6); // 0 + 6
expect(acc03Record2).to.eq(185); // 100 + 50 + 25 + 10 expect(acc03Record2).to.eq(185); // 100 + 50 + 25 + 10
await expect(tx).to.changeTokenBalances(
erc20, const addresses = [
[
acc01.address, acc01.address,
acc02.address, acc02.address,
acc03.address, acc03.address,
p2pix.address, p2pix.address,
], ];
const balances = [
[0, 100, 0, "-100"], [0, 100, 0, "-100"],
);
await expect(tx1).to.changeTokenBalances(
erc20,
[
acc01.address,
acc02.address,
acc03.address,
p2pix.address,
],
[0, 47, 3, "-50"], [0, 47, 3, "-50"],
);
await expect(tx2).to.changeTokenBalances(
erc20,
[
acc01.address,
acc02.address,
acc03.address,
p2pix.address,
],
[0, 20, 5, "-25"], [0, 20, 5, "-25"],
];
for (let i = 0; i < 3; i++) {
const txs = [tx, tx1, tx2][i];
await expect(txs).to.changeTokenBalances(
erc20,
addresses,
balances[i],
);
}
expect(lockStatus1[0].toString()).to.equal(
ls1[0].toString(),
);
expect(lockStatus1[1].toString()).to.equal(
ls1[1].toString(),
);
expect(lockStatus2[0].toString()).to.equal(
ls2[0].toString(),
);
expect(lockStatus2[1].toString()).to.equal(
ls2[1].toString(),
);
await expect(
multicall.callStatic.mtc1(cData),
).to.be.revertedWithCustomError(
multicall,
P2PixErrors.CallFailed,
); );
}); });
}); });
@ -1643,7 +1903,7 @@ describe("P2PIX", () => {
0, 0,
1, 1,
[], [],
[] [],
); );
const lockID = ethers.constants.One; const lockID = ethers.constants.One;
const fail = p2pix.unlockExpired([lockID]); const fail = p2pix.unlockExpired([lockID]);
@ -1684,7 +1944,7 @@ describe("P2PIX", () => {
0, 0,
1, 1,
[], [],
[] [],
); );
const lockID = ethers.constants.One; const lockID = ethers.constants.One;
// await mine(10); // await mine(10);
@ -1723,10 +1983,22 @@ describe("P2PIX", () => {
0, 0,
1, 1,
[], [],
[] [],
); );
const lockID = ethers.constants.One; const lockID = ethers.constants.One;
await mine(11); await mine(11);
const lockStatus1 =
await p2pix.callStatic.getLocksStatus([11, 1, 777]);
const ls1: [BigNumber[], BigNumber[]] = [
[
ethers.BigNumber.from(11),
ethers.constants.One,
ethers.BigNumber.from(777),
],
getBnFrom([0, 2, 0]),
];
const storage: Lock = await p2pix.callStatic.mapLocks( const storage: Lock = await p2pix.callStatic.mapLocks(
lockID, lockID,
); );
@ -1752,6 +2024,9 @@ describe("P2PIX", () => {
expect(storage2.amount).to.eq(ethers.constants.Zero); expect(storage2.amount).to.eq(ethers.constants.Zero);
expect(record1).to.eq(0); expect(record1).to.eq(0);
expect(record2).to.eq(price); expect(record2).to.eq(price);
expect(lockStatus1[0].toString()).to.equal(
ls1[0].toString(),
);
}); });
it("should unlock expired through lock function", async () => { it("should unlock expired through lock function", async () => {
const target = ethers.BigNumber.from(101); const target = ethers.BigNumber.from(101);
@ -1818,7 +2093,10 @@ describe("P2PIX", () => {
[], [],
[lockID], [lockID],
); );
const remaining = await p2pix.callStatic.getBalance(owner.address,erc20.address); const remaining = await p2pix.callStatic.getBalance(
owner.address,
erc20.address,
);
expect(tx1).to.be.ok; expect(tx1).to.be.ok;
await expect(tx1) await expect(tx1)
@ -1854,8 +2132,13 @@ describe("P2PIX", () => {
const lockID = ethers.constants.One; const lockID = ethers.constants.One;
// mine blocks to expire lock // mine blocks to expire lock
await mine(11); await mine(11);
const tx = await p2pix.withdraw(erc20.address, price, [lockID]); const tx = await p2pix.withdraw(erc20.address, price, [
const remaining = await p2pix.callStatic.getBalance(owner.address, erc20.address); lockID,
]);
const remaining = await p2pix.callStatic.getBalance(
owner.address,
erc20.address,
);
expect(tx).to.be.ok; expect(tx).to.be.ok;
await expect(tx) await expect(tx)
@ -1876,13 +2159,18 @@ describe("P2PIX", () => {
true, true,
merkleRoot, merkleRoot,
); );
const fail = p2pix.connect(acc02).withdraw(erc20.address, price.mul(ethers.constants.Two),[]); const fail = p2pix
.connect(acc02)
.withdraw(
erc20.address,
price.mul(ethers.constants.Two),
[],
);
await expect(fail).to.be.revertedWithCustomError( await expect(fail).to.be.revertedWithCustomError(
p2pix, p2pix,
P2PixErrors.DecOverflow, P2PixErrors.DecOverflow,
); );
}); });
it("should withdraw remaining funds from deposit, update storage and emit event", async () => { it("should withdraw remaining funds from deposit, update storage and emit event", async () => {
const newPrice = price.div(ethers.constants.Two); const newPrice = price.div(ethers.constants.Two);
@ -1897,7 +2185,7 @@ describe("P2PIX", () => {
const tx = await p2pix.withdraw( const tx = await p2pix.withdraw(
erc20.address, erc20.address,
price.div(ethers.constants.Two), price.div(ethers.constants.Two),
[] [],
); );
expect(tx).to.be.ok; expect(tx).to.be.ok;
@ -1925,6 +2213,7 @@ describe("P2PIX", () => {
.withArgs(owner.address, erc20.address, newPrice); .withArgs(owner.address, erc20.address, newPrice);
}); });
}); });
describe("Allowlist Settings", async () => { describe("Allowlist Settings", async () => {
it("should revert if the msg.sender differs from deposit's seller", async () => { it("should revert if the msg.sender differs from deposit's seller", async () => {
const root = ethers.utils.keccak256( const root = ethers.utils.keccak256(

View File

@ -19,4 +19,5 @@ export enum P2PixErrors {
MaxBalExceeded = "MaxBalExceeded", MaxBalExceeded = "MaxBalExceeded",
NotInitialized = "NotInitialized", NotInitialized = "NotInitialized",
DecOverflow = "DecOverflow", DecOverflow = "DecOverflow",
CallFailed = "CallFailed",
} }

View File

@ -6,7 +6,9 @@ import { MerkleTree } from "merkletreejs";
import { import {
MockToken, MockToken,
Multicall,
P2PIX, P2PIX,
P2PIX__factory,
Reputation, Reputation,
} from "../../src/types"; } from "../../src/types";
@ -17,14 +19,6 @@ export interface Deploys {
token: string; token: string;
} }
// export interface Deposit {
// remaining: BigNumber;
// pixTarget: string;
// seller: string;
// token: string;
// valid: boolean;
// }
export interface Lock { export interface Lock {
sellerKey: BigNumber; sellerKey: BigNumber;
counter: BigNumber; counter: BigNumber;
@ -38,6 +32,16 @@ export interface Lock {
token: string; token: string;
} }
export interface Call {
target: string;
callData: string;
}
export interface Result {
success: boolean;
returnData: string;
}
export interface P2pixFixture { export interface P2pixFixture {
p2pix: P2PIX; p2pix: P2PIX;
erc20: MockToken; erc20: MockToken;
@ -49,19 +53,40 @@ export interface RepFixture {
reputation: Reputation; reputation: Reputation;
} }
type P2PixAndReputation = P2pixFixture & RepFixture; export interface MtcFixture {
multicall: Multicall;
}
type P2PixAndReputation = P2pixFixture &
RepFixture &
MtcFixture;
// exported constants // exported constants
export const getSignerAddrs = ( export const getSignerAddrs = (
amount: number, amount: number,
addrs: SignerWithAddress[], addrs: SignerWithAddress[],
): string[] => { ): string[] => {
const signers: string[] = []; return addrs.slice(0, amount).map(({ address }) => address);
const buffr = addrs.slice(0, amount); };
for (let i = 0; i < amount; i++) {
signers.push(buffr[i].address); export const getBnFrom = (nums: number[]): BigNumber[] => {
} const bns = nums.map(num => ethers.BigNumber.from(num));
return signers; return bns;
};
export const getLockData = (
addr: string,
locks: BigNumber[][],
): Call[] => {
const iface = new ethers.utils.Interface(
P2PIX__factory.abi,
);
return locks.map(lock => ({
target: addr,
callData: iface.encodeFunctionData("getLocksStatus", [
lock,
]),
}));
}; };
export const randomSigners = (amount: number): Signer[] => { export const randomSigners = (amount: number): Signer[] => {
@ -128,6 +153,11 @@ export async function p2pixFixture(): Promise<P2PixAndReputation> {
[true], [true],
)) as P2PIX; )) as P2PIX;
const Multicall = await ethers.getContractFactory(
"Multicall",
);
const multicall = (await Multicall.deploy()) as Multicall;
const signers = await ethers.getSigners(); const signers = await ethers.getSigners();
const whitelisted = signers.slice(0, 2); const whitelisted = signers.slice(0, 2);
const leaves = whitelisted.map(account => const leaves = whitelisted.map(account =>
@ -142,6 +172,7 @@ export async function p2pixFixture(): Promise<P2PixAndReputation> {
); );
return { return {
multicall,
reputation, reputation,
erc20, erc20,
p2pix, p2pix,

View File

@ -6049,16 +6049,17 @@ fsevents@~2.1.1:
languageName: node languageName: node
linkType: hard linkType: hard
"hardhat-tracer@npm:^1.2.0": "hardhat-tracer@npm:beta":
version: 1.2.0 version: 2.0.0-beta.6
resolution: "hardhat-tracer@npm:1.2.0" resolution: "hardhat-tracer@npm:2.0.0-beta.6"
dependencies: dependencies:
ethers: ^5.6.1 ethers: ^5.6.1
peerDependencies: peerDependencies:
chai: 4.x
chalk: 4.x chalk: 4.x
ethers: 5.x ethers: 5.x
hardhat: 2.x hardhat: 2.x
checksum: 1d348fb3ed60cbde2287329730ccd37c73af80cc2cf4ccfb045f26af26c7efebd4a6fdf611035f34ca7fb75d0eb95985e8f5ed4f0537d2615fb6e126d1d035f0 checksum: b14795adf3eecd487b874ef06799ab43c342a4908bcf58bbd0bc7274caa7976456a0c75a702aaf3a937fe7c8afbfe2e2a9f263b6a0c7e2fc56e6a54144288369
languageName: node languageName: node
linkType: hard linkType: hard
@ -8459,7 +8460,7 @@ fsevents@~2.1.1:
fs-extra: ^10.1.0 fs-extra: ^10.1.0
hardhat: ^2.12.2 hardhat: ^2.12.2
hardhat-gas-reporter: ^1.0.9 hardhat-gas-reporter: ^1.0.9
hardhat-tracer: ^1.2.0 hardhat-tracer: beta
husky: ^8.0.1 husky: ^8.0.1
keccak256: ^1.0.6 keccak256: ^1.0.6
lint-staged: ^13.0.3 lint-staged: ^13.0.3