Compare commits
1 Commits
dev
...
7d8e0f13bb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d8e0f13bb |
2
.commitlintrc.yaml
Normal file
2
.commitlintrc.yaml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
extends:
|
||||||
|
- "@commitlint/config-conventional"
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
MNEMONIC="{INSERT_12_WORD_MNEMONIC}"
|
MNEMONIC="{INSERT_12_WORD_MNEMONIC}"
|
||||||
PRIVATE_KEY="{INSERT_0x_PRIVATE_KEY}"
|
|
||||||
|
|
||||||
INFURA_API_KEY="{INSERT_API_KEY}"
|
INFURA_API_KEY="{INSERT_API_KEY}"
|
||||||
ALCHEMY_API_KEY="{INSERT_API_KEY}"
|
ALCHEMY_API_KEY="{INSERT_API_KEY}"
|
||||||
|
|||||||
21
.eslintignore
Normal file
21
.eslintignore
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# directories
|
||||||
|
.yarn/
|
||||||
|
**/.coverage_artifacts
|
||||||
|
**/.coverage_cache
|
||||||
|
**/.coverage_contracts
|
||||||
|
**/artifacts
|
||||||
|
**/build
|
||||||
|
**/cache
|
||||||
|
**/coverage
|
||||||
|
**/dist
|
||||||
|
**/node_modules
|
||||||
|
**/types
|
||||||
|
|
||||||
|
# files
|
||||||
|
*.env
|
||||||
|
*.log
|
||||||
|
.pnp.*
|
||||||
|
coverage.json
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
21
.eslintrc.yaml
Normal file
21
.eslintrc.yaml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
extends:
|
||||||
|
- "eslint:recommended"
|
||||||
|
- "plugin:@typescript-eslint/eslint-recommended"
|
||||||
|
- "plugin:@typescript-eslint/recommended"
|
||||||
|
- "prettier"
|
||||||
|
parser: "@typescript-eslint/parser"
|
||||||
|
parserOptions:
|
||||||
|
project: "./tsconfig.json"
|
||||||
|
plugins:
|
||||||
|
- "@typescript-eslint"
|
||||||
|
root: true
|
||||||
|
rules:
|
||||||
|
"@typescript-eslint/no-floating-promises":
|
||||||
|
- error
|
||||||
|
- ignoreIIFE: true
|
||||||
|
ignoreVoid: true
|
||||||
|
"@typescript-eslint/no-inferrable-types": "off"
|
||||||
|
"@typescript-eslint/no-unused-vars":
|
||||||
|
- error
|
||||||
|
- argsIgnorePattern: "_"
|
||||||
|
varsIgnorePattern: "_"
|
||||||
32
.github/workflows/lint.yml
vendored
32
.github/workflows/lint.yml
vendored
@@ -1,32 +0,0 @@
|
|||||||
name: Lint
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [main, dev]
|
|
||||||
pull_request:
|
|
||||||
branches: [main, dev]
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: lint-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
lint:
|
|
||||||
name: Solidity + TypeScript + Prettier
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Enable Corepack
|
|
||||||
run: corepack enable
|
|
||||||
|
|
||||||
- uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 22
|
|
||||||
cache: yarn
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: yarn install --immutable
|
|
||||||
|
|
||||||
- name: Run lint
|
|
||||||
run: yarn lint
|
|
||||||
35
.github/workflows/test.yml
vendored
35
.github/workflows/test.yml
vendored
@@ -1,35 +0,0 @@
|
|||||||
name: Test
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [main, dev]
|
|
||||||
pull_request:
|
|
||||||
branches: [main, dev]
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: test-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test:
|
|
||||||
name: Hardhat tests
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Enable Corepack
|
|
||||||
run: corepack enable
|
|
||||||
|
|
||||||
- uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 22
|
|
||||||
cache: yarn
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: yarn install --immutable
|
|
||||||
|
|
||||||
- name: Compile contracts
|
|
||||||
run: yarn compile
|
|
||||||
|
|
||||||
- name: Run tests
|
|
||||||
run: yarn test
|
|
||||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -28,11 +28,3 @@ coverage.json
|
|||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
docs/lib/mock/*.md
|
|
||||||
.dagrobin/
|
|
||||||
|
|
||||||
# Hardhat Ignition local/ephemeral deployments
|
|
||||||
ignition/deployments/chain-31337/
|
|
||||||
|
|
||||||
# Per-developer local deploy state (deterministic per mnemonic)
|
|
||||||
deploys/localhost.json
|
|
||||||
|
|||||||
1
.husky/.gitignore
vendored
Normal file
1
.husky/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
_
|
||||||
4
.husky/commit-msg
Executable file
4
.husky/commit-msg
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
. "$(dirname "$0")/_/husky.sh"
|
||||||
|
|
||||||
|
yarn dlx commitlint --edit $1
|
||||||
4
.husky/pre-commit
Executable file
4
.husky/pre-commit
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
. "$(dirname "$0")/_/husky.sh"
|
||||||
|
|
||||||
|
yarn dlx lint-staged
|
||||||
@@ -11,12 +11,6 @@
|
|||||||
**/node_modules
|
**/node_modules
|
||||||
**/types
|
**/types
|
||||||
|
|
||||||
# deploy artifacts
|
|
||||||
deploys/old/
|
|
||||||
|
|
||||||
# auto-generated docs
|
|
||||||
docs/
|
|
||||||
|
|
||||||
# files
|
# files
|
||||||
*.env
|
*.env
|
||||||
*.log
|
*.log
|
||||||
@@ -25,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
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
plugins:
|
|
||||||
- prettier-plugin-solidity
|
|
||||||
arrowParens: avoid
|
arrowParens: avoid
|
||||||
bracketSpacing: true
|
bracketSpacing: true
|
||||||
endOfLine: auto
|
endOfLine: auto
|
||||||
|
importOrder: ["<THIRD_PARTY_MODULES>", "^[./]"]
|
||||||
|
importOrderParserPlugins: ["typescript"]
|
||||||
|
importOrderSeparation: true
|
||||||
|
importOrderSortSpecifiers: true
|
||||||
printWidth: 62
|
printWidth: 62
|
||||||
singleQuote: false
|
singleQuote: false
|
||||||
tabWidth: 2
|
tabWidth: 2
|
||||||
|
|||||||
@@ -14,9 +14,5 @@ module.exports = {
|
|||||||
providerOptions: {
|
providerOptions: {
|
||||||
mnemonic: process.env.MNEMONIC,
|
mnemonic: process.env.MNEMONIC,
|
||||||
},
|
},
|
||||||
skipFiles: [
|
skipFiles: ["test", 'core/BaseUtils.sol', 'core/OwnerSettings.sol'],
|
||||||
"test",
|
|
||||||
"core/BaseUtils.sol",
|
|
||||||
"core/OwnerSettings.sol",
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
"plugins": ["prettier"],
|
"plugins": ["prettier"],
|
||||||
"rules": {
|
"rules": {
|
||||||
"code-complexity": ["error", 8],
|
"code-complexity": ["error", 8],
|
||||||
"avoid-low-level-calls": "off",
|
|
||||||
"compiler-version": ["error", ">=0.8.4"],
|
"compiler-version": ["error", ">=0.8.4"],
|
||||||
"const-name-snakecase": "off",
|
"const-name-snakecase": "off",
|
||||||
"constructor-syntax": "error",
|
"constructor-syntax": "error",
|
||||||
@@ -11,14 +10,7 @@
|
|||||||
"error",
|
"error",
|
||||||
{ "ignoreConstructors": true }
|
{ "ignoreConstructors": true }
|
||||||
],
|
],
|
||||||
"function-max-lines": "off",
|
|
||||||
"gas-calldata-parameters": "off",
|
|
||||||
"gas-indexed-events": "off",
|
|
||||||
"gas-strict-inequalities": "off",
|
|
||||||
"gas-struct-packing": "off",
|
|
||||||
"interface-starts-with-i": "off",
|
|
||||||
"max-line-length": ["error", 120],
|
"max-line-length": ["error", 120],
|
||||||
"no-inline-assembly": "off",
|
|
||||||
"not-rely-on-time": "off",
|
"not-rely-on-time": "off",
|
||||||
"prettier/prettier": [
|
"prettier/prettier": [
|
||||||
"error",
|
"error",
|
||||||
@@ -26,7 +18,6 @@
|
|||||||
"endOfLine": "auto"
|
"endOfLine": "auto"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"reason-string": ["warn", { "maxLength": 64 }],
|
"reason-string": ["warn", { "maxLength": 64 }]
|
||||||
"use-natspec": "off"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
# directories
|
# directories
|
||||||
**/artifacts
|
**/artifacts
|
||||||
**/cache
|
|
||||||
**/node_modules
|
**/node_modules
|
||||||
deploys/
|
|
||||||
docs/
|
|
||||||
|
|||||||
546
.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
vendored
Normal file
546
.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
vendored
Normal file
File diff suppressed because one or more lines are too long
786
.yarn/releases/yarn-3.2.1.cjs
vendored
Executable file
786
.yarn/releases/yarn-3.2.1.cjs
vendored
Executable file
File diff suppressed because one or more lines are too long
942
.yarn/releases/yarn-4.9.2.cjs
vendored
942
.yarn/releases/yarn-4.9.2.cjs
vendored
File diff suppressed because one or more lines are too long
10
.yarnrc.yml
10
.yarnrc.yml
@@ -1,7 +1,7 @@
|
|||||||
compressionLevel: mixed
|
|
||||||
|
|
||||||
enableGlobalCache: false
|
|
||||||
|
|
||||||
nodeLinker: node-modules
|
nodeLinker: node-modules
|
||||||
|
|
||||||
yarnPath: .yarn/releases/yarn-4.9.2.cjs
|
plugins:
|
||||||
|
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
|
||||||
|
spec: "@yarnpkg/plugin-interactive-tools"
|
||||||
|
|
||||||
|
yarnPath: .yarn/releases/yarn-3.2.1.cjs
|
||||||
|
|||||||
87
README.md
87
README.md
@@ -55,23 +55,25 @@
|
|||||||
|
|
||||||
| Testnet | Token Address | P2pix Address | Reputation Address | Multicall Address |
|
| Testnet | Token Address | P2pix Address | Reputation Address | Multicall Address |
|
||||||
| ------- | ------------------------------------------ | ------------------------------------------ | ------------------------------------------ | ------------------------------------------ |
|
| ------- | ------------------------------------------ | ------------------------------------------ | ------------------------------------------ | ------------------------------------------ |
|
||||||
| Sepolia | 0x3eBE212377D847828eBb9D2a100f5c5EA1EF3A72 | 0xb7cDAE58C6e715Cfd795BB142041E43b9CB02497 | 0xFd1194A56995Ef7B62730F4061408e79d88E5207 | 0x2f7f9848A803E67d79C0C8aa42b663dCF6E1B5ed |
|
| Goerli | 0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00 | 0x2414817FF64A114d91eCFA16a834d3fCf69103d4 | 0x2CFD9354Ec7614fEf036EFd6A730dA1d5fC2762A | 0x8FE009992d96A86c7f0Bccdaf1eC3471E302a8a6 |
|
||||||
|
| Mumbai | 0xC86042E9F2977C62Da8c9dDF7F9c40fde4796A29 | 0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00 | 0x570445E3eF413bCDb5De79ed27B1c3840683e385 | 0x718B2C4DE4F9654E1349F610ff561249bfe1c418 |
|
||||||
|
|
||||||
<!-- All contracts deployed by 0x8dC06F985C131166570825F52447E8c88d64aE20 -->
|
<!-- All contracts deployed by 0x8dC06F985C131166570825F52447E8c88d64aE20 -->
|
||||||
<!-- https://sepolia.etherscan.io/address/0x3eBE212377D847828eBb9D2a100f5c5EA1EF3A72#code -->
|
<!-- https://goerli.etherscan.io/address/0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00#code -->
|
||||||
<!-- https://sepolia.etherscan.io/address/0xb7cDAE58C6e715Cfd795BB142041E43b9CB02497#code -->
|
<!-- https://goerli.etherscan.io/address/0x2414817FF64A114d91eCFA16a834d3fCf69103d4#code -->
|
||||||
<!-- https://sepolia.etherscan.io/address/0xFd1194A56995Ef7B62730F4061408e79d88E5207#code -->
|
<!-- https://goerli.etherscan.io/address/0x2CFD9354Ec7614fEf036EFd6A730dA1d5fC2762A#code -->
|
||||||
<!-- https://sepolia.etherscan.io/address/0x2f7f9848A803E67d79C0C8aa42b663dCF6E1B5ed#code -->
|
<!-- https://goerli.etherscan.io/address/0x8FE009992d96A86c7f0Bccdaf1eC3471E302a8a6#code -->
|
||||||
|
|
||||||
|
<!-- https://mumbai.polygonscan.com/address/0xC86042E9F2977C62Da8c9dDF7F9c40fde4796A29#code -->
|
||||||
|
<!-- https://mumbai.polygonscan.com/address/0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00#code -->
|
||||||
|
<!-- https://mumbai.polygonscan.com/address/0x570445e3ef413bcdb5de79ed27b1c3840683e385#code -->
|
||||||
|
<!-- https://mumbai.polygonscan.com/address/0x718B2C4DE4F9654E1349F610ff561249bfe1c418#code -->
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### Pre Requisites
|
### Pre Requisites
|
||||||
|
|
||||||
Before installing, create a `.env` file and set the authentication method and other env criteria as in `.env.example`.
|
Before installing, create a `.env` file and set a BIP-39 compatible mnemonic and other env criteria as in `.env.example`.
|
||||||
|
|
||||||
You can authenticate with either:
|
|
||||||
- `PRIVATE_KEY` — a raw hex private key (e.g. `0x123...`). Takes priority if both are set.
|
|
||||||
- `MNEMONIC` — a BIP-39 compatible 12-word mnemonic phrase. Used as fallback when `PRIVATE_KEY` is not set.
|
|
||||||
|
|
||||||
### Install
|
### Install
|
||||||
|
|
||||||
@@ -123,71 +125,36 @@ To grab deployment addresses you can just grab from deploys folder:
|
|||||||
import localhostDeploys from "p2pix-smart-contracts/deploys/localhost.json";
|
import localhostDeploys from "p2pix-smart-contracts/deploys/localhost.json";
|
||||||
```
|
```
|
||||||
|
|
||||||
## Deployment (Hardhat Ignition)
|
## Deploying to local environment
|
||||||
|
|
||||||
Deployments are orchestrated by
|
On the first teminal, use the following command and import some wallets to your Metamask, then connect to the network pointed:
|
||||||
[Hardhat Ignition](https://hardhat.org/ignition). Each module declares its
|
|
||||||
contracts; Ignition handles ordering, idempotency, and per-network state
|
|
||||||
under `ignition/deployments/`.
|
|
||||||
|
|
||||||
### Modules
|
|
||||||
|
|
||||||
- `ignition/modules/MockToken.ts` — ERC20 mock used in dev / testnets.
|
|
||||||
- `ignition/modules/Reputation.ts` — Reputation + Multicall.
|
|
||||||
- `ignition/modules/P2PIX.ts` — production deploy (no MockToken). Token
|
|
||||||
addresses passed via parameters (`tokens` + `allowed`).
|
|
||||||
- `ignition/modules/P2PIXWithMock.ts` — dev/test deploy. Wires Reputation +
|
|
||||||
MockToken and deploys P2PIX.
|
|
||||||
|
|
||||||
### Per-network parameters
|
|
||||||
|
|
||||||
Network-specific values (e.g. `defaultBlocks`, `validSigners`, MockToken
|
|
||||||
`supply`) live in `ignition/parameters/<network>.json`. Only
|
|
||||||
`localhost.json` is checked in; copy it to e.g. `sepolia.json` and set the
|
|
||||||
network values before running the deploy script.
|
|
||||||
|
|
||||||
### Local environment
|
|
||||||
|
|
||||||
On the first terminal:
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
yarn hardhat node
|
yarn hardhat node
|
||||||
```
|
```
|
||||||
|
|
||||||
On the second terminal:
|
On the second teminal, run the following commands:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
yarn deploy:mock --network localhost --parameters ignition/parameters/localhost.json
|
yarn deploy1:localhost
|
||||||
|
yarn deploy2:localhost
|
||||||
```
|
```
|
||||||
|
|
||||||
Addresses for every deployed contract are written to
|
**_NOTE_:** The second script transfers 2M tokens to the first wallet of the node.
|
||||||
`ignition/deployments/chain-31337/deployed_addresses.json` (this path is
|
To use the P2Pix smart contract first transfer some of the tokens to other wallets.
|
||||||
gitignored — local-only state).
|
|
||||||
|
|
||||||
### Testnets
|
## Deploying to testnets
|
||||||
|
|
||||||
|
Deploy to Ethereum's Goerli testnet:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
yarn deploy:mock --network sepolia
|
yarn deploy1:goerli
|
||||||
|
yarn deploy2:goerli
|
||||||
```
|
```
|
||||||
|
|
||||||
Requires the matching `ignition/parameters/sepolia.json` and the relevant
|
Deploy to Polygon's Mumbai testnet:
|
||||||
API keys in `.env`.
|
|
||||||
|
|
||||||
### Production (real tokens)
|
|
||||||
|
|
||||||
Use the `P2PIX` module when the target network already has the ERC20
|
|
||||||
tokens you want P2PIX to support — no MockToken is deployed.
|
|
||||||
|
|
||||||
1. Copy `ignition/parameters/prod.example.json` to
|
|
||||||
`ignition/parameters/<network>.json` and set:
|
|
||||||
- `defaultBlocks`, `validSigners`
|
|
||||||
- `tokens` — array of ERC20 addresses on the target network
|
|
||||||
- `allowed` — array of booleans, same length as `tokens`
|
|
||||||
2. Run:
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
yarn deploy --network <network> --parameters ignition/parameters/<network>.json
|
yarn deploy1:mumbai
|
||||||
|
yarn deploy2:mumbai
|
||||||
```
|
```
|
||||||
|
|
||||||
The deployed Reputation/Multicall/P2PIX addresses are written to
|
|
||||||
`ignition/deployments/chain-<id>/deployed_addresses.json`.
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
pragma solidity ^0.8.19;
|
pragma solidity 0.8.19;
|
||||||
|
|
||||||
import { IReputation } from "./lib/interfaces/IReputation.sol";
|
import { IReputation } from "./lib/interfaces/IReputation.sol";
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
pragma solidity ^0.8.19;
|
pragma solidity 0.8.19;
|
||||||
|
|
||||||
import { ERC20, OwnerSettings } from "contracts/core/OwnerSettings.sol";
|
import { ERC20, OwnerSettings } from "contracts/core/OwnerSettings.sol";
|
||||||
|
|
||||||
import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
|
import { ECDSA } from "contracts/lib/utils/ECDSA.sol";
|
||||||
import { MessageHashUtils } from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
|
import { MerkleProofLib as Merkle } from "contracts/lib/utils/MerkleProofLib.sol";
|
||||||
import { MerkleProof as Merkle } from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
|
import { ReentrancyGuard } from "contracts/lib/utils/ReentrancyGuard.sol";
|
||||||
import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
|
|
||||||
|
|
||||||
abstract contract BaseUtils is
|
abstract contract BaseUtils is
|
||||||
OwnerSettings,
|
OwnerSettings,
|
||||||
@@ -44,9 +43,10 @@ abstract contract BaseUtils is
|
|||||||
if (
|
if (
|
||||||
!validBacenSigners(
|
!validBacenSigners(
|
||||||
_castAddrToKey(
|
_castAddrToKey(
|
||||||
ECDSA.recover(
|
ECDSA.recoverCalldata(
|
||||||
MessageHashUtils
|
ECDSA.toEthSignedMessageHash(
|
||||||
.toEthSignedMessageHash(_message),
|
_message
|
||||||
|
),
|
||||||
_signature
|
_signature
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,26 +1,22 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
pragma solidity ^0.8.19;
|
pragma solidity 0.8.19;
|
||||||
|
|
||||||
abstract contract Constants {
|
abstract contract Constants {
|
||||||
/// ███ Constants ██████████████████████████████████████████████████████████
|
/// ███ Constants ██████████████████████████████████████████████████████████
|
||||||
|
|
||||||
uint256 internal constant _ROOT_UPDATED_EVENT_SIGNATURE =
|
uint256 constant _ROOT_UPDATED_EVENT_SIGNATURE =
|
||||||
0x0b294da292f26e55fd442b5c0164fbb9013036ff00c5cfdde0efd01c1baaf632;
|
0x0b294da292f26e55fd442b5c0164fbb9013036ff00c5cfdde0efd01c1baaf632;
|
||||||
uint256
|
uint256 constant _ALLOWED_ERC20_UPDATED_EVENT_SIGNATURE =
|
||||||
internal constant _ALLOWED_ERC20_UPDATED_EVENT_SIGNATURE =
|
|
||||||
0x5d6e86e5341d57a92c49934296c51542a25015c9b1782a1c2722a940131c3d9a;
|
0x5d6e86e5341d57a92c49934296c51542a25015c9b1782a1c2722a940131c3d9a;
|
||||||
uint256
|
uint256 constant _TRUSTED_FORWARDER_UPDATED_EVENT_SIGNATURE =
|
||||||
internal constant _TRUSTED_FORWARDER_UPDATED_EVENT_SIGNATURE =
|
|
||||||
0xbee55516e29d3969d3cb8eb01351eb3c52d06f9e2435bd5a8bfe3647e185df92;
|
0xbee55516e29d3969d3cb8eb01351eb3c52d06f9e2435bd5a8bfe3647e185df92;
|
||||||
|
|
||||||
/// @dev Seller casted to key => Seller's allowlist merkleroot.
|
/// @dev Seller casted to key => Seller's allowlist merkleroot.
|
||||||
/// mapping(uint256 => bytes32) public sellerAllowList;
|
/// mapping(uint256 => bytes32) public sellerAllowList;
|
||||||
uint256 internal constant _SELLER_ALLOWLIST_SLOT_SEED =
|
uint256 constant _SELLER_ALLOWLIST_SLOT_SEED = 0x74dfee70;
|
||||||
0x74dfee70;
|
|
||||||
/// @dev Tokens allowed to serve as the underlying amount of a deposit.
|
/// @dev Tokens allowed to serve as the underlying amount of a deposit.
|
||||||
/// mapping(ERC20 => bool) public allowedERC20s;
|
/// mapping(ERC20 => bool) public allowedERC20s;
|
||||||
uint256 internal constant _ALLOWED_ERC20_SLOT_SEED =
|
uint256 constant _ALLOWED_ERC20_SLOT_SEED = 0xcbc9d1c4;
|
||||||
0xcbc9d1c4;
|
|
||||||
|
|
||||||
/// @dev `balance` max. value = 10**26.
|
/// @dev `balance` max. value = 10**26.
|
||||||
/// @dev `pixTarget` keys are restricted to 160 bits.
|
/// @dev `pixTarget` keys are restricted to 160 bits.
|
||||||
@@ -36,21 +32,16 @@ abstract contract Constants {
|
|||||||
/// mstore(0x0c, _SELLER_BALANCE_SLOT_SEED)
|
/// mstore(0x0c, _SELLER_BALANCE_SLOT_SEED)
|
||||||
/// mstore(0x00, seller)
|
/// mstore(0x00, seller)
|
||||||
/// let value := sload(keccak256(0x0c, 0x34)).
|
/// let value := sload(keccak256(0x0c, 0x34)).
|
||||||
uint256 internal constant _SELLER_BALANCE_SLOT_SEED =
|
uint256 constant _SELLER_BALANCE_SLOT_SEED = 0x739094b1;
|
||||||
0x739094b1;
|
|
||||||
|
|
||||||
/// @dev The bitmask of `sellerBalance` entry.
|
/// @dev The bitmask of `sellerBalance` entry.
|
||||||
uint256 internal constant BITMASK_SB_ENTRY =
|
uint256 constant BITMASK_SB_ENTRY = (1 << 94) - 1;
|
||||||
(1 << 94) - 1;
|
|
||||||
/// @dev The bit position of `valid` in `sellerBalance`.
|
/// @dev The bit position of `valid` in `sellerBalance`.
|
||||||
uint256 internal constant BITPOS_VALID = 95;
|
uint256 constant BITPOS_VALID = 95;
|
||||||
|
|
||||||
/// @dev The scalar of BRZ token.
|
/// @dev The scalar of BRZ token.
|
||||||
uint256 internal constant WAD = 1e18;
|
uint256 constant WAD = 1e18;
|
||||||
uint256 internal constant MAXBALANCE_UPPERBOUND =
|
uint256 constant MAXBALANCE_UPPERBOUND = 1e8 ether;
|
||||||
1e8 ether;
|
uint256 constant REPUTATION_LOWERBOUND = 1e2 ether;
|
||||||
uint256 internal constant REPUTATION_LOWERBOUND =
|
uint256 constant LOCKAMOUNT_UPPERBOUND = 1e6 ether;
|
||||||
1e2 ether;
|
|
||||||
uint256 internal constant LOCKAMOUNT_UPPERBOUND =
|
|
||||||
1e6 ether;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
pragma solidity ^0.8.19;
|
pragma solidity 0.8.19;
|
||||||
|
|
||||||
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
|
import { ERC20 } from "contracts/lib/tokens/ERC20.sol";
|
||||||
|
|
||||||
library DataTypes {
|
library DataTypes {
|
||||||
|
|
||||||
struct Lock {
|
struct Lock {
|
||||||
uint256 counter;
|
uint256 counter;
|
||||||
uint256 expirationBlock;
|
uint256 expirationBlock;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
pragma solidity ^0.8.19;
|
pragma solidity 0.8.19;
|
||||||
|
|
||||||
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
|
import { ERC20 } from "contracts/lib/tokens/ERC20.sol";
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
interface EventAndErrors {
|
interface EventAndErrors {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
pragma solidity ^0.8.19;
|
pragma solidity 0.8.19;
|
||||||
|
|
||||||
import { ERC2771 } from "contracts/lib/metatx/ERC2771Context.sol";
|
import { ERC2771Context as ERC2771 } from "contracts/lib/metatx/ERC2771Context.sol";
|
||||||
import { ERC20, SafeTransferLib } from "contracts/lib/utils/SafeTransferLib.sol";
|
import { ERC20, SafeTransferLib } from "contracts/lib/utils/SafeTransferLib.sol";
|
||||||
import { IReputation } from "contracts/lib/interfaces/IReputation.sol";
|
import { IReputation } from "contracts/lib/interfaces/IReputation.sol";
|
||||||
import { EventAndErrors } from "contracts/core/EventAndErrors.sol";
|
import { EventAndErrors } from "contracts/core/EventAndErrors.sol";
|
||||||
|
|||||||
@@ -1,15 +1,87 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
pragma solidity ^0.8.20;
|
pragma solidity >=0.8.4;
|
||||||
|
|
||||||
import { ERC2771Context } from "@openzeppelin/contracts/metatx/ERC2771Context.sol";
|
/// @author OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
|
||||||
|
/// (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Context.sol)
|
||||||
|
|
||||||
abstract contract ERC2771 is ERC2771Context(address(0)) {
|
/// @dev Provides information about the current execution context, including the
|
||||||
|
/// sender of the transaction and its data. While these are generally available
|
||||||
|
/// via msg.sender and msg.data, they should not be accessed in such a direct
|
||||||
|
/// manner, since when dealing with meta-transactions the account sending and
|
||||||
|
/// paying for execution may not be the actual sender (as far as an application
|
||||||
|
/// is concerned).
|
||||||
|
///
|
||||||
|
/// This contract is only required for intermediate, library-like contracts.
|
||||||
|
abstract contract Context {
|
||||||
|
function _msgSender()
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
virtual
|
||||||
|
returns (address)
|
||||||
|
{
|
||||||
|
return msg.sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _msgData()
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
virtual
|
||||||
|
returns (bytes calldata)
|
||||||
|
{
|
||||||
|
return msg.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @author Modified from OpenZeppelin Contracts (last updated v4.7.0) (metatx/ERC2771Context.sol)
|
||||||
|
/// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/metatx/ERC2771Context.sol
|
||||||
|
|
||||||
|
/// @dev Context variant with ERC2771 support.
|
||||||
|
abstract contract ERC2771Context is Context {
|
||||||
|
// address private immutable _trustedForwarder;
|
||||||
mapping(address => bool) public trustedForwarders;
|
mapping(address => bool) public trustedForwarders;
|
||||||
|
|
||||||
function isTrustedForwarder(
|
/// @custom:oz-upgrades-unsafe-allow constructor
|
||||||
address forwarder
|
// constructor(address trustedForwarder) {
|
||||||
) public view override returns (bool) {
|
// _trustedForwarder = trustedForwarder;
|
||||||
|
// }
|
||||||
|
|
||||||
|
function _msgSender()
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
virtual
|
||||||
|
override
|
||||||
|
returns (address sender)
|
||||||
|
{
|
||||||
|
if (trustedForwarders[msg.sender]) {
|
||||||
|
// The assembly code is more direct than the Solidity version using `abi.decode`.
|
||||||
|
/// @solidity memory-safe-assembly
|
||||||
|
assembly {
|
||||||
|
sender := shr(
|
||||||
|
96,
|
||||||
|
calldataload(sub(calldatasize(), 20))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return super._msgSender();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isTrustedForwarder(address forwarder) public view virtual returns (bool) {
|
||||||
return trustedForwarders[forwarder];
|
return trustedForwarders[forwarder];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _msgData()
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
virtual
|
||||||
|
override
|
||||||
|
returns (bytes calldata)
|
||||||
|
{
|
||||||
|
if (isTrustedForwarder(msg.sender)) {
|
||||||
|
return msg.data[:msg.data.length - 20];
|
||||||
|
} else {
|
||||||
|
return super._msgData();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
pragma solidity ^0.8.19;
|
pragma solidity 0.8.19;
|
||||||
|
|
||||||
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
|
import { ERC20 } from "../tokens/ERC20.sol";
|
||||||
|
|
||||||
contract MockToken is ERC20 {
|
contract MockToken is ERC20 {
|
||||||
constructor(uint256 supply) ERC20("MockBRL", "MBRL") {
|
constructor(uint256 supply) ERC20("MockBRL", "MBRL", 18) {
|
||||||
_mint(msg.sender, supply);
|
_mint(msg.sender, supply);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
250
contracts/lib/tokens/ERC20.sol
Normal file
250
contracts/lib/tokens/ERC20.sol
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity >=0.8.4;
|
||||||
|
|
||||||
|
/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
|
||||||
|
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol)
|
||||||
|
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
|
||||||
|
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
|
||||||
|
abstract contract ERC20 {
|
||||||
|
/*//////////////////////////////////////////////////////////////
|
||||||
|
EVENTS
|
||||||
|
//////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
event Transfer(
|
||||||
|
address indexed from,
|
||||||
|
address indexed to,
|
||||||
|
uint256 amount
|
||||||
|
);
|
||||||
|
|
||||||
|
event Approval(
|
||||||
|
address indexed owner,
|
||||||
|
address indexed spender,
|
||||||
|
uint256 amount
|
||||||
|
);
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////
|
||||||
|
METADATA STORAGE
|
||||||
|
//////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
string public name;
|
||||||
|
|
||||||
|
string public symbol;
|
||||||
|
|
||||||
|
uint8 public immutable decimals;
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////
|
||||||
|
ERC20 STORAGE
|
||||||
|
//////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
uint256 public totalSupply;
|
||||||
|
|
||||||
|
mapping(address => uint256) public balanceOf;
|
||||||
|
|
||||||
|
mapping(address => mapping(address => uint256))
|
||||||
|
public allowance;
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////
|
||||||
|
EIP-2612 STORAGE
|
||||||
|
//////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
uint256 internal immutable INITIAL_CHAIN_ID;
|
||||||
|
|
||||||
|
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
|
||||||
|
|
||||||
|
mapping(address => uint256) public nonces;
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////
|
||||||
|
CONSTRUCTOR
|
||||||
|
//////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
string memory _name,
|
||||||
|
string memory _symbol,
|
||||||
|
uint8 _decimals
|
||||||
|
) {
|
||||||
|
name = _name;
|
||||||
|
symbol = _symbol;
|
||||||
|
decimals = _decimals;
|
||||||
|
|
||||||
|
INITIAL_CHAIN_ID = block.chainid;
|
||||||
|
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////
|
||||||
|
ERC20 LOGIC
|
||||||
|
//////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
function approve(
|
||||||
|
address spender,
|
||||||
|
uint256 amount
|
||||||
|
) public virtual returns (bool) {
|
||||||
|
allowance[msg.sender][spender] = amount;
|
||||||
|
|
||||||
|
emit Approval(msg.sender, spender, amount);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function transfer(
|
||||||
|
address to,
|
||||||
|
uint256 amount
|
||||||
|
) public virtual returns (bool) {
|
||||||
|
balanceOf[msg.sender] -= amount;
|
||||||
|
|
||||||
|
// Cannot overflow because the sum of all user
|
||||||
|
// balances can't exceed the max uint256 value.
|
||||||
|
unchecked {
|
||||||
|
balanceOf[to] += amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit Transfer(msg.sender, to, amount);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function transferFrom(
|
||||||
|
address from,
|
||||||
|
address to,
|
||||||
|
uint256 amount
|
||||||
|
) public virtual returns (bool) {
|
||||||
|
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
|
||||||
|
|
||||||
|
if (allowed != type(uint256).max)
|
||||||
|
allowance[from][msg.sender] = allowed - amount;
|
||||||
|
|
||||||
|
balanceOf[from] -= amount;
|
||||||
|
|
||||||
|
// Cannot overflow because the sum of all user
|
||||||
|
// balances can't exceed the max uint256 value.
|
||||||
|
unchecked {
|
||||||
|
balanceOf[to] += amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit Transfer(from, to, amount);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////
|
||||||
|
EIP-2612 LOGIC
|
||||||
|
//////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
function permit(
|
||||||
|
address owner,
|
||||||
|
address spender,
|
||||||
|
uint256 value,
|
||||||
|
uint256 deadline,
|
||||||
|
uint8 v,
|
||||||
|
bytes32 r,
|
||||||
|
bytes32 s
|
||||||
|
) public virtual {
|
||||||
|
require(
|
||||||
|
deadline >= block.timestamp,
|
||||||
|
"PERMIT_DEADLINE_EXPIRED"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Unchecked because the only math done is incrementing
|
||||||
|
// the owner's nonce which cannot realistically overflow.
|
||||||
|
unchecked {
|
||||||
|
address recoveredAddress = ecrecover(
|
||||||
|
keccak256(
|
||||||
|
abi.encodePacked(
|
||||||
|
"\x19\x01",
|
||||||
|
DOMAIN_SEPARATOR(),
|
||||||
|
keccak256(
|
||||||
|
abi.encode(
|
||||||
|
keccak256(
|
||||||
|
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
|
||||||
|
),
|
||||||
|
owner,
|
||||||
|
spender,
|
||||||
|
value,
|
||||||
|
nonces[owner]++,
|
||||||
|
deadline
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
v,
|
||||||
|
r,
|
||||||
|
s
|
||||||
|
);
|
||||||
|
|
||||||
|
require(
|
||||||
|
recoveredAddress != address(0) &&
|
||||||
|
recoveredAddress == owner,
|
||||||
|
"INVALID_SIGNER"
|
||||||
|
);
|
||||||
|
|
||||||
|
allowance[recoveredAddress][spender] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit Approval(owner, spender, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function DOMAIN_SEPARATOR()
|
||||||
|
public
|
||||||
|
view
|
||||||
|
virtual
|
||||||
|
returns (bytes32)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
block.chainid == INITIAL_CHAIN_ID
|
||||||
|
? INITIAL_DOMAIN_SEPARATOR
|
||||||
|
: computeDomainSeparator();
|
||||||
|
}
|
||||||
|
|
||||||
|
function computeDomainSeparator()
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
virtual
|
||||||
|
returns (bytes32)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
keccak256(
|
||||||
|
abi.encode(
|
||||||
|
keccak256(
|
||||||
|
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
|
||||||
|
),
|
||||||
|
keccak256(bytes(name)),
|
||||||
|
keccak256("1"),
|
||||||
|
block.chainid,
|
||||||
|
address(this)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////
|
||||||
|
INTERNAL MINT/BURN LOGIC
|
||||||
|
//////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
function _mint(
|
||||||
|
address to,
|
||||||
|
uint256 amount
|
||||||
|
) internal virtual {
|
||||||
|
totalSupply += amount;
|
||||||
|
|
||||||
|
// Cannot overflow because the sum of all user
|
||||||
|
// balances can't exceed the max uint256 value.
|
||||||
|
unchecked {
|
||||||
|
balanceOf[to] += amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit Transfer(address(0), to, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _burn(
|
||||||
|
address from,
|
||||||
|
uint256 amount
|
||||||
|
) internal virtual {
|
||||||
|
balanceOf[from] -= amount;
|
||||||
|
|
||||||
|
// Cannot underflow because a user's balance
|
||||||
|
// will never be larger than the total supply.
|
||||||
|
unchecked {
|
||||||
|
totalSupply -= amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit Transfer(from, address(0), amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
95
contracts/lib/utils/ECDSA.sol
Normal file
95
contracts/lib/utils/ECDSA.sol
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity >=0.8.4;
|
||||||
|
|
||||||
|
/// @notice Gas optimized ECDSA wrapper.
|
||||||
|
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ECDSA.sol)
|
||||||
|
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ECDSA.sol)
|
||||||
|
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol)
|
||||||
|
library ECDSA {
|
||||||
|
/// @dev The signature is invalid.
|
||||||
|
error InvalidSignature();
|
||||||
|
|
||||||
|
/// @dev The number which `s` must not exceed in order for
|
||||||
|
/// the signature to be non-malleable.
|
||||||
|
bytes32 private constant _MALLEABILITY_THRESHOLD =
|
||||||
|
0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0;
|
||||||
|
|
||||||
|
/// @dev Recovers the signer's address from a message digest `hash`,
|
||||||
|
/// and the `signature`.
|
||||||
|
///
|
||||||
|
/// This function does NOT accept EIP-2098 short form signatures.
|
||||||
|
/// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098
|
||||||
|
/// short form signatures instead.
|
||||||
|
function recoverCalldata(
|
||||||
|
bytes32 hash,
|
||||||
|
bytes calldata signature
|
||||||
|
) internal view returns (address result) {
|
||||||
|
/// @solidity memory-safe-assembly
|
||||||
|
assembly {
|
||||||
|
// Copy the free memory pointer so that we can restore it later.
|
||||||
|
let m := mload(0x40)
|
||||||
|
// Directly copy `r` and `s` from the calldata.
|
||||||
|
calldatacopy(0x40, signature.offset, 0x40)
|
||||||
|
// Store the `hash` in the scratch space.
|
||||||
|
mstore(0x00, hash)
|
||||||
|
// Compute `v` and store it in the scratch space.
|
||||||
|
mstore(
|
||||||
|
0x20,
|
||||||
|
byte(
|
||||||
|
0,
|
||||||
|
calldataload(add(signature.offset, 0x40))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
pop(
|
||||||
|
staticcall(
|
||||||
|
gas(), // Amount of gas left for the transaction.
|
||||||
|
and(
|
||||||
|
// If the signature is exactly 65 bytes in length.
|
||||||
|
eq(signature.length, 65),
|
||||||
|
// If `s` in lower half order, such that the signature is not malleable.
|
||||||
|
lt(
|
||||||
|
mload(0x60),
|
||||||
|
add(_MALLEABILITY_THRESHOLD, 1)
|
||||||
|
)
|
||||||
|
), // Address of `ecrecover`.
|
||||||
|
0x00, // Start of input.
|
||||||
|
0x80, // Size of input.
|
||||||
|
0x00, // Start of output.
|
||||||
|
0x20 // Size of output.
|
||||||
|
)
|
||||||
|
)
|
||||||
|
result := mload(0x00)
|
||||||
|
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
|
||||||
|
if iszero(returndatasize()) {
|
||||||
|
// Store the function selector of `InvalidSignature()`.
|
||||||
|
mstore(0x00, 0x8baa579f)
|
||||||
|
// Revert with (offset, size).
|
||||||
|
revert(0x1c, 0x04)
|
||||||
|
}
|
||||||
|
// Restore the zero slot.
|
||||||
|
mstore(0x60, 0)
|
||||||
|
// Restore the free memory pointer.
|
||||||
|
mstore(0x40, m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Returns an Ethereum Signed Message, created from a `hash`.
|
||||||
|
/// This produces a hash corresponding to the one signed with the
|
||||||
|
/// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign)
|
||||||
|
/// JSON-RPC method as part of EIP-191.
|
||||||
|
function toEthSignedMessageHash(
|
||||||
|
bytes32 hash
|
||||||
|
) internal pure returns (bytes32 result) {
|
||||||
|
/// @solidity memory-safe-assembly
|
||||||
|
assembly {
|
||||||
|
// Store into scratch space for keccak256.
|
||||||
|
mstore(0x20, hash)
|
||||||
|
mstore(
|
||||||
|
0x00,
|
||||||
|
"\x00\x00\x00\x00\x19Ethereum Signed Message:\n32"
|
||||||
|
)
|
||||||
|
// 0x40 - 0x04 = 0x3c
|
||||||
|
result := keccak256(0x04, 0x3c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
58
contracts/lib/utils/MerkleProofLib.sol
Normal file
58
contracts/lib/utils/MerkleProofLib.sol
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity >=0.8.4;
|
||||||
|
|
||||||
|
/// @notice Gas optimized verification of proof of inclusion for a leaf in a Merkle tree.
|
||||||
|
/// @author Solady
|
||||||
|
/// (https://github.com/vectorized/solady/blob/main/src/utils/MerkleProofLib.sol)
|
||||||
|
/// @author Modified from Solmate
|
||||||
|
/// (https://github.com/transmissions11/solmate/blob/main/src/utils/MerkleProofLib.sol)
|
||||||
|
/// @author Modified from OpenZeppelin
|
||||||
|
/// (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/MerkleProof.sol)
|
||||||
|
library MerkleProofLib {
|
||||||
|
/// @dev Returns whether `leaf` exists in the Merkle tree with `root`, given `proof`.
|
||||||
|
function verify(
|
||||||
|
bytes32[] calldata proof,
|
||||||
|
bytes32 root,
|
||||||
|
bytes32 leaf
|
||||||
|
) internal pure returns (bool isValid) {
|
||||||
|
/// @solidity memory-safe-assembly
|
||||||
|
assembly {
|
||||||
|
if proof.length {
|
||||||
|
// Left shift by 5 is equivalent to multiplying by 0x20.
|
||||||
|
let end := add(
|
||||||
|
proof.offset,
|
||||||
|
shl(5, proof.length)
|
||||||
|
)
|
||||||
|
// Initialize `offset` to the offset of `proof` in the calldata.
|
||||||
|
let offset := proof.offset
|
||||||
|
// Iterate over proof elements to compute root hash.
|
||||||
|
for {
|
||||||
|
|
||||||
|
} 1 {
|
||||||
|
|
||||||
|
} {
|
||||||
|
// Slot of `leaf` in scratch space.
|
||||||
|
// If the condition is true: 0x20, otherwise: 0x00.
|
||||||
|
let scratch := shl(
|
||||||
|
5,
|
||||||
|
gt(leaf, calldataload(offset))
|
||||||
|
)
|
||||||
|
// Store elements to hash contiguously in scratch space.
|
||||||
|
// Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes.
|
||||||
|
mstore(scratch, leaf)
|
||||||
|
mstore(
|
||||||
|
xor(scratch, 0x20),
|
||||||
|
calldataload(offset)
|
||||||
|
)
|
||||||
|
// Reuse `leaf` to store the hash to reduce stack operations.
|
||||||
|
leaf := keccak256(0x00, 0x40)
|
||||||
|
offset := add(offset, 0x20)
|
||||||
|
if iszero(lt(offset, end)) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isValid := eq(leaf, root)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,12 +19,12 @@ contract Multicall {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//prettier-ignore
|
//prettier-ignore
|
||||||
//solhint-disable-next-line no-empty-blocks
|
|
||||||
constructor(/* */) payable {/* */}
|
constructor(/* */) payable {/* */}
|
||||||
|
|
||||||
function mtc1(
|
function mtc1(Call[] calldata calls)
|
||||||
Call[] calldata calls
|
external
|
||||||
) external returns (uint256, bytes[] memory) {
|
returns (uint256, bytes[] memory)
|
||||||
|
{
|
||||||
uint256 bn = block.number;
|
uint256 bn = block.number;
|
||||||
uint256 len = calls.length;
|
uint256 len = calls.length;
|
||||||
bytes[] memory res = new bytes[](len);
|
bytes[] memory res = new bytes[](len);
|
||||||
@@ -49,14 +49,21 @@ contract Multicall {
|
|||||||
return (bn, res);
|
return (bn, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mtc2(
|
function mtc2(Call[] calldata calls)
|
||||||
Call[] calldata calls
|
external
|
||||||
) external returns (uint256, bytes32, Result[] memory) {
|
returns (
|
||||||
|
uint256,
|
||||||
|
bytes32,
|
||||||
|
Result[] memory
|
||||||
|
)
|
||||||
|
{
|
||||||
uint256 bn = block.number;
|
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 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
|
// 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).
|
// blocks behind the current block (Yellow Paper, p. 33, https://ethereum.github.io/yellowpaper/paper.pdf).
|
||||||
bytes32 bh = blockhash(bn /* - 1 */);
|
bytes32 bh = blockhash(
|
||||||
|
bn /* - 1 */
|
||||||
|
);
|
||||||
uint256 len = calls.length;
|
uint256 len = calls.length;
|
||||||
Result[] memory res = new Result[](len);
|
Result[] memory res = new Result[](len);
|
||||||
uint256 i;
|
uint256 i;
|
||||||
|
|||||||
34
contracts/lib/utils/ReentrancyGuard.sol
Normal file
34
contracts/lib/utils/ReentrancyGuard.sol
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity >=0.8.4;
|
||||||
|
|
||||||
|
/// @notice Reentrancy protection for smart contracts.
|
||||||
|
/// @author z0r0z.eth
|
||||||
|
/// @author Modified from Seaport
|
||||||
|
/// (https://github.com/ProjectOpenSea/seaport/blob/main/contracts/lib/ReentrancyGuard.sol)
|
||||||
|
/// @author Modified from Solmate
|
||||||
|
/// (https://github.com/Rari-Capital/solmate/blob/main/src/utils/ReentrancyGuard.sol)
|
||||||
|
abstract contract ReentrancyGuard {
|
||||||
|
error Reentrancy();
|
||||||
|
|
||||||
|
uint256 private guard = 1;
|
||||||
|
|
||||||
|
modifier nonReentrant() virtual {
|
||||||
|
setReentrancyGuard();
|
||||||
|
|
||||||
|
_;
|
||||||
|
|
||||||
|
clearReentrancyGuard();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Check guard sentinel value and set it.
|
||||||
|
function setReentrancyGuard() internal virtual {
|
||||||
|
if (guard == 2) revert Reentrancy();
|
||||||
|
|
||||||
|
guard = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Unset sentinel value.
|
||||||
|
function clearReentrancyGuard() internal virtual {
|
||||||
|
guard = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
pragma solidity >=0.8.4;
|
pragma solidity >=0.8.4;
|
||||||
|
|
||||||
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
|
import { ERC20 } from "../tokens/ERC20.sol";
|
||||||
|
|
||||||
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
|
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
|
||||||
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
|
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
pragma solidity ^0.8.19;
|
pragma solidity 0.8.19;
|
||||||
|
|
||||||
/// ______ __
|
/// ______ __
|
||||||
/// .-----.|__ |.-----.|__|.--.--.
|
/// .-----.|__ |.-----.|__|.--.--.
|
||||||
@@ -12,6 +12,7 @@ import { OwnerSettings, ERC20, SafeTransferLib } from "contracts/core/OwnerSetti
|
|||||||
import { BaseUtils } from "contracts/core/BaseUtils.sol";
|
import { BaseUtils } from "contracts/core/BaseUtils.sol";
|
||||||
import { DataTypes as DT } from "contracts/core/DataTypes.sol";
|
import { DataTypes as DT } from "contracts/core/DataTypes.sol";
|
||||||
|
|
||||||
|
|
||||||
contract P2PIX is BaseUtils {
|
contract P2PIX is BaseUtils {
|
||||||
// solhint-disable use-forbidden-name
|
// solhint-disable use-forbidden-name
|
||||||
// solhint-disable no-inline-assembly
|
// solhint-disable no-inline-assembly
|
||||||
@@ -34,7 +35,6 @@ contract P2PIX is BaseUtils {
|
|||||||
ERC20[] memory tokens,
|
ERC20[] memory tokens,
|
||||||
bool[] memory tokenStates
|
bool[] memory tokenStates
|
||||||
)
|
)
|
||||||
payable
|
|
||||||
OwnerSettings(
|
OwnerSettings(
|
||||||
defaultBlocks,
|
defaultBlocks,
|
||||||
validSigners,
|
validSigners,
|
||||||
@@ -42,9 +42,7 @@ contract P2PIX is BaseUtils {
|
|||||||
tokens,
|
tokens,
|
||||||
tokenStates
|
tokenStates
|
||||||
)
|
)
|
||||||
{
|
payable {/* */}
|
||||||
/* */
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @notice Creates a deposit order based on a seller's
|
/// @notice Creates a deposit order based on a seller's
|
||||||
/// offer of an amount of ERC20 tokens.
|
/// offer of an amount of ERC20 tokens.
|
||||||
@@ -60,13 +58,10 @@ contract P2PIX is BaseUtils {
|
|||||||
uint96 amount,
|
uint96 amount,
|
||||||
bool valid
|
bool valid
|
||||||
) public nonReentrant {
|
) public nonReentrant {
|
||||||
if (bytes(pixTarget).length == 0)
|
|
||||||
revert EmptyPixTarget();
|
if (bytes(pixTarget).length == 0) revert EmptyPixTarget();
|
||||||
if (!allowedERC20s(token)) revert TokenDenied();
|
if (!allowedERC20s(token)) revert TokenDenied();
|
||||||
uint256 _sellerBalance = __sellerBalance(
|
uint256 _sellerBalance = __sellerBalance(msg.sender, token);
|
||||||
msg.sender,
|
|
||||||
token
|
|
||||||
);
|
|
||||||
|
|
||||||
uint256 currBal = _sellerBalance & BITMASK_SB_ENTRY;
|
uint256 currBal = _sellerBalance & BITMASK_SB_ENTRY;
|
||||||
uint256 _newBal = uint256(currBal + amount);
|
uint256 _newBal = uint256(currBal + amount);
|
||||||
@@ -102,10 +97,7 @@ contract P2PIX is BaseUtils {
|
|||||||
/// @notice This function does not affect any ongoing active locks.
|
/// @notice This function does not affect any ongoing active locks.
|
||||||
/// @dev Function sighash: 0x6d82d9e0
|
/// @dev Function sighash: 0x6d82d9e0
|
||||||
function setValidState(ERC20 token, bool state) public {
|
function setValidState(ERC20 token, bool state) public {
|
||||||
uint256 _sellerBalance = __sellerBalance(
|
uint256 _sellerBalance = __sellerBalance(msg.sender, token);
|
||||||
msg.sender,
|
|
||||||
token
|
|
||||||
);
|
|
||||||
|
|
||||||
if (_sellerBalance != 0) {
|
if (_sellerBalance != 0) {
|
||||||
uint256 _valid = _castBool(state);
|
uint256 _valid = _castBool(state);
|
||||||
@@ -156,8 +148,9 @@ contract P2PIX is BaseUtils {
|
|||||||
lockID = ++lockCounter;
|
lockID = ++lockCounter;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mapLocks[lockID].expirationBlock >= block.number)
|
if (
|
||||||
revert NotExpired();
|
mapLocks[lockID].expirationBlock >= block.number
|
||||||
|
) revert NotExpired();
|
||||||
|
|
||||||
bytes32 _pixTarget = getPixTarget(seller, token);
|
bytes32 _pixTarget = getPixTarget(seller, token);
|
||||||
|
|
||||||
@@ -165,19 +158,12 @@ contract P2PIX is BaseUtils {
|
|||||||
// otherwise, the trustedForwarder must be previously added
|
// otherwise, the trustedForwarder must be previously added
|
||||||
// to a seller whitelist.
|
// to a seller whitelist.
|
||||||
if (merkleProof.length != 0) {
|
if (merkleProof.length != 0) {
|
||||||
_merkleVerify(
|
_merkleVerify( merkleProof, sellerAllowList(seller), _msgSender());
|
||||||
merkleProof,
|
|
||||||
sellerAllowList(seller),
|
} else if ( amount > REPUTATION_LOWERBOUND && msg.sender == _msgSender() ) {
|
||||||
_msgSender()
|
|
||||||
);
|
uint256 spendLimit; uint256 userCredit =
|
||||||
} else if (
|
userRecord[_castAddrToKey(_msgSender())];
|
||||||
amount > REPUTATION_LOWERBOUND &&
|
|
||||||
msg.sender == _msgSender()
|
|
||||||
) {
|
|
||||||
uint256 spendLimit;
|
|
||||||
uint256 userCredit = userRecord[
|
|
||||||
_castAddrToKey(_msgSender())
|
|
||||||
];
|
|
||||||
(spendLimit) = _limiter(userCredit / WAD);
|
(spendLimit) = _limiter(userCredit / WAD);
|
||||||
if (
|
if (
|
||||||
amount > (spendLimit * WAD) ||
|
amount > (spendLimit * WAD) ||
|
||||||
@@ -242,18 +228,11 @@ contract P2PIX is BaseUtils {
|
|||||||
|
|
||||||
if (_msgSender() == msg.sender) {
|
if (_msgSender() == msg.sender) {
|
||||||
if (msg.sender != l.buyerAddress) {
|
if (msg.sender != l.buyerAddress) {
|
||||||
userRecord[
|
userRecord[_castAddrToKey(msg.sender)] += (lockAmount >> 1);
|
||||||
_castAddrToKey(msg.sender)
|
userRecord[_castAddrToKey(l.buyerAddress)] += (lockAmount >> 1);
|
||||||
] += (lockAmount >> 1);
|
|
||||||
userRecord[
|
|
||||||
_castAddrToKey(l.buyerAddress)
|
|
||||||
] += (lockAmount >> 1);
|
|
||||||
} else {
|
} else {
|
||||||
userRecord[
|
userRecord[_castAddrToKey(msg.sender)] += lockAmount;
|
||||||
_castAddrToKey(msg.sender)
|
}}
|
||||||
] += lockAmount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SafeTransferLib.safeTransfer(
|
SafeTransferLib.safeTransfer(
|
||||||
t,
|
t,
|
||||||
@@ -270,9 +249,9 @@ contract P2PIX is BaseUtils {
|
|||||||
/// @notice For each successfull unexpired lock recovered,
|
/// @notice For each successfull unexpired lock recovered,
|
||||||
/// `userRecord[_castAddrToKey(l.relayerAddress)]` is decreased by half of its value.
|
/// `userRecord[_castAddrToKey(l.relayerAddress)]` is decreased by half of its value.
|
||||||
/// @dev Function sighash: 0xb0983d39
|
/// @dev Function sighash: 0xb0983d39
|
||||||
function unlockExpired(
|
function unlockExpired(uint256[] calldata lockIDs)
|
||||||
uint256[] calldata lockIDs
|
public
|
||||||
) public {
|
{
|
||||||
uint256 i;
|
uint256 i;
|
||||||
uint256 locksSize = lockIDs.length;
|
uint256 locksSize = lockIDs.length;
|
||||||
|
|
||||||
@@ -281,21 +260,19 @@ contract P2PIX is BaseUtils {
|
|||||||
|
|
||||||
_notExpired(l);
|
_notExpired(l);
|
||||||
|
|
||||||
uint256 _sellerBalance = __sellerBalance(
|
uint256 _sellerBalance =
|
||||||
l.seller,
|
__sellerBalance(l.seller, l.token) & BITMASK_SB_ENTRY;
|
||||||
l.token
|
|
||||||
) & BITMASK_SB_ENTRY;
|
|
||||||
|
|
||||||
if (
|
if ((_sellerBalance + l.amount) > MAXBALANCE_UPPERBOUND)
|
||||||
(_sellerBalance + l.amount) >
|
revert MaxBalExceeded();
|
||||||
MAXBALANCE_UPPERBOUND
|
|
||||||
) revert MaxBalExceeded();
|
|
||||||
|
|
||||||
_addSellerBalance(l.seller, l.token, l.amount);
|
_addSellerBalance(l.seller, l.token, l.amount);
|
||||||
|
|
||||||
l.amount = 0;
|
l.amount = 0;
|
||||||
|
|
||||||
uint256 userKey = _castAddrToKey(l.buyerAddress);
|
uint256 userKey = _castAddrToKey(
|
||||||
|
l.buyerAddress
|
||||||
|
);
|
||||||
uint256 _newUserRecord = (userRecord[userKey] >>
|
uint256 _newUserRecord = (userRecord[userKey] >>
|
||||||
1);
|
1);
|
||||||
|
|
||||||
@@ -335,8 +312,7 @@ contract P2PIX is BaseUtils {
|
|||||||
setValidState(token, false);
|
setValidState(token, false);
|
||||||
|
|
||||||
_decBal(
|
_decBal(
|
||||||
(__sellerBalance(msg.sender, token) &
|
(__sellerBalance(msg.sender, token) & BITMASK_SB_ENTRY),
|
||||||
BITMASK_SB_ENTRY),
|
|
||||||
amount,
|
amount,
|
||||||
token,
|
token,
|
||||||
msg.sender
|
msg.sender
|
||||||
@@ -349,13 +325,16 @@ contract P2PIX is BaseUtils {
|
|||||||
amount
|
amount
|
||||||
);
|
);
|
||||||
|
|
||||||
emit DepositWithdrawn(msg.sender, token, amount);
|
emit DepositWithdrawn(
|
||||||
|
msg.sender,
|
||||||
|
token,
|
||||||
|
amount
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setRoot(
|
function setRoot(address addr, bytes32 merkleroot)
|
||||||
address addr,
|
public
|
||||||
bytes32 merkleroot
|
{
|
||||||
) public {
|
|
||||||
assembly ("memory-safe") {
|
assembly ("memory-safe") {
|
||||||
// if (addr != msg.sender)
|
// if (addr != msg.sender)
|
||||||
if iszero(eq(addr, caller())) {
|
if iszero(eq(addr, caller())) {
|
||||||
@@ -432,10 +411,11 @@ contract P2PIX is BaseUtils {
|
|||||||
_decSellerBalance(_k,_t, _amount);
|
_decSellerBalance(_k,_t, _amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBalance(
|
function getBalance(address seller, ERC20 token)
|
||||||
address seller,
|
public
|
||||||
ERC20 token
|
view
|
||||||
) public view returns (uint256 bal) {
|
returns (uint256 bal)
|
||||||
|
{
|
||||||
assembly ("memory-safe") {
|
assembly ("memory-safe") {
|
||||||
for {
|
for {
|
||||||
/* */
|
/* */
|
||||||
@@ -454,10 +434,11 @@ contract P2PIX is BaseUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getValid(
|
function getValid(address seller, ERC20 token)
|
||||||
address seller,
|
public
|
||||||
ERC20 token
|
view
|
||||||
) public view returns (bool valid) {
|
returns (bool valid)
|
||||||
|
{
|
||||||
assembly ("memory-safe") {
|
assembly ("memory-safe") {
|
||||||
for {
|
for {
|
||||||
/* */
|
/* */
|
||||||
@@ -471,9 +452,7 @@ contract P2PIX is BaseUtils {
|
|||||||
BITMASK_SB_ENTRY,
|
BITMASK_SB_ENTRY,
|
||||||
shr(
|
shr(
|
||||||
BITPOS_VALID,
|
BITPOS_VALID,
|
||||||
sload(
|
sload(add(keccak256(0x0c, 0x34), 0x01))
|
||||||
add(keccak256(0x0c, 0x34), 0x01)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
@@ -481,10 +460,11 @@ contract P2PIX is BaseUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPixTarget(
|
function getPixTarget(address seller, ERC20 token)
|
||||||
address seller,
|
public
|
||||||
ERC20 token
|
view
|
||||||
) public view returns (bytes32 pixTarget) {
|
returns (bytes32 pixTarget)
|
||||||
|
{
|
||||||
assembly ("memory-safe") {
|
assembly ("memory-safe") {
|
||||||
for {
|
for {
|
||||||
/* */
|
/* */
|
||||||
@@ -500,10 +480,7 @@ contract P2PIX is BaseUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPixTargetString(
|
function getPixTargetString(address seller, ERC20 token) public view returns (string memory pixTarget) {
|
||||||
address seller,
|
|
||||||
ERC20 token
|
|
||||||
) public view returns (string memory pixTarget) {
|
|
||||||
bytes32 _pixEnc = getPixTarget(seller, token);
|
bytes32 _pixEnc = getPixTarget(seller, token);
|
||||||
pixTarget = string(abi.encodePacked(_pixEnc));
|
pixTarget = string(abi.encodePacked(_pixEnc));
|
||||||
}
|
}
|
||||||
@@ -529,9 +506,7 @@ contract P2PIX is BaseUtils {
|
|||||||
/// @notice External getter that returns the status of a lockIDs array.
|
/// @notice External getter that returns the status of a lockIDs array.
|
||||||
/// @notice Call will not revert if provided with an empty array as parameter.
|
/// @notice Call will not revert if provided with an empty array as parameter.
|
||||||
/// @dev Function sighash: 0x49ef8448
|
/// @dev Function sighash: 0x49ef8448
|
||||||
function getLocksStatus(
|
function getLocksStatus(uint256[] memory ids)
|
||||||
uint256[] memory ids
|
|
||||||
)
|
|
||||||
external
|
external
|
||||||
view
|
view
|
||||||
returns (uint256[] memory, DT.LockStatus[] memory)
|
returns (uint256[] memory, DT.LockStatus[] memory)
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
||||||
"0x70997970C51812dc3A010C7d01b50e0d17dc79C8"
|
"0x70997970C51812dc3A010C7d01b50e0d17dc79C8"
|
||||||
],
|
],
|
||||||
"p2pix": "",
|
"p2pix": "0xC86042E9F2977C62Da8c9dDF7F9c40fde4796A29",
|
||||||
"token": ""
|
"token": "0xD38D6367f452D097ccBfDe4490b7de570B6A72Db"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"signers": [
|
|
||||||
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
||||||
"0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
|
|
||||||
"0x8963E134E6d22Ee9A26ac62a99964aB391ead816"
|
|
||||||
],
|
|
||||||
"token": "0xfE841c74250e57640390f46d914C88d22C51e82e",
|
|
||||||
"p2pix": "0x57Dcba05980761169508886eEdc6f5E7EC0411Dc"
|
|
||||||
}
|
|
||||||
@@ -3,6 +3,6 @@
|
|||||||
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
||||||
"0x70997970C51812dc3A010C7d01b50e0d17dc79C8"
|
"0x70997970C51812dc3A010C7d01b50e0d17dc79C8"
|
||||||
],
|
],
|
||||||
"p2pix": "0xb7cD135F5eFD9760981e02E2a898790b688939fe",
|
"token": "0xfE841c74250e57640390f46d914C88d22C51e82e",
|
||||||
"token": "0x3eBE67A2C7bdB2081CBd34ba3281E90377462289"
|
"p2pix": "0x98ba35eb14b38D6Aa709338283af3e922476dE34"
|
||||||
}
|
}
|
||||||
224
docs/lib/mock/MockToken.md
Normal file
224
docs/lib/mock/MockToken.md
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
# MockToken
|
||||||
|
|
||||||
|
## Methods
|
||||||
|
|
||||||
|
### DOMAIN_SEPARATOR
|
||||||
|
|
||||||
|
```solidity
|
||||||
|
function DOMAIN_SEPARATOR() external view returns (bytes32)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | ------- | ----------- |
|
||||||
|
| \_0 | bytes32 | undefined |
|
||||||
|
|
||||||
|
### allowance
|
||||||
|
|
||||||
|
```solidity
|
||||||
|
function allowance(address, address) external view returns (uint256)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | ------- | ----------- |
|
||||||
|
| \_0 | address | undefined |
|
||||||
|
| \_1 | address | undefined |
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | ------- | ----------- |
|
||||||
|
| \_0 | uint256 | undefined |
|
||||||
|
|
||||||
|
### approve
|
||||||
|
|
||||||
|
```solidity
|
||||||
|
function approve(address spender, uint256 amount) external nonpayable returns (bool)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ------- | ------- | ----------- |
|
||||||
|
| spender | address | undefined |
|
||||||
|
| amount | uint256 | undefined |
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | ---- | ----------- |
|
||||||
|
| \_0 | bool | undefined |
|
||||||
|
|
||||||
|
### balanceOf
|
||||||
|
|
||||||
|
```solidity
|
||||||
|
function balanceOf(address) external view returns (uint256)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | ------- | ----------- |
|
||||||
|
| \_0 | address | undefined |
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | ------- | ----------- |
|
||||||
|
| \_0 | uint256 | undefined |
|
||||||
|
|
||||||
|
### decimals
|
||||||
|
|
||||||
|
```solidity
|
||||||
|
function decimals() external view returns (uint8)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | ----- | ----------- |
|
||||||
|
| \_0 | uint8 | undefined |
|
||||||
|
|
||||||
|
### name
|
||||||
|
|
||||||
|
```solidity
|
||||||
|
function name() external view returns (string)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | ------ | ----------- |
|
||||||
|
| \_0 | string | undefined |
|
||||||
|
|
||||||
|
### nonces
|
||||||
|
|
||||||
|
```solidity
|
||||||
|
function nonces(address) external view returns (uint256)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | ------- | ----------- |
|
||||||
|
| \_0 | address | undefined |
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | ------- | ----------- |
|
||||||
|
| \_0 | uint256 | undefined |
|
||||||
|
|
||||||
|
### permit
|
||||||
|
|
||||||
|
```solidity
|
||||||
|
function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external nonpayable
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| -------- | ------- | ----------- |
|
||||||
|
| owner | address | undefined |
|
||||||
|
| spender | address | undefined |
|
||||||
|
| value | uint256 | undefined |
|
||||||
|
| deadline | uint256 | undefined |
|
||||||
|
| v | uint8 | undefined |
|
||||||
|
| r | bytes32 | undefined |
|
||||||
|
| s | bytes32 | undefined |
|
||||||
|
|
||||||
|
### symbol
|
||||||
|
|
||||||
|
```solidity
|
||||||
|
function symbol() external view returns (string)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | ------ | ----------- |
|
||||||
|
| \_0 | string | undefined |
|
||||||
|
|
||||||
|
### totalSupply
|
||||||
|
|
||||||
|
```solidity
|
||||||
|
function totalSupply() external view returns (uint256)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | ------- | ----------- |
|
||||||
|
| \_0 | uint256 | undefined |
|
||||||
|
|
||||||
|
### transfer
|
||||||
|
|
||||||
|
```solidity
|
||||||
|
function transfer(address to, uint256 amount) external nonpayable returns (bool)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ------ | ------- | ----------- |
|
||||||
|
| to | address | undefined |
|
||||||
|
| amount | uint256 | undefined |
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | ---- | ----------- |
|
||||||
|
| \_0 | bool | undefined |
|
||||||
|
|
||||||
|
### transferFrom
|
||||||
|
|
||||||
|
```solidity
|
||||||
|
function transferFrom(address from, address to, uint256 amount) external nonpayable returns (bool)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ------ | ------- | ----------- |
|
||||||
|
| from | address | undefined |
|
||||||
|
| to | address | undefined |
|
||||||
|
| amount | uint256 | undefined |
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | ---- | ----------- |
|
||||||
|
| \_0 | bool | undefined |
|
||||||
|
|
||||||
|
## Events
|
||||||
|
|
||||||
|
### Approval
|
||||||
|
|
||||||
|
```solidity
|
||||||
|
event Approval(address indexed owner, address indexed spender, uint256 amount)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ----------------- | ------- | ----------- |
|
||||||
|
| owner `indexed` | address | undefined |
|
||||||
|
| spender `indexed` | address | undefined |
|
||||||
|
| amount | uint256 | undefined |
|
||||||
|
|
||||||
|
### Transfer
|
||||||
|
|
||||||
|
```solidity
|
||||||
|
event Transfer(address indexed from, address indexed to, uint256 amount)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| -------------- | ------- | ----------- |
|
||||||
|
| from `indexed` | address | undefined |
|
||||||
|
| to `indexed` | address | undefined |
|
||||||
|
| amount | uint256 | undefined |
|
||||||
16
docs/lib/mock/mockToken.md
Normal file
16
docs/lib/mock/mockToken.md
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# Solidity API
|
||||||
|
|
||||||
|
## MockToken
|
||||||
|
|
||||||
|
### constructor
|
||||||
|
|
||||||
|
```solidity
|
||||||
|
constructor(uint256 supply) public
|
||||||
|
```
|
||||||
|
|
||||||
|
### mint
|
||||||
|
|
||||||
|
```solidity
|
||||||
|
function mint(address[] to, uint256 value) public virtual
|
||||||
|
```
|
||||||
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
const tseslint = require("typescript-eslint");
|
|
||||||
const js = require("@eslint/js");
|
|
||||||
const eslintConfigPrettier = require("eslint-config-prettier");
|
|
||||||
|
|
||||||
module.exports = tseslint.config(
|
|
||||||
{
|
|
||||||
ignores: [
|
|
||||||
".yarn/",
|
|
||||||
"**/.coverage_artifacts",
|
|
||||||
"**/.coverage_cache",
|
|
||||||
"**/.coverage_contracts",
|
|
||||||
"**/artifacts",
|
|
||||||
"**/build",
|
|
||||||
"**/cache",
|
|
||||||
"**/coverage",
|
|
||||||
"**/dist",
|
|
||||||
"**/node_modules",
|
|
||||||
"**/types",
|
|
||||||
"deploys/old/",
|
|
||||||
"docs/",
|
|
||||||
"*.env",
|
|
||||||
"*.log",
|
|
||||||
".pnp.*",
|
|
||||||
"coverage.json",
|
|
||||||
"npm-debug.log*",
|
|
||||||
"yarn-debug.log*",
|
|
||||||
"yarn-error.log*",
|
|
||||||
".solcover.js",
|
|
||||||
"eslint.config.js",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
js.configs.recommended,
|
|
||||||
...tseslint.configs.recommended,
|
|
||||||
eslintConfigPrettier,
|
|
||||||
{
|
|
||||||
languageOptions: {
|
|
||||||
parserOptions: {
|
|
||||||
projectService: true,
|
|
||||||
tsconfigRootDir: __dirname,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
"@typescript-eslint/no-floating-promises": [
|
|
||||||
"error",
|
|
||||||
{ ignoreIIFE: true, ignoreVoid: true },
|
|
||||||
],
|
|
||||||
"@typescript-eslint/no-inferrable-types": "off",
|
|
||||||
"@typescript-eslint/no-unused-vars": [
|
|
||||||
"error",
|
|
||||||
{ argsIgnorePattern: "_", varsIgnorePattern: "_" },
|
|
||||||
],
|
|
||||||
"@typescript-eslint/no-unused-expressions": "off",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import "@nomicfoundation/hardhat-chai-matchers";
|
import "@nomicfoundation/hardhat-chai-matchers";
|
||||||
import "@nomicfoundation/hardhat-toolbox";
|
import "@nomicfoundation/hardhat-toolbox";
|
||||||
import { config as dotenvConfig } from "dotenv";
|
import { config as dotenvConfig } from "dotenv";
|
||||||
|
import "hardhat-tracer";
|
||||||
import { HardhatUserConfig } from "hardhat/config";
|
import { HardhatUserConfig } from "hardhat/config";
|
||||||
import { NetworkUserConfig } from "hardhat/types";
|
import { NetworkUserConfig } from "hardhat/types";
|
||||||
import "hardhat-contract-sizer";
|
import "hardhat-contract-sizer";
|
||||||
@@ -9,74 +10,79 @@ import "solidity-docgen";
|
|||||||
|
|
||||||
dotenvConfig({ path: resolve(__dirname, "./.env") });
|
dotenvConfig({ path: resolve(__dirname, "./.env") });
|
||||||
|
|
||||||
// Default mnemonic used by Hardhat / Anvil for deterministic accounts.
|
const mnemonic: string | undefined = process.env.MNEMONIC;
|
||||||
// Lets `--network localhost` (and the default in-process `hardhat` net)
|
if (!mnemonic) {
|
||||||
// run without a .env. Public networks still require a real MNEMONIC.
|
throw new Error("Please set your MNEMONIC in a .env file");
|
||||||
const DEFAULT_MNEMONIC =
|
}
|
||||||
"test test test test test test test test test test test junk";
|
|
||||||
|
const infuraApiKey: string | undefined =
|
||||||
|
process.env.INFURA_API_KEY;
|
||||||
|
if (!infuraApiKey) {
|
||||||
|
throw new Error(
|
||||||
|
"Please set your INFURA_API_KEY in a .env file",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const mnemonic: string =
|
|
||||||
process.env.MNEMONIC ?? DEFAULT_MNEMONIC;
|
|
||||||
const alchemyApiKey: string | undefined =
|
const alchemyApiKey: string | undefined =
|
||||||
process.env.ALCHEMY_API_KEY;
|
process.env.ALCHEMY_API_KEY;
|
||||||
const privateKey: string | undefined =
|
if (!alchemyApiKey) {
|
||||||
process.env.PRIVATE_KEY;
|
throw new Error(
|
||||||
|
"Please set your ALCHEMY_API_KEY in a .env file",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const chainIds = {
|
const chainIds = {
|
||||||
// "{INSERT_NAME}": {INSERT_ID},
|
// "{INSERT_NAME}": {INSERT_ID},
|
||||||
hardhat: 31337,
|
hardhat: 31337,
|
||||||
localhost: 31337,
|
|
||||||
mainnet: 1,
|
mainnet: 1,
|
||||||
"eth-sepolia": 11155111,
|
sepolia: 11155111,
|
||||||
"polygon-mainnet": 137,
|
goerli: 5,
|
||||||
"arb-mainnet": 42161,
|
"polygon-mumbai": 80001,
|
||||||
rootstock:30,
|
rootstock:30,
|
||||||
"rootstock-testnet": 31,
|
rsktestnet:31,
|
||||||
};
|
};
|
||||||
|
|
||||||
function getChainConfig(
|
function getChainConfig(
|
||||||
chain: keyof typeof chainIds,
|
chain: keyof typeof chainIds,
|
||||||
): NetworkUserConfig {
|
): NetworkUserConfig {
|
||||||
if (!alchemyApiKey) {
|
let jsonRpcUrl: string;
|
||||||
throw new Error(
|
switch (chain) {
|
||||||
`Please set ALCHEMY_API_KEY in a .env file before targeting ${chain}`,
|
case "polygon-mumbai":
|
||||||
);
|
jsonRpcUrl =
|
||||||
|
"https://polygon-mumbai.g.alchemy.com/v2/" +
|
||||||
|
alchemyApiKey;
|
||||||
|
break;
|
||||||
|
case "rsktestnet":
|
||||||
|
jsonRpcUrl = "https://public-node.testnet.rsk.co/";
|
||||||
|
break;
|
||||||
|
case "rootstock":
|
||||||
|
jsonRpcUrl = "https://public-node.rsk.co/"
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
jsonRpcUrl =
|
||||||
|
"https://" + chain + ".infura.io/v3/" + infuraApiKey;
|
||||||
}
|
}
|
||||||
const jsonRpcUrl =
|
|
||||||
"https://" + chain + ".g.alchemy.com/v2/" + alchemyApiKey;
|
|
||||||
return {
|
return {
|
||||||
accounts: privateKey
|
// Comment out for default hardhat account settings
|
||||||
? [privateKey]
|
accounts: {
|
||||||
: {
|
|
||||||
count: 10,
|
count: 10,
|
||||||
mnemonic,
|
mnemonic,
|
||||||
path: "m/44'/60'/0'/0",
|
path: "m/44'/60'/0'/0",
|
||||||
},
|
},
|
||||||
|
// gasPrice: 8000000000,
|
||||||
chainId: chainIds[chain],
|
chainId: chainIds[chain],
|
||||||
url: jsonRpcUrl,
|
url: jsonRpcUrl,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const liveNetworks: Record<string, NetworkUserConfig> =
|
|
||||||
alchemyApiKey
|
|
||||||
? {
|
|
||||||
mainnet: getChainConfig("mainnet"),
|
|
||||||
sepolia: getChainConfig("eth-sepolia"),
|
|
||||||
polygon: getChainConfig("polygon-mainnet"),
|
|
||||||
arbitrum: getChainConfig("arb-mainnet"),
|
|
||||||
rootstock: getChainConfig("rootstock"),
|
|
||||||
rsktestnet: getChainConfig("rootstock-testnet"),
|
|
||||||
}
|
|
||||||
: {};
|
|
||||||
|
|
||||||
const config: HardhatUserConfig = {
|
const config: HardhatUserConfig = {
|
||||||
defaultNetwork: "hardhat",
|
defaultNetwork: "hardhat",
|
||||||
etherscan: {
|
etherscan: {
|
||||||
apiKey: {
|
apiKey: {
|
||||||
mainnet: process.env.ETHERSCAN_API_KEY || "",
|
mainnet: process.env.ETHERSCAN_API_KEY || "",
|
||||||
sepolia: process.env.ETHERSCAN_API_KEY || "",
|
rinkeby: process.env.ETHERSCAN_API_KEY || "",
|
||||||
polygon: process.env.POLYGONSCAN_API_KEY || "",
|
goerli: process.env.ETHERSCAN_API_KEY || "",
|
||||||
arbitrumOne: process.env.ARBISCAN_API_KEY || "",
|
polygonMumbai: process.env.POLYGONSCAN_API_KEY || "",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
gasReporter: {
|
gasReporter: {
|
||||||
@@ -84,7 +90,6 @@ const config: HardhatUserConfig = {
|
|||||||
process.env.REPORT_GAS &&
|
process.env.REPORT_GAS &&
|
||||||
process.env.REPORT_GAS != "false"
|
process.env.REPORT_GAS != "false"
|
||||||
),
|
),
|
||||||
offline: true,
|
|
||||||
showTimeSpent: true,
|
showTimeSpent: true,
|
||||||
showMethodSig: true,
|
showMethodSig: true,
|
||||||
token: "ETH",
|
token: "ETH",
|
||||||
@@ -102,16 +107,13 @@ const config: HardhatUserConfig = {
|
|||||||
},
|
},
|
||||||
chainId: chainIds.hardhat,
|
chainId: chainIds.hardhat,
|
||||||
},
|
},
|
||||||
// External Anvil / Hardhat node (e.g. `anvil --port 8545`). Used by
|
// network: getChainConfig("{INSERT_NAME}"),
|
||||||
// the frontend e2e suite to deploy a fresh chain per CI run.
|
mainnet: getChainConfig("mainnet"),
|
||||||
localhost: {
|
goerli: getChainConfig("goerli"),
|
||||||
url: "http://127.0.0.1:8545",
|
sepolia: getChainConfig("sepolia"),
|
||||||
chainId: chainIds.localhost,
|
"polygon-mumbai": getChainConfig("polygon-mumbai"),
|
||||||
accounts: {
|
rootstock: getChainConfig("rootstock"),
|
||||||
mnemonic,
|
rsktestnet: getChainConfig("rsktestnet"),
|
||||||
},
|
|
||||||
},
|
|
||||||
...liveNetworks,
|
|
||||||
},
|
},
|
||||||
paths: {
|
paths: {
|
||||||
artifacts: "./artifacts",
|
artifacts: "./artifacts",
|
||||||
@@ -120,10 +122,10 @@ const config: HardhatUserConfig = {
|
|||||||
tests: "./test",
|
tests: "./test",
|
||||||
},
|
},
|
||||||
solidity: {
|
solidity: {
|
||||||
version: "0.8.28",
|
version: "0.8.19",
|
||||||
settings: {
|
settings: {
|
||||||
viaIR: true,
|
viaIR: true,
|
||||||
evmVersion: "cancun",
|
evmVersion: "paris",
|
||||||
optimizer: {
|
optimizer: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
runs: 20_000,
|
runs: 20_000,
|
||||||
@@ -143,11 +145,11 @@ const config: HardhatUserConfig = {
|
|||||||
},
|
},
|
||||||
typechain: {
|
typechain: {
|
||||||
outDir: "src/types",
|
outDir: "src/types",
|
||||||
target: "ethers-v6",
|
target: "ethers-v5",
|
||||||
},
|
},
|
||||||
docgen: {
|
docgen: {
|
||||||
pages: "files",
|
pages: "files",
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";
|
|
||||||
import { ethers } from "ethers";
|
|
||||||
|
|
||||||
const DEFAULT_SUPPLY = ethers
|
|
||||||
.parseEther("20000000")
|
|
||||||
.toString();
|
|
||||||
|
|
||||||
export default buildModule("MockToken", m => {
|
|
||||||
const supply = m.getParameter("supply", DEFAULT_SUPPLY);
|
|
||||||
|
|
||||||
const token = m.contract("MockToken", [supply]);
|
|
||||||
|
|
||||||
return { token };
|
|
||||||
});
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";
|
|
||||||
|
|
||||||
import ReputationModule from "./Reputation";
|
|
||||||
|
|
||||||
export default buildModule("P2PIX", m => {
|
|
||||||
const { reputation, multicall } = m.useModule(
|
|
||||||
ReputationModule,
|
|
||||||
);
|
|
||||||
|
|
||||||
const defaultBlocks = m.getParameter("defaultBlocks", 10);
|
|
||||||
const validSigners = m.getParameter<string[]>(
|
|
||||||
"validSigners",
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
const tokens = m.getParameter<string[]>("tokens");
|
|
||||||
const allowed = m.getParameter<boolean[]>("allowed");
|
|
||||||
|
|
||||||
const p2pix = m.contract("P2PIX", [
|
|
||||||
defaultBlocks,
|
|
||||||
validSigners,
|
|
||||||
reputation,
|
|
||||||
tokens,
|
|
||||||
allowed,
|
|
||||||
]);
|
|
||||||
|
|
||||||
return {
|
|
||||||
p2pix,
|
|
||||||
reputation,
|
|
||||||
multicall,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";
|
|
||||||
|
|
||||||
import MockTokenModule from "./MockToken";
|
|
||||||
import ReputationModule from "./Reputation";
|
|
||||||
|
|
||||||
export default buildModule("P2PIXWithMock", m => {
|
|
||||||
const { token } = m.useModule(MockTokenModule);
|
|
||||||
const { reputation, multicall } = m.useModule(
|
|
||||||
ReputationModule,
|
|
||||||
);
|
|
||||||
|
|
||||||
const defaultBlocks = m.getParameter("defaultBlocks", 10);
|
|
||||||
const validSigners = m.getParameter<string[]>(
|
|
||||||
"validSigners",
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
const p2pix = m.contract("P2PIX", [
|
|
||||||
defaultBlocks,
|
|
||||||
validSigners,
|
|
||||||
reputation,
|
|
||||||
[token],
|
|
||||||
[true],
|
|
||||||
]);
|
|
||||||
|
|
||||||
return {
|
|
||||||
p2pix,
|
|
||||||
reputation,
|
|
||||||
multicall,
|
|
||||||
token,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";
|
|
||||||
|
|
||||||
export default buildModule("Reputation", m => {
|
|
||||||
const reputation = m.contract("Reputation", []);
|
|
||||||
const multicall = m.contract("Multicall", []);
|
|
||||||
|
|
||||||
return { reputation, multicall };
|
|
||||||
});
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"P2PIXWithMock": {
|
|
||||||
"defaultBlocks": 10,
|
|
||||||
"validSigners": []
|
|
||||||
},
|
|
||||||
"MockToken": {
|
|
||||||
"supply": "20000000000000000000000000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"P2PIX": {
|
|
||||||
"defaultBlocks": 10,
|
|
||||||
"validSigners": [],
|
|
||||||
"tokens": ["0x0000000000000000000000000000000000000000"],
|
|
||||||
"allowed": [true]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
109
package.json
109
package.json
@@ -9,65 +9,86 @@
|
|||||||
"url": "https://github.com/doiim/p2pix-smart-contracts/issues"
|
"url": "https://github.com/doiim/p2pix-smart-contracts/issues"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"clean": "hardhat clean",
|
"clean": "shx rm -rf ./artifacts ./cache ./coverage ./src/types ./coverage.json && yarn typechain",
|
||||||
"compile": "hardhat compile",
|
"commit": "git-cz",
|
||||||
"typechain": "hardhat typechain",
|
"compile": "cross-env TS_NODE_TRANSPILE_ONLY=true hardhat compile",
|
||||||
|
"typechain": "cross-env TS_NODE_TRANSPILE_ONLY=true hardhat typechain",
|
||||||
"test": "hardhat test",
|
"test": "hardhat test",
|
||||||
"deploy": "hardhat ignition deploy ignition/modules/P2PIX.ts",
|
"deploy1:localhost": "hardhat run scripts/1-deploy-mockToken.ts --network localhost",
|
||||||
"deploy:mock": "hardhat ignition deploy ignition/modules/P2PIXWithMock.ts",
|
"deploy2:localhost": "hardhat run scripts/2-deploy-p2pix.ts --network localhost",
|
||||||
|
"deploy1:goerli": "hardhat run scripts/1-deploy-mockToken.ts --network goerli",
|
||||||
|
"deploy2:goerli": "hardhat run scripts/2-deploy-p2pix.ts --network goerli",
|
||||||
|
"deploy1:mumbai": "hardhat run scripts/1-deploy-mockToken.ts --network polygon-mumbai",
|
||||||
|
"deploy2:mumbai": "hardhat run scripts/2-deploy-p2pix.ts --network polygon-mumbai",
|
||||||
"coverage": "hardhat coverage --solcoverjs ./.solcover.js --temp artifacts --testfiles \"test/**/*.ts\" && yarn typechain",
|
"coverage": "hardhat coverage --solcoverjs ./.solcover.js --temp artifacts --testfiles \"test/**/*.ts\" && yarn typechain",
|
||||||
"lint": "yarn lint:sol && yarn lint:ts && yarn prettier:check",
|
"lint": "yarn lint:sol && yarn lint:ts && yarn prettier:check",
|
||||||
"lint:sol": "solhint --config ./.solhint.json --max-warnings 0 \"contracts/**/*.sol\"",
|
"lint:sol": "solhint --config ./.solhint.json --max-warnings 0 \"contracts/**/*.sol\"",
|
||||||
"lint:ts": "eslint .",
|
"lint:ts": "eslint --config ./.eslintrc.yaml --ignore-path ./.eslintignore --ext .js,.ts .",
|
||||||
|
"_postinstall": "husky install",
|
||||||
|
"postpublish": "pinst --enable",
|
||||||
|
"prepublishOnly": "pinst --disable",
|
||||||
"prettier": "prettier --config ./.prettierrc.yaml --write \"**/*.{js,json,md,sol,ts,yaml,yml}\"",
|
"prettier": "prettier --config ./.prettierrc.yaml --write \"**/*.{js,json,md,sol,ts,yaml,yml}\"",
|
||||||
"prettier:check": "prettier --check --config ./.prettierrc.yaml \"**/*.{js,json,md,sol,ts,yaml,yml}\""
|
"prettier:check": "prettier --check --config ./.prettierrc.yaml \"**/*.{js,json,md,sol,ts,yaml,yml}\""
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@ethersproject/abi": "^5.8.0",
|
"@commitlint/cli": "^17.2.0",
|
||||||
"@ethersproject/providers": "^5.8.0",
|
"@commitlint/config-conventional": "^17.2.0",
|
||||||
"@nomicfoundation/hardhat-chai-matchers": "^2.1.0",
|
"@ethersproject/abi": "^5.7.0",
|
||||||
"@nomicfoundation/hardhat-ethers": "^3.1.0",
|
"@ethersproject/abstract-signer": "^5.7.0",
|
||||||
"@nomicfoundation/hardhat-ignition": "^0.15.13",
|
"@ethersproject/bignumber": "^5.7.0",
|
||||||
"@nomicfoundation/hardhat-ignition-ethers": "^0.15.14",
|
"@ethersproject/bytes": "^5.7.0",
|
||||||
"@nomicfoundation/hardhat-network-helpers": "^1.1.0",
|
"@ethersproject/providers": "^5.7.2",
|
||||||
"@nomicfoundation/hardhat-toolbox": "^6.1.0",
|
"@nomicfoundation/hardhat-chai-matchers": "^1.0.4",
|
||||||
"@nomicfoundation/hardhat-verify": "^2.1.0",
|
"@nomicfoundation/hardhat-network-helpers": "1.0.6",
|
||||||
"@nomicfoundation/hardhat-viem": "^2.1.0",
|
"@nomicfoundation/hardhat-toolbox": "^2.0.0",
|
||||||
"@nomicfoundation/ignition-core": "^0.15.13",
|
"@nomiclabs/hardhat-ethers": "^2.2.1",
|
||||||
"@openzeppelin/contracts": "5.5.0",
|
"@nomiclabs/hardhat-etherscan": "^3.1.2",
|
||||||
"@typechain/ethers-v6": "^0.5.1",
|
"@trivago/prettier-plugin-sort-imports": "^3.4.0",
|
||||||
"@typechain/hardhat": "^9.1.0",
|
"@typechain/ethers-v5": "^10.1.1",
|
||||||
"@types/chai": "^4.3.20",
|
"@typechain/hardhat": "^6.1.4",
|
||||||
"@types/mocha": "^10.0.10",
|
"@types/chai": "^4.3.3",
|
||||||
"@types/node": "^24.1.0",
|
"@types/fs-extra": "^9.0.13",
|
||||||
"chai": "4.5.0",
|
"@types/mocha": "^9.1.1",
|
||||||
"dotenv": "^16.6.1",
|
"@types/node": "^18.11.9",
|
||||||
"eslint": "^9.32.0",
|
"@typescript-eslint/eslint-plugin": "^5.42.0",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"@typescript-eslint/parser": "^5.42.0",
|
||||||
"ethers": "^6.15.0",
|
"chai": "^4.3.6",
|
||||||
"hardhat": "^2.26.1",
|
"chalk": "4.x",
|
||||||
"hardhat-contract-sizer": "^2.10.0",
|
"commitizen": "^4.2.5",
|
||||||
"hardhat-gas-reporter": "^2.3.0",
|
"cross-env": "^7.0.3",
|
||||||
|
"cz-conventional-changelog": "^3.3.0",
|
||||||
|
"dotenv": "^16.0.3",
|
||||||
|
"eslint": "^8.26.0",
|
||||||
|
"eslint-config-prettier": "^8.5.0",
|
||||||
|
"ethers": "^5.7.2",
|
||||||
|
"fs-extra": "^10.1.0",
|
||||||
|
"hardhat": "^2.12.2",
|
||||||
|
"hardhat-contract-sizer": "^2.8.0",
|
||||||
|
"hardhat-gas-reporter": "^1.0.9",
|
||||||
|
"hardhat-tracer": "beta",
|
||||||
|
"husky": "^8.0.1",
|
||||||
"keccak256": "^1.0.6",
|
"keccak256": "^1.0.6",
|
||||||
|
"lint-staged": "^13.0.3",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"merkletreejs": "^0.5.2",
|
"merkletreejs": "^0.2.32",
|
||||||
"mocha": "^10.8.2",
|
"mocha": "^10.1.0",
|
||||||
"prettier": "^3.0.0",
|
"pinst": "^3.0.0",
|
||||||
"prettier-plugin-solidity": "^1.0.0",
|
"prettier": "^2.7.1",
|
||||||
"solhint": "^6.2.1",
|
"prettier-plugin-solidity": "^1.0.0-rc.1",
|
||||||
"solhint-plugin-prettier": "^0.1.0",
|
"shx": "^0.3.4",
|
||||||
"solidity-coverage": "^0.8.16",
|
"solhint": "^3.3.7",
|
||||||
|
"solhint-plugin-prettier": "^0.0.5",
|
||||||
|
"solidity-coverage": "^0.8.2",
|
||||||
"solidity-docgen": "^0.6.0-beta.36",
|
"solidity-docgen": "^0.6.0-beta.36",
|
||||||
"ts-node": "^10.9.2",
|
"ts-generator": "^0.1.1",
|
||||||
"typechain": "^8.3.2",
|
"ts-node": "^10.9.1",
|
||||||
"typescript": "^5.8.3",
|
"typechain": "^8.1.1",
|
||||||
"typescript-eslint": "^8.60.0",
|
"typescript": "^4.8.4"
|
||||||
"viem": "^2.33.1"
|
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"/contracts"
|
"/contracts"
|
||||||
],
|
],
|
||||||
"packageManager": "yarn@4.9.2",
|
"packageManager": "yarn@3.2.1",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
}
|
}
|
||||||
|
|||||||
56
scripts/1-deploy-mockToken.ts
Normal file
56
scripts/1-deploy-mockToken.ts
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import "@nomiclabs/hardhat-ethers";
|
||||||
|
import "@nomiclabs/hardhat-etherscan";
|
||||||
|
import { BigNumber } from "ethers";
|
||||||
|
import * as fs from "fs";
|
||||||
|
import { ethers, network } from "hardhat";
|
||||||
|
import hre from "hardhat";
|
||||||
|
|
||||||
|
import { Deploys } from "../test/utils/interfaces";
|
||||||
|
|
||||||
|
let deploysJson: Deploys;
|
||||||
|
const supply: BigNumber = ethers.utils.parseEther("20000000");
|
||||||
|
|
||||||
|
const main = async () => {
|
||||||
|
try {
|
||||||
|
const data = fs.readFileSync(
|
||||||
|
`./deploys/${network.name}.json`,
|
||||||
|
{ encoding: "utf-8" },
|
||||||
|
);
|
||||||
|
deploysJson = JSON.parse(data);
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Error loading Master address: ", err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const [deployer] = await ethers.getSigners();
|
||||||
|
console.log(`Deploying contracts with ${deployer.address}`);
|
||||||
|
|
||||||
|
const ERC20Factory = await ethers.getContractFactory(
|
||||||
|
"MockToken",
|
||||||
|
);
|
||||||
|
const erc20 = await ERC20Factory.deploy(supply);
|
||||||
|
await erc20.deployed();
|
||||||
|
|
||||||
|
deploysJson.token = erc20.address;
|
||||||
|
console.log("🚀 Mock Token Deployed:", erc20.address);
|
||||||
|
await erc20.deployTransaction.wait(6);
|
||||||
|
|
||||||
|
fs.writeFileSync(
|
||||||
|
`./deploys/${network.name}.json`,
|
||||||
|
JSON.stringify(deploysJson, undefined, 2),
|
||||||
|
);
|
||||||
|
|
||||||
|
/* UNCOMMENT WHEN DEPLOYING TO MAINNET/PUBLIC TESTNETS */
|
||||||
|
// verify
|
||||||
|
// await hre.run("verify:verify", {
|
||||||
|
// address: erc20.address,
|
||||||
|
// constructorArguments: [supply],
|
||||||
|
// });
|
||||||
|
};
|
||||||
|
|
||||||
|
main()
|
||||||
|
.then(() => process.exit(0))
|
||||||
|
.catch(error => {
|
||||||
|
console.log(error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
85
scripts/2-deploy-p2pix.ts
Normal file
85
scripts/2-deploy-p2pix.ts
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
import "@nomiclabs/hardhat-ethers";
|
||||||
|
import "@nomiclabs/hardhat-etherscan";
|
||||||
|
import * as fs from "fs";
|
||||||
|
import { ethers, network } from "hardhat";
|
||||||
|
import hre from "hardhat";
|
||||||
|
|
||||||
|
import { Deploys } from "../test/utils/interfaces";
|
||||||
|
|
||||||
|
let deploysJson: Deploys;
|
||||||
|
|
||||||
|
const main = async () => {
|
||||||
|
try {
|
||||||
|
const data = fs.readFileSync(
|
||||||
|
`./deploys/${network.name}.json`,
|
||||||
|
{ encoding: "utf-8" },
|
||||||
|
);
|
||||||
|
deploysJson = JSON.parse(data);
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Error loading Master address: ", err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const [deployer] = await ethers.getSigners();
|
||||||
|
console.log(`Deploying contracts with ${deployer.address}`);
|
||||||
|
|
||||||
|
const Reputation = await ethers.getContractFactory(
|
||||||
|
"Reputation",
|
||||||
|
);
|
||||||
|
const Multicall = await ethers.getContractFactory(
|
||||||
|
"Multicall",
|
||||||
|
);
|
||||||
|
const reputation = await Reputation.deploy();
|
||||||
|
await reputation.deployed();
|
||||||
|
const mutlicall = await Multicall.deploy();
|
||||||
|
await mutlicall.deployed();
|
||||||
|
|
||||||
|
const P2PIX = await ethers.getContractFactory("P2PIX");
|
||||||
|
const p2pix = await P2PIX.deploy(
|
||||||
|
10,
|
||||||
|
deploysJson.signers,
|
||||||
|
reputation.address,
|
||||||
|
[deploysJson.token],
|
||||||
|
[true],
|
||||||
|
);
|
||||||
|
await p2pix.deployed();
|
||||||
|
|
||||||
|
deploysJson.p2pix = 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);
|
||||||
|
|
||||||
|
fs.writeFileSync(
|
||||||
|
`./deploys/${network.name}.json`,
|
||||||
|
JSON.stringify(deploysJson, undefined, 2),
|
||||||
|
);
|
||||||
|
|
||||||
|
/* UNCOMMENT WHEN DEPLOYING TO MAINNET/PUBLIC TESTNETS */
|
||||||
|
//verify
|
||||||
|
// await hre.run("verify:verify", {
|
||||||
|
// address: p2pix.address,
|
||||||
|
// constructorArguments: [
|
||||||
|
// 10,
|
||||||
|
// deploysJson.signers,
|
||||||
|
// reputation.address,
|
||||||
|
// [deploysJson.token],
|
||||||
|
// [true],
|
||||||
|
// ],
|
||||||
|
// });
|
||||||
|
// await hre.run("verify:verify", {
|
||||||
|
// address: reputation.address,
|
||||||
|
// constructorArguments: [],
|
||||||
|
// });
|
||||||
|
// await hre.run("verify:verify", {
|
||||||
|
// address: mutlicall.address,
|
||||||
|
// constructorArguments: [],
|
||||||
|
// });
|
||||||
|
};
|
||||||
|
|
||||||
|
main()
|
||||||
|
.then(() => process.exit(0))
|
||||||
|
.catch(error => {
|
||||||
|
console.log(error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
@@ -20,22 +20,12 @@ const main = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const [deployer] = await ethers.getSigners();
|
const [deployer] = await ethers.getSigners();
|
||||||
console.log(
|
console.log(`Signing transactions with ${deployer.address}`);
|
||||||
`Signing transactions with ${deployer.address}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
const iface = new ethers.utils.Interface(
|
const iface = new ethers.utils.Interface(P2PIX__factory.abi);
|
||||||
P2PIX__factory.abi,
|
const calldata = iface.encodeFunctionData("setDefaultLockBlocks", ["10000"]);
|
||||||
);
|
|
||||||
const calldata = iface.encodeFunctionData(
|
|
||||||
"setDefaultLockBlocks",
|
|
||||||
["10000"],
|
|
||||||
);
|
|
||||||
|
|
||||||
const tx = await deployer.sendTransaction({
|
const tx = await deployer.sendTransaction({to:deploysJson.p2pix, data: calldata});
|
||||||
to: deploysJson.p2pix,
|
|
||||||
data: calldata,
|
|
||||||
});
|
|
||||||
const done = await tx.wait();
|
const done = await tx.wait();
|
||||||
console.log(done.transactionHash);
|
console.log(done.transactionHash);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import "@nomicfoundation/hardhat-chai-matchers";
|
import "@nomicfoundation/hardhat-chai-matchers";
|
||||||
import { loadFixture } from "@nomicfoundation/hardhat-network-helpers";
|
import { loadFixture } from "@nomicfoundation/hardhat-network-helpers";
|
||||||
|
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
|
||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
import { ethers, network } from "hardhat";
|
import { ethers, network } from "hardhat";
|
||||||
|
|
||||||
@@ -7,11 +8,14 @@ import { Reputation } from "../src/types";
|
|||||||
import { curve, repFixture } from "./utils/fixtures";
|
import { curve, repFixture } from "./utils/fixtures";
|
||||||
|
|
||||||
describe("Reputation", () => {
|
describe("Reputation", () => {
|
||||||
|
// contract deployer/admin
|
||||||
|
let owner: SignerWithAddress;
|
||||||
// Reputation Interface instance;
|
// Reputation Interface instance;
|
||||||
let reputation: Reputation;
|
let reputation: Reputation;
|
||||||
|
|
||||||
before("Set signers and reset network", async () => {
|
before("Set signers and reset network", async () => {
|
||||||
await ethers.getSigners();
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
[owner] = await (ethers as any).getSigners();
|
||||||
|
|
||||||
await network.provider.send("hardhat_reset");
|
await network.provider.send("hardhat_reset");
|
||||||
});
|
});
|
||||||
@@ -56,7 +60,7 @@ describe("Reputation", () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
x: Number.MAX_SAFE_INTEGER,
|
x: Number.MAX_SAFE_INTEGER,
|
||||||
expected: curve(Number.MAX_SAFE_INTEGER),
|
shouldRevert: "overflow",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
x: Number.POSITIVE_INFINITY,
|
x: Number.POSITIVE_INFINITY,
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable no-useless-escape */
|
||||||
|
|
||||||
describe("_", () => {
|
describe("_", () => {
|
||||||
console.log(
|
console.log(
|
||||||
"/// ______ __\r\n/// .-----.|__ |.-----.|__|.--.--.\r\n/// | _ || __|| _ || ||_ _|\r\n/// | __||______|| __||__||__.__|\r\n/// |__| |__|\r\n///",
|
"/// ______ __\r\n/// .-----.|__ |.-----.|__|.--.--.\r\n/// | _ || __|| _ || ||_ _|\r\n/// | __||______|| __||__||__.__|\r\n/// |__| |__|\r\n///",
|
||||||
|
|||||||
1295
test/p2pix.test.ts
1295
test/p2pix.test.ts
File diff suppressed because it is too large
Load Diff
@@ -1,16 +1,19 @@
|
|||||||
import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers";
|
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
|
||||||
import { Signer } from "ethers";
|
import { BigNumber, Signer } from "ethers";
|
||||||
import { ethers } from "hardhat";
|
import { ethers } from "hardhat";
|
||||||
import keccak256 from "keccak256";
|
import keccak256 from "keccak256";
|
||||||
import { MerkleTree } from "merkletreejs";
|
import { MerkleTree } from "merkletreejs";
|
||||||
|
|
||||||
import { MockToken, P2PIX__factory } from "../../src/types";
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Call,
|
MockToken,
|
||||||
RepFixture,
|
Multicall,
|
||||||
P2PixAndReputation,
|
P2PIX,
|
||||||
} from "./interfaces";
|
P2PIX__factory,
|
||||||
|
Reputation,
|
||||||
|
} from "../../src/types";
|
||||||
|
|
||||||
|
import { Call, RepFixture, P2PixAndReputation, DepositArgs, LockArgs, ReleaseArgs } from "./interfaces";
|
||||||
|
|
||||||
|
|
||||||
// exported constants
|
// exported constants
|
||||||
export const getSignerAddrs = (
|
export const getSignerAddrs = (
|
||||||
@@ -20,16 +23,18 @@ export const getSignerAddrs = (
|
|||||||
return addrs.slice(0, amount).map(({ address }) => address);
|
return addrs.slice(0, amount).map(({ address }) => address);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getBnFrom = (nums: number[]): bigint[] => {
|
export const getBnFrom = (nums: number[]): BigNumber[] => {
|
||||||
const bns = nums.map(num => BigInt(num));
|
const bns = nums.map(num => ethers.BigNumber.from(num));
|
||||||
return bns;
|
return bns;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getLockData = (
|
export const getLockData = (
|
||||||
addr: string,
|
addr: string,
|
||||||
locks: bigint[][],
|
locks: BigNumber[][],
|
||||||
): Call[] => {
|
): Call[] => {
|
||||||
const iface = new ethers.Interface(P2PIX__factory.abi);
|
const iface = new ethers.utils.Interface(
|
||||||
|
P2PIX__factory.abi,
|
||||||
|
);
|
||||||
return locks.map(lock => ({
|
return locks.map(lock => ({
|
||||||
target: addr,
|
target: addr,
|
||||||
callData: iface.encodeFunctionData("getLocksStatus", [
|
callData: iface.encodeFunctionData("getLocksStatus", [
|
||||||
@@ -67,9 +72,13 @@ export const curve = (x: number): number => {
|
|||||||
|
|
||||||
// exported async functions
|
// exported async functions
|
||||||
export async function repFixture(): Promise<RepFixture> {
|
export async function repFixture(): Promise<RepFixture> {
|
||||||
|
const Reputation = await ethers.getContractFactory(
|
||||||
|
"Reputation",
|
||||||
|
);
|
||||||
const reputation =
|
const reputation =
|
||||||
await ethers.deployContract("Reputation");
|
(await Reputation.deploy()) as Reputation;
|
||||||
return { reputation: await reputation.waitForDeployment() };
|
|
||||||
|
return { reputation };
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function p2pixFixture(): Promise<P2PixAndReputation> {
|
export async function p2pixFixture(): Promise<P2PixAndReputation> {
|
||||||
@@ -78,22 +87,30 @@ export async function p2pixFixture(): Promise<P2PixAndReputation> {
|
|||||||
await ethers.getSigners(),
|
await ethers.getSigners(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const Reputation = await ethers.getContractFactory(
|
||||||
|
"Reputation",
|
||||||
|
);
|
||||||
const reputation =
|
const reputation =
|
||||||
await ethers.deployContract("Reputation");
|
(await Reputation.deploy()) as Reputation;
|
||||||
|
|
||||||
const erc20 = (await ethers.deployContract("MockToken", [
|
const ERC20 = await ethers.getContractFactory("MockToken");
|
||||||
ethers.parseEther("20000000"), // 20M
|
const erc20 = (await ERC20.deploy(
|
||||||
])) as MockToken;
|
ethers.utils.parseEther("20000000"), // 20M
|
||||||
|
)) as MockToken;
|
||||||
|
|
||||||
const p2pix = await ethers.deployContract("P2PIX", [
|
const P2PIX = await ethers.getContractFactory("P2PIX");
|
||||||
|
const p2pix = (await P2PIX.deploy(
|
||||||
10,
|
10,
|
||||||
validSigners,
|
validSigners,
|
||||||
reputation.target,
|
reputation.address,
|
||||||
[erc20.target],
|
[erc20.address],
|
||||||
[true],
|
[true],
|
||||||
]);
|
)) as P2PIX;
|
||||||
|
|
||||||
const multicall = await ethers.deployContract("Multicall");
|
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);
|
||||||
@@ -109,10 +126,10 @@ export async function p2pixFixture(): Promise<P2PixAndReputation> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
multicall: await multicall.waitForDeployment(),
|
multicall,
|
||||||
reputation: await reputation.waitForDeployment(),
|
reputation,
|
||||||
erc20: await erc20.waitForDeployment(),
|
erc20,
|
||||||
p2pix: await p2pix.waitForDeployment(),
|
p2pix,
|
||||||
merkleRoot,
|
merkleRoot,
|
||||||
proof,
|
proof,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { BigNumber } from "ethers";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
MockToken,
|
MockToken,
|
||||||
Multicall,
|
Multicall,
|
||||||
@@ -5,6 +7,7 @@ import {
|
|||||||
Reputation,
|
Reputation,
|
||||||
} from "../../src/types";
|
} from "../../src/types";
|
||||||
|
|
||||||
|
|
||||||
// exported interfaces
|
// exported interfaces
|
||||||
export interface Deploys {
|
export interface Deploys {
|
||||||
signers: string[];
|
signers: string[];
|
||||||
@@ -16,29 +19,29 @@ export interface DepositArgs {
|
|||||||
pixTarget: string;
|
pixTarget: string;
|
||||||
allowlistRoot: string;
|
allowlistRoot: string;
|
||||||
token: string;
|
token: string;
|
||||||
amount: bigint;
|
amount: BigNumber;
|
||||||
valid: boolean;
|
valid: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LockArgs {
|
export interface LockArgs {
|
||||||
seller: string;
|
seller: string;
|
||||||
token: string;
|
token: string;
|
||||||
amount: bigint;
|
amount: BigNumber;
|
||||||
merkleProof: string[];
|
merkleProof: string[];
|
||||||
expiredLocks: bigint[];
|
expiredLocks: BigNumber[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ReleaseArgs {
|
export interface ReleaseArgs {
|
||||||
lockID: bigint;
|
lockID: BigNumber;
|
||||||
pixTimestamp: string;
|
pixTimestamp: string;
|
||||||
signature: string;
|
signature: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Lock {
|
export interface Lock {
|
||||||
counter: bigint;
|
counter: BigNumber;
|
||||||
expirationBlock: bigint;
|
expirationBlock: BigNumber;
|
||||||
pixTarget: string;
|
pixTarget: string;
|
||||||
amount: bigint;
|
amount: BigNumber;
|
||||||
token: string;
|
token: string;
|
||||||
buyerAddress: string;
|
buyerAddress: string;
|
||||||
seller: string;
|
seller: string;
|
||||||
|
|||||||
@@ -18,10 +18,5 @@
|
|||||||
},
|
},
|
||||||
"exclude": ["node_modules"],
|
"exclude": ["node_modules"],
|
||||||
"files": ["./hardhat.config.ts"],
|
"files": ["./hardhat.config.ts"],
|
||||||
"include": [
|
"include": ["src/**/*", "test/**/*", "scripts/**/*"]
|
||||||
"src/**/*",
|
|
||||||
"test/**/*",
|
|
||||||
"scripts/**/*",
|
|
||||||
"ignition/**/*"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user