├── .DS_Store ├── .env.example ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── Bug_report.md │ ├── Feature_request.md │ └── config.yaml ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── hardhat.yml ├── .gitignore ├── .openzeppelin ├── arbitrum-one.json ├── arbitrum-sepolia.json ├── base-sepolia.json ├── base.json ├── bsc.json ├── celo.json ├── optimism.json ├── polygon.json ├── sepolia.json ├── unknown-1135.json ├── unknown-2494104990.json ├── unknown-421614.json ├── unknown-42420.json ├── unknown-42421.json ├── unknown-534352.json └── unknown-728126428.json ├── .soliumignore ├── .soliumrc.json ├── .vscode └── extensions.json ├── GatewayFlattened.sol ├── README.md ├── artifacts ├── @openzeppelin │ ├── contracts-upgradeable │ │ ├── access │ │ │ ├── Ownable2StepUpgradeable.sol │ │ │ │ ├── Ownable2StepUpgradeable.dbg.json │ │ │ │ └── Ownable2StepUpgradeable.json │ │ │ └── OwnableUpgradeable.sol │ │ │ │ ├── OwnableUpgradeable.dbg.json │ │ │ │ └── OwnableUpgradeable.json │ │ ├── proxy │ │ │ └── utils │ │ │ │ └── Initializable.sol │ │ │ │ ├── Initializable.dbg.json │ │ │ │ └── Initializable.json │ │ ├── security │ │ │ └── PausableUpgradeable.sol │ │ │ │ ├── PausableUpgradeable.dbg.json │ │ │ │ └── PausableUpgradeable.json │ │ └── utils │ │ │ ├── AddressUpgradeable.sol │ │ │ ├── AddressUpgradeable.dbg.json │ │ │ └── AddressUpgradeable.json │ │ │ └── ContextUpgradeable.sol │ │ │ ├── ContextUpgradeable.dbg.json │ │ │ └── ContextUpgradeable.json │ └── contracts │ │ ├── token │ │ └── ERC20 │ │ │ ├── ERC20.sol │ │ │ ├── ERC20.dbg.json │ │ │ └── ERC20.json │ │ │ ├── IERC20.sol │ │ │ ├── IERC20.dbg.json │ │ │ └── IERC20.json │ │ │ └── extensions │ │ │ └── IERC20Metadata.sol │ │ │ ├── IERC20Metadata.dbg.json │ │ │ └── IERC20Metadata.json │ │ └── utils │ │ └── Context.sol │ │ ├── Context.dbg.json │ │ └── Context.json ├── build-info │ ├── b8a88c4b130e7a569c3029307ef5f126.json │ └── b92a18bd36be0e82f59e420b9f0d4c50.json └── contracts │ ├── Gateway.sol │ ├── Gateway.dbg.json │ └── Gateway.json │ ├── GatewaySettingManager.sol │ ├── GatewaySettingManager.dbg.json │ └── GatewaySettingManager.json │ ├── interfaces │ └── IGateway.sol │ │ ├── IGateway.dbg.json │ │ └── IGateway.json │ └── mocks │ └── MockUSDC.sol │ ├── MockUSDT.dbg.json │ └── MockUSDT.json ├── build └── contracts │ ├── AddressUpgradeable.json │ ├── Context.json │ ├── ContextUpgradeable.json │ ├── ERC20.json │ ├── Gateway.json │ ├── GatewaySettingManager.json │ ├── IERC20.json │ ├── IERC20Metadata.json │ ├── IGateway.json │ ├── Initializable.json │ ├── MockUSDT.json │ ├── Ownable2StepUpgradeable.json │ ├── OwnableUpgradeable.json │ └── PausableUpgradeable.json ├── contracts ├── .DS_Store ├── Gateway.sol ├── GatewaySettingManager.sol ├── interfaces │ └── IGateway.sol └── mocks │ └── MockUSDC.sol ├── flattened └── Gateway.sol ├── hardhat.config.ts ├── migrations ├── 1_deploy.js └── 2_upgrade.js ├── package-lock.json ├── package.json ├── scripts ├── config.ts ├── deploy.ts ├── forceImport.ts ├── setSupportedTokens.ts ├── tron │ ├── setSupportedTokens.ts │ ├── updateProtocolAddresses.ts │ └── updateProtocolFee.ts ├── updateProtocolAddresses.ts ├── updateProtocolFee.ts ├── upgrade.ts └── utils.ts ├── test ├── fixtures │ ├── gateway.js │ └── mockUSDT.js ├── gateway │ ├── gateway.createorder.test.js │ ├── gateway.ownable.test.js │ └── gateway.settleOrder.test.js └── utils │ └── utils.manager.js ├── tronbox-config.js ├── tronbox.js ├── tsconfig.json └── yarn.lock /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paycrest/contracts/4c10417c4d37f6c11a8e55485e32cb35efc47254/.DS_Store -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | DEPLOYER_PRIVATE_KEY= 2 | 3 | ETHERSCAN_API_KEY= 4 | POLYGONSCAN_API_KEY= 5 | BASESCAN_API_KEY= 6 | ARBISCAN_API_KEY= 7 | BSCSCAN_API_KEY= 8 | 9 | SHIELD3_API_KEY= 10 | 11 | TREASURY_ADDRESS= 12 | AGGREGATOR_ADDRESS= 13 | 14 | TREASURY_ADDRESS_TRON= 15 | AGGREGATOR_ADDRESS_TRON= 16 | DEPLOYER_PRIVATE_KEY_TRON= 17 | TRON_PRO_API_KEY= -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # These owners will be the default owners for everything in 2 | # the repo. Unless a later match takes precedence, 3 | # @chibie @onahprosper will be requested for 4 | # review when someone opens a pull request. 5 | * @chibie @onahprosper 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Report a bug to help us improve 4 | title: "[BUG] " 5 | labels: bug 6 | assignees: "" 7 | --- 8 | 9 | **Describe the bug** 10 | A clear and concise description of what the bug is. 11 | 12 | **To Reproduce** 13 | Steps to reproduce the behavior: 14 | 1. Go to '...' 15 | 2. Click on '...' 16 | 3. Scroll down to '...' 17 | 4. See error 18 | 19 | **Expected behavior** 20 | A clear and concise description of what you expected to happen. 21 | 22 | **Screenshots** 23 | If applicable, add screenshots to help explain your problem. 24 | 25 | **Environment:** 26 | - OS: [e.g., Windows 10, macOS Ventura] 27 | - Browser: [e.g., Chrome 112] 28 | - Version: [e.g., 22.5] 29 | 30 | **Additional context** 31 | Add any other context about the problem here. 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: New feature for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | --- 8 | 9 | 10 | **User Story** 11 | > Add the details of this issue from the user's POV 12 | 13 | **Acceptance Criteria** 14 | > 1. **GIVEN** Given that something happens 15 | > **WHEN** Under certain conditions 16 | > **THEN** Then we expect a particular result 17 | 18 | **Tech Details** 19 | >* Add the technical details of the feature 20 | 21 | **Notes/Assumptions** 22 | >* Notes or assumption that has to remain constant. 23 | 24 | **Open Questions** -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yaml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: "Paycrest Dev Community" 4 | url: "https://t.me/+Stx-wLOdj49iNDM0" 5 | about: "Please ask and answer questions here." 6 | - name: "Paycrest Security Bug Bounty" 7 | url: "engineering@paycrest.io" 8 | about: "Please report security vulnerabilities here." -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | > Describe the purpose of this PR along with any background information and the impacts of the proposed change. For the benefit of the community, please do not assume prior context. 4 | > 5 | > Provide details that support your chosen implementation, including: breaking changes, alternatives considered, changes to the API, contracts etc. 6 | 7 | 8 | ### References 9 | 10 | > Include any links supporting this change such as a: 11 | > 12 | > - GitHub Issue/PR number addressed or fixed e.g closes #407 13 | > - StackOverflow post 14 | > - Support forum thread 15 | > - Related pull requests/issues from other repos 16 | > 17 | > If there are no references, simply delete this section. 18 | 19 | ### Testing 20 | 21 | > Describe how this can be tested by reviewers. Be specific about anything not tested and reasons why. If this project has unit and/or integration testing, tests should be added for new functionality and existing tests should complete without errors. 22 | > 23 | > Please include any manual steps for testing end-to-end or functionality not covered by unit/integration tests. 24 | > 25 | > Also include details of the environment this PR was developed in (language/platform/browser version). 26 | 27 | - [ ] This change adds test coverage for new/changed/fixed functionality 28 | 29 | ### Checklist 30 | 31 | - [ ] I have added documentation for new/changed functionality in this PR 32 | - [ ] All active GitHub checks for tests, formatting, and security are passing 33 | - [ ] The correct base branch is being used, if not `main` 34 | 35 | 36 | By submitting a PR, I agree to Paycrest's [Contributor Code of Conduct](https://paycrest.notion.site/Contributor-Code-of-Conduct-1602482d45a2806bab75fd314b381f4c) and [Contribution Guide](https://paycrest.notion.site/Contribution-Guide-1602482d45a2809a8930e6ad565c906a). 37 | -------------------------------------------------------------------------------- /.github/workflows/hardhat.yml: -------------------------------------------------------------------------------- 1 | name: Solidity unit test 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v3 12 | - name: Use Node.js 18 13 | uses: actions/setup-node@v3 14 | with: 15 | node-version: 18.16.0 16 | - name: Install node modules 17 | run: yarn install 18 | - name: Unit test hardhat 19 | run: | 20 | npx hardhat node & 21 | npx hardhat test 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | .vscode 4 | coverage 5 | coverage.json 6 | typechain 7 | typechain-types 8 | 9 | privateKey.txt 10 | publicKey.txt 11 | # Hardhat files 12 | cache 13 | # artifacts 14 | 15 | # Tron Package 16 | src/js/metacoin-config.js 17 | 18 | 19 | -------------------------------------------------------------------------------- /.openzeppelin/arbitrum-sepolia.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifestVersion": "3.2", 3 | "admin": { 4 | "address": "0x16c9C78Dbb224889E3e2ADef991C8c4438ea797B", 5 | "txHash": "0x5f7ae97dd6c5a1a50334a3988aee23ccaa24c23917b4d1f5b25e2d34a988f8b5" 6 | }, 7 | "proxies": [ 8 | { 9 | "address": "0x663C5BfE7d44bA946C2dd4b2D1Cf9580319F9338", 10 | "txHash": "0x75ef4c907d85ed7855a4f8295fd777c38008e8be2ea9e765f7f21a954d58fb72", 11 | "kind": "transparent" 12 | } 13 | ], 14 | "impls": { 15 | "a06bd01b1573ee7d3c8afb6c3ddfab3682efcc3a7a683950a0d6a0042d2ed693": { 16 | "address": "0xD293fCd3dBc025603911853d893A4724CF9f70a0", 17 | "txHash": "0xb050c3dcf96ef53d5fddd9a7ab0758ca54133070934a82cc5745c6a6598f62f2", 18 | "layout": { 19 | "solcVersion": "0.8.18", 20 | "storage": [ 21 | { 22 | "label": "_initialized", 23 | "offset": 0, 24 | "slot": "0", 25 | "type": "t_uint8", 26 | "contract": "Initializable", 27 | "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", 28 | "retypedFrom": "bool" 29 | }, 30 | { 31 | "label": "_initializing", 32 | "offset": 1, 33 | "slot": "0", 34 | "type": "t_bool", 35 | "contract": "Initializable", 36 | "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" 37 | }, 38 | { 39 | "label": "__gap", 40 | "offset": 0, 41 | "slot": "1", 42 | "type": "t_array(t_uint256)50_storage", 43 | "contract": "ContextUpgradeable", 44 | "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:40" 45 | }, 46 | { 47 | "label": "_owner", 48 | "offset": 0, 49 | "slot": "51", 50 | "type": "t_address", 51 | "contract": "OwnableUpgradeable", 52 | "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:22" 53 | }, 54 | { 55 | "label": "__gap", 56 | "offset": 0, 57 | "slot": "52", 58 | "type": "t_array(t_uint256)49_storage", 59 | "contract": "OwnableUpgradeable", 60 | "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:94" 61 | }, 62 | { 63 | "label": "_pendingOwner", 64 | "offset": 0, 65 | "slot": "101", 66 | "type": "t_address", 67 | "contract": "Ownable2StepUpgradeable", 68 | "src": "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol:21" 69 | }, 70 | { 71 | "label": "__gap", 72 | "offset": 0, 73 | "slot": "102", 74 | "type": "t_array(t_uint256)49_storage", 75 | "contract": "Ownable2StepUpgradeable", 76 | "src": "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol:70" 77 | }, 78 | { 79 | "label": "MAX_BPS", 80 | "offset": 0, 81 | "slot": "151", 82 | "type": "t_uint256", 83 | "contract": "GatewaySettingManager", 84 | "src": "contracts/GatewaySettingManager.sol:14" 85 | }, 86 | { 87 | "label": "protocolFeePercent", 88 | "offset": 0, 89 | "slot": "152", 90 | "type": "t_uint64", 91 | "contract": "GatewaySettingManager", 92 | "src": "contracts/GatewaySettingManager.sol:15" 93 | }, 94 | { 95 | "label": "treasuryAddress", 96 | "offset": 8, 97 | "slot": "152", 98 | "type": "t_address", 99 | "contract": "GatewaySettingManager", 100 | "src": "contracts/GatewaySettingManager.sol:16" 101 | }, 102 | { 103 | "label": "_aggregatorAddress", 104 | "offset": 0, 105 | "slot": "153", 106 | "type": "t_address", 107 | "contract": "GatewaySettingManager", 108 | "src": "contracts/GatewaySettingManager.sol:17" 109 | }, 110 | { 111 | "label": "__gap", 112 | "offset": 0, 113 | "slot": "154", 114 | "type": "t_array(t_uint256)50_storage", 115 | "contract": "GatewaySettingManager", 116 | "src": "contracts/GatewaySettingManager.sol:20" 117 | }, 118 | { 119 | "label": "_isTokenSupported", 120 | "offset": 0, 121 | "slot": "204", 122 | "type": "t_mapping(t_address,t_uint256)", 123 | "contract": "GatewaySettingManager", 124 | "src": "contracts/GatewaySettingManager.sol:22" 125 | }, 126 | { 127 | "label": "supportedInstitutions", 128 | "offset": 0, 129 | "slot": "205", 130 | "type": "t_mapping(t_bytes32,t_array(t_struct(Institution)2074_storage)dyn_storage)", 131 | "contract": "GatewaySettingManager", 132 | "src": "contracts/GatewaySettingManager.sol:24" 133 | }, 134 | { 135 | "label": "supportedInstitutionsByCode", 136 | "offset": 0, 137 | "slot": "206", 138 | "type": "t_mapping(t_bytes32,t_struct(InstitutionByCode)2079_storage)", 139 | "contract": "GatewaySettingManager", 140 | "src": "contracts/GatewaySettingManager.sol:25" 141 | }, 142 | { 143 | "label": "_paused", 144 | "offset": 0, 145 | "slot": "207", 146 | "type": "t_bool", 147 | "contract": "PausableUpgradeable", 148 | "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:29" 149 | }, 150 | { 151 | "label": "__gap", 152 | "offset": 0, 153 | "slot": "208", 154 | "type": "t_array(t_uint256)49_storage", 155 | "contract": "PausableUpgradeable", 156 | "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:116" 157 | }, 158 | { 159 | "label": "order", 160 | "offset": 0, 161 | "slot": "257", 162 | "type": "t_mapping(t_bytes32,t_struct(Order)1976_storage)", 163 | "contract": "Gateway", 164 | "src": "contracts/Gateway.sol:20" 165 | }, 166 | { 167 | "label": "_nonce", 168 | "offset": 0, 169 | "slot": "258", 170 | "type": "t_mapping(t_address,t_uint256)", 171 | "contract": "Gateway", 172 | "src": "contracts/Gateway.sol:21" 173 | }, 174 | { 175 | "label": "__gap", 176 | "offset": 0, 177 | "slot": "259", 178 | "type": "t_array(t_uint256)50_storage", 179 | "contract": "Gateway", 180 | "src": "contracts/Gateway.sol:22" 181 | } 182 | ], 183 | "types": { 184 | "t_address": { 185 | "label": "address", 186 | "numberOfBytes": "20" 187 | }, 188 | "t_array(t_struct(Institution)2074_storage)dyn_storage": { 189 | "label": "struct SharedStructs.Institution[]", 190 | "numberOfBytes": "32" 191 | }, 192 | "t_array(t_uint256)49_storage": { 193 | "label": "uint256[49]", 194 | "numberOfBytes": "1568" 195 | }, 196 | "t_array(t_uint256)50_storage": { 197 | "label": "uint256[50]", 198 | "numberOfBytes": "1600" 199 | }, 200 | "t_bool": { 201 | "label": "bool", 202 | "numberOfBytes": "1" 203 | }, 204 | "t_bytes32": { 205 | "label": "bytes32", 206 | "numberOfBytes": "32" 207 | }, 208 | "t_mapping(t_address,t_uint256)": { 209 | "label": "mapping(address => uint256)", 210 | "numberOfBytes": "32" 211 | }, 212 | "t_mapping(t_bytes32,t_array(t_struct(Institution)2074_storage)dyn_storage)": { 213 | "label": "mapping(bytes32 => struct SharedStructs.Institution[])", 214 | "numberOfBytes": "32" 215 | }, 216 | "t_mapping(t_bytes32,t_struct(InstitutionByCode)2079_storage)": { 217 | "label": "mapping(bytes32 => struct SharedStructs.InstitutionByCode)", 218 | "numberOfBytes": "32" 219 | }, 220 | "t_mapping(t_bytes32,t_struct(Order)1976_storage)": { 221 | "label": "mapping(bytes32 => struct IGateway.Order)", 222 | "numberOfBytes": "32" 223 | }, 224 | "t_struct(Institution)2074_storage": { 225 | "label": "struct SharedStructs.Institution", 226 | "members": [ 227 | { 228 | "label": "code", 229 | "type": "t_bytes32", 230 | "offset": 0, 231 | "slot": "0" 232 | }, 233 | { 234 | "label": "name", 235 | "type": "t_bytes32", 236 | "offset": 0, 237 | "slot": "1" 238 | } 239 | ], 240 | "numberOfBytes": "64" 241 | }, 242 | "t_struct(InstitutionByCode)2079_storage": { 243 | "label": "struct SharedStructs.InstitutionByCode", 244 | "members": [ 245 | { 246 | "label": "name", 247 | "type": "t_bytes32", 248 | "offset": 0, 249 | "slot": "0" 250 | }, 251 | { 252 | "label": "currency", 253 | "type": "t_bytes32", 254 | "offset": 0, 255 | "slot": "1" 256 | } 257 | ], 258 | "numberOfBytes": "64" 259 | }, 260 | "t_struct(Order)1976_storage": { 261 | "label": "struct IGateway.Order", 262 | "members": [ 263 | { 264 | "label": "sender", 265 | "type": "t_address", 266 | "offset": 0, 267 | "slot": "0" 268 | }, 269 | { 270 | "label": "token", 271 | "type": "t_address", 272 | "offset": 0, 273 | "slot": "1" 274 | }, 275 | { 276 | "label": "senderFeeRecipient", 277 | "type": "t_address", 278 | "offset": 0, 279 | "slot": "2" 280 | }, 281 | { 282 | "label": "senderFee", 283 | "type": "t_uint256", 284 | "offset": 0, 285 | "slot": "3" 286 | }, 287 | { 288 | "label": "protocolFee", 289 | "type": "t_uint256", 290 | "offset": 0, 291 | "slot": "4" 292 | }, 293 | { 294 | "label": "isFulfilled", 295 | "type": "t_bool", 296 | "offset": 0, 297 | "slot": "5" 298 | }, 299 | { 300 | "label": "isRefunded", 301 | "type": "t_bool", 302 | "offset": 1, 303 | "slot": "5" 304 | }, 305 | { 306 | "label": "refundAddress", 307 | "type": "t_address", 308 | "offset": 2, 309 | "slot": "5" 310 | }, 311 | { 312 | "label": "currentBPS", 313 | "type": "t_uint96", 314 | "offset": 0, 315 | "slot": "6" 316 | }, 317 | { 318 | "label": "amount", 319 | "type": "t_uint256", 320 | "offset": 0, 321 | "slot": "7" 322 | } 323 | ], 324 | "numberOfBytes": "256" 325 | }, 326 | "t_uint256": { 327 | "label": "uint256", 328 | "numberOfBytes": "32" 329 | }, 330 | "t_uint64": { 331 | "label": "uint64", 332 | "numberOfBytes": "8" 333 | }, 334 | "t_uint8": { 335 | "label": "uint8", 336 | "numberOfBytes": "1" 337 | }, 338 | "t_uint96": { 339 | "label": "uint96", 340 | "numberOfBytes": "12" 341 | } 342 | } 343 | } 344 | } 345 | } 346 | } 347 | -------------------------------------------------------------------------------- /.openzeppelin/celo.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifestVersion": "3.2", 3 | "admin": { 4 | "address": "0xc38D6817F736b1cb44785e14A8cb7152385d3210", 5 | "txHash": "0xff1fd14319b0800f413e7067581f5d883887a54c57ef9ea949e04205ae35b66c" 6 | }, 7 | "proxies": [ 8 | { 9 | "address": "0xF418217E3f81092eF44b81C5C8336e6A6fDB0E4b", 10 | "txHash": "0x77b071d29651e3369d500eddb002d86cde87224e7ca967f19e28be08dd9e1a1e", 11 | "kind": "transparent" 12 | } 13 | ], 14 | "impls": { 15 | "845d5fbd026630944b1c5aefed90760eff97550d40b8982548deafb809b1f206": { 16 | "address": "0x8508c1C9f29BD1e73B5A9bD8FB87720927c681FA", 17 | "txHash": "0xe480f56df0cb804c162cbaa4e35be63bf1f617c634eb5a24dd6b143405b5a0fe", 18 | "layout": { 19 | "solcVersion": "0.8.18", 20 | "storage": [ 21 | { 22 | "label": "_initialized", 23 | "offset": 0, 24 | "slot": "0", 25 | "type": "t_uint8", 26 | "contract": "Initializable", 27 | "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", 28 | "retypedFrom": "bool" 29 | }, 30 | { 31 | "label": "_initializing", 32 | "offset": 1, 33 | "slot": "0", 34 | "type": "t_bool", 35 | "contract": "Initializable", 36 | "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" 37 | }, 38 | { 39 | "label": "__gap", 40 | "offset": 0, 41 | "slot": "1", 42 | "type": "t_array(t_uint256)50_storage", 43 | "contract": "ContextUpgradeable", 44 | "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:40" 45 | }, 46 | { 47 | "label": "_owner", 48 | "offset": 0, 49 | "slot": "51", 50 | "type": "t_address", 51 | "contract": "OwnableUpgradeable", 52 | "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:22" 53 | }, 54 | { 55 | "label": "__gap", 56 | "offset": 0, 57 | "slot": "52", 58 | "type": "t_array(t_uint256)49_storage", 59 | "contract": "OwnableUpgradeable", 60 | "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:94" 61 | }, 62 | { 63 | "label": "_pendingOwner", 64 | "offset": 0, 65 | "slot": "101", 66 | "type": "t_address", 67 | "contract": "Ownable2StepUpgradeable", 68 | "src": "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol:21" 69 | }, 70 | { 71 | "label": "__gap", 72 | "offset": 0, 73 | "slot": "102", 74 | "type": "t_array(t_uint256)49_storage", 75 | "contract": "Ownable2StepUpgradeable", 76 | "src": "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol:70" 77 | }, 78 | { 79 | "label": "MAX_BPS", 80 | "offset": 0, 81 | "slot": "151", 82 | "type": "t_uint256", 83 | "contract": "GatewaySettingManager", 84 | "src": "contracts/GatewaySettingManager.sol:12" 85 | }, 86 | { 87 | "label": "protocolFeePercent", 88 | "offset": 0, 89 | "slot": "152", 90 | "type": "t_uint64", 91 | "contract": "GatewaySettingManager", 92 | "src": "contracts/GatewaySettingManager.sol:13" 93 | }, 94 | { 95 | "label": "treasuryAddress", 96 | "offset": 8, 97 | "slot": "152", 98 | "type": "t_address", 99 | "contract": "GatewaySettingManager", 100 | "src": "contracts/GatewaySettingManager.sol:14" 101 | }, 102 | { 103 | "label": "_aggregatorAddress", 104 | "offset": 0, 105 | "slot": "153", 106 | "type": "t_address", 107 | "contract": "GatewaySettingManager", 108 | "src": "contracts/GatewaySettingManager.sol:15" 109 | }, 110 | { 111 | "label": "_isTokenSupported", 112 | "offset": 0, 113 | "slot": "154", 114 | "type": "t_mapping(t_address,t_uint256)", 115 | "contract": "GatewaySettingManager", 116 | "src": "contracts/GatewaySettingManager.sol:16" 117 | }, 118 | { 119 | "label": "__gap", 120 | "offset": 0, 121 | "slot": "155", 122 | "type": "t_array(t_uint256)50_storage", 123 | "contract": "GatewaySettingManager", 124 | "src": "contracts/GatewaySettingManager.sol:19" 125 | }, 126 | { 127 | "label": "_paused", 128 | "offset": 0, 129 | "slot": "205", 130 | "type": "t_bool", 131 | "contract": "PausableUpgradeable", 132 | "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:29" 133 | }, 134 | { 135 | "label": "__gap", 136 | "offset": 0, 137 | "slot": "206", 138 | "type": "t_array(t_uint256)49_storage", 139 | "contract": "PausableUpgradeable", 140 | "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:116" 141 | }, 142 | { 143 | "label": "order", 144 | "offset": 0, 145 | "slot": "255", 146 | "type": "t_mapping(t_bytes32,t_struct(Order)2469_storage)", 147 | "contract": "Gateway", 148 | "src": "contracts/Gateway.sol:19" 149 | }, 150 | { 151 | "label": "_nonce", 152 | "offset": 0, 153 | "slot": "256", 154 | "type": "t_mapping(t_address,t_uint256)", 155 | "contract": "Gateway", 156 | "src": "contracts/Gateway.sol:20" 157 | }, 158 | { 159 | "label": "__gap", 160 | "offset": 0, 161 | "slot": "257", 162 | "type": "t_array(t_uint256)50_storage", 163 | "contract": "Gateway", 164 | "src": "contracts/Gateway.sol:21" 165 | } 166 | ], 167 | "types": { 168 | "t_address": { 169 | "label": "address", 170 | "numberOfBytes": "20" 171 | }, 172 | "t_array(t_uint256)49_storage": { 173 | "label": "uint256[49]", 174 | "numberOfBytes": "1568" 175 | }, 176 | "t_array(t_uint256)50_storage": { 177 | "label": "uint256[50]", 178 | "numberOfBytes": "1600" 179 | }, 180 | "t_bool": { 181 | "label": "bool", 182 | "numberOfBytes": "1" 183 | }, 184 | "t_bytes32": { 185 | "label": "bytes32", 186 | "numberOfBytes": "32" 187 | }, 188 | "t_mapping(t_address,t_uint256)": { 189 | "label": "mapping(address => uint256)", 190 | "numberOfBytes": "32" 191 | }, 192 | "t_mapping(t_bytes32,t_struct(Order)2469_storage)": { 193 | "label": "mapping(bytes32 => struct IGateway.Order)", 194 | "numberOfBytes": "32" 195 | }, 196 | "t_struct(Order)2469_storage": { 197 | "label": "struct IGateway.Order", 198 | "members": [ 199 | { 200 | "label": "sender", 201 | "type": "t_address", 202 | "offset": 0, 203 | "slot": "0" 204 | }, 205 | { 206 | "label": "token", 207 | "type": "t_address", 208 | "offset": 0, 209 | "slot": "1" 210 | }, 211 | { 212 | "label": "senderFeeRecipient", 213 | "type": "t_address", 214 | "offset": 0, 215 | "slot": "2" 216 | }, 217 | { 218 | "label": "senderFee", 219 | "type": "t_uint256", 220 | "offset": 0, 221 | "slot": "3" 222 | }, 223 | { 224 | "label": "protocolFee", 225 | "type": "t_uint256", 226 | "offset": 0, 227 | "slot": "4" 228 | }, 229 | { 230 | "label": "isFulfilled", 231 | "type": "t_bool", 232 | "offset": 0, 233 | "slot": "5" 234 | }, 235 | { 236 | "label": "isRefunded", 237 | "type": "t_bool", 238 | "offset": 1, 239 | "slot": "5" 240 | }, 241 | { 242 | "label": "refundAddress", 243 | "type": "t_address", 244 | "offset": 2, 245 | "slot": "5" 246 | }, 247 | { 248 | "label": "currentBPS", 249 | "type": "t_uint96", 250 | "offset": 0, 251 | "slot": "6" 252 | }, 253 | { 254 | "label": "amount", 255 | "type": "t_uint256", 256 | "offset": 0, 257 | "slot": "7" 258 | } 259 | ], 260 | "numberOfBytes": "256" 261 | }, 262 | "t_uint256": { 263 | "label": "uint256", 264 | "numberOfBytes": "32" 265 | }, 266 | "t_uint64": { 267 | "label": "uint64", 268 | "numberOfBytes": "8" 269 | }, 270 | "t_uint8": { 271 | "label": "uint8", 272 | "numberOfBytes": "1" 273 | }, 274 | "t_uint96": { 275 | "label": "uint96", 276 | "numberOfBytes": "12" 277 | } 278 | }, 279 | "namespaces": {} 280 | } 281 | } 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /.openzeppelin/optimism.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifestVersion": "3.2", 3 | "admin": { 4 | "address": "0xb9B5280AB99E48a9662D4740B1e1398abdf87b6D", 5 | "txHash": "0x1f8bb658262a60ce2dd11fdde14576ba79b755447180a1a2cc72934d1dc94cf4" 6 | }, 7 | "proxies": [ 8 | { 9 | "address": "0x431b48b30485Bc9b153599b32b5DdC8e1003AfDD", 10 | "txHash": "0xa769313f13851764f211323e0f55bf995ee73ddb12b71a1ff06a4285c42b6c7d", 11 | "kind": "transparent" 12 | }, 13 | { 14 | "address": "0xD293fCd3dBc025603911853d893A4724CF9f70a0", 15 | "txHash": "0xc8e05500dcbcfbe5930323d0ddde1411dc8f5125c767eebd92896d6e0a1df9bc", 16 | "kind": "transparent" 17 | } 18 | ], 19 | "impls": { 20 | "056b3403c14493917c8bfaa99095b137aa28f666f706bfc65f694ea338f7248d": { 21 | "address": "0x7bA90e38327A4B82D8BF6B481C1b2Ed14228E91A", 22 | "txHash": "0x114049430a09c71ba8571980b4d7572f971f442d4cc72a065013470085e10201", 23 | "layout": { 24 | "solcVersion": "0.8.18", 25 | "storage": [ 26 | { 27 | "label": "_initialized", 28 | "offset": 0, 29 | "slot": "0", 30 | "type": "t_uint8", 31 | "contract": "Initializable", 32 | "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", 33 | "retypedFrom": "bool" 34 | }, 35 | { 36 | "label": "_initializing", 37 | "offset": 1, 38 | "slot": "0", 39 | "type": "t_bool", 40 | "contract": "Initializable", 41 | "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" 42 | }, 43 | { 44 | "label": "__gap", 45 | "offset": 0, 46 | "slot": "1", 47 | "type": "t_array(t_uint256)50_storage", 48 | "contract": "ContextUpgradeable", 49 | "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:40" 50 | }, 51 | { 52 | "label": "_owner", 53 | "offset": 0, 54 | "slot": "51", 55 | "type": "t_address", 56 | "contract": "OwnableUpgradeable", 57 | "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:22" 58 | }, 59 | { 60 | "label": "__gap", 61 | "offset": 0, 62 | "slot": "52", 63 | "type": "t_array(t_uint256)49_storage", 64 | "contract": "OwnableUpgradeable", 65 | "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:94" 66 | }, 67 | { 68 | "label": "_pendingOwner", 69 | "offset": 0, 70 | "slot": "101", 71 | "type": "t_address", 72 | "contract": "Ownable2StepUpgradeable", 73 | "src": "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol:21" 74 | }, 75 | { 76 | "label": "__gap", 77 | "offset": 0, 78 | "slot": "102", 79 | "type": "t_array(t_uint256)49_storage", 80 | "contract": "Ownable2StepUpgradeable", 81 | "src": "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol:70" 82 | }, 83 | { 84 | "label": "MAX_BPS", 85 | "offset": 0, 86 | "slot": "151", 87 | "type": "t_uint256", 88 | "contract": "GatewaySettingManager", 89 | "src": "contracts/GatewaySettingManager.sol:12" 90 | }, 91 | { 92 | "label": "protocolFeePercent", 93 | "offset": 0, 94 | "slot": "152", 95 | "type": "t_uint64", 96 | "contract": "GatewaySettingManager", 97 | "src": "contracts/GatewaySettingManager.sol:13" 98 | }, 99 | { 100 | "label": "treasuryAddress", 101 | "offset": 8, 102 | "slot": "152", 103 | "type": "t_address", 104 | "contract": "GatewaySettingManager", 105 | "src": "contracts/GatewaySettingManager.sol:14" 106 | }, 107 | { 108 | "label": "_aggregatorAddress", 109 | "offset": 0, 110 | "slot": "153", 111 | "type": "t_address", 112 | "contract": "GatewaySettingManager", 113 | "src": "contracts/GatewaySettingManager.sol:15" 114 | }, 115 | { 116 | "label": "_isTokenSupported", 117 | "offset": 0, 118 | "slot": "154", 119 | "type": "t_mapping(t_address,t_uint256)", 120 | "contract": "GatewaySettingManager", 121 | "src": "contracts/GatewaySettingManager.sol:16" 122 | }, 123 | { 124 | "label": "__gap", 125 | "offset": 0, 126 | "slot": "155", 127 | "type": "t_array(t_uint256)50_storage", 128 | "contract": "GatewaySettingManager", 129 | "src": "contracts/GatewaySettingManager.sol:19" 130 | }, 131 | { 132 | "label": "_paused", 133 | "offset": 0, 134 | "slot": "205", 135 | "type": "t_bool", 136 | "contract": "PausableUpgradeable", 137 | "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:29" 138 | }, 139 | { 140 | "label": "__gap", 141 | "offset": 0, 142 | "slot": "206", 143 | "type": "t_array(t_uint256)49_storage", 144 | "contract": "PausableUpgradeable", 145 | "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:116" 146 | }, 147 | { 148 | "label": "order", 149 | "offset": 0, 150 | "slot": "255", 151 | "type": "t_mapping(t_bytes32,t_struct(Order)1830_storage)", 152 | "contract": "Gateway", 153 | "src": "contracts/Gateway.sol:19" 154 | }, 155 | { 156 | "label": "_nonce", 157 | "offset": 0, 158 | "slot": "256", 159 | "type": "t_mapping(t_address,t_uint256)", 160 | "contract": "Gateway", 161 | "src": "contracts/Gateway.sol:20" 162 | }, 163 | { 164 | "label": "__gap", 165 | "offset": 0, 166 | "slot": "257", 167 | "type": "t_array(t_uint256)50_storage", 168 | "contract": "Gateway", 169 | "src": "contracts/Gateway.sol:21" 170 | } 171 | ], 172 | "types": { 173 | "t_address": { 174 | "label": "address", 175 | "numberOfBytes": "20" 176 | }, 177 | "t_array(t_uint256)49_storage": { 178 | "label": "uint256[49]", 179 | "numberOfBytes": "1568" 180 | }, 181 | "t_array(t_uint256)50_storage": { 182 | "label": "uint256[50]", 183 | "numberOfBytes": "1600" 184 | }, 185 | "t_bool": { 186 | "label": "bool", 187 | "numberOfBytes": "1" 188 | }, 189 | "t_bytes32": { 190 | "label": "bytes32", 191 | "numberOfBytes": "32" 192 | }, 193 | "t_mapping(t_address,t_uint256)": { 194 | "label": "mapping(address => uint256)", 195 | "numberOfBytes": "32" 196 | }, 197 | "t_mapping(t_bytes32,t_struct(Order)1830_storage)": { 198 | "label": "mapping(bytes32 => struct IGateway.Order)", 199 | "numberOfBytes": "32" 200 | }, 201 | "t_struct(Order)1830_storage": { 202 | "label": "struct IGateway.Order", 203 | "members": [ 204 | { 205 | "label": "sender", 206 | "type": "t_address", 207 | "offset": 0, 208 | "slot": "0" 209 | }, 210 | { 211 | "label": "token", 212 | "type": "t_address", 213 | "offset": 0, 214 | "slot": "1" 215 | }, 216 | { 217 | "label": "senderFeeRecipient", 218 | "type": "t_address", 219 | "offset": 0, 220 | "slot": "2" 221 | }, 222 | { 223 | "label": "senderFee", 224 | "type": "t_uint256", 225 | "offset": 0, 226 | "slot": "3" 227 | }, 228 | { 229 | "label": "protocolFee", 230 | "type": "t_uint256", 231 | "offset": 0, 232 | "slot": "4" 233 | }, 234 | { 235 | "label": "isFulfilled", 236 | "type": "t_bool", 237 | "offset": 0, 238 | "slot": "5" 239 | }, 240 | { 241 | "label": "isRefunded", 242 | "type": "t_bool", 243 | "offset": 1, 244 | "slot": "5" 245 | }, 246 | { 247 | "label": "refundAddress", 248 | "type": "t_address", 249 | "offset": 2, 250 | "slot": "5" 251 | }, 252 | { 253 | "label": "currentBPS", 254 | "type": "t_uint96", 255 | "offset": 0, 256 | "slot": "6" 257 | }, 258 | { 259 | "label": "amount", 260 | "type": "t_uint256", 261 | "offset": 0, 262 | "slot": "7" 263 | } 264 | ], 265 | "numberOfBytes": "256" 266 | }, 267 | "t_uint256": { 268 | "label": "uint256", 269 | "numberOfBytes": "32" 270 | }, 271 | "t_uint64": { 272 | "label": "uint64", 273 | "numberOfBytes": "8" 274 | }, 275 | "t_uint8": { 276 | "label": "uint8", 277 | "numberOfBytes": "1" 278 | }, 279 | "t_uint96": { 280 | "label": "uint96", 281 | "numberOfBytes": "12" 282 | } 283 | }, 284 | "namespaces": {} 285 | } 286 | }, 287 | "0f100866e1d2f49be7a59745c8f958cdaad8acdf57c5197a7fef1472f55f7a43": { 288 | "address": "0xB04c9622a583DEbe5fef8f5E594582490604D45c", 289 | "txHash": "0xd1b54aebec1586998b0f52544ee427db67af4689e12b6be2e5bbc67aff24eeeb", 290 | "layout": { 291 | "solcVersion": "0.8.18", 292 | "storage": [ 293 | { 294 | "label": "_initialized", 295 | "offset": 0, 296 | "slot": "0", 297 | "type": "t_uint8", 298 | "contract": "Initializable", 299 | "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", 300 | "retypedFrom": "bool" 301 | }, 302 | { 303 | "label": "_initializing", 304 | "offset": 1, 305 | "slot": "0", 306 | "type": "t_bool", 307 | "contract": "Initializable", 308 | "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" 309 | }, 310 | { 311 | "label": "__gap", 312 | "offset": 0, 313 | "slot": "1", 314 | "type": "t_array(t_uint256)50_storage", 315 | "contract": "ContextUpgradeable", 316 | "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:40" 317 | }, 318 | { 319 | "label": "_owner", 320 | "offset": 0, 321 | "slot": "51", 322 | "type": "t_address", 323 | "contract": "OwnableUpgradeable", 324 | "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:22" 325 | }, 326 | { 327 | "label": "__gap", 328 | "offset": 0, 329 | "slot": "52", 330 | "type": "t_array(t_uint256)49_storage", 331 | "contract": "OwnableUpgradeable", 332 | "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:94" 333 | }, 334 | { 335 | "label": "_pendingOwner", 336 | "offset": 0, 337 | "slot": "101", 338 | "type": "t_address", 339 | "contract": "Ownable2StepUpgradeable", 340 | "src": "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol:21" 341 | }, 342 | { 343 | "label": "__gap", 344 | "offset": 0, 345 | "slot": "102", 346 | "type": "t_array(t_uint256)49_storage", 347 | "contract": "Ownable2StepUpgradeable", 348 | "src": "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol:70" 349 | }, 350 | { 351 | "label": "MAX_BPS", 352 | "offset": 0, 353 | "slot": "151", 354 | "type": "t_uint256", 355 | "contract": "GatewaySettingManager", 356 | "src": "contracts/GatewaySettingManager.sol:12" 357 | }, 358 | { 359 | "label": "protocolFeePercent", 360 | "offset": 0, 361 | "slot": "152", 362 | "type": "t_uint64", 363 | "contract": "GatewaySettingManager", 364 | "src": "contracts/GatewaySettingManager.sol:13" 365 | }, 366 | { 367 | "label": "treasuryAddress", 368 | "offset": 8, 369 | "slot": "152", 370 | "type": "t_address", 371 | "contract": "GatewaySettingManager", 372 | "src": "contracts/GatewaySettingManager.sol:14" 373 | }, 374 | { 375 | "label": "_aggregatorAddress", 376 | "offset": 0, 377 | "slot": "153", 378 | "type": "t_address", 379 | "contract": "GatewaySettingManager", 380 | "src": "contracts/GatewaySettingManager.sol:15" 381 | }, 382 | { 383 | "label": "_isTokenSupported", 384 | "offset": 0, 385 | "slot": "154", 386 | "type": "t_mapping(t_address,t_uint256)", 387 | "contract": "GatewaySettingManager", 388 | "src": "contracts/GatewaySettingManager.sol:16" 389 | }, 390 | { 391 | "label": "__gap", 392 | "offset": 0, 393 | "slot": "155", 394 | "type": "t_array(t_uint256)50_storage", 395 | "contract": "GatewaySettingManager", 396 | "src": "contracts/GatewaySettingManager.sol:19" 397 | }, 398 | { 399 | "label": "_paused", 400 | "offset": 0, 401 | "slot": "205", 402 | "type": "t_bool", 403 | "contract": "PausableUpgradeable", 404 | "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:29" 405 | }, 406 | { 407 | "label": "__gap", 408 | "offset": 0, 409 | "slot": "206", 410 | "type": "t_array(t_uint256)49_storage", 411 | "contract": "PausableUpgradeable", 412 | "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:116" 413 | }, 414 | { 415 | "label": "order", 416 | "offset": 0, 417 | "slot": "255", 418 | "type": "t_mapping(t_bytes32,t_struct(Order)1827_storage)", 419 | "contract": "Gateway", 420 | "src": "contracts/Gateway.sol:19" 421 | }, 422 | { 423 | "label": "_nonce", 424 | "offset": 0, 425 | "slot": "256", 426 | "type": "t_mapping(t_address,t_uint256)", 427 | "contract": "Gateway", 428 | "src": "contracts/Gateway.sol:20" 429 | }, 430 | { 431 | "label": "__gap", 432 | "offset": 0, 433 | "slot": "257", 434 | "type": "t_array(t_uint256)50_storage", 435 | "contract": "Gateway", 436 | "src": "contracts/Gateway.sol:21" 437 | } 438 | ], 439 | "types": { 440 | "t_address": { 441 | "label": "address", 442 | "numberOfBytes": "20" 443 | }, 444 | "t_array(t_uint256)49_storage": { 445 | "label": "uint256[49]", 446 | "numberOfBytes": "1568" 447 | }, 448 | "t_array(t_uint256)50_storage": { 449 | "label": "uint256[50]", 450 | "numberOfBytes": "1600" 451 | }, 452 | "t_bool": { 453 | "label": "bool", 454 | "numberOfBytes": "1" 455 | }, 456 | "t_bytes32": { 457 | "label": "bytes32", 458 | "numberOfBytes": "32" 459 | }, 460 | "t_mapping(t_address,t_uint256)": { 461 | "label": "mapping(address => uint256)", 462 | "numberOfBytes": "32" 463 | }, 464 | "t_mapping(t_bytes32,t_struct(Order)1827_storage)": { 465 | "label": "mapping(bytes32 => struct IGateway.Order)", 466 | "numberOfBytes": "32" 467 | }, 468 | "t_struct(Order)1827_storage": { 469 | "label": "struct IGateway.Order", 470 | "members": [ 471 | { 472 | "label": "sender", 473 | "type": "t_address", 474 | "offset": 0, 475 | "slot": "0" 476 | }, 477 | { 478 | "label": "token", 479 | "type": "t_address", 480 | "offset": 0, 481 | "slot": "1" 482 | }, 483 | { 484 | "label": "senderFeeRecipient", 485 | "type": "t_address", 486 | "offset": 0, 487 | "slot": "2" 488 | }, 489 | { 490 | "label": "senderFee", 491 | "type": "t_uint256", 492 | "offset": 0, 493 | "slot": "3" 494 | }, 495 | { 496 | "label": "protocolFee", 497 | "type": "t_uint256", 498 | "offset": 0, 499 | "slot": "4" 500 | }, 501 | { 502 | "label": "isFulfilled", 503 | "type": "t_bool", 504 | "offset": 0, 505 | "slot": "5" 506 | }, 507 | { 508 | "label": "isRefunded", 509 | "type": "t_bool", 510 | "offset": 1, 511 | "slot": "5" 512 | }, 513 | { 514 | "label": "refundAddress", 515 | "type": "t_address", 516 | "offset": 2, 517 | "slot": "5" 518 | }, 519 | { 520 | "label": "currentBPS", 521 | "type": "t_uint96", 522 | "offset": 0, 523 | "slot": "6" 524 | }, 525 | { 526 | "label": "amount", 527 | "type": "t_uint256", 528 | "offset": 0, 529 | "slot": "7" 530 | } 531 | ], 532 | "numberOfBytes": "256" 533 | }, 534 | "t_uint256": { 535 | "label": "uint256", 536 | "numberOfBytes": "32" 537 | }, 538 | "t_uint64": { 539 | "label": "uint64", 540 | "numberOfBytes": "8" 541 | }, 542 | "t_uint8": { 543 | "label": "uint8", 544 | "numberOfBytes": "1" 545 | }, 546 | "t_uint96": { 547 | "label": "uint96", 548 | "numberOfBytes": "12" 549 | } 550 | }, 551 | "namespaces": {} 552 | } 553 | } 554 | } 555 | } 556 | -------------------------------------------------------------------------------- /.openzeppelin/unknown-1135.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifestVersion": "3.2", 3 | "admin": { 4 | "address": "0x8FD1f78d88Dd008E557273b5Cd517487C2A9A7de", 5 | "txHash": "0x0711b3c3d75f99b8fefaf880d892e7d7bb3b61517295cf506f899d617ec2c68d" 6 | }, 7 | "proxies": [ 8 | { 9 | "address": "0xff0E00E0110C1FBb5315D276243497b66D3a4d8a", 10 | "txHash": "0x5f89c6752c144b69fbe09f9be78a0feabfff80cda61221c44719de943bd31f5e", 11 | "kind": "transparent" 12 | } 13 | ], 14 | "impls": { 15 | "8689ffc4c401435f48792097adca219ffd47d52aa60869b4623055b9563f9927": { 16 | "address": "0x3Dc80272cE93cBFF3351913bB089B59C4a9141DE", 17 | "txHash": "0xe5a082ffb6844d7c662a6f8be4f16045368df884fbf5bd3c26094995cfcfaf6c", 18 | "layout": { 19 | "solcVersion": "0.8.18", 20 | "storage": [ 21 | { 22 | "label": "_initialized", 23 | "offset": 0, 24 | "slot": "0", 25 | "type": "t_uint8", 26 | "contract": "Initializable", 27 | "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", 28 | "retypedFrom": "bool" 29 | }, 30 | { 31 | "label": "_initializing", 32 | "offset": 1, 33 | "slot": "0", 34 | "type": "t_bool", 35 | "contract": "Initializable", 36 | "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" 37 | }, 38 | { 39 | "label": "__gap", 40 | "offset": 0, 41 | "slot": "1", 42 | "type": "t_array(t_uint256)50_storage", 43 | "contract": "ContextUpgradeable", 44 | "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:40" 45 | }, 46 | { 47 | "label": "_owner", 48 | "offset": 0, 49 | "slot": "51", 50 | "type": "t_address", 51 | "contract": "OwnableUpgradeable", 52 | "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:22" 53 | }, 54 | { 55 | "label": "__gap", 56 | "offset": 0, 57 | "slot": "52", 58 | "type": "t_array(t_uint256)49_storage", 59 | "contract": "OwnableUpgradeable", 60 | "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:94" 61 | }, 62 | { 63 | "label": "_pendingOwner", 64 | "offset": 0, 65 | "slot": "101", 66 | "type": "t_address", 67 | "contract": "Ownable2StepUpgradeable", 68 | "src": "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol:21" 69 | }, 70 | { 71 | "label": "__gap", 72 | "offset": 0, 73 | "slot": "102", 74 | "type": "t_array(t_uint256)49_storage", 75 | "contract": "Ownable2StepUpgradeable", 76 | "src": "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol:70" 77 | }, 78 | { 79 | "label": "MAX_BPS", 80 | "offset": 0, 81 | "slot": "151", 82 | "type": "t_uint256", 83 | "contract": "GatewaySettingManager", 84 | "src": "contracts/GatewaySettingManager.sol:12" 85 | }, 86 | { 87 | "label": "protocolFeePercent", 88 | "offset": 0, 89 | "slot": "152", 90 | "type": "t_uint64", 91 | "contract": "GatewaySettingManager", 92 | "src": "contracts/GatewaySettingManager.sol:13" 93 | }, 94 | { 95 | "label": "treasuryAddress", 96 | "offset": 8, 97 | "slot": "152", 98 | "type": "t_address", 99 | "contract": "GatewaySettingManager", 100 | "src": "contracts/GatewaySettingManager.sol:14" 101 | }, 102 | { 103 | "label": "_aggregatorAddress", 104 | "offset": 0, 105 | "slot": "153", 106 | "type": "t_address", 107 | "contract": "GatewaySettingManager", 108 | "src": "contracts/GatewaySettingManager.sol:15" 109 | }, 110 | { 111 | "label": "_isTokenSupported", 112 | "offset": 0, 113 | "slot": "154", 114 | "type": "t_mapping(t_address,t_uint256)", 115 | "contract": "GatewaySettingManager", 116 | "src": "contracts/GatewaySettingManager.sol:16" 117 | }, 118 | { 119 | "label": "__gap", 120 | "offset": 0, 121 | "slot": "155", 122 | "type": "t_array(t_uint256)50_storage", 123 | "contract": "GatewaySettingManager", 124 | "src": "contracts/GatewaySettingManager.sol:19" 125 | }, 126 | { 127 | "label": "_paused", 128 | "offset": 0, 129 | "slot": "205", 130 | "type": "t_bool", 131 | "contract": "PausableUpgradeable", 132 | "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:29" 133 | }, 134 | { 135 | "label": "__gap", 136 | "offset": 0, 137 | "slot": "206", 138 | "type": "t_array(t_uint256)49_storage", 139 | "contract": "PausableUpgradeable", 140 | "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:116" 141 | }, 142 | { 143 | "label": "order", 144 | "offset": 0, 145 | "slot": "255", 146 | "type": "t_mapping(t_bytes32,t_struct(Order)1824_storage)", 147 | "contract": "Gateway", 148 | "src": "contracts/Gateway.sol:19" 149 | }, 150 | { 151 | "label": "_nonce", 152 | "offset": 0, 153 | "slot": "256", 154 | "type": "t_mapping(t_address,t_uint256)", 155 | "contract": "Gateway", 156 | "src": "contracts/Gateway.sol:20" 157 | }, 158 | { 159 | "label": "__gap", 160 | "offset": 0, 161 | "slot": "257", 162 | "type": "t_array(t_uint256)50_storage", 163 | "contract": "Gateway", 164 | "src": "contracts/Gateway.sol:21" 165 | } 166 | ], 167 | "types": { 168 | "t_address": { 169 | "label": "address", 170 | "numberOfBytes": "20" 171 | }, 172 | "t_array(t_uint256)49_storage": { 173 | "label": "uint256[49]", 174 | "numberOfBytes": "1568" 175 | }, 176 | "t_array(t_uint256)50_storage": { 177 | "label": "uint256[50]", 178 | "numberOfBytes": "1600" 179 | }, 180 | "t_bool": { 181 | "label": "bool", 182 | "numberOfBytes": "1" 183 | }, 184 | "t_bytes32": { 185 | "label": "bytes32", 186 | "numberOfBytes": "32" 187 | }, 188 | "t_mapping(t_address,t_uint256)": { 189 | "label": "mapping(address => uint256)", 190 | "numberOfBytes": "32" 191 | }, 192 | "t_mapping(t_bytes32,t_struct(Order)1824_storage)": { 193 | "label": "mapping(bytes32 => struct IGateway.Order)", 194 | "numberOfBytes": "32" 195 | }, 196 | "t_struct(Order)1824_storage": { 197 | "label": "struct IGateway.Order", 198 | "members": [ 199 | { 200 | "label": "sender", 201 | "type": "t_address", 202 | "offset": 0, 203 | "slot": "0" 204 | }, 205 | { 206 | "label": "token", 207 | "type": "t_address", 208 | "offset": 0, 209 | "slot": "1" 210 | }, 211 | { 212 | "label": "senderFeeRecipient", 213 | "type": "t_address", 214 | "offset": 0, 215 | "slot": "2" 216 | }, 217 | { 218 | "label": "senderFee", 219 | "type": "t_uint256", 220 | "offset": 0, 221 | "slot": "3" 222 | }, 223 | { 224 | "label": "protocolFee", 225 | "type": "t_uint256", 226 | "offset": 0, 227 | "slot": "4" 228 | }, 229 | { 230 | "label": "isFulfilled", 231 | "type": "t_bool", 232 | "offset": 0, 233 | "slot": "5" 234 | }, 235 | { 236 | "label": "isRefunded", 237 | "type": "t_bool", 238 | "offset": 1, 239 | "slot": "5" 240 | }, 241 | { 242 | "label": "refundAddress", 243 | "type": "t_address", 244 | "offset": 2, 245 | "slot": "5" 246 | }, 247 | { 248 | "label": "currentBPS", 249 | "type": "t_uint96", 250 | "offset": 0, 251 | "slot": "6" 252 | }, 253 | { 254 | "label": "amount", 255 | "type": "t_uint256", 256 | "offset": 0, 257 | "slot": "7" 258 | } 259 | ], 260 | "numberOfBytes": "256" 261 | }, 262 | "t_uint256": { 263 | "label": "uint256", 264 | "numberOfBytes": "32" 265 | }, 266 | "t_uint64": { 267 | "label": "uint64", 268 | "numberOfBytes": "8" 269 | }, 270 | "t_uint8": { 271 | "label": "uint8", 272 | "numberOfBytes": "1" 273 | }, 274 | "t_uint96": { 275 | "label": "uint96", 276 | "numberOfBytes": "12" 277 | } 278 | }, 279 | "namespaces": {} 280 | } 281 | } 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /.openzeppelin/unknown-42420.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifestVersion": "3.2", 3 | "admin": { 4 | "address": "0x8FD1f78d88Dd008E557273b5Cd517487C2A9A7de", 5 | "txHash": "0x0af691605b219065d51db5f2bef9ad10eb5696535ce60b858dec7d9fd03c3518" 6 | }, 7 | "proxies": [ 8 | { 9 | "address": "0xff0E00E0110C1FBb5315D276243497b66D3a4d8a", 10 | "txHash": "0x5060ef7aebb70f94c87ec82b480b0d659824fa237aec9c5c6e9d2fb0ca3b79b9", 11 | "kind": "transparent" 12 | } 13 | ], 14 | "impls": { 15 | "8689ffc4c401435f48792097adca219ffd47d52aa60869b4623055b9563f9927": { 16 | "address": "0x3Dc80272cE93cBFF3351913bB089B59C4a9141DE", 17 | "txHash": "0xbebbb0ff7a02864d0d1bb39df90946ce270d34fd214fcffd90ee7a1c72b7e3b6", 18 | "layout": { 19 | "solcVersion": "0.8.18", 20 | "storage": [ 21 | { 22 | "label": "_initialized", 23 | "offset": 0, 24 | "slot": "0", 25 | "type": "t_uint8", 26 | "contract": "Initializable", 27 | "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", 28 | "retypedFrom": "bool" 29 | }, 30 | { 31 | "label": "_initializing", 32 | "offset": 1, 33 | "slot": "0", 34 | "type": "t_bool", 35 | "contract": "Initializable", 36 | "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" 37 | }, 38 | { 39 | "label": "__gap", 40 | "offset": 0, 41 | "slot": "1", 42 | "type": "t_array(t_uint256)50_storage", 43 | "contract": "ContextUpgradeable", 44 | "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:40" 45 | }, 46 | { 47 | "label": "_owner", 48 | "offset": 0, 49 | "slot": "51", 50 | "type": "t_address", 51 | "contract": "OwnableUpgradeable", 52 | "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:22" 53 | }, 54 | { 55 | "label": "__gap", 56 | "offset": 0, 57 | "slot": "52", 58 | "type": "t_array(t_uint256)49_storage", 59 | "contract": "OwnableUpgradeable", 60 | "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:94" 61 | }, 62 | { 63 | "label": "_pendingOwner", 64 | "offset": 0, 65 | "slot": "101", 66 | "type": "t_address", 67 | "contract": "Ownable2StepUpgradeable", 68 | "src": "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol:21" 69 | }, 70 | { 71 | "label": "__gap", 72 | "offset": 0, 73 | "slot": "102", 74 | "type": "t_array(t_uint256)49_storage", 75 | "contract": "Ownable2StepUpgradeable", 76 | "src": "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol:70" 77 | }, 78 | { 79 | "label": "MAX_BPS", 80 | "offset": 0, 81 | "slot": "151", 82 | "type": "t_uint256", 83 | "contract": "GatewaySettingManager", 84 | "src": "contracts/GatewaySettingManager.sol:12" 85 | }, 86 | { 87 | "label": "protocolFeePercent", 88 | "offset": 0, 89 | "slot": "152", 90 | "type": "t_uint64", 91 | "contract": "GatewaySettingManager", 92 | "src": "contracts/GatewaySettingManager.sol:13" 93 | }, 94 | { 95 | "label": "treasuryAddress", 96 | "offset": 8, 97 | "slot": "152", 98 | "type": "t_address", 99 | "contract": "GatewaySettingManager", 100 | "src": "contracts/GatewaySettingManager.sol:14" 101 | }, 102 | { 103 | "label": "_aggregatorAddress", 104 | "offset": 0, 105 | "slot": "153", 106 | "type": "t_address", 107 | "contract": "GatewaySettingManager", 108 | "src": "contracts/GatewaySettingManager.sol:15" 109 | }, 110 | { 111 | "label": "_isTokenSupported", 112 | "offset": 0, 113 | "slot": "154", 114 | "type": "t_mapping(t_address,t_uint256)", 115 | "contract": "GatewaySettingManager", 116 | "src": "contracts/GatewaySettingManager.sol:16" 117 | }, 118 | { 119 | "label": "__gap", 120 | "offset": 0, 121 | "slot": "155", 122 | "type": "t_array(t_uint256)50_storage", 123 | "contract": "GatewaySettingManager", 124 | "src": "contracts/GatewaySettingManager.sol:19" 125 | }, 126 | { 127 | "label": "_paused", 128 | "offset": 0, 129 | "slot": "205", 130 | "type": "t_bool", 131 | "contract": "PausableUpgradeable", 132 | "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:29" 133 | }, 134 | { 135 | "label": "__gap", 136 | "offset": 0, 137 | "slot": "206", 138 | "type": "t_array(t_uint256)49_storage", 139 | "contract": "PausableUpgradeable", 140 | "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:116" 141 | }, 142 | { 143 | "label": "order", 144 | "offset": 0, 145 | "slot": "255", 146 | "type": "t_mapping(t_bytes32,t_struct(Order)1824_storage)", 147 | "contract": "Gateway", 148 | "src": "contracts/Gateway.sol:19" 149 | }, 150 | { 151 | "label": "_nonce", 152 | "offset": 0, 153 | "slot": "256", 154 | "type": "t_mapping(t_address,t_uint256)", 155 | "contract": "Gateway", 156 | "src": "contracts/Gateway.sol:20" 157 | }, 158 | { 159 | "label": "__gap", 160 | "offset": 0, 161 | "slot": "257", 162 | "type": "t_array(t_uint256)50_storage", 163 | "contract": "Gateway", 164 | "src": "contracts/Gateway.sol:21" 165 | } 166 | ], 167 | "types": { 168 | "t_address": { 169 | "label": "address", 170 | "numberOfBytes": "20" 171 | }, 172 | "t_array(t_uint256)49_storage": { 173 | "label": "uint256[49]", 174 | "numberOfBytes": "1568" 175 | }, 176 | "t_array(t_uint256)50_storage": { 177 | "label": "uint256[50]", 178 | "numberOfBytes": "1600" 179 | }, 180 | "t_bool": { 181 | "label": "bool", 182 | "numberOfBytes": "1" 183 | }, 184 | "t_bytes32": { 185 | "label": "bytes32", 186 | "numberOfBytes": "32" 187 | }, 188 | "t_mapping(t_address,t_uint256)": { 189 | "label": "mapping(address => uint256)", 190 | "numberOfBytes": "32" 191 | }, 192 | "t_mapping(t_bytes32,t_struct(Order)1824_storage)": { 193 | "label": "mapping(bytes32 => struct IGateway.Order)", 194 | "numberOfBytes": "32" 195 | }, 196 | "t_struct(Order)1824_storage": { 197 | "label": "struct IGateway.Order", 198 | "members": [ 199 | { 200 | "label": "sender", 201 | "type": "t_address", 202 | "offset": 0, 203 | "slot": "0" 204 | }, 205 | { 206 | "label": "token", 207 | "type": "t_address", 208 | "offset": 0, 209 | "slot": "1" 210 | }, 211 | { 212 | "label": "senderFeeRecipient", 213 | "type": "t_address", 214 | "offset": 0, 215 | "slot": "2" 216 | }, 217 | { 218 | "label": "senderFee", 219 | "type": "t_uint256", 220 | "offset": 0, 221 | "slot": "3" 222 | }, 223 | { 224 | "label": "protocolFee", 225 | "type": "t_uint256", 226 | "offset": 0, 227 | "slot": "4" 228 | }, 229 | { 230 | "label": "isFulfilled", 231 | "type": "t_bool", 232 | "offset": 0, 233 | "slot": "5" 234 | }, 235 | { 236 | "label": "isRefunded", 237 | "type": "t_bool", 238 | "offset": 1, 239 | "slot": "5" 240 | }, 241 | { 242 | "label": "refundAddress", 243 | "type": "t_address", 244 | "offset": 2, 245 | "slot": "5" 246 | }, 247 | { 248 | "label": "currentBPS", 249 | "type": "t_uint96", 250 | "offset": 0, 251 | "slot": "6" 252 | }, 253 | { 254 | "label": "amount", 255 | "type": "t_uint256", 256 | "offset": 0, 257 | "slot": "7" 258 | } 259 | ], 260 | "numberOfBytes": "256" 261 | }, 262 | "t_uint256": { 263 | "label": "uint256", 264 | "numberOfBytes": "32" 265 | }, 266 | "t_uint64": { 267 | "label": "uint64", 268 | "numberOfBytes": "8" 269 | }, 270 | "t_uint8": { 271 | "label": "uint8", 272 | "numberOfBytes": "1" 273 | }, 274 | "t_uint96": { 275 | "label": "uint96", 276 | "numberOfBytes": "12" 277 | } 278 | }, 279 | "namespaces": {} 280 | } 281 | } 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /.openzeppelin/unknown-42421.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifestVersion": "3.2", 3 | "admin": { 4 | "address": "0x3bECd7DD69DcDe95d03a1e27d93ea9D9f8c06708", 5 | "txHash": "0xc9c7eefad983da68fad0338b447cfc925b1bd508f762467a9ffa574c18cd0360" 6 | }, 7 | "proxies": [ 8 | { 9 | "address": "0xBe6dE889795677736919A7880324A71Dc7dFa162", 10 | "txHash": "0xb0bec39077a8a67df2f0f61830a56677017fac026009ff11576faec0340fd699", 11 | "kind": "transparent" 12 | } 13 | ], 14 | "impls": { 15 | "845d5fbd026630944b1c5aefed90760eff97550d40b8982548deafb809b1f206": { 16 | "address": "0x9519D63fbF9717Fa3419846eBA92B01Cd1d1D131", 17 | "txHash": "0xf9b53fde29323110e1f3c1a75362c6ac682010e863587dd6607b56a7190babb5", 18 | "layout": { 19 | "solcVersion": "0.8.18", 20 | "storage": [ 21 | { 22 | "label": "_initialized", 23 | "offset": 0, 24 | "slot": "0", 25 | "type": "t_uint8", 26 | "contract": "Initializable", 27 | "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", 28 | "retypedFrom": "bool" 29 | }, 30 | { 31 | "label": "_initializing", 32 | "offset": 1, 33 | "slot": "0", 34 | "type": "t_bool", 35 | "contract": "Initializable", 36 | "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" 37 | }, 38 | { 39 | "label": "__gap", 40 | "offset": 0, 41 | "slot": "1", 42 | "type": "t_array(t_uint256)50_storage", 43 | "contract": "ContextUpgradeable", 44 | "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:40" 45 | }, 46 | { 47 | "label": "_owner", 48 | "offset": 0, 49 | "slot": "51", 50 | "type": "t_address", 51 | "contract": "OwnableUpgradeable", 52 | "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:22" 53 | }, 54 | { 55 | "label": "__gap", 56 | "offset": 0, 57 | "slot": "52", 58 | "type": "t_array(t_uint256)49_storage", 59 | "contract": "OwnableUpgradeable", 60 | "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:94" 61 | }, 62 | { 63 | "label": "_pendingOwner", 64 | "offset": 0, 65 | "slot": "101", 66 | "type": "t_address", 67 | "contract": "Ownable2StepUpgradeable", 68 | "src": "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol:21" 69 | }, 70 | { 71 | "label": "__gap", 72 | "offset": 0, 73 | "slot": "102", 74 | "type": "t_array(t_uint256)49_storage", 75 | "contract": "Ownable2StepUpgradeable", 76 | "src": "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol:70" 77 | }, 78 | { 79 | "label": "MAX_BPS", 80 | "offset": 0, 81 | "slot": "151", 82 | "type": "t_uint256", 83 | "contract": "GatewaySettingManager", 84 | "src": "contracts/GatewaySettingManager.sol:12" 85 | }, 86 | { 87 | "label": "protocolFeePercent", 88 | "offset": 0, 89 | "slot": "152", 90 | "type": "t_uint64", 91 | "contract": "GatewaySettingManager", 92 | "src": "contracts/GatewaySettingManager.sol:13" 93 | }, 94 | { 95 | "label": "treasuryAddress", 96 | "offset": 8, 97 | "slot": "152", 98 | "type": "t_address", 99 | "contract": "GatewaySettingManager", 100 | "src": "contracts/GatewaySettingManager.sol:14" 101 | }, 102 | { 103 | "label": "_aggregatorAddress", 104 | "offset": 0, 105 | "slot": "153", 106 | "type": "t_address", 107 | "contract": "GatewaySettingManager", 108 | "src": "contracts/GatewaySettingManager.sol:15" 109 | }, 110 | { 111 | "label": "_isTokenSupported", 112 | "offset": 0, 113 | "slot": "154", 114 | "type": "t_mapping(t_address,t_uint256)", 115 | "contract": "GatewaySettingManager", 116 | "src": "contracts/GatewaySettingManager.sol:16" 117 | }, 118 | { 119 | "label": "__gap", 120 | "offset": 0, 121 | "slot": "155", 122 | "type": "t_array(t_uint256)50_storage", 123 | "contract": "GatewaySettingManager", 124 | "src": "contracts/GatewaySettingManager.sol:19" 125 | }, 126 | { 127 | "label": "_paused", 128 | "offset": 0, 129 | "slot": "205", 130 | "type": "t_bool", 131 | "contract": "PausableUpgradeable", 132 | "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:29" 133 | }, 134 | { 135 | "label": "__gap", 136 | "offset": 0, 137 | "slot": "206", 138 | "type": "t_array(t_uint256)49_storage", 139 | "contract": "PausableUpgradeable", 140 | "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:116" 141 | }, 142 | { 143 | "label": "order", 144 | "offset": 0, 145 | "slot": "255", 146 | "type": "t_mapping(t_bytes32,t_struct(Order)1827_storage)", 147 | "contract": "Gateway", 148 | "src": "contracts/Gateway.sol:19" 149 | }, 150 | { 151 | "label": "_nonce", 152 | "offset": 0, 153 | "slot": "256", 154 | "type": "t_mapping(t_address,t_uint256)", 155 | "contract": "Gateway", 156 | "src": "contracts/Gateway.sol:20" 157 | }, 158 | { 159 | "label": "__gap", 160 | "offset": 0, 161 | "slot": "257", 162 | "type": "t_array(t_uint256)50_storage", 163 | "contract": "Gateway", 164 | "src": "contracts/Gateway.sol:21" 165 | } 166 | ], 167 | "types": { 168 | "t_address": { 169 | "label": "address", 170 | "numberOfBytes": "20" 171 | }, 172 | "t_array(t_uint256)49_storage": { 173 | "label": "uint256[49]", 174 | "numberOfBytes": "1568" 175 | }, 176 | "t_array(t_uint256)50_storage": { 177 | "label": "uint256[50]", 178 | "numberOfBytes": "1600" 179 | }, 180 | "t_bool": { 181 | "label": "bool", 182 | "numberOfBytes": "1" 183 | }, 184 | "t_bytes32": { 185 | "label": "bytes32", 186 | "numberOfBytes": "32" 187 | }, 188 | "t_mapping(t_address,t_uint256)": { 189 | "label": "mapping(address => uint256)", 190 | "numberOfBytes": "32" 191 | }, 192 | "t_mapping(t_bytes32,t_struct(Order)1827_storage)": { 193 | "label": "mapping(bytes32 => struct IGateway.Order)", 194 | "numberOfBytes": "32" 195 | }, 196 | "t_struct(Order)1827_storage": { 197 | "label": "struct IGateway.Order", 198 | "members": [ 199 | { 200 | "label": "sender", 201 | "type": "t_address", 202 | "offset": 0, 203 | "slot": "0" 204 | }, 205 | { 206 | "label": "token", 207 | "type": "t_address", 208 | "offset": 0, 209 | "slot": "1" 210 | }, 211 | { 212 | "label": "senderFeeRecipient", 213 | "type": "t_address", 214 | "offset": 0, 215 | "slot": "2" 216 | }, 217 | { 218 | "label": "senderFee", 219 | "type": "t_uint256", 220 | "offset": 0, 221 | "slot": "3" 222 | }, 223 | { 224 | "label": "protocolFee", 225 | "type": "t_uint256", 226 | "offset": 0, 227 | "slot": "4" 228 | }, 229 | { 230 | "label": "isFulfilled", 231 | "type": "t_bool", 232 | "offset": 0, 233 | "slot": "5" 234 | }, 235 | { 236 | "label": "isRefunded", 237 | "type": "t_bool", 238 | "offset": 1, 239 | "slot": "5" 240 | }, 241 | { 242 | "label": "refundAddress", 243 | "type": "t_address", 244 | "offset": 2, 245 | "slot": "5" 246 | }, 247 | { 248 | "label": "currentBPS", 249 | "type": "t_uint96", 250 | "offset": 0, 251 | "slot": "6" 252 | }, 253 | { 254 | "label": "amount", 255 | "type": "t_uint256", 256 | "offset": 0, 257 | "slot": "7" 258 | } 259 | ], 260 | "numberOfBytes": "256" 261 | }, 262 | "t_uint256": { 263 | "label": "uint256", 264 | "numberOfBytes": "32" 265 | }, 266 | "t_uint64": { 267 | "label": "uint64", 268 | "numberOfBytes": "8" 269 | }, 270 | "t_uint8": { 271 | "label": "uint8", 272 | "numberOfBytes": "1" 273 | }, 274 | "t_uint96": { 275 | "label": "uint96", 276 | "numberOfBytes": "12" 277 | } 278 | }, 279 | "namespaces": {} 280 | } 281 | } 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /.openzeppelin/unknown-728126428.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifestVersion": "3.2", 3 | "admin": { 4 | "address": "0x7842d825595d3ae08a41d8958d4fefad99ea87bc", 5 | "txHash": "dacbb2d090ef949bc12fd4dcb35bacab79d301d38ee59d2682d9de7981e7076d" 6 | }, 7 | "proxies": [ 8 | { 9 | "address": "0x57c2fe20719a4e41af71a36281ca4073eb5049ae", 10 | "txHash": "a4ab56f7d5e374cbd13f55b0739958be67277bc4ae67e6bba5e9da9784b004d7", 11 | "kind": "transparent" 12 | } 13 | ], 14 | "impls": { 15 | "49038d1dfd2f19419b54334f79478a8ac29469cc0cfff76d359474e71d2f7114": { 16 | "address": "0x28d8f1be31301a05abbb85a006a68c334c37396a", 17 | "txHash": "16bddcb123614d18419bc13d399e02026da37f5e2ac54eda9ea0fb8abdd28d44", 18 | "layout": { 19 | "solcVersion": "0.8.18", 20 | "storage": [ 21 | { 22 | "contract": "Initializable", 23 | "label": "_initialized", 24 | "type": "t_uint8", 25 | "src": "../@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", 26 | "retypedFrom": "bool" 27 | }, 28 | { 29 | "contract": "Initializable", 30 | "label": "_initializing", 31 | "type": "t_bool", 32 | "src": "../@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" 33 | }, 34 | { 35 | "contract": "ContextUpgradeable", 36 | "label": "__gap", 37 | "type": "t_array(t_uint256)50_storage", 38 | "src": "../@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:40" 39 | }, 40 | { 41 | "contract": "OwnableUpgradeable", 42 | "label": "_owner", 43 | "type": "t_address", 44 | "src": "../@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:22" 45 | }, 46 | { 47 | "contract": "OwnableUpgradeable", 48 | "label": "__gap", 49 | "type": "t_array(t_uint256)49_storage", 50 | "src": "../@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:94" 51 | }, 52 | { 53 | "contract": "Ownable2StepUpgradeable", 54 | "label": "_pendingOwner", 55 | "type": "t_address", 56 | "src": "../@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol:21" 57 | }, 58 | { 59 | "contract": "Ownable2StepUpgradeable", 60 | "label": "__gap", 61 | "type": "t_array(t_uint256)49_storage", 62 | "src": "../@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol:70" 63 | }, 64 | { 65 | "contract": "GatewaySettingManager", 66 | "label": "MAX_BPS", 67 | "type": "t_uint256", 68 | "src": "GatewaySettingManager.sol:12" 69 | }, 70 | { 71 | "contract": "GatewaySettingManager", 72 | "label": "protocolFeePercent", 73 | "type": "t_uint64", 74 | "src": "GatewaySettingManager.sol:13" 75 | }, 76 | { 77 | "contract": "GatewaySettingManager", 78 | "label": "treasuryAddress", 79 | "type": "t_address", 80 | "src": "GatewaySettingManager.sol:14" 81 | }, 82 | { 83 | "contract": "GatewaySettingManager", 84 | "label": "_aggregatorAddress", 85 | "type": "t_address", 86 | "src": "GatewaySettingManager.sol:15" 87 | }, 88 | { 89 | "contract": "GatewaySettingManager", 90 | "label": "_isTokenSupported", 91 | "type": "t_mapping(t_address,t_uint256)", 92 | "src": "GatewaySettingManager.sol:16" 93 | }, 94 | { 95 | "contract": "GatewaySettingManager", 96 | "label": "__gap", 97 | "type": "t_array(t_uint256)50_storage", 98 | "src": "GatewaySettingManager.sol:19" 99 | }, 100 | { 101 | "contract": "PausableUpgradeable", 102 | "label": "_paused", 103 | "type": "t_bool", 104 | "src": "../@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:29" 105 | }, 106 | { 107 | "contract": "PausableUpgradeable", 108 | "label": "__gap", 109 | "type": "t_array(t_uint256)49_storage", 110 | "src": "../@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:116" 111 | }, 112 | { 113 | "contract": "Gateway", 114 | "label": "order", 115 | "type": "t_mapping(t_bytes32,t_struct(Order)834_storage)", 116 | "src": "Gateway.sol:19" 117 | }, 118 | { 119 | "contract": "Gateway", 120 | "label": "_nonce", 121 | "type": "t_mapping(t_address,t_uint256)", 122 | "src": "Gateway.sol:20" 123 | }, 124 | { 125 | "contract": "Gateway", 126 | "label": "__gap", 127 | "type": "t_array(t_uint256)50_storage", 128 | "src": "Gateway.sol:21" 129 | } 130 | ], 131 | "types": { 132 | "t_mapping(t_bytes32,t_struct(Order)834_storage)": { 133 | "label": "mapping(bytes32 => struct IGateway.Order)" 134 | }, 135 | "t_bytes32": { 136 | "label": "bytes32" 137 | }, 138 | "t_struct(Order)834_storage": { 139 | "label": "struct IGateway.Order", 140 | "members": [ 141 | { 142 | "label": "sender", 143 | "type": "t_address" 144 | }, 145 | { 146 | "label": "token", 147 | "type": "t_address" 148 | }, 149 | { 150 | "label": "senderFeeRecipient", 151 | "type": "t_address" 152 | }, 153 | { 154 | "label": "senderFee", 155 | "type": "t_uint256" 156 | }, 157 | { 158 | "label": "protocolFee", 159 | "type": "t_uint256" 160 | }, 161 | { 162 | "label": "isFulfilled", 163 | "type": "t_bool" 164 | }, 165 | { 166 | "label": "isRefunded", 167 | "type": "t_bool" 168 | }, 169 | { 170 | "label": "refundAddress", 171 | "type": "t_address" 172 | }, 173 | { 174 | "label": "currentBPS", 175 | "type": "t_uint96" 176 | }, 177 | { 178 | "label": "amount", 179 | "type": "t_uint256" 180 | } 181 | ] 182 | }, 183 | "t_address": { 184 | "label": "address" 185 | }, 186 | "t_uint256": { 187 | "label": "uint256" 188 | }, 189 | "t_bool": { 190 | "label": "bool" 191 | }, 192 | "t_uint96": { 193 | "label": "uint96" 194 | }, 195 | "t_mapping(t_address,t_uint256)": { 196 | "label": "mapping(address => uint256)" 197 | }, 198 | "t_array(t_uint256)50_storage": { 199 | "label": "uint256[50]" 200 | }, 201 | "t_array(t_uint256)49_storage": { 202 | "label": "uint256[49]" 203 | }, 204 | "t_uint64": { 205 | "label": "uint64" 206 | }, 207 | "t_uint8": { 208 | "label": "uint8" 209 | } 210 | }, 211 | "namespaces": {} 212 | } 213 | } 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /.soliumignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | contracts/Migrations.sol 3 | -------------------------------------------------------------------------------- /.soliumrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "solium:recommended", 3 | "plugins": [ 4 | "security" 5 | ], 6 | "rules": { 7 | "quotes": [ 8 | "error", 9 | "double" 10 | ], 11 | "indentation": [ 12 | "error", 13 | 4 14 | ], 15 | "linebreak-style": [ 16 | "error", 17 | "unix" 18 | ] 19 | } 20 | } -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["github.copilot"] 3 | } 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | solidity v0.8.18 2 | 3 | # Paycrest Contracts 4 | 5 | ## Description 6 | 7 | Paycrest contracts are multi-chain EVM-based smart contracts that facilitate the on-chain lifecycle of a payment order. They empower a sender to create a payment order, enable a liquidity provider to receive cryptocurrency in escrow, and much more. 8 | 9 | ![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXd9vDhbrwj3ikJ9ghsVPc4qaZ7_RmgzNn3CjbW2jvAWepYYBmIat8Mtidid8OCBzuP7Sr-_zab6gjjpM6tSJm3p00akfR9xhkkzckDoZOhO9jiqgnO0EkZRyH4QoxgGAXRelCSNxQ?key=xfQ-CdRhtjGdAX7gL41tK8t-) 10 | 11 | ## Deployment 12 | 13 | Deployment is done using Hardhat scripts 14 | 15 | #### Deploy and verify upgradeable proxy contract 16 | 17 | ```bash 18 | npx hardhat run scripts/deploy.ts --network 19 | 20 | npx hardhat verify --network 21 | 22 | # for Tron network, 23 | tronbox migrate -f 1 --to 1 --network 24 | ``` 25 | 26 | #### Upgrade proxy contract 27 | 28 | ```bash 29 | npx hardhat run scripts/upgrade.ts --network 30 | 31 | # upgrade across all EVM chains 32 | npx hardhat run scripts/upgrade.ts --network arbitrumOne && npx hardhat run scripts/upgrade.ts --network base && npx hardhat run scripts/upgrade.ts --network bsc && npx hardhat run scripts/upgrade.ts --network polygon && npx hardhat run scripts/upgrade.ts --network optimisticEthereum && npx hardhat run scripts/upgrade.ts --network scroll 33 | 34 | # upgrade across all EVM testnet chains 35 | npx hardhat run scripts/upgrade.ts --network arbitrumSepolia && npx hardhat run scripts/upgrade.ts --network amoy && npx hardhat run scripts/upgrade.ts --network baseSepolia && npx hardhat run scripts/upgrade.ts --network sepolia 36 | 37 | # for Tron network, 38 | tronbox migrate -f 2 --to 2 --network 39 | ``` 40 | 41 | #### Owner configurations 42 | 43 | Update network settings in `scripts/config.ts` 44 | 45 | ```bash 46 | npx hardhat run scripts/setSupportedTokens.ts --network 47 | 48 | npx hardhat run scripts/updateProtocolAddresses.ts --network 49 | 50 | npx hardhat run scripts/updateProtocolFee.ts --network 51 | 52 | # for Tron network, 53 | npx hardhat run scripts/tron/setSupportedTokens.ts 54 | 55 | npx hardhat run scripts/tron/updateProtocolAddresses.ts 56 | 57 | npx hardhat run scripts/tron/updateProtocolFee.ts 58 | ``` 59 | 60 | 61 | ## Testnet Contracts 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 |
NetworkContractsAddress
Ethereum SepoliaGateway Proxy0xCAD53Ff499155Cc2fAA2082A85716322906886c2
Gateway Implementation0xafbf71A72d30f81eb66baaF904ea537fD35dd106
Polygon AmoyGateway Proxy0xCAD53Ff499155Cc2fAA2082A85716322906886c2
Gateway Implementation0xd2d97002ec87ba57fcf3f6b510f20d5a80a6c33a
Arbitrum SepoliaGateway Proxy0x87B321fc77A0fDD0ca1fEe7Ab791131157B9841A
Gateway Implementation0xd2d97002Ec87ba57FCf3f6b510f20d5A80A6C33a
Base SepoliaGateway Proxy0x847dfdAa218F9137229CF8424378871A1DA8f625
Gateway Implementation0xd2d97002Ec87ba57FCf3f6b510f20d5A80A6C33a
Asset Chain TestnetGateway Proxy0xBe6dE889795677736919A7880324A71Dc7dFa162
Gateway Implementation0x9519D63fbF9717Fa3419846eBA92B01Cd1d1D131
Tron ShastaGateway ProxyTYA8urq7nkN2yU7rJqAgwDShCusDZrrsxZ
Gateway ImplementationTSGr6Ri7NZ7FxN1gCiWkn8cPA2qtF6ctdF
Gateway AdminTNcogTDoWxpuv77WtsiNTRhqjRbZmmDLTR
147 | 148 | ## Mainnet Contracts 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 |
NetworkContractsAddress
EthereumGateway Proxy0x16c9C78Dbb224889E3e2ADef991C8c4438ea797B
Gateway Implementation0xD293fCd3dBc025603911853d893A4724CF9f70a0
PolygonGateway Proxy0xfB411Cc6385Af50A562aFCb441864E9d541CDA67
Gateway Implementation0xd2d97002ec87ba57fcf3f6b510f20d5a80a6c33a
BaseGateway Proxy0x30F6A8457F8E42371E204a9c103f2Bd42341dD0F
Gateway Implementation0xd28da2E11FCd2A9F44D5a4952430CE8b4f3Ee05f
BNB Smart ChainGateway Proxy0x1FA0EE7F9410F6fa49B7AD5Da72Cf01647090028
Gateway Implementation0xd2d97002ec87ba57fcf3f6b510f20d5a80a6c33a
Arbitrum OneGateway Proxy0xE8bc3B607CfE68F47000E3d200310D49041148Fc
Gateway Implementation0x8fd1f78d88dd008e557273b5cd517487c2a9a7de
Optimism EthereumGateway Proxy0xD293fCd3dBc025603911853d893A4724CF9f70a0
Gateway Implementation0xd2d97002Ec87ba57FCf3f6b510f20d5A80A6C33a
Gateway Admin0xb9B5280AB99E48a9662D4740B1e1398abdf87b6D
ScrollGateway Proxy0x663C5BfE7d44bA946C2dd4b2D1Cf9580319F9338
Gateway Implementation0xd2d97002ec87ba57fcf3f6b510f20d5a80a6c33a
Gateway Admin0x16c9C78Dbb224889E3e2ADef991C8c4438ea797B
CeloGateway Proxy0xF418217E3f81092eF44b81C5C8336e6A6fDB0E4b
Gateway Implementation0x8508c1C9f29BD1e73B5A9bD8FB87720927c681FA
Gateway Admin0xc38D6817F736b1cb44785e14A8cb7152385d3210
LiskGateway Proxy0xff0E00E0110C1FBb5315D276243497b66D3a4d8a
Gateway Implementation0x3Dc80272cE93cBFF3351913bB089B59C4a9141DE
Gateway Admin0x8FD1f78d88Dd008E557273b5Cd517487C2A9A7de
Asset ChainGateway Proxy0xff0E00E0110C1FBb5315D276243497b66D3a4d8a
Gateway Implementation0x3Dc80272cE93cBFF3351913bB089B59C4a9141DE
TronGateway ProxyTHyFP5ST9YyLZn6EzjKjFhZti6aKPgEXNU
Gateway ImplementationTDhBvHbnF8nN7YctokpdZAVPcmBx2Jrn2d
Gateway AdminTLw6AW9khfwLVq5gq9uV71wTVZEPxKjoiZ
304 | 305 | ## Testing 306 | 307 | Contract tests are defined under the tests directory. To run all the tests, run: 308 | 309 | ```bash 310 | npx hardhat test 311 | ``` 312 | 313 | ## **Commits and PRs** 314 | 315 | This project uses Conventional Commits to generate release notes and to determine versioning. Commit messages should adhere to this standard and be of the form: 316 | 317 | ```bash 318 | $ git commit -m "feat: Add new feature x" 319 | $ git commit -m "fix: Fix bug in feature x" 320 | $ git commit -m "docs: Add documentation for feature x" 321 | $ git commit -m "test: Add test suite for feature x" 322 | ``` 323 | 324 | Further details on `conventional commits` can be found [here](https://www.conventionalcommits.org/en/v1.0.0/) 325 | 326 | ## Contributing 327 | 328 | We welcome contributions to the Paycrest gateway contract! To get started, follow these steps: 329 | 330 | **Important:** Before you begin contributing, please ensure you've read and understood these important documents: 331 | 332 | - [Contribution Guide](https://paycrest.notion.site/Contribution-Guide-1602482d45a2809a8930e6ad565c906a) - Critical information about development process, standards, and guidelines. 333 | 334 | - [Code of Conduct](https://paycrest.notion.site/Contributor-Code-of-Conduct-1602482d45a2806bab75fd314b381f4c) - Our community standards and expectations. 335 | 336 | Our team will review your pull request and work with you to get it merged into the main branch of the repository. 337 | 338 | If you encounter any issues or have questions, feel free to open an issue on the repository or leave a message in our [developer community on Telegram](https://t.me/+Stx-wLOdj49iNDM0) 339 | 340 | ## Contributors ✨ 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 359 | 360 | 361 |
Prosperity
Prosperity

💻
chibie
chibie

💻
355 | 356 | Add your contributions 357 | 358 |
362 | 363 | 364 | 365 | 366 | 367 | 368 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 369 | 370 | ## License 371 | [Affero General Public License v3.0](https://choosealicense.com/licenses/agpl-3.0/) 372 | -------------------------------------------------------------------------------- /artifacts/@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol/Ownable2StepUpgradeable.dbg.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-dbg-1", 3 | "buildInfo": "../../../../build-info/b8a88c4b130e7a569c3029307ef5f126.json" 4 | } 5 | -------------------------------------------------------------------------------- /artifacts/@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol/Ownable2StepUpgradeable.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-artifact-1", 3 | "contractName": "Ownable2StepUpgradeable", 4 | "sourceName": "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol", 5 | "abi": [ 6 | { 7 | "anonymous": false, 8 | "inputs": [ 9 | { 10 | "indexed": false, 11 | "internalType": "uint8", 12 | "name": "version", 13 | "type": "uint8" 14 | } 15 | ], 16 | "name": "Initialized", 17 | "type": "event" 18 | }, 19 | { 20 | "anonymous": false, 21 | "inputs": [ 22 | { 23 | "indexed": true, 24 | "internalType": "address", 25 | "name": "previousOwner", 26 | "type": "address" 27 | }, 28 | { 29 | "indexed": true, 30 | "internalType": "address", 31 | "name": "newOwner", 32 | "type": "address" 33 | } 34 | ], 35 | "name": "OwnershipTransferStarted", 36 | "type": "event" 37 | }, 38 | { 39 | "anonymous": false, 40 | "inputs": [ 41 | { 42 | "indexed": true, 43 | "internalType": "address", 44 | "name": "previousOwner", 45 | "type": "address" 46 | }, 47 | { 48 | "indexed": true, 49 | "internalType": "address", 50 | "name": "newOwner", 51 | "type": "address" 52 | } 53 | ], 54 | "name": "OwnershipTransferred", 55 | "type": "event" 56 | }, 57 | { 58 | "inputs": [], 59 | "name": "acceptOwnership", 60 | "outputs": [], 61 | "stateMutability": "nonpayable", 62 | "type": "function" 63 | }, 64 | { 65 | "inputs": [], 66 | "name": "owner", 67 | "outputs": [ 68 | { 69 | "internalType": "address", 70 | "name": "", 71 | "type": "address" 72 | } 73 | ], 74 | "stateMutability": "view", 75 | "type": "function" 76 | }, 77 | { 78 | "inputs": [], 79 | "name": "pendingOwner", 80 | "outputs": [ 81 | { 82 | "internalType": "address", 83 | "name": "", 84 | "type": "address" 85 | } 86 | ], 87 | "stateMutability": "view", 88 | "type": "function" 89 | }, 90 | { 91 | "inputs": [], 92 | "name": "renounceOwnership", 93 | "outputs": [], 94 | "stateMutability": "nonpayable", 95 | "type": "function" 96 | }, 97 | { 98 | "inputs": [ 99 | { 100 | "internalType": "address", 101 | "name": "newOwner", 102 | "type": "address" 103 | } 104 | ], 105 | "name": "transferOwnership", 106 | "outputs": [], 107 | "stateMutability": "nonpayable", 108 | "type": "function" 109 | } 110 | ], 111 | "bytecode": "0x", 112 | "deployedBytecode": "0x", 113 | "linkReferences": {}, 114 | "deployedLinkReferences": {} 115 | } 116 | -------------------------------------------------------------------------------- /artifacts/@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol/OwnableUpgradeable.dbg.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-dbg-1", 3 | "buildInfo": "../../../../build-info/b8a88c4b130e7a569c3029307ef5f126.json" 4 | } 5 | -------------------------------------------------------------------------------- /artifacts/@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol/OwnableUpgradeable.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-artifact-1", 3 | "contractName": "OwnableUpgradeable", 4 | "sourceName": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol", 5 | "abi": [ 6 | { 7 | "anonymous": false, 8 | "inputs": [ 9 | { 10 | "indexed": false, 11 | "internalType": "uint8", 12 | "name": "version", 13 | "type": "uint8" 14 | } 15 | ], 16 | "name": "Initialized", 17 | "type": "event" 18 | }, 19 | { 20 | "anonymous": false, 21 | "inputs": [ 22 | { 23 | "indexed": true, 24 | "internalType": "address", 25 | "name": "previousOwner", 26 | "type": "address" 27 | }, 28 | { 29 | "indexed": true, 30 | "internalType": "address", 31 | "name": "newOwner", 32 | "type": "address" 33 | } 34 | ], 35 | "name": "OwnershipTransferred", 36 | "type": "event" 37 | }, 38 | { 39 | "inputs": [], 40 | "name": "owner", 41 | "outputs": [ 42 | { 43 | "internalType": "address", 44 | "name": "", 45 | "type": "address" 46 | } 47 | ], 48 | "stateMutability": "view", 49 | "type": "function" 50 | }, 51 | { 52 | "inputs": [], 53 | "name": "renounceOwnership", 54 | "outputs": [], 55 | "stateMutability": "nonpayable", 56 | "type": "function" 57 | }, 58 | { 59 | "inputs": [ 60 | { 61 | "internalType": "address", 62 | "name": "newOwner", 63 | "type": "address" 64 | } 65 | ], 66 | "name": "transferOwnership", 67 | "outputs": [], 68 | "stateMutability": "nonpayable", 69 | "type": "function" 70 | } 71 | ], 72 | "bytecode": "0x", 73 | "deployedBytecode": "0x", 74 | "linkReferences": {}, 75 | "deployedLinkReferences": {} 76 | } 77 | -------------------------------------------------------------------------------- /artifacts/@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol/Initializable.dbg.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-dbg-1", 3 | "buildInfo": "../../../../../build-info/b8a88c4b130e7a569c3029307ef5f126.json" 4 | } 5 | -------------------------------------------------------------------------------- /artifacts/@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol/Initializable.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-artifact-1", 3 | "contractName": "Initializable", 4 | "sourceName": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol", 5 | "abi": [ 6 | { 7 | "anonymous": false, 8 | "inputs": [ 9 | { 10 | "indexed": false, 11 | "internalType": "uint8", 12 | "name": "version", 13 | "type": "uint8" 14 | } 15 | ], 16 | "name": "Initialized", 17 | "type": "event" 18 | } 19 | ], 20 | "bytecode": "0x", 21 | "deployedBytecode": "0x", 22 | "linkReferences": {}, 23 | "deployedLinkReferences": {} 24 | } 25 | -------------------------------------------------------------------------------- /artifacts/@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol/PausableUpgradeable.dbg.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-dbg-1", 3 | "buildInfo": "../../../../build-info/b8a88c4b130e7a569c3029307ef5f126.json" 4 | } 5 | -------------------------------------------------------------------------------- /artifacts/@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol/PausableUpgradeable.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-artifact-1", 3 | "contractName": "PausableUpgradeable", 4 | "sourceName": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol", 5 | "abi": [ 6 | { 7 | "anonymous": false, 8 | "inputs": [ 9 | { 10 | "indexed": false, 11 | "internalType": "uint8", 12 | "name": "version", 13 | "type": "uint8" 14 | } 15 | ], 16 | "name": "Initialized", 17 | "type": "event" 18 | }, 19 | { 20 | "anonymous": false, 21 | "inputs": [ 22 | { 23 | "indexed": false, 24 | "internalType": "address", 25 | "name": "account", 26 | "type": "address" 27 | } 28 | ], 29 | "name": "Paused", 30 | "type": "event" 31 | }, 32 | { 33 | "anonymous": false, 34 | "inputs": [ 35 | { 36 | "indexed": false, 37 | "internalType": "address", 38 | "name": "account", 39 | "type": "address" 40 | } 41 | ], 42 | "name": "Unpaused", 43 | "type": "event" 44 | }, 45 | { 46 | "inputs": [], 47 | "name": "paused", 48 | "outputs": [ 49 | { 50 | "internalType": "bool", 51 | "name": "", 52 | "type": "bool" 53 | } 54 | ], 55 | "stateMutability": "view", 56 | "type": "function" 57 | } 58 | ], 59 | "bytecode": "0x", 60 | "deployedBytecode": "0x", 61 | "linkReferences": {}, 62 | "deployedLinkReferences": {} 63 | } 64 | -------------------------------------------------------------------------------- /artifacts/@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol/AddressUpgradeable.dbg.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-dbg-1", 3 | "buildInfo": "../../../../build-info/b8a88c4b130e7a569c3029307ef5f126.json" 4 | } 5 | -------------------------------------------------------------------------------- /artifacts/@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol/AddressUpgradeable.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-artifact-1", 3 | "contractName": "AddressUpgradeable", 4 | "sourceName": "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol", 5 | "abi": [], 6 | "bytecode": "0x60566050600b82828239805160001a6073146043577f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220df70283ff728a1a88debad8b56cd6b31b858a143aff601e8f42a16699317e70d64736f6c63430008120033", 7 | "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220df70283ff728a1a88debad8b56cd6b31b858a143aff601e8f42a16699317e70d64736f6c63430008120033", 8 | "linkReferences": {}, 9 | "deployedLinkReferences": {} 10 | } 11 | -------------------------------------------------------------------------------- /artifacts/@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol/ContextUpgradeable.dbg.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-dbg-1", 3 | "buildInfo": "../../../../build-info/b8a88c4b130e7a569c3029307ef5f126.json" 4 | } 5 | -------------------------------------------------------------------------------- /artifacts/@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol/ContextUpgradeable.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-artifact-1", 3 | "contractName": "ContextUpgradeable", 4 | "sourceName": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol", 5 | "abi": [ 6 | { 7 | "anonymous": false, 8 | "inputs": [ 9 | { 10 | "indexed": false, 11 | "internalType": "uint8", 12 | "name": "version", 13 | "type": "uint8" 14 | } 15 | ], 16 | "name": "Initialized", 17 | "type": "event" 18 | } 19 | ], 20 | "bytecode": "0x", 21 | "deployedBytecode": "0x", 22 | "linkReferences": {}, 23 | "deployedLinkReferences": {} 24 | } 25 | -------------------------------------------------------------------------------- /artifacts/@openzeppelin/contracts/token/ERC20/ERC20.sol/ERC20.dbg.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-dbg-1", 3 | "buildInfo": "../../../../../build-info/b8a88c4b130e7a569c3029307ef5f126.json" 4 | } 5 | -------------------------------------------------------------------------------- /artifacts/@openzeppelin/contracts/token/ERC20/IERC20.sol/IERC20.dbg.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-dbg-1", 3 | "buildInfo": "../../../../../build-info/b8a88c4b130e7a569c3029307ef5f126.json" 4 | } 5 | -------------------------------------------------------------------------------- /artifacts/@openzeppelin/contracts/token/ERC20/IERC20.sol/IERC20.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-artifact-1", 3 | "contractName": "IERC20", 4 | "sourceName": "@openzeppelin/contracts/token/ERC20/IERC20.sol", 5 | "abi": [ 6 | { 7 | "anonymous": false, 8 | "inputs": [ 9 | { 10 | "indexed": true, 11 | "internalType": "address", 12 | "name": "owner", 13 | "type": "address" 14 | }, 15 | { 16 | "indexed": true, 17 | "internalType": "address", 18 | "name": "spender", 19 | "type": "address" 20 | }, 21 | { 22 | "indexed": false, 23 | "internalType": "uint256", 24 | "name": "value", 25 | "type": "uint256" 26 | } 27 | ], 28 | "name": "Approval", 29 | "type": "event" 30 | }, 31 | { 32 | "anonymous": false, 33 | "inputs": [ 34 | { 35 | "indexed": true, 36 | "internalType": "address", 37 | "name": "from", 38 | "type": "address" 39 | }, 40 | { 41 | "indexed": true, 42 | "internalType": "address", 43 | "name": "to", 44 | "type": "address" 45 | }, 46 | { 47 | "indexed": false, 48 | "internalType": "uint256", 49 | "name": "value", 50 | "type": "uint256" 51 | } 52 | ], 53 | "name": "Transfer", 54 | "type": "event" 55 | }, 56 | { 57 | "inputs": [ 58 | { 59 | "internalType": "address", 60 | "name": "owner", 61 | "type": "address" 62 | }, 63 | { 64 | "internalType": "address", 65 | "name": "spender", 66 | "type": "address" 67 | } 68 | ], 69 | "name": "allowance", 70 | "outputs": [ 71 | { 72 | "internalType": "uint256", 73 | "name": "", 74 | "type": "uint256" 75 | } 76 | ], 77 | "stateMutability": "view", 78 | "type": "function" 79 | }, 80 | { 81 | "inputs": [ 82 | { 83 | "internalType": "address", 84 | "name": "spender", 85 | "type": "address" 86 | }, 87 | { 88 | "internalType": "uint256", 89 | "name": "amount", 90 | "type": "uint256" 91 | } 92 | ], 93 | "name": "approve", 94 | "outputs": [ 95 | { 96 | "internalType": "bool", 97 | "name": "", 98 | "type": "bool" 99 | } 100 | ], 101 | "stateMutability": "nonpayable", 102 | "type": "function" 103 | }, 104 | { 105 | "inputs": [ 106 | { 107 | "internalType": "address", 108 | "name": "account", 109 | "type": "address" 110 | } 111 | ], 112 | "name": "balanceOf", 113 | "outputs": [ 114 | { 115 | "internalType": "uint256", 116 | "name": "", 117 | "type": "uint256" 118 | } 119 | ], 120 | "stateMutability": "view", 121 | "type": "function" 122 | }, 123 | { 124 | "inputs": [], 125 | "name": "totalSupply", 126 | "outputs": [ 127 | { 128 | "internalType": "uint256", 129 | "name": "", 130 | "type": "uint256" 131 | } 132 | ], 133 | "stateMutability": "view", 134 | "type": "function" 135 | }, 136 | { 137 | "inputs": [ 138 | { 139 | "internalType": "address", 140 | "name": "to", 141 | "type": "address" 142 | }, 143 | { 144 | "internalType": "uint256", 145 | "name": "amount", 146 | "type": "uint256" 147 | } 148 | ], 149 | "name": "transfer", 150 | "outputs": [ 151 | { 152 | "internalType": "bool", 153 | "name": "", 154 | "type": "bool" 155 | } 156 | ], 157 | "stateMutability": "nonpayable", 158 | "type": "function" 159 | }, 160 | { 161 | "inputs": [ 162 | { 163 | "internalType": "address", 164 | "name": "from", 165 | "type": "address" 166 | }, 167 | { 168 | "internalType": "address", 169 | "name": "to", 170 | "type": "address" 171 | }, 172 | { 173 | "internalType": "uint256", 174 | "name": "amount", 175 | "type": "uint256" 176 | } 177 | ], 178 | "name": "transferFrom", 179 | "outputs": [ 180 | { 181 | "internalType": "bool", 182 | "name": "", 183 | "type": "bool" 184 | } 185 | ], 186 | "stateMutability": "nonpayable", 187 | "type": "function" 188 | } 189 | ], 190 | "bytecode": "0x", 191 | "deployedBytecode": "0x", 192 | "linkReferences": {}, 193 | "deployedLinkReferences": {} 194 | } 195 | -------------------------------------------------------------------------------- /artifacts/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol/IERC20Metadata.dbg.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-dbg-1", 3 | "buildInfo": "../../../../../../build-info/b8a88c4b130e7a569c3029307ef5f126.json" 4 | } 5 | -------------------------------------------------------------------------------- /artifacts/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol/IERC20Metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-artifact-1", 3 | "contractName": "IERC20Metadata", 4 | "sourceName": "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol", 5 | "abi": [ 6 | { 7 | "anonymous": false, 8 | "inputs": [ 9 | { 10 | "indexed": true, 11 | "internalType": "address", 12 | "name": "owner", 13 | "type": "address" 14 | }, 15 | { 16 | "indexed": true, 17 | "internalType": "address", 18 | "name": "spender", 19 | "type": "address" 20 | }, 21 | { 22 | "indexed": false, 23 | "internalType": "uint256", 24 | "name": "value", 25 | "type": "uint256" 26 | } 27 | ], 28 | "name": "Approval", 29 | "type": "event" 30 | }, 31 | { 32 | "anonymous": false, 33 | "inputs": [ 34 | { 35 | "indexed": true, 36 | "internalType": "address", 37 | "name": "from", 38 | "type": "address" 39 | }, 40 | { 41 | "indexed": true, 42 | "internalType": "address", 43 | "name": "to", 44 | "type": "address" 45 | }, 46 | { 47 | "indexed": false, 48 | "internalType": "uint256", 49 | "name": "value", 50 | "type": "uint256" 51 | } 52 | ], 53 | "name": "Transfer", 54 | "type": "event" 55 | }, 56 | { 57 | "inputs": [ 58 | { 59 | "internalType": "address", 60 | "name": "owner", 61 | "type": "address" 62 | }, 63 | { 64 | "internalType": "address", 65 | "name": "spender", 66 | "type": "address" 67 | } 68 | ], 69 | "name": "allowance", 70 | "outputs": [ 71 | { 72 | "internalType": "uint256", 73 | "name": "", 74 | "type": "uint256" 75 | } 76 | ], 77 | "stateMutability": "view", 78 | "type": "function" 79 | }, 80 | { 81 | "inputs": [ 82 | { 83 | "internalType": "address", 84 | "name": "spender", 85 | "type": "address" 86 | }, 87 | { 88 | "internalType": "uint256", 89 | "name": "amount", 90 | "type": "uint256" 91 | } 92 | ], 93 | "name": "approve", 94 | "outputs": [ 95 | { 96 | "internalType": "bool", 97 | "name": "", 98 | "type": "bool" 99 | } 100 | ], 101 | "stateMutability": "nonpayable", 102 | "type": "function" 103 | }, 104 | { 105 | "inputs": [ 106 | { 107 | "internalType": "address", 108 | "name": "account", 109 | "type": "address" 110 | } 111 | ], 112 | "name": "balanceOf", 113 | "outputs": [ 114 | { 115 | "internalType": "uint256", 116 | "name": "", 117 | "type": "uint256" 118 | } 119 | ], 120 | "stateMutability": "view", 121 | "type": "function" 122 | }, 123 | { 124 | "inputs": [], 125 | "name": "decimals", 126 | "outputs": [ 127 | { 128 | "internalType": "uint8", 129 | "name": "", 130 | "type": "uint8" 131 | } 132 | ], 133 | "stateMutability": "view", 134 | "type": "function" 135 | }, 136 | { 137 | "inputs": [], 138 | "name": "name", 139 | "outputs": [ 140 | { 141 | "internalType": "string", 142 | "name": "", 143 | "type": "string" 144 | } 145 | ], 146 | "stateMutability": "view", 147 | "type": "function" 148 | }, 149 | { 150 | "inputs": [], 151 | "name": "symbol", 152 | "outputs": [ 153 | { 154 | "internalType": "string", 155 | "name": "", 156 | "type": "string" 157 | } 158 | ], 159 | "stateMutability": "view", 160 | "type": "function" 161 | }, 162 | { 163 | "inputs": [], 164 | "name": "totalSupply", 165 | "outputs": [ 166 | { 167 | "internalType": "uint256", 168 | "name": "", 169 | "type": "uint256" 170 | } 171 | ], 172 | "stateMutability": "view", 173 | "type": "function" 174 | }, 175 | { 176 | "inputs": [ 177 | { 178 | "internalType": "address", 179 | "name": "to", 180 | "type": "address" 181 | }, 182 | { 183 | "internalType": "uint256", 184 | "name": "amount", 185 | "type": "uint256" 186 | } 187 | ], 188 | "name": "transfer", 189 | "outputs": [ 190 | { 191 | "internalType": "bool", 192 | "name": "", 193 | "type": "bool" 194 | } 195 | ], 196 | "stateMutability": "nonpayable", 197 | "type": "function" 198 | }, 199 | { 200 | "inputs": [ 201 | { 202 | "internalType": "address", 203 | "name": "from", 204 | "type": "address" 205 | }, 206 | { 207 | "internalType": "address", 208 | "name": "to", 209 | "type": "address" 210 | }, 211 | { 212 | "internalType": "uint256", 213 | "name": "amount", 214 | "type": "uint256" 215 | } 216 | ], 217 | "name": "transferFrom", 218 | "outputs": [ 219 | { 220 | "internalType": "bool", 221 | "name": "", 222 | "type": "bool" 223 | } 224 | ], 225 | "stateMutability": "nonpayable", 226 | "type": "function" 227 | } 228 | ], 229 | "bytecode": "0x", 230 | "deployedBytecode": "0x", 231 | "linkReferences": {}, 232 | "deployedLinkReferences": {} 233 | } 234 | -------------------------------------------------------------------------------- /artifacts/@openzeppelin/contracts/utils/Context.sol/Context.dbg.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-dbg-1", 3 | "buildInfo": "../../../../build-info/b8a88c4b130e7a569c3029307ef5f126.json" 4 | } 5 | -------------------------------------------------------------------------------- /artifacts/@openzeppelin/contracts/utils/Context.sol/Context.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-artifact-1", 3 | "contractName": "Context", 4 | "sourceName": "@openzeppelin/contracts/utils/Context.sol", 5 | "abi": [], 6 | "bytecode": "0x", 7 | "deployedBytecode": "0x", 8 | "linkReferences": {}, 9 | "deployedLinkReferences": {} 10 | } 11 | -------------------------------------------------------------------------------- /artifacts/contracts/Gateway.sol/Gateway.dbg.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-dbg-1", 3 | "buildInfo": "../../build-info/b92a18bd36be0e82f59e420b9f0d4c50.json" 4 | } 5 | -------------------------------------------------------------------------------- /artifacts/contracts/GatewaySettingManager.sol/GatewaySettingManager.dbg.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-dbg-1", 3 | "buildInfo": "../../build-info/b8a88c4b130e7a569c3029307ef5f126.json" 4 | } 5 | -------------------------------------------------------------------------------- /artifacts/contracts/interfaces/IGateway.sol/IGateway.dbg.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-dbg-1", 3 | "buildInfo": "../../../build-info/b8a88c4b130e7a569c3029307ef5f126.json" 4 | } 5 | -------------------------------------------------------------------------------- /artifacts/contracts/interfaces/IGateway.sol/IGateway.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-artifact-1", 3 | "contractName": "IGateway", 4 | "sourceName": "contracts/interfaces/IGateway.sol", 5 | "abi": [ 6 | { 7 | "anonymous": false, 8 | "inputs": [ 9 | { 10 | "indexed": true, 11 | "internalType": "address", 12 | "name": "sender", 13 | "type": "address" 14 | }, 15 | { 16 | "indexed": true, 17 | "internalType": "address", 18 | "name": "token", 19 | "type": "address" 20 | }, 21 | { 22 | "indexed": true, 23 | "internalType": "uint256", 24 | "name": "amount", 25 | "type": "uint256" 26 | }, 27 | { 28 | "indexed": false, 29 | "internalType": "uint256", 30 | "name": "protocolFee", 31 | "type": "uint256" 32 | }, 33 | { 34 | "indexed": false, 35 | "internalType": "bytes32", 36 | "name": "orderId", 37 | "type": "bytes32" 38 | }, 39 | { 40 | "indexed": false, 41 | "internalType": "uint256", 42 | "name": "rate", 43 | "type": "uint256" 44 | }, 45 | { 46 | "indexed": false, 47 | "internalType": "string", 48 | "name": "messageHash", 49 | "type": "string" 50 | } 51 | ], 52 | "name": "OrderCreated", 53 | "type": "event" 54 | }, 55 | { 56 | "anonymous": false, 57 | "inputs": [ 58 | { 59 | "indexed": false, 60 | "internalType": "uint256", 61 | "name": "fee", 62 | "type": "uint256" 63 | }, 64 | { 65 | "indexed": true, 66 | "internalType": "bytes32", 67 | "name": "orderId", 68 | "type": "bytes32" 69 | } 70 | ], 71 | "name": "OrderRefunded", 72 | "type": "event" 73 | }, 74 | { 75 | "anonymous": false, 76 | "inputs": [ 77 | { 78 | "indexed": false, 79 | "internalType": "bytes32", 80 | "name": "splitOrderId", 81 | "type": "bytes32" 82 | }, 83 | { 84 | "indexed": true, 85 | "internalType": "bytes32", 86 | "name": "orderId", 87 | "type": "bytes32" 88 | }, 89 | { 90 | "indexed": true, 91 | "internalType": "address", 92 | "name": "liquidityProvider", 93 | "type": "address" 94 | }, 95 | { 96 | "indexed": false, 97 | "internalType": "uint96", 98 | "name": "settlePercent", 99 | "type": "uint96" 100 | } 101 | ], 102 | "name": "OrderSettled", 103 | "type": "event" 104 | }, 105 | { 106 | "anonymous": false, 107 | "inputs": [ 108 | { 109 | "indexed": true, 110 | "internalType": "address", 111 | "name": "sender", 112 | "type": "address" 113 | }, 114 | { 115 | "indexed": true, 116 | "internalType": "uint256", 117 | "name": "amount", 118 | "type": "uint256" 119 | } 120 | ], 121 | "name": "SenderFeeTransferred", 122 | "type": "event" 123 | }, 124 | { 125 | "inputs": [ 126 | { 127 | "internalType": "address", 128 | "name": "_token", 129 | "type": "address" 130 | }, 131 | { 132 | "internalType": "uint256", 133 | "name": "_amount", 134 | "type": "uint256" 135 | }, 136 | { 137 | "internalType": "uint96", 138 | "name": "_rate", 139 | "type": "uint96" 140 | }, 141 | { 142 | "internalType": "address", 143 | "name": "_senderFeeRecipient", 144 | "type": "address" 145 | }, 146 | { 147 | "internalType": "uint256", 148 | "name": "_senderFee", 149 | "type": "uint256" 150 | }, 151 | { 152 | "internalType": "address", 153 | "name": "_refundAddress", 154 | "type": "address" 155 | }, 156 | { 157 | "internalType": "string", 158 | "name": "messageHash", 159 | "type": "string" 160 | } 161 | ], 162 | "name": "createOrder", 163 | "outputs": [ 164 | { 165 | "internalType": "bytes32", 166 | "name": "_orderId", 167 | "type": "bytes32" 168 | } 169 | ], 170 | "stateMutability": "nonpayable", 171 | "type": "function" 172 | }, 173 | { 174 | "inputs": [], 175 | "name": "getFeeDetails", 176 | "outputs": [ 177 | { 178 | "internalType": "uint64", 179 | "name": "protocolReward", 180 | "type": "uint64" 181 | }, 182 | { 183 | "internalType": "uint256", 184 | "name": "max_bps", 185 | "type": "uint256" 186 | } 187 | ], 188 | "stateMutability": "view", 189 | "type": "function" 190 | }, 191 | { 192 | "inputs": [ 193 | { 194 | "internalType": "bytes32", 195 | "name": "_orderId", 196 | "type": "bytes32" 197 | } 198 | ], 199 | "name": "getOrderInfo", 200 | "outputs": [ 201 | { 202 | "components": [ 203 | { 204 | "internalType": "address", 205 | "name": "sender", 206 | "type": "address" 207 | }, 208 | { 209 | "internalType": "address", 210 | "name": "token", 211 | "type": "address" 212 | }, 213 | { 214 | "internalType": "address", 215 | "name": "senderFeeRecipient", 216 | "type": "address" 217 | }, 218 | { 219 | "internalType": "uint256", 220 | "name": "senderFee", 221 | "type": "uint256" 222 | }, 223 | { 224 | "internalType": "uint256", 225 | "name": "protocolFee", 226 | "type": "uint256" 227 | }, 228 | { 229 | "internalType": "bool", 230 | "name": "isFulfilled", 231 | "type": "bool" 232 | }, 233 | { 234 | "internalType": "bool", 235 | "name": "isRefunded", 236 | "type": "bool" 237 | }, 238 | { 239 | "internalType": "address", 240 | "name": "refundAddress", 241 | "type": "address" 242 | }, 243 | { 244 | "internalType": "uint96", 245 | "name": "currentBPS", 246 | "type": "uint96" 247 | }, 248 | { 249 | "internalType": "uint256", 250 | "name": "amount", 251 | "type": "uint256" 252 | } 253 | ], 254 | "internalType": "struct IGateway.Order", 255 | "name": "", 256 | "type": "tuple" 257 | } 258 | ], 259 | "stateMutability": "view", 260 | "type": "function" 261 | }, 262 | { 263 | "inputs": [ 264 | { 265 | "internalType": "address", 266 | "name": "_token", 267 | "type": "address" 268 | } 269 | ], 270 | "name": "isTokenSupported", 271 | "outputs": [ 272 | { 273 | "internalType": "bool", 274 | "name": "", 275 | "type": "bool" 276 | } 277 | ], 278 | "stateMutability": "view", 279 | "type": "function" 280 | }, 281 | { 282 | "inputs": [ 283 | { 284 | "internalType": "uint256", 285 | "name": "_fee", 286 | "type": "uint256" 287 | }, 288 | { 289 | "internalType": "bytes32", 290 | "name": "_orderId", 291 | "type": "bytes32" 292 | } 293 | ], 294 | "name": "refund", 295 | "outputs": [ 296 | { 297 | "internalType": "bool", 298 | "name": "", 299 | "type": "bool" 300 | } 301 | ], 302 | "stateMutability": "nonpayable", 303 | "type": "function" 304 | }, 305 | { 306 | "inputs": [ 307 | { 308 | "internalType": "bytes32", 309 | "name": "_splitOrderId", 310 | "type": "bytes32" 311 | }, 312 | { 313 | "internalType": "bytes32", 314 | "name": "_orderId", 315 | "type": "bytes32" 316 | }, 317 | { 318 | "internalType": "address", 319 | "name": "_liquidityProvider", 320 | "type": "address" 321 | }, 322 | { 323 | "internalType": "uint64", 324 | "name": "_settlePercent", 325 | "type": "uint64" 326 | } 327 | ], 328 | "name": "settle", 329 | "outputs": [ 330 | { 331 | "internalType": "bool", 332 | "name": "", 333 | "type": "bool" 334 | } 335 | ], 336 | "stateMutability": "nonpayable", 337 | "type": "function" 338 | } 339 | ], 340 | "bytecode": "0x", 341 | "deployedBytecode": "0x", 342 | "linkReferences": {}, 343 | "deployedLinkReferences": {} 344 | } 345 | -------------------------------------------------------------------------------- /artifacts/contracts/mocks/MockUSDC.sol/MockUSDT.dbg.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-dbg-1", 3 | "buildInfo": "../../../build-info/b8a88c4b130e7a569c3029307ef5f126.json" 4 | } 5 | -------------------------------------------------------------------------------- /contracts/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paycrest/contracts/4c10417c4d37f6c11a8e55485e32cb35efc47254/contracts/.DS_Store -------------------------------------------------------------------------------- /contracts/Gateway.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.18; 3 | 4 | import '@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol'; 5 | 6 | import {GatewaySettingManager} from './GatewaySettingManager.sol'; 7 | import {IGateway, IERC20} from './interfaces/IGateway.sol'; 8 | 9 | /** 10 | * @title Gateway 11 | * @notice This contract serves as a gateway for creating orders and managing settlements. 12 | */ 13 | contract Gateway is IGateway, GatewaySettingManager, PausableUpgradeable { 14 | struct fee { 15 | uint256 protocolFee; 16 | uint256 liquidityProviderAmount; 17 | } 18 | 19 | mapping(bytes32 => Order) private order; 20 | mapping(address => uint256) private _nonce; 21 | uint256[50] private __gap; 22 | 23 | /// @custom:oz-upgrades-unsafe-allow constructor 24 | constructor() { 25 | _disableInitializers(); 26 | } 27 | 28 | /** 29 | * @dev Initialize function. 30 | */ 31 | function initialize() external initializer { 32 | MAX_BPS = 100_000; 33 | __Ownable2Step_init(); 34 | __Pausable_init(); 35 | } 36 | 37 | /** 38 | * @dev Modifier that allows only the aggregator to call a function. 39 | */ 40 | modifier onlyAggregator() { 41 | require(msg.sender == _aggregatorAddress, 'OnlyAggregator'); 42 | _; 43 | } 44 | 45 | /* ################################################################## 46 | OWNER FUNCTIONS 47 | ################################################################## */ 48 | /** 49 | * @dev Pause the contract. 50 | */ 51 | function pause() external onlyOwner { 52 | _pause(); 53 | } 54 | 55 | /** 56 | * @dev Unpause the contract. 57 | */ 58 | function unpause() external onlyOwner { 59 | _unpause(); 60 | } 61 | 62 | /* ################################################################## 63 | USER CALLS 64 | ################################################################## */ 65 | /** @dev See {createOrder-IGateway}. */ 66 | function createOrder( 67 | address _token, 68 | uint256 _amount, 69 | uint96 _rate, 70 | address _senderFeeRecipient, 71 | uint256 _senderFee, 72 | address _refundAddress, 73 | string calldata messageHash 74 | ) external whenNotPaused returns (bytes32 orderId) { 75 | // checks that are required 76 | _handler(_token, _amount, _refundAddress, _senderFeeRecipient, _senderFee); 77 | 78 | // validate messageHash 79 | require(bytes(messageHash).length != 0, 'InvalidMessageHash'); 80 | 81 | // transfer token from msg.sender to contract 82 | IERC20(_token).transferFrom(msg.sender, address(this), _amount + _senderFee); 83 | 84 | // increase users nonce to avoid replay attacks 85 | _nonce[msg.sender]++; 86 | 87 | // generate transaction id for the transaction 88 | orderId = keccak256(abi.encode(msg.sender, _nonce[msg.sender])); 89 | 90 | // update transaction 91 | uint256 _protocolFee = (_amount * protocolFeePercent) / MAX_BPS; 92 | order[orderId] = Order({ 93 | sender: msg.sender, 94 | token: _token, 95 | senderFeeRecipient: _senderFeeRecipient, 96 | senderFee: _senderFee, 97 | protocolFee: _protocolFee, 98 | isFulfilled: false, 99 | isRefunded: false, 100 | refundAddress: _refundAddress, 101 | currentBPS: uint64(MAX_BPS), 102 | amount: _amount 103 | }); 104 | 105 | // emit order created event 106 | emit OrderCreated( 107 | _refundAddress, 108 | _token, 109 | order[orderId].amount, 110 | _protocolFee, 111 | orderId, 112 | _rate, 113 | messageHash 114 | ); 115 | } 116 | 117 | /** 118 | * @dev Internal function to handle order creation. 119 | * @param _token The address of the token being traded. 120 | * @param _amount The amount of tokens being traded. 121 | * @param _refundAddress The address to refund the tokens in case of cancellation. 122 | * @param _senderFeeRecipient The address of the recipient for the sender fee. 123 | * @param _senderFee The amount of the sender fee. 124 | */ 125 | function _handler( 126 | address _token, 127 | uint256 _amount, 128 | address _refundAddress, 129 | address _senderFeeRecipient, 130 | uint256 _senderFee 131 | ) internal view { 132 | require(_isTokenSupported[_token] == 1, 'TokenNotSupported'); 133 | require(_amount != 0, 'AmountIsZero'); 134 | require(_refundAddress != address(0), 'ThrowZeroAddress'); 135 | 136 | if (_senderFee != 0) { 137 | require(_senderFeeRecipient != address(0), 'InvalidSenderFeeRecipient'); 138 | } 139 | } 140 | 141 | /* ################################################################## 142 | AGGREGATOR FUNCTIONS 143 | ################################################################## */ 144 | /** @dev See {settle-IGateway}. */ 145 | function settle( 146 | bytes32 _splitOrderId, 147 | bytes32 _orderId, 148 | address _liquidityProvider, 149 | uint64 _settlePercent 150 | ) external onlyAggregator returns (bool) { 151 | // ensure the transaction has not been fulfilled 152 | require(!order[_orderId].isFulfilled, 'OrderFulfilled'); 153 | require(!order[_orderId].isRefunded, 'OrderRefunded'); 154 | 155 | // load the token into memory 156 | address token = order[_orderId].token; 157 | 158 | // subtract sum of amount based on the input _settlePercent 159 | order[_orderId].currentBPS -= _settlePercent; 160 | 161 | if (order[_orderId].currentBPS == 0) { 162 | // update the transaction to be fulfilled 163 | order[_orderId].isFulfilled = true; 164 | 165 | if (order[_orderId].senderFee != 0) { 166 | // transfer sender fee 167 | IERC20(order[_orderId].token).transfer( 168 | order[_orderId].senderFeeRecipient, 169 | order[_orderId].senderFee 170 | ); 171 | 172 | // emit event 173 | emit SenderFeeTransferred( 174 | order[_orderId].senderFeeRecipient, 175 | order[_orderId].senderFee 176 | ); 177 | } 178 | 179 | } 180 | 181 | // transfer to liquidity provider 182 | uint256 liquidityProviderAmount = (order[_orderId].amount * _settlePercent) / MAX_BPS; 183 | order[_orderId].amount -= liquidityProviderAmount; 184 | 185 | uint256 protocolFee = (liquidityProviderAmount * protocolFeePercent) / MAX_BPS; 186 | liquidityProviderAmount -= protocolFee; 187 | 188 | // transfer protocol fee 189 | IERC20(token).transfer(treasuryAddress, protocolFee); 190 | 191 | IERC20(token).transfer(_liquidityProvider, liquidityProviderAmount); 192 | 193 | // emit settled event 194 | emit OrderSettled(_splitOrderId, _orderId, _liquidityProvider, _settlePercent); 195 | 196 | return true; 197 | } 198 | 199 | /** @dev See {refund-IGateway}. */ 200 | function refund(uint256 _fee, bytes32 _orderId) external onlyAggregator returns (bool) { 201 | // ensure the transaction has not been fulfilled 202 | require(!order[_orderId].isFulfilled, 'OrderFulfilled'); 203 | require(!order[_orderId].isRefunded, 'OrderRefunded'); 204 | require(order[_orderId].protocolFee >= _fee, 'FeeExceedsProtocolFee'); 205 | 206 | if (_fee > 0) { 207 | // transfer refund fee to the treasury 208 | IERC20(order[_orderId].token).transfer(treasuryAddress, _fee); 209 | } 210 | 211 | // reset state values 212 | order[_orderId].isRefunded = true; 213 | order[_orderId].currentBPS = 0; 214 | 215 | // deduct fee from order amount 216 | uint256 refundAmount = order[_orderId].amount - _fee; 217 | 218 | // transfer refund amount and sender fee to the refund address 219 | IERC20(order[_orderId].token).transfer( 220 | order[_orderId].refundAddress, 221 | refundAmount + order[_orderId].senderFee 222 | ); 223 | 224 | // emit refunded event 225 | emit OrderRefunded(_fee, _orderId); 226 | 227 | return true; 228 | } 229 | 230 | /* ################################################################## 231 | VIEW CALLS 232 | ################################################################## */ 233 | /** @dev See {getOrderInfo-IGateway}. */ 234 | function getOrderInfo(bytes32 _orderId) external view returns (Order memory) { 235 | return order[_orderId]; 236 | } 237 | 238 | /** @dev See {isTokenSupported-IGateway}. */ 239 | function isTokenSupported(address _token) external view returns (bool) { 240 | if (_isTokenSupported[_token] == 1) return true; 241 | return false; 242 | } 243 | 244 | /** @dev See {getFeeDetails-IGateway}. */ 245 | function getFeeDetails() external view returns (uint64, uint256) { 246 | return (protocolFeePercent, MAX_BPS); 247 | } 248 | } 249 | -------------------------------------------------------------------------------- /contracts/GatewaySettingManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | 3 | /** 4 | * @title GatewaySettingManager 5 | * @dev This contract manages the settings and configurations for the Gateway protocol. 6 | */ 7 | pragma solidity ^0.8.18; 8 | 9 | import '@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol'; 10 | 11 | contract GatewaySettingManager is Ownable2StepUpgradeable { 12 | uint256 internal MAX_BPS; 13 | uint64 internal protocolFeePercent; 14 | address internal treasuryAddress; 15 | address internal _aggregatorAddress; 16 | mapping(address => uint256) internal _isTokenSupported; 17 | 18 | // this should decrease if more slots are needed on this contract to avoid collisions with base contract 19 | uint256[50] private __gap; 20 | 21 | 22 | event SettingManagerBool(bytes32 indexed what, address indexed value, uint256 status); 23 | event ProtocolFeeUpdated(uint64 protocolFee); 24 | event ProtocolAddressUpdated(bytes32 indexed what, address indexed treasuryAddress); 25 | event SetFeeRecipient(address indexed treasuryAddress); 26 | 27 | /* ################################################################## 28 | OWNER FUNCTIONS 29 | ################################################################## */ 30 | 31 | /** 32 | * @dev Sets the boolean value for a specific setting. 33 | * @param what The setting to be updated. 34 | * @param value The address or value associated with the setting. 35 | * @param status The boolean value to be set. 36 | * Requirements: 37 | * - The value must not be a zero address. 38 | */ 39 | function settingManagerBool(bytes32 what, address value, uint256 status) external onlyOwner { 40 | require(value != address(0), 'Gateway: zero address'); 41 | require(status == 1 || status == 2, 'Gateway: invalid status'); 42 | if (what == 'token') { 43 | _isTokenSupported[value] = status; 44 | emit SettingManagerBool(what, value, status); 45 | } 46 | } 47 | 48 | /** 49 | * @dev Updates the protocol fee percentage. 50 | * @param _protocolFeePercent The new protocol fee percentage to be set. 51 | */ 52 | function updateProtocolFee(uint64 _protocolFeePercent) external onlyOwner { 53 | protocolFeePercent = _protocolFeePercent; 54 | emit ProtocolFeeUpdated(_protocolFeePercent); 55 | } 56 | 57 | /** 58 | * @dev Updates a protocol address. 59 | * @param what The address type to be updated (treasury or aggregator). 60 | * @param value The new address to be set. 61 | * Requirements: 62 | * - The value must not be a zero address. 63 | */ 64 | function updateProtocolAddress(bytes32 what, address value) external onlyOwner { 65 | require(value != address(0), 'Gateway: zero address'); 66 | bool updated; 67 | if (what == 'treasury') { 68 | require(treasuryAddress != value, 'Gateway: treasury address already set'); 69 | treasuryAddress = value; 70 | updated = true; 71 | } else if (what == 'aggregator') { 72 | require(_aggregatorAddress != value, 'Gateway: aggregator address already set'); 73 | _aggregatorAddress = value; 74 | updated = true; 75 | } 76 | if (updated) { 77 | emit ProtocolAddressUpdated(what, value); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /contracts/interfaces/IGateway.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.18; 3 | 4 | import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; 5 | 6 | /** 7 | * @title IGateway 8 | * @notice Interface for the Gateway contract. 9 | */ 10 | interface IGateway { 11 | /* ################################################################## 12 | EVENTS 13 | ################################################################## */ 14 | /** 15 | * @dev Emitted when a deposit is made. 16 | * @param sender The address of the sender. 17 | * @param token The address of the deposited token. 18 | * @param amount The amount of the deposit. 19 | * @param orderId The ID of the order. 20 | * @param rate The rate at which the deposit is made. 21 | * @param messageHash The hash of the message. 22 | */ 23 | event OrderCreated( 24 | address indexed sender, 25 | address indexed token, 26 | uint256 indexed amount, 27 | uint256 protocolFee, 28 | bytes32 orderId, 29 | uint256 rate, 30 | string messageHash 31 | ); 32 | 33 | /** 34 | * @dev Emitted when an aggregator settles a transaction. 35 | * @param splitOrderId The ID of the split order. 36 | * @param orderId The ID of the order. 37 | * @param liquidityProvider The address of the liquidity provider. 38 | * @param settlePercent The percentage at which the transaction is settled. 39 | */ 40 | event OrderSettled( 41 | bytes32 splitOrderId, 42 | bytes32 indexed orderId, 43 | address indexed liquidityProvider, 44 | uint96 settlePercent 45 | ); 46 | 47 | /** 48 | * @dev Emitted when an aggregator refunds a transaction. 49 | * @param fee The fee deducted from the refund amount. 50 | * @param orderId The ID of the order. 51 | */ 52 | event OrderRefunded(uint256 fee, bytes32 indexed orderId); 53 | 54 | /** 55 | * @dev Emitted when the sender's fee is transferred. 56 | * @param sender The address of the sender. 57 | * @param amount The amount of the fee transferred. 58 | */ 59 | event SenderFeeTransferred(address indexed sender, uint256 indexed amount); 60 | 61 | /* ################################################################## 62 | STRUCTS 63 | ################################################################## */ 64 | /** 65 | * @dev Struct representing an order. 66 | * @param sender The address of the sender. 67 | * @param token The address of the token. 68 | * @param senderFeeRecipient The address of the sender fee recipient. 69 | * @param senderFee The fee to be paid to the sender fee recipient. 70 | * @param protocolFee The protocol fee to be paid. 71 | * @param isFulfilled Whether the order is fulfilled. 72 | * @param isRefunded Whether the order is refunded. 73 | * @param refundAddress The address to which the refund is made. 74 | * @param currentBPS The current basis points. 75 | * @param amount The amount of the order. 76 | */ 77 | struct Order { 78 | address sender; 79 | address token; 80 | address senderFeeRecipient; 81 | uint256 senderFee; 82 | uint256 protocolFee; 83 | bool isFulfilled; 84 | bool isRefunded; 85 | address refundAddress; 86 | uint96 currentBPS; 87 | uint256 amount; 88 | } 89 | 90 | /* ################################################################## 91 | EXTERNAL CALLS 92 | ################################################################## */ 93 | /** 94 | * @notice Locks the sender's amount of token into Gateway. 95 | * @dev Requirements: 96 | * - `msg.sender` must approve Gateway contract on `_token` of at least `amount` before function call. 97 | * - `_token` must be an acceptable token. See {isTokenSupported}. 98 | * - `amount` must be greater than minimum. 99 | * - `_refundAddress` refund address must not be zero address. 100 | * @param _token The address of the token. 101 | * @param _amount The amount in the decimal of `_token` to be locked. 102 | * @param _rate The rate at which the sender intends to sell `_amount` of `_token`. 103 | * @param _senderFeeRecipient The address that will receive `_senderFee` in `_token`. 104 | * @param _senderFee The amount in the decimal of `_token` that will be paid to `_senderFeeRecipient`. 105 | * @param _refundAddress The address that will receive `_amount` in `_token` when there is a need to refund. 106 | * @param messageHash The hash of the message. 107 | * @return _orderId The ID of the order. 108 | */ 109 | function createOrder( 110 | address _token, 111 | uint256 _amount, 112 | uint96 _rate, 113 | address _senderFeeRecipient, 114 | uint256 _senderFee, 115 | address _refundAddress, 116 | string calldata messageHash 117 | ) external returns (bytes32 _orderId); 118 | 119 | /** 120 | * @notice Settles a transaction and distributes rewards accordingly. 121 | * @param _splitOrderId The ID of the split order. 122 | * @param _orderId The ID of the transaction. 123 | * @param _liquidityProvider The address of the liquidity provider. 124 | * @param _settlePercent The rate at which the transaction is settled. 125 | * @return bool the settlement is successful. 126 | */ 127 | function settle( 128 | bytes32 _splitOrderId, 129 | bytes32 _orderId, 130 | address _liquidityProvider, 131 | uint64 _settlePercent 132 | ) external returns (bool); 133 | 134 | /** 135 | * @notice Refunds to the specified refundable address. 136 | * @dev Requirements: 137 | * - Only aggregators can call this function. 138 | * @param _fee The amount to be deducted from the amount to be refunded. 139 | * @param _orderId The ID of the transaction. 140 | * @return bool the refund is successful. 141 | */ 142 | function refund(uint256 _fee, bytes32 _orderId) external returns (bool); 143 | 144 | /** 145 | * @notice Checks if a token is supported by Gateway. 146 | * @param _token The address of the token to check. 147 | * @return bool the token is supported. 148 | */ 149 | function isTokenSupported(address _token) external view returns (bool); 150 | 151 | /** 152 | * @notice Gets the details of an order. 153 | * @param _orderId The ID of the order. 154 | * @return Order The order details. 155 | */ 156 | function getOrderInfo(bytes32 _orderId) external view returns (Order memory); 157 | 158 | /** 159 | * @notice Gets the fee details of Gateway. 160 | * @return protocolReward The protocol reward amount. 161 | * @return max_bps The maximum basis points. 162 | */ 163 | function getFeeDetails() external view returns (uint64 protocolReward, uint256 max_bps); 164 | } 165 | -------------------------------------------------------------------------------- /contracts/mocks/MockUSDC.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.18; 3 | 4 | import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 5 | 6 | /// @dev Mock mintable USDC 7 | contract MockUSDT is ERC20 { 8 | constructor() ERC20("MockUDSC", "MUSDC") { 9 | _mint(msg.sender, 1_000_000E18); 10 | } 11 | 12 | function mint(uint256 _amount) external { 13 | _mint(msg.sender, _amount); 14 | } 15 | 16 | function burn(uint256 _amount) external { 17 | _burn(msg.sender, _amount); 18 | } 19 | 20 | function burnAll() external { 21 | uint256 _balanceOf = balanceOf(msg.sender); 22 | require(_balanceOf > 0, "MockUSDT: Nothing to burn"); 23 | _burn(msg.sender, _balanceOf); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import "hardhat-deploy"; 2 | import "@nomicfoundation/hardhat-toolbox"; 3 | import "@nomiclabs/hardhat-ethers"; 4 | import "@nomiclabs/hardhat-etherscan"; 5 | import "@openzeppelin/hardhat-upgrades"; 6 | import "@typechain/hardhat"; 7 | import { task, types } from "hardhat/config"; 8 | import type { HardhatUserConfig } from "hardhat/types"; 9 | 10 | import dotenv from "dotenv"; 11 | 12 | dotenv.config(); 13 | 14 | let { 15 | DEPLOYER_PRIVATE_KEY, 16 | SHIELD3_API_KEY, 17 | ETHERSCAN_API_KEY, 18 | BASESCAN_API_KEY, 19 | ARBISCAN_API_KEY, 20 | BSCSCAN_API_KEY, 21 | POLYGONSCAN_API_KEY, 22 | OPTIMISM_API, 23 | SCROLL_API, 24 | CELO_API, 25 | } = process.env; 26 | 27 | const testPrivateKey = "0000000000000000000000000000000000000000000000000000000000000001" 28 | 29 | const config: HardhatUserConfig = { 30 | namedAccounts: { 31 | deployer: { 32 | default: 0, // here this will by default take the first account as deployer 33 | }, 34 | }, 35 | networks: { 36 | // Mainnets 37 | arbitrumOne: { 38 | url: `https://rpc.shield3.com/v3/0xa4b1/${SHIELD3_API_KEY}/rpc`, 39 | accounts: [DEPLOYER_PRIVATE_KEY || testPrivateKey], 40 | chainId: 42161, 41 | saveDeployments: true, 42 | }, 43 | base: { 44 | url: `https://rpc.shield3.com/v3/0x2105/${SHIELD3_API_KEY}/rpc`, 45 | accounts: [DEPLOYER_PRIVATE_KEY || testPrivateKey], 46 | chainId: 8453, 47 | saveDeployments: true, 48 | }, 49 | bsc: { 50 | url: `https://rpc.shield3.com/v3/0x38/${SHIELD3_API_KEY}/rpc`, 51 | accounts: [DEPLOYER_PRIVATE_KEY || testPrivateKey], 52 | chainId: 56, 53 | saveDeployments: true, 54 | }, 55 | polygon: { 56 | url: `https://rpc.shield3.com/v3/0x89/${SHIELD3_API_KEY}/rpc`, 57 | accounts: [DEPLOYER_PRIVATE_KEY || testPrivateKey], 58 | chainId: 137, 59 | saveDeployments: true, 60 | }, 61 | mainnet: { 62 | url: `https://rpc.shield3.com/v3/0x1/${SHIELD3_API_KEY}/rpc`, 63 | accounts: [DEPLOYER_PRIVATE_KEY || testPrivateKey], 64 | chainId: 1, 65 | saveDeployments: true, 66 | }, 67 | optimisticEthereum: { 68 | url: `https://rpc.shield3.com/v3/0x0a/${SHIELD3_API_KEY}/rpc`, 69 | accounts: [DEPLOYER_PRIVATE_KEY || testPrivateKey], 70 | chainId: 10, 71 | saveDeployments: true, 72 | }, 73 | scroll: { 74 | url: "https://scroll.drpc.org", // @note this is a public rpc 75 | accounts: [DEPLOYER_PRIVATE_KEY || testPrivateKey], 76 | chainId: 534352, 77 | saveDeployments: true, 78 | }, 79 | celo: { 80 | url: "https://forno.celo.org", // @note this is a public rpc 81 | accounts: [DEPLOYER_PRIVATE_KEY || testPrivateKey], 82 | chainId: 42220, 83 | saveDeployments: true, 84 | }, 85 | assetChain: { 86 | url: "https://mainnet-rpc.assetchain.org", // @note this is a public rpc 87 | accounts: [DEPLOYER_PRIVATE_KEY || testPrivateKey], 88 | chainId: 42420, 89 | saveDeployments: true, 90 | }, 91 | lisk: { 92 | url: "https://rpc.api.lisk.com", // @note this is a public rpc 93 | accounts: [DEPLOYER_PRIVATE_KEY || testPrivateKey], 94 | chainId: 1135, 95 | saveDeployments: true, 96 | }, 97 | 98 | // Testnets 99 | arbitrumSepolia: { 100 | url: `https://rpc.shield3.com/v3/0x66eee/${SHIELD3_API_KEY}/rpc`, 101 | accounts: [DEPLOYER_PRIVATE_KEY || testPrivateKey], 102 | chainId: 421614, 103 | gasPrice: "auto", 104 | saveDeployments: true, 105 | }, 106 | amoy: { 107 | url: `https://rpc.shield3.com/v3/0x13882/${SHIELD3_API_KEY}/rpc`, 108 | accounts: [DEPLOYER_PRIVATE_KEY || testPrivateKey], 109 | chainId: 80002, 110 | saveDeployments: true, 111 | }, 112 | baseSepolia: { 113 | url: `https://rpc.shield3.com/v3/0x14a34/${SHIELD3_API_KEY}/rpc`, 114 | accounts: [DEPLOYER_PRIVATE_KEY || testPrivateKey], 115 | chainId: 84532, 116 | saveDeployments: true, 117 | }, 118 | sepolia: { 119 | url: `https://rpc.shield3.com/v3/0xaa36a7/${SHIELD3_API_KEY}/rpc`, 120 | accounts: [DEPLOYER_PRIVATE_KEY || testPrivateKey], 121 | chainId: 11155111, 122 | saveDeployments: true, 123 | }, 124 | assetchainTestnet: { 125 | url: "https://enugu-rpc.assetchain.org/", // @note this is a public rpc 126 | accounts: [DEPLOYER_PRIVATE_KEY || testPrivateKey], 127 | chainId: 42421, 128 | saveDeployments: true, 129 | }, 130 | }, 131 | solidity: { 132 | settings: { 133 | optimizer: { 134 | enabled: true, 135 | runs: 200, 136 | }, 137 | viaIR: true, 138 | }, 139 | 140 | compilers: [ 141 | { 142 | version: "0.8.18", 143 | }, 144 | { 145 | version: "0.8.9", 146 | }, 147 | ], 148 | }, 149 | etherscan: { 150 | apiKey: { 151 | base: BASESCAN_API_KEY!, 152 | baseSepolia: BASESCAN_API_KEY!, 153 | arbitrumOne: ARBISCAN_API_KEY!, 154 | arbitrumSepolia: ARBISCAN_API_KEY!, 155 | bsc: BSCSCAN_API_KEY!, 156 | polygon: POLYGONSCAN_API_KEY!, 157 | amoy: POLYGONSCAN_API_KEY!, 158 | mainnet: ETHERSCAN_API_KEY!, 159 | sepolia: ETHERSCAN_API_KEY!, 160 | optimisticEthereum: OPTIMISM_API!, 161 | scroll: SCROLL_API!, 162 | celo: CELO_API!, 163 | lisk: "Paycrest", // @note https://docs.blockscout.com/devs/verification/hardhat-verification-plugin#config-file-and-unsupported-networks 164 | assetChain: "Paycrest", 165 | }, 166 | customChains: [ 167 | { 168 | network: "base", 169 | chainId: 8453, 170 | urls: { 171 | apiURL: "https://api.basescan.org/api", 172 | browserURL: "https://basescan.org", 173 | }, 174 | }, 175 | { 176 | network: "scroll", 177 | chainId: 534352, 178 | urls: { 179 | apiURL: "https://api.scrollscan.com/api", 180 | browserURL: "https://scrollscan.com/", 181 | }, 182 | }, 183 | { 184 | network: "lisk", 185 | chainId: 1135, 186 | urls: { 187 | apiURL: "https://blockscout.lisk.com/api", 188 | browserURL: "https://blockscout.lisk.com/", 189 | }, 190 | }, 191 | { 192 | network: "assetChain", 193 | chainId: 42421, 194 | urls: { 195 | apiURL: "https://scan.assetchain.org/api", 196 | browserURL: "https://scan.assetchain.org/", 197 | }, 198 | }, 199 | { 200 | network: "baseSepolia", 201 | chainId: 84532, 202 | urls: { 203 | apiURL: "https://api-sepolia.basescan.org/api", 204 | browserURL: "https://sepolia.basescan.org", 205 | }, 206 | }, 207 | { 208 | network: "arbitrumSepolia", 209 | chainId: 421614, 210 | urls: { 211 | apiURL: "https://api-sepolia.arbiscan.io/api", 212 | browserURL: "https://sepolia.arbiscan.io", 213 | }, 214 | }, 215 | { 216 | network: "amoy", 217 | chainId: 80002, 218 | urls: { 219 | apiURL: "https://api-amoy.polygonscan.com/api", 220 | browserURL: "https://amoy.polygonscan.com", 221 | }, 222 | }, 223 | { 224 | network: "celo", 225 | chainId: 42220, 226 | urls: { 227 | apiURL: "https://api.celoscan.io/api", 228 | browserURL: "https://celoscan.io/", 229 | }, 230 | }, 231 | ], 232 | }, 233 | }; 234 | 235 | task("flat", "Flattens and prints contracts and their dependencies (Resolves licenses)") 236 | .addOptionalVariadicPositionalParam("files", "The files to flatten", undefined, types.inputFile) 237 | .setAction(async ({ files }, hre) => { 238 | let flattened = await hre.run("flatten:get-flattened-sources", { files }); 239 | 240 | // Remove every line started with "// SPDX-License-Identifier:" 241 | flattened = flattened.replace(/SPDX-License-Identifier:/gm, "License-Identifier:"); 242 | flattened = `// SPDX-License-Identifier: MIXED\n\n${flattened}`; 243 | 244 | // Remove every line started with "pragma experimental ABIEncoderV2;" except the first one 245 | flattened = flattened.replace(/pragma experimental ABIEncoderV2;\n/gm, ((i) => (m: any) => (!i++ ? m : ""))(0)); 246 | console.log(flattened); 247 | }); 248 | 249 | task("accounts", "Prints the list of accounts", async (taskArgs, hre) => { 250 | const accounts = await hre.ethers.getSigners(); 251 | const provider = hre.ethers.provider; 252 | 253 | for (const account of accounts) { 254 | console.log( 255 | "%s (%i ETH)", 256 | account.address, 257 | // hre.ethers.utils.formatEther( 258 | // getBalance returns wei amount, format to ETH amount 259 | await provider.getBalance(account.address) 260 | // ) 261 | ); 262 | } 263 | }); 264 | 265 | export default config; -------------------------------------------------------------------------------- /migrations/1_deploy.js: -------------------------------------------------------------------------------- 1 | const { deployProxy } = require("@openzeppelin/truffle-upgrades"); 2 | const Gateway = artifacts.require("Gateway"); 3 | 4 | module.exports = async function (deployer) { 5 | try { 6 | deployer.trufflePlugin = true; 7 | const gatewayContractInstance = await deployProxy(Gateway, { 8 | deployer, 9 | }); 10 | await Gateway.deployed(); 11 | console.info("✅ Deployed Gateway: ", gatewayContractInstance.address); 12 | } catch (error) { 13 | console.error("Transparent: deploy contract error", error); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /migrations/2_upgrade.js: -------------------------------------------------------------------------------- 1 | const { admin } = require('@openzeppelin/truffle-upgrades'); 2 | const ProxyAdmin = artifacts.require( 3 | '@openzeppelin/upgrades-core/artifacts/@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol/ProxyAdmin.json' 4 | ); 5 | const Gateway = artifacts.require("Gateway"); 6 | 7 | const proxyContractAddress = "THyFP5ST9YyLZn6EzjKjFhZti6aKPgEXNU"; 8 | // Shasta: 9 | // const proxyContractAddress = "TYA8urq7nkN2yU7rJqAgwDShCusDZrrsxZ"; 10 | 11 | module.exports = async function (deployer) { 12 | try { 13 | // Deploy the new Gateway implementation contract 14 | await deployer.deploy(Gateway); 15 | 16 | // Upgrade proxy contract 17 | const adminIns = await admin.getInstance(); 18 | const adminContract = await ProxyAdmin.at(adminIns.address); 19 | await adminContract.upgrade(proxyContractAddress, Gateway.address); 20 | console.info("✅ Upgraded Gateway: ", proxyContractAddress); 21 | } catch (error) { 22 | console.error("UUPS: upgrade contract error", error); 23 | } 24 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "paycrest", 3 | "version": "1.0.0", 4 | "description": "cross-border payment facilitator, using blockchain technology and peer-to-peer off-ramps for transactions", 5 | "main": "index.js", 6 | "repository": "https://github.com/paycrest/contracts", 7 | "scripts": { 8 | "test": "npx hardhat test", 9 | "ownership": "npx hardhat test test/paycrest/paycrest.ownable.test.js", 10 | "settleOrder": "npx hardhat test test/paycrest/paycrest.settleOrder.test.js", 11 | "createOrder": "npx hardhat test test/paycrest/paycrest.createorder.test.js", 12 | "compile": "npx hardhat compile", 13 | "lint:sol": "prettier --loglevel warn --ignore-path .gitignore 'contracts/**/*.sol' --check && solhint 'contracts/**/*.sol'", 14 | "lint:sol:fix": "prettier --loglevel warn --ignore-path .gitignore 'contracts/**/*.sol' --write" 15 | }, 16 | "keywords": [], 17 | "author": "https://onahprosperity.github.io/", 18 | "license": "MIT", 19 | "devDependencies": { 20 | "@daochild/tronweb-typescript": "^1.1.2", 21 | "@ethersproject/abi": "^5.7.0", 22 | "@ethersproject/providers": "^5.7.2", 23 | "@nomicfoundation/hardhat-chai-matchers": "^1.0.6", 24 | "@nomicfoundation/hardhat-network-helpers": "^1.0.8", 25 | "@nomicfoundation/hardhat-toolbox": "^2.0.2", 26 | "@nomiclabs/hardhat-ethers": "^2.2.3", 27 | "@nomiclabs/hardhat-etherscan": "^3.1.7", 28 | "@openzeppelin/hardhat-upgrades": "^1.27.0", 29 | "@openzeppelin/truffle-upgrades": "^1.21.0", 30 | "@typechain/ethers-v5": "^10.2.0", 31 | "@typechain/hardhat": "^6.1.5", 32 | "chai": "^4.3.7", 33 | "dotenv": "^16.0.2", 34 | "ethers": "^5.7.2", 35 | "hardhat": "^2.14.0", 36 | "hardhat-deploy": "^0.11.34", 37 | "hardhat-gas-reporter": "^1.0.9", 38 | "solidity-coverage": "^0.8.2", 39 | "ts-node": "^10.9.2", 40 | "typechain": "^8.1.1", 41 | "typescript": "^5.3.3" 42 | }, 43 | "dependencies": { 44 | "@openzeppelin/contracts": "^4.9.5", 45 | "@openzeppelin/contracts-upgradeable": "^4.9.5", 46 | "crypto-js": "^4.1.1", 47 | "tronweb": "^5.3.1" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /scripts/config.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from "ethers"; 2 | import dotenv from "dotenv"; 3 | 4 | dotenv.config(); 5 | 6 | let { SHIELD3_API_KEY } = process.env; 7 | 8 | const NETWORKS = { 9 | ///////////////////////////////// 10 | // Mainnets 11 | ///////////////////////////////// 12 | 13 | /** 14 | * @dev Arbitrum One 15 | */ 16 | 42161: { 17 | RPC_URL: `https://rpc.shield3.com/v3/0xa4b1/${SHIELD3_API_KEY}/rpc`, 18 | SUPPORTED_TOKENS: { 19 | USDC: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", 20 | USDT: "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9", 21 | }, 22 | TREASURY_FEE_PERCENT: 500, // in BPS i.e 0.5% 23 | GATEWAY_CONTRACT: "0xE8bc3B607CfE68F47000E3d200310D49041148Fc", 24 | IMPERSONATE_ACCOUNT: "", 25 | }, 26 | 27 | /** 28 | * @dev Base 29 | */ 30 | 8453: { 31 | GATEWAY_IMPLEMENTATION: "0xd28da2E11FCd2A9F44D5a4952430CE8b4f3Ee05f", 32 | RPC_URL: `https://rpc.shield3.com/v3/0x2105/${SHIELD3_API_KEY}/rpc`, 33 | SUPPORTED_TOKENS: { 34 | USDC: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", 35 | cNGN: "0x46C85152bFe9f96829aA94755D9f915F9B10EF5F" 36 | }, 37 | TREASURY_FEE_PERCENT: 500, // in BPS i.e 0.5% 38 | GATEWAY_CONTRACT: "0x30F6A8457F8E42371E204a9c103f2Bd42341dD0F", 39 | IMPERSONATE_ACCOUNT: "", 40 | }, 41 | 42 | /** 43 | * @dev Binance Smart Chain 44 | */ 45 | 56: { 46 | RPC_URL: `https://rpc.shield3.com/v3/0x38/${SHIELD3_API_KEY}/rpc`, 47 | SUPPORTED_TOKENS: { 48 | USDC: "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d", 49 | USDT: "0x55d398326f99059ff775485246999027b3197955", 50 | cNGN: "0xa8AEA66B361a8d53e8865c62D142167Af28Af058" 51 | }, 52 | TREASURY_FEE_PERCENT: 500, // in BPS i.e 0.5% 53 | GATEWAY_CONTRACT: "0x1FA0EE7F9410F6fa49B7AD5Da72Cf01647090028", 54 | }, 55 | 56 | /** 57 | * @dev Polygon Mainnet 58 | */ 59 | 137: { 60 | RPC_URL: `https://rpc.shield3.com/v3/0x89/${SHIELD3_API_KEY}/rpc`, 61 | SUPPORTED_TOKENS: { 62 | USDC: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", 63 | USDT: "0xc2132D05D31c914a87C6611C10748AEb04B58e8F", 64 | cNGN: "0x52828daa48C1a9A06F37500882b42daf0bE04C3B" 65 | }, 66 | TREASURY_FEE_PERCENT: 500, // in BPS i.e 0.5% 67 | GATEWAY_CONTRACT: "0xfB411Cc6385Af50A562aFCb441864E9d541CDA67", 68 | IMPERSONATE_ACCOUNT: "", 69 | }, 70 | 71 | /** 72 | * @dev Ethereum Mainnet 73 | */ 74 | 1: { 75 | RPC_URL: `https://rpc.shield3.com/v3/0x1/${SHIELD3_API_KEY}/rpc`, 76 | SUPPORTED_TOKENS: { 77 | USDC: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", 78 | USDT: "0xdac17f958d2ee523a2206206994597c13d831ec7", 79 | }, 80 | TREASURY_FEE_PERCENT: 500, // in BPS i.e 0.5% 81 | GATEWAY_CONTRACT: "", 82 | IMPERSONATE_ACCOUNT: "", 83 | }, 84 | 85 | /** 86 | * @dev Optimism Mainnet 87 | */ 88 | 10: { 89 | RPC_URL: `https://rpc.shield3.com/v3/0x1/${SHIELD3_API_KEY}/rpc`, 90 | SUPPORTED_TOKENS: { 91 | USDC: "0x0b2c639c533813f4aa9d7837caf62653d097ff85", 92 | USDT: "0x94b008aa00579c1307b0ef2c499ad98a8ce58e58", 93 | }, 94 | TREASURY_FEE_PERCENT: 500, // in BPS i.e 0.5% 95 | GATEWAY_CONTRACT: "0xD293fCd3dBc025603911853d893A4724CF9f70a0", 96 | IMPERSONATE_ACCOUNT: "", 97 | }, 98 | 99 | /** 100 | * @dev Scroll Mainnet 101 | */ 102 | 534352: { 103 | RPC_URL: `https://rpc.shield3.com/v3/0x82750/${SHIELD3_API_KEY}/rpc`, 104 | SUPPORTED_TOKENS: { 105 | USDC: "0x06eFdBFf2a14a7c8E15944D1F4A48F9F95F663A4", 106 | }, 107 | TREASURY_FEE_PERCENT: 500, // in BPS i.e 0.5% 108 | GATEWAY_CONTRACT: "0x663C5BfE7d44bA946C2dd4b2D1Cf9580319F9338", 109 | IMPERSONATE_ACCOUNT: "", 110 | }, 111 | 112 | /** 113 | * @dev Tron Mainnet 114 | * @Note This is a placeholder network as Tron chainID will interfere with ETH chainID 115 | */ 116 | 12001: { 117 | RPC_URL: `https://api.trongrid.io`, 118 | SUPPORTED_TOKENS: { 119 | USDT: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", 120 | }, 121 | TREASURY_FEE_PERCENT: 500, // in BPS i.e 0.5% 122 | GATEWAY_CONTRACT: "THyFP5ST9YyLZn6EzjKjFhZti6aKPgEXNU", 123 | }, 124 | /** 125 | * @dev Celo Mainnet 126 | */ 127 | 42220: { 128 | GATEWAY_IMPLEMENTATION: "0x8508c1C9f29BD1e73B5A9bD8FB87720927c681FA", 129 | RPC_URL: `https://forno.celo.org`, 130 | SUPPORTED_TOKENS: { 131 | USDC: "0xcebA9300f2b948710d2653dD7B07f33A8B32118C", 132 | cUSD: "0x765DE816845861e75A25fCA122bb6898B8B1282a", 133 | USDT: "0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e", 134 | }, 135 | TREASURY_FEE_PERCENT: 500, // in BPS i.e 0.5% 136 | GATEWAY_CONTRACT: "0xF418217E3f81092eF44b81C5C8336e6A6fDB0E4b", 137 | IMPERSONATE_ACCOUNT: "", 138 | }, 139 | /** 140 | * @dev AssetChain Mainnet 141 | */ 142 | 42420: { 143 | RPC_URL: `https://mainnet-rpc.assetchain.org`, 144 | GATEWAY_IMPLEMENTATION: "0x3Dc80272cE93cBFF3351913bB089B59C4a9141DE", 145 | SUPPORTED_TOKENS: { 146 | USDC: "0x2B7C1342Cc64add10B2a79C8f9767d2667DE64B2", 147 | cNGN: "0x7923C0f6FA3d1BA6EAFCAedAaD93e737Fd22FC4F" 148 | }, 149 | TREASURY_FEE_PERCENT: 500, // in BPS i.e 0.5% 150 | GATEWAY_CONTRACT: "0xff0E00E0110C1FBb5315D276243497b66D3a4d8a", 151 | IMPERSONATE_ACCOUNT: "", 152 | }, 153 | /** 154 | * @dev Lisk Mainnet 155 | */ 156 | 1135: { 157 | RPC_URL: `https://rpc.api.lisk.com`, 158 | GATEWAY_IMPLEMENTATION: "0x3Dc80272cE93cBFF3351913bB089B59C4a9141DE", 159 | SUPPORTED_TOKENS: { 160 | USDT: "0x05D032ac25d322df992303dCa074EE7392C117b9", 161 | }, 162 | TREASURY_FEE_PERCENT: 500, // in BPS i.e 0.5% 163 | GATEWAY_CONTRACT: "0xff0E00E0110C1FBb5315D276243497b66D3a4d8a", 164 | IMPERSONATE_ACCOUNT: "", 165 | }, 166 | 167 | ///////////////////////////////// 168 | // Testnets 169 | ///////////////////////////////// 170 | 171 | /** 172 | * @dev Polygon Amoy 173 | */ 174 | 80002: { 175 | RPC_URL: `https://rpc.shield3.com/v3/0x13882/${SHIELD3_API_KEY}/rpc`, 176 | SUPPORTED_TOKENS: { 177 | USDC: "0x41E94Eb019C0762f9Bfcf9Fb1E58725BfB0e7582", 178 | cNGN: "0x1BE5EaCb5D503fe8D64c810a0b14cdD7eC48df1f" 179 | }, 180 | TREASURY_FEE_PERCENT: 500, // in BPS i.e 0.5% 181 | GATEWAY_CONTRACT: "", 182 | IMPERSONATE_ACCOUNT: "", 183 | }, 184 | 185 | /** 186 | * @dev Arbitrum Sepolia 187 | */ 188 | 421614: { 189 | RPC_URL: `https://rpc.shield3.com/v3/0x66eee/${SHIELD3_API_KEY}/rpc`, 190 | SUPPORTED_TOKENS: { 191 | "6TEST": "0x3870419Ba2BBf0127060bCB37f69A1b1C090992B", 192 | USDC: "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", 193 | }, 194 | TREASURY_FEE_PERCENT: 500, // in BPS i.e 0.5% 195 | GATEWAY_CONTRACT: "0x87B321fc77A0fDD0ca1fEe7Ab791131157B9841A", 196 | IMPERSONATE_ACCOUNT: "", 197 | }, 198 | 199 | /** 200 | * @dev Base Sepolia 201 | */ 202 | 84532: { 203 | GATEWAY_IMPLEMENTATION: "0xff0E00E0110C1FBb5315D276243497b66D3a4d8a", 204 | RPC_URL: `https://rpc.shield3.com/v3/0x14a34/${SHIELD3_API_KEY}/rpc`, 205 | SUPPORTED_TOKENS: { 206 | USDC: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", 207 | DAI: "0x7683022d84f726a96c4a6611cd31dbf5409c0ac9", 208 | cNGN: "0x24FcDa8602a75e065c1cc6d765e7Ad3217b2827b" 209 | }, 210 | TREASURY_FEE_PERCENT: 500, // in BPS i.e 0.5% 211 | GATEWAY_CONTRACT: "0x847dfdAa218F9137229CF8424378871A1DA8f625", 212 | IMPERSONATE_ACCOUNT: "", 213 | }, 214 | 215 | /** 216 | * @dev Ethereum Sepolia 217 | */ 218 | 11155111: { 219 | RPC_URL: `https://rpc.shield3.com/v3/0xaa36a7/${SHIELD3_API_KEY}/rpc`, 220 | SUPPORTED_TOKENS: { 221 | "6TEST": "0x3870419Ba2BBf0127060bCB37f69A1b1C090992B", 222 | DAI: "0x77Ab54631BfBAE40383c62044dC30B229c7df9f5", 223 | cNGN: "0x38528a3100E5e19b3043041FF9b00A983145Fb1A" 224 | }, 225 | TREASURY_FEE_PERCENT: 500, // in BPS i.e 0.5% 226 | GATEWAY_CONTRACT: "0xCAD53Ff499155Cc2fAA2082A85716322906886c2", 227 | IMPERSONATE_ACCOUNT: "", 228 | }, 229 | 230 | /** 231 | * @dev Tron Shasta 232 | * @Note This is a placeholder network as Tron chainID will interfere with ETH chainID 233 | */ 234 | 12002: { 235 | RPC_URL: `https://api.shasta.trongrid.io`, 236 | SUPPORTED_TOKENS: { 237 | USDT: "TG3XXyExBkPp9nzdajDZsozEu4BkaSJozs", 238 | }, 239 | TREASURY_FEE_PERCENT: 500, // in BPS i.e 0.5% 240 | GATEWAY_CONTRACT: "TYA8urq7nkN2yU7rJqAgwDShCusDZrrsxZ", 241 | }, 242 | /** 243 | * @dev AssetChain Testnet 244 | */ 245 | 42421: { 246 | GATEWAY_IMPLEMENTATION: "0x9519D63fbF9717Fa3419846eBA92B01Cd1d1D131", 247 | RPC_URL: `https://enugu-rpc.assetchain.org/`, 248 | SUPPORTED_TOKENS: { 249 | USDC: "0x04f868C5b3F0A100a207c7e9312946cC2c48a7a3", 250 | cNGN: "0x069404d2F76Aa4519819a41B4E385074A9F4E8eA" 251 | }, 252 | TREASURY_FEE_PERCENT: 500, // in BPS i.e 0.5% 253 | GATEWAY_CONTRACT: "0xBe6dE889795677736919A7880324A71Dc7dFa162", 254 | IMPERSONATE_ACCOUNT: "", 255 | }, 256 | }; 257 | 258 | export { NETWORKS }; 259 | -------------------------------------------------------------------------------- /scripts/deploy.ts: -------------------------------------------------------------------------------- 1 | import { ethers, upgrades, network } from "hardhat"; 2 | import { confirmContinue, assertEnvironment, waitForInput, updateConfigFile } from "./utils"; 3 | import hre from "hardhat"; 4 | 5 | assertEnvironment(); 6 | 7 | // Function declarations 8 | async function deployGatewayProxy(): Promise { 9 | await confirmContinue({ 10 | contract: "Gateway", 11 | network: network.name, 12 | chainId: network.config.chainId, 13 | }); 14 | 15 | const factory = await ethers.getContractFactory("Gateway"); 16 | const contract = await upgrades.deployProxy(factory); 17 | 18 | const tx = await contract.deployTransaction.wait(); 19 | 20 | console.log("✅ Deployed Gateway: ", tx.transactionHash); 21 | 22 | if (network.config.chainId !== undefined) { 23 | await updateConfigFile(network.config.chainId, contract.address); 24 | } 25 | console.log(`Proxy Contract Address: ${contract.address}`); 26 | 27 | return tx; 28 | } 29 | 30 | async function deployGateway(): Promise { 31 | await confirmContinue({ 32 | contract: "Gateway", 33 | network: network.name, 34 | chainId: network.config.chainId, 35 | }); 36 | 37 | const factory = await ethers.getContractFactory("Gateway"); 38 | const contract = await factory.deploy(); 39 | 40 | const tx = await contract.deployTransaction.wait(); 41 | 42 | console.log("✅ Deployed Gateway: ", tx.transactionHash); 43 | 44 | // const implementationAddress = await contract.implementation(); 45 | await hre.run("verify:verify", { 46 | address: contract.address, 47 | }); 48 | 49 | if (network.config.chainId !== undefined) { 50 | await updateConfigFile(network.config.chainId, contract.address); 51 | } 52 | 53 | console.log(`Proxy Contract Address: ${contract.address}`); 54 | 55 | return tx; 56 | } 57 | 58 | 59 | async function main() { 60 | const response = await waitForInput("\nDo you want to deploy a new Gateway proxy? y\n"); 61 | const responseStr = response as string; // Cast response to string 62 | if (responseStr.toLowerCase() !== "y") { 63 | await deployGateway(); 64 | } else { 65 | await deployGatewayProxy(); 66 | } 67 | } 68 | 69 | main().catch((error) => { 70 | console.error(error); 71 | process.exitCode = 1; 72 | }); 73 | -------------------------------------------------------------------------------- /scripts/forceImport.ts: -------------------------------------------------------------------------------- 1 | // Import necessary libraries 2 | import { ethers, upgrades } from "hardhat"; 3 | 4 | async function main() { 5 | // Define the address of the existing implementation contract 6 | const existingContractAddress: string = 7 | "0xd28da2E11FCd2A9F44D5a4952430CE8b4f3Ee05f"; 8 | 9 | // Define the implementation contract factory 10 | const deployedImplementation = await ethers.getContractFactory("Gateway"); 11 | 12 | // Optionally, specify the kind of proxy 13 | const opts = { 14 | kind: 'uups' as const, // or 'transparent', 'beacon' 15 | }; 16 | 17 | // Forcefully import the existing contract 18 | const importedContract = await upgrades.forceImport( 19 | existingContractAddress, 20 | deployedImplementation, 21 | opts 22 | ); 23 | 24 | console.log("Contract successfully imported at address:", importedContract.address); 25 | 26 | } 27 | 28 | main() 29 | .then(() => process.exit(0)) 30 | .catch(error => { 31 | console.error(error); 32 | process.exit; 33 | }); -------------------------------------------------------------------------------- /scripts/setSupportedTokens.ts: -------------------------------------------------------------------------------- 1 | import { BigNumber } from "@ethersproject/bignumber"; 2 | import { ethers, network } from "hardhat"; 3 | import { NETWORKS } from "./config"; 4 | import { getContracts } from "./utils"; 5 | 6 | const networkConfig = NETWORKS[network.config.chainId as keyof typeof NETWORKS]; 7 | 8 | async function main() { 9 | // Get contract instances 10 | const { gatewayInstance, wallet } = await getContracts(); 11 | const contractWithSigner = gatewayInstance.connect(wallet); 12 | 13 | const token = ethers.utils.formatBytes32String("token"); 14 | 15 | // Get the current nonce 16 | const currentNonce = await wallet.getTransactionCount(); 17 | // get provider 18 | const provider = new ethers.providers.JsonRpcProvider(networkConfig.RPC_URL); 19 | 20 | const maxPriorityFeePerGas = network.config.chainId === 42220 21 | ? ethers.utils.parseUnits("90", "gwei") // Fallback to 30 Gwei 22 | : await provider.getGasPrice() 23 | 24 | const maxFeePerGas = network.config.chainId === 42220 25 | ? ethers.utils.parseUnits("120", "gwei") 26 | : await provider.getGasPrice() 27 | 28 | // Call contract methods 29 | Object.entries(networkConfig.SUPPORTED_TOKENS).forEach(async ([key, value], index) => { 30 | const tx = await contractWithSigner.settingManagerBool(token, value, BigNumber.from(1), { 31 | nonce: currentNonce + index, 32 | maxPriorityFeePerGas, 33 | maxFeePerGas, 34 | }); 35 | await tx.wait(); 36 | console.log(`✅ Set token ${key}: ${tx.hash}`); 37 | }); 38 | } 39 | 40 | main().catch((error) => { 41 | console.error(error); 42 | process.exitCode = 1; 43 | }); 44 | -------------------------------------------------------------------------------- /scripts/tron/setSupportedTokens.ts: -------------------------------------------------------------------------------- 1 | import { BigNumber } from "@ethersproject/bignumber"; 2 | import { getTronContracts } from "../utils"; 3 | import { NETWORKS } from "../config"; 4 | import { ethers } from "ethers"; 5 | 6 | async function main() { 7 | const { gatewayInstance } = await getTronContracts(); 8 | const networkConfig = NETWORKS[12002]; 9 | 10 | // let result = await gatewayInstance["getFeeDetails"]().call(); 11 | // console.log(result[0].toString(), result[1].toString()); 12 | const token = ethers.utils.formatBytes32String("token"); 13 | 14 | Object.entries(networkConfig.SUPPORTED_TOKENS).forEach( 15 | async ([key, value], index) => { 16 | try { 17 | const tx = await gatewayInstance 18 | .settingManagerBool(token, value, BigNumber.from(1)) 19 | .send({ 20 | feeLimit: 100_000_000, 21 | tokenValue: 0, 22 | shouldPollResponse: true, 23 | }); 24 | console.log(`✅ Set token ${key}: ${tx}`); 25 | } catch(e) { 26 | console.log(`❌ Error setting token: ${e}}`) 27 | } 28 | } 29 | ); 30 | } 31 | 32 | main().catch((error) => { 33 | console.error(error); 34 | process.exitCode = 1; 35 | }); 36 | -------------------------------------------------------------------------------- /scripts/tron/updateProtocolAddresses.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from "ethers"; 2 | import { assertTronEnvironment, getTronContracts } from "../utils"; 3 | import dotenv from "dotenv"; 4 | 5 | dotenv.config(); 6 | 7 | assertTronEnvironment(); 8 | 9 | async function main() { 10 | // Get contract instances 11 | const { gatewayInstance } = await getTronContracts(); 12 | const treasury = ethers.utils.formatBytes32String("treasury"); 13 | const aggregator = ethers.utils.formatBytes32String("aggregator"); 14 | 15 | // Call contract methods 16 | let hash = await gatewayInstance 17 | .updateProtocolAddress(treasury, process.env.TREASURY_ADDRESS_TRON) 18 | .send({ 19 | feeLimit: 100_000_000, 20 | tokenValue: 0, 21 | }); 22 | console.log(`✅ Update treasury address: ${hash}`); 23 | 24 | hash = await gatewayInstance 25 | .updateProtocolAddress(aggregator, process.env.AGGREGATOR_ADDRESS_TRON) 26 | .send({ 27 | feeLimit: 100_000_000, 28 | tokenValue: 0, 29 | }); 30 | console.log(`✅ Update aggregator address: ${hash}`); 31 | } 32 | 33 | main().catch((error) => { 34 | console.error(error); 35 | process.exitCode = 1; 36 | }); 37 | -------------------------------------------------------------------------------- /scripts/tron/updateProtocolFee.ts: -------------------------------------------------------------------------------- 1 | import { BigNumber } from "@ethersproject/bignumber"; 2 | 3 | import { NETWORKS } from "../config"; 4 | import { getTronContracts } from "../utils"; 5 | 6 | async function main() { 7 | // Get contract instances 8 | const { gatewayInstance } = await getTronContracts(); 9 | 10 | const treasuryFeePercent = BigNumber.from(NETWORKS[12002].TREASURY_FEE_PERCENT); 11 | 12 | // call contract methods 13 | const hash = await gatewayInstance 14 | .updateProtocolFee(treasuryFeePercent) 15 | .send({ 16 | feeLimit: 100_000_000, 17 | tokenValue: 0, 18 | }); 19 | 20 | console.log(`✅ Update protocol fee: ${hash}`); 21 | } 22 | 23 | main().catch((error) => { 24 | console.error(error); 25 | process.exitCode = 1; 26 | }); 27 | -------------------------------------------------------------------------------- /scripts/updateProtocolAddresses.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from "ethers"; 2 | import { assertEnvironment, getContracts } from "./utils"; 3 | import dotenv from "dotenv"; 4 | 5 | dotenv.config(); 6 | 7 | assertEnvironment(); 8 | 9 | async function main() { 10 | // Get contract instances 11 | const { gatewayInstance, wallet } = await getContracts(); 12 | const contractWithSigner = gatewayInstance.connect(wallet); 13 | 14 | const treasury = ethers.utils.formatBytes32String("treasury"); 15 | const aggregator = ethers.utils.formatBytes32String("aggregator"); 16 | 17 | // Call contract methods 18 | let tx = await contractWithSigner.updateProtocolAddress( 19 | treasury, 20 | process.env.TREASURY_ADDRESS, 21 | ); 22 | await tx.wait(); 23 | console.log(`✅ Update treasury address: ${tx.hash}`); 24 | 25 | tx = await contractWithSigner.updateProtocolAddress( 26 | aggregator, 27 | process.env.AGGREGATOR_ADDRESS, 28 | ); 29 | await tx.wait(); 30 | console.log(`✅ Update aggregator address: ${tx.hash}`); 31 | } 32 | 33 | main().catch((error) => { 34 | console.error(error); 35 | process.exitCode = 1; 36 | }); 37 | -------------------------------------------------------------------------------- /scripts/updateProtocolFee.ts: -------------------------------------------------------------------------------- 1 | import { network } from "hardhat"; 2 | import { BigNumber } from "@ethersproject/bignumber"; 3 | import { ethers } from "ethers"; 4 | 5 | import { NETWORKS } from "./config"; 6 | import { getContracts } from "./utils"; 7 | 8 | const networkConfig = NETWORKS[network.config.chainId as keyof typeof NETWORKS]; 9 | 10 | async function main() { 11 | // Get contract instances 12 | const { gatewayInstance, wallet } = await getContracts(); 13 | const contractWithSigner = gatewayInstance.connect(wallet); 14 | 15 | const treasuryFeePercent = BigNumber.from(networkConfig.TREASURY_FEE_PERCENT); 16 | 17 | const provider = new ethers.providers.JsonRpcProvider(networkConfig.RPC_URL); 18 | 19 | const maxPriorityFeePerGas = network.config.chainId === 137 20 | ? ethers.utils.parseUnits("90", "gwei") // Fallback to 30 Gwei 21 | : await provider.getGasPrice() 22 | 23 | const maxFeePerGas = network.config.chainId === 137 24 | ? ethers.utils.parseUnits("120", "gwei") 25 | : await provider.getGasPrice() 26 | 27 | // call contract methods 28 | const tx = await contractWithSigner.updateProtocolFee(treasuryFeePercent, 29 | { 30 | maxPriorityFeePerGas, 31 | maxFeePerGas, 32 | } 33 | ); 34 | 35 | await tx.wait(); 36 | console.log(`✅ Update protocol fee: ${tx.hash}`); 37 | } 38 | 39 | main().catch((error) => { 40 | console.error(error); 41 | process.exitCode = 1; 42 | }); 43 | -------------------------------------------------------------------------------- /scripts/upgrade.ts: -------------------------------------------------------------------------------- 1 | import { ethers, upgrades, network } from "hardhat"; 2 | import { NETWORKS } from "./config"; 3 | import hre from "hardhat"; 4 | import { confirmContinue, waitForInput } from "./utils"; 5 | 6 | const networkConfig = NETWORKS[network.config.chainId as keyof typeof NETWORKS]; 7 | 8 | async function deployNewImplementation() { 9 | const factory = await ethers.getContractFactory("Gateway"); 10 | const newImplementation = await factory.deploy(); 11 | await newImplementation.deployed(); 12 | console.log("✅ Deployed new implementation: ", newImplementation.address); 13 | return newImplementation.address; 14 | } 15 | 16 | async function upgradeProxy() { 17 | await confirmContinue({ 18 | contract: "Gateway", 19 | network: network.name, 20 | chainId: network.config.chainId, 21 | }); 22 | try { 23 | const [signer] = await ethers.getSigners(); // Get the signer (the account performing the upgrade) 24 | const balance = await signer.getBalance(); // Get the balance of the signer's address 25 | 26 | if (balance.eq(0)) { 27 | throw new Error( 28 | `"Can't upgrade ${network.config.chainId} with 0 balance` 29 | ); 30 | } 31 | 32 | const proxyContractAddress = networkConfig.GATEWAY_CONTRACT; 33 | const factory = await ethers.getContractFactory("Gateway"); 34 | const contract = await upgrades.upgradeProxy(proxyContractAddress, factory); 35 | 36 | console.log("✅ Upgraded Gateway: ", contract.address); 37 | 38 | await hre.run("verify:verify", { 39 | address: contract.address, 40 | }); 41 | } catch (error) { 42 | if (error instanceof Error) { 43 | console.error("❌ Upgrade failed: ", error.message); 44 | } else { 45 | console.error("❌ Upgrade failed: Unknown error occurred"); 46 | } 47 | 48 | } 49 | } 50 | 51 | async function manualUpgrade() { 52 | await confirmContinue({ 53 | contract: "Gateway", 54 | network: network.name, 55 | chainId: network.config.chainId, 56 | }); 57 | 58 | try { 59 | 60 | const [signer] = await ethers.getSigners(); // Get the signer (the account performing the upgrade) 61 | const balance = await signer.getBalance(); // Get the balance of the signer's address 62 | if (balance.eq(0)) { 63 | throw new Error(`Can't upgrade ${network.config.chainId} with 0 balance`); 64 | } 65 | const proxyContractAddress = networkConfig.GATEWAY_CONTRACT; 66 | 67 | const currentImplAddress = await upgrades.erc1967.getImplementationAddress(proxyContractAddress); 68 | 69 | // Deploy the new implementation contract 70 | const newImplementationAddress = await deployNewImplementation(); 71 | 72 | // Check if the new implementation address is the same as the current one 73 | if (currentImplAddress.toLowerCase() === newImplementationAddress.toLowerCase()) { 74 | throw new Error("New implementation address is the same as the current implementation."); 75 | } 76 | 77 | const proxyAdminAddress = await upgrades.admin.getInstance().then((instance) => 78 | instance.getProxyAdmin(proxyContractAddress) 79 | ); 80 | 81 | // Connect to the ProxyAdmin contract 82 | const ProxyAdminABI = [ 83 | "function upgrade(address proxy, address implementation) public", 84 | ]; 85 | const proxyAdmin = new ethers.Contract(proxyAdminAddress, ProxyAdminABI, signer); 86 | 87 | // Perform the upgrade 88 | const tx = await proxyAdmin.upgrade(proxyContractAddress, newImplementationAddress); 89 | await tx.wait(); 90 | 91 | await hre.run("verify:verify", { 92 | address: proxyContractAddress, 93 | }); 94 | 95 | console.log("✅ Proxy upgraded successfully!"); 96 | 97 | } catch (error) { 98 | if (error instanceof Error) { 99 | console.error("❌ Upgrade failed: ", error.message); 100 | } else { 101 | console.error("❌ Upgrade failed: Unknown error occurred"); 102 | } 103 | } 104 | 105 | } 106 | 107 | async function main() { 108 | const response = await waitForInput("\nDo you want to deploy and upgrade? y/N\n"); 109 | if (response !== "y") { 110 | await manualUpgrade(); 111 | } else { 112 | await upgradeProxy(); 113 | } 114 | } 115 | main().catch((error) => { 116 | console.error(error); 117 | process.exitCode = 1; 118 | }); 119 | -------------------------------------------------------------------------------- /scripts/utils.ts: -------------------------------------------------------------------------------- 1 | import readline from "readline"; 2 | import dotenv from "dotenv"; 3 | import { artifacts, ethers, network } from "hardhat"; 4 | import { NETWORKS } from "./config"; 5 | import { promises as fs } from 'fs'; 6 | import * as path from 'path'; 7 | const TronWeb = require("tronweb"); 8 | 9 | dotenv.config(); 10 | 11 | const shastaConfig = NETWORKS[12002]; 12 | const tronWeb = new TronWeb({ 13 | fullHost: shastaConfig.RPC_URL, // I am not sure tron has an other way to get it chainID, at least to the best of my search 14 | headers: { "TRON-PRO-API-KEY": process.env.TRON_PRO_API_KEY }, 15 | privateKey: process.env.DEPLOYER_PRIVATE_KEY_TRON, 16 | }); 17 | 18 | /** 19 | * Asserts that environment variables are set as expected 20 | */ 21 | export const assertEnvironment = () => { 22 | if (!process.env.DEPLOYER_PRIVATE_KEY) { 23 | console.error("Please set DEPLOYER_PRIVATE_KEY in a .env file"); 24 | process.exit(1); // Kill the process if DEPLOYER_PRIVATE_KEY is not set 25 | } 26 | if (!process.env.TREASURY_ADDRESS) { 27 | console.error("Please set TREASURY_ADDRESS in a .env file"); 28 | process.exit(1); // Kill the process if TREASURY_ADDRESS is not set 29 | } 30 | if (!process.env.AGGREGATOR_ADDRESS) { 31 | console.error("Please set AGGREGATOR_ADDRESS in a .env file"); 32 | process.exit(1); // Kill the process if AGGREGATOR_ADDRESS is not set 33 | } 34 | }; 35 | 36 | /** 37 | * Asserts that environment variables are set as expected for Tron Network 38 | */ 39 | export const assertTronEnvironment = () => { 40 | if (!process.env.TRON_PRO_API_KEY) { 41 | console.error("Please set TRON_PRO_API_KEY in a .env file"); 42 | process.exit(1); // Kill the process if TRON_PRO_API_KEY is not set 43 | } 44 | if (!process.env.DEPLOYER_PRIVATE_KEY_TRON) { 45 | console.error("Please set DEPLOYER_PRIVATE_KEY_TRON in a .env file"); 46 | process.exit(1); // Kill the process if DEPLOYER_PRIVATE_KEY_TRON is not set 47 | } 48 | if (!process.env.TREASURY_ADDRESS_TRON) { 49 | console.error("Please set TREASURY_ADDRESS_TRON in a .env file"); 50 | process.exit(1); // Kill the process if TREASURY_ADDRESS_TRON is not set 51 | } 52 | if (!process.env.AGGREGATOR_ADDRESS_TRON) { 53 | console.error("Please set AGGREGATOR_ADDRESS_TRON in a .env file"); 54 | process.exit(1); // Kill the process if AGGREGATOR_ADDRESS_TRON is not set 55 | } 56 | }; 57 | 58 | /** 59 | * Helper method for waiting on user input. Source: https://stackoverflow.com/a/50890409 60 | * @param query 61 | */ 62 | export async function waitForInput(query: string) { 63 | const rl = readline.createInterface({ 64 | input: process.stdin, 65 | output: process.stdout 66 | }); 67 | return new Promise((resolve) => 68 | rl.question(query, (ans) => { 69 | rl.close(); 70 | resolve(ans); 71 | }) 72 | ); 73 | } 74 | 75 | /** 76 | * Helper method for confirming user input 77 | * 78 | * @param params 79 | */ 80 | export async function confirmContinue(params: any) { 81 | console.log("\nPARAMETERS"); 82 | console.table(params); 83 | 84 | const response = await waitForInput("\nDo you want to continue? y/N\n"); 85 | if (response !== "y") 86 | throw new Error("Aborting script: User chose to exit script"); 87 | console.log("\n"); 88 | } 89 | 90 | 91 | export async function updateConfigFile(chainId: number, implementationAddress: string): Promise { 92 | try { 93 | const configFilePath = path.join(__dirname, 'config.ts'); 94 | // Read the existing config file 95 | let configContent = await fs.readFile(configFilePath, 'utf-8'); 96 | 97 | // Create a regex to match the network object for the specific chainId 98 | const networkRegex = new RegExp(`(${chainId}:\\s*{[\\s\\S]*?)(},?)`, 'g'); 99 | 100 | if (networkRegex.test(configContent)) { 101 | configContent = configContent.replace(networkRegex, (match) => { 102 | const lines = match.split('\n'); 103 | const updatedLines = lines.map(line => { 104 | if (line.trim().startsWith('GATEWAY_IMPLEMENTATION:')) { 105 | return line.replace(/IMPLEMENTATION:.*/, `GATEWAY_IMPLEMENTATION: "${implementationAddress}",`); 106 | } 107 | return line; 108 | }); 109 | 110 | if (!updatedLines.some(line => line.trim().startsWith('GATEWAY_IMPLEMENTATION:'))) { 111 | // If IMPLEMENTATION doesn't exist, add it before the closing brace 112 | updatedLines.splice(-1, 0, `\t\GATEWAY_IMPLEMENTATION: "${implementationAddress}",`); 113 | } 114 | 115 | return updatedLines.join('\n'); 116 | }); 117 | } else { 118 | console.error(`Network configuration for chainId ${chainId} not found in config file.`); 119 | return; 120 | } 121 | 122 | // Write the updated content back to the file 123 | await fs.writeFile(configFilePath, configContent, 'utf-8'); 124 | 125 | console.log(`Updated config.ts with chainId: ${chainId} and implementation address: ${implementationAddress}`); 126 | } catch (error) { 127 | console.error('Error updating config file:', error); 128 | } 129 | } 130 | 131 | 132 | /** 133 | * Retrieves the wallet and contract instances. 134 | * 135 | * @returns An object containing the wallet and contract instances. 136 | */ 137 | export async function getContracts(): Promise { 138 | assertEnvironment(); 139 | 140 | const networkConfig = NETWORKS[network.config.chainId as keyof typeof NETWORKS]; 141 | const Gateway = await artifacts.readArtifact("Gateway"); 142 | 143 | // Get signer 144 | const provider = new ethers.providers.JsonRpcProvider(networkConfig.RPC_URL); 145 | const wallet = new ethers.Wallet(process.env.DEPLOYER_PRIVATE_KEY!, provider); 146 | 147 | // Get contract instances 148 | const gatewayInstance = new ethers.Contract( 149 | networkConfig.GATEWAY_CONTRACT, 150 | Gateway.abi, 151 | provider 152 | ); 153 | 154 | return { 155 | wallet, 156 | gatewayInstance, 157 | tronWeb, 158 | }; 159 | } 160 | 161 | /** 162 | * Retrieves the contract instances for TRON Network. 163 | * 164 | * @returns An object containing the contract instances. 165 | */ 166 | export async function getTronContracts(): Promise { 167 | assertTronEnvironment(); 168 | const Gateway = await artifacts.readArtifact("Gateway"); 169 | 170 | const gatewayContractAddress = shastaConfig.GATEWAY_CONTRACT; 171 | let gatewayInstance = await tronWeb.contract( 172 | Gateway.abi, 173 | gatewayContractAddress 174 | ); 175 | return { 176 | gatewayInstance, 177 | gatewayContractAddress, 178 | }; 179 | } -------------------------------------------------------------------------------- /test/fixtures/gateway.js: -------------------------------------------------------------------------------- 1 | const { upgrades } = require("hardhat"); 2 | const hardhat = require("hardhat"); 3 | const { mockUSDTFixture } = require("./mockUSDT.js"); 4 | 5 | async function gateway() { 6 | const { mockUSDT } = await mockUSDTFixture(); 7 | const gatewayFactory = await hardhat.ethers.getContractFactory("Gateway"); 8 | const gateway = await upgrades.deployProxy(gatewayFactory); 9 | await gateway.deployed(); 10 | 11 | console.log("Gateway deployed to:", gateway.address); 12 | 13 | return { gateway, mockUSDT }; 14 | } 15 | 16 | const gatewayFixture = hardhat.deployments.createFixture(gateway); 17 | 18 | module.exports = { 19 | gatewayFixture 20 | }; 21 | 22 | -------------------------------------------------------------------------------- /test/fixtures/mockUSDT.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require("hardhat"); 2 | const hardhat = require("hardhat"); 3 | 4 | async function mockUSDT() { 5 | // get mock usdc contract and deploy it 6 | const MockUSDT = await ethers.getContractFactory("MockUSDT"); 7 | const mockUSDT = await MockUSDT.deploy(); 8 | await mockUSDT.deployed(); 9 | console.log("MockUSDT deployed to:", mockUSDT.address); 10 | return { mockUSDT }; 11 | } 12 | const mockUSDTFixture = hardhat.deployments.createFixture(mockUSDT); 13 | module.exports = { 14 | mockUSDTFixture, 15 | }; 16 | -------------------------------------------------------------------------------- /test/gateway/gateway.createorder.test.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require("hardhat"); 2 | const { BigNumber } = require("@ethersproject/bignumber"); 3 | const CryptoJS = require("crypto-js"); 4 | 5 | const { gatewayFixture } = require("../fixtures/gateway.js"); 6 | 7 | const { 8 | deployContract, 9 | ZERO_AMOUNT, 10 | ZERO_ADDRESS, 11 | FEE_BPS, 12 | MAX_BPS, 13 | Errors, 14 | Events, 15 | getSupportedInstitutions, 16 | } = require("../utils/utils.manager.js"); 17 | const { expect } = require("chai"); 18 | 19 | describe("Gateway create order", function () { 20 | beforeEach(async function () { 21 | [ 22 | this.deployer, 23 | this.treasuryAddress, 24 | this.keeper, 25 | this.aggregator, 26 | this.alice, 27 | this.sender, 28 | this.hacker, 29 | ...this.accounts 30 | ] = await ethers.getSigners(); 31 | 32 | ({ gateway, mockUSDT } = await gatewayFixture()); 33 | 34 | this.mockDAI = await deployContract("MockUSDT"); 35 | 36 | this.mockUSDT = mockUSDT; 37 | this.gateway = gateway; 38 | 39 | this.mintAmount = ethers.utils.parseEther("27000000"); 40 | this.orderAmount = ethers.utils.parseEther("27000000"); 41 | this.protocolFee = ethers.utils.parseEther("27000"); 42 | 43 | 44 | this.senderFee = ethers.utils.parseEther("0"); 45 | await this.mockUSDT.connect(this.alice).mint(this.mintAmount); 46 | await this.mockDAI.connect(this.alice).mint(this.mintAmount); 47 | await this.mockUSDT 48 | .connect(this.alice) 49 | .transfer(this.sender.address, this.mintAmount); 50 | 51 | expect(await this.mockUSDT.balanceOf(this.alice.address)).to.eq( 52 | ZERO_AMOUNT 53 | ); 54 | expect(await this.mockDAI.balanceOf(this.alice.address)).to.eq( 55 | this.mintAmount 56 | ); 57 | 58 | const token = ethers.utils.formatBytes32String("token"); 59 | 60 | await expect( 61 | this.gateway 62 | .connect(this.deployer) 63 | .settingManagerBool(token, this.mockUSDT.address, BigNumber.from(1)) 64 | ) 65 | .to.emit(this.gateway, Events.Gateway.SettingManagerBool) 66 | .withArgs(token, this.mockUSDT.address, BigNumber.from(1)); 67 | }); 68 | 69 | it("Should be able to create order by Sender for Alice", async function () { 70 | const ret = await getSupportedInstitutions(); 71 | const treasury = ethers.utils.formatBytes32String("treasury"); 72 | const aggregator = ethers.utils.formatBytes32String("aggregator"); 73 | 74 | await this.gateway 75 | .connect(this.deployer) 76 | .updateProtocolAddress(treasury, this.treasuryAddress.address); 77 | 78 | await this.gateway 79 | .connect(this.deployer) 80 | .updateProtocolAddress(aggregator, this.aggregator.address); 81 | 82 | await this.gateway.connect(this.deployer).updateProtocolFee(FEE_BPS); 83 | 84 | await this.mockUSDT 85 | .connect(this.sender) 86 | .approve(this.gateway.address, this.orderAmount.add(this.senderFee)); 87 | 88 | const rate = 750; 89 | 90 | const data = [ 91 | { bank_account: "09090990901" }, 92 | { bank_name: "ACCESS BANK" }, 93 | { account_name: "Jeff Dean" }, 94 | { institution_code: ret.accessBank.code }, 95 | ]; 96 | 97 | const password = "123"; 98 | 99 | const cipher = CryptoJS.AES.encrypt( 100 | JSON.stringify(data), 101 | password 102 | ).toString(); 103 | 104 | const messageHash = "0x" + cipher; 105 | 106 | const argOrderID = [this.sender.address, 1]; 107 | 108 | const encoded = ethers.utils.defaultAbiCoder.encode( 109 | ["address", "uint256"], 110 | argOrderID 111 | ); 112 | const orderId = ethers.utils.solidityKeccak256(["bytes"], [encoded]); 113 | 114 | await expect( 115 | this.gateway 116 | .connect(this.sender) 117 | .createOrder( 118 | this.mockUSDT.address, 119 | this.orderAmount, 120 | rate, 121 | this.sender.address, 122 | this.senderFee, 123 | this.alice.address, 124 | messageHash.toString() 125 | ) 126 | ) 127 | .to.emit(this.gateway, Events.Gateway.OrderCreated) 128 | .withArgs( 129 | this.alice.address, 130 | this.mockUSDT.address, 131 | BigNumber.from(this.orderAmount), 132 | this.protocolFee, 133 | orderId, 134 | rate, 135 | messageHash.toString() 136 | ); 137 | 138 | [ 139 | this.seller, 140 | this.token, 141 | this.senderRecipient, 142 | this.senderFee, 143 | this.protocolFee, 144 | this.isFulfilled, 145 | this.isRefunded, 146 | this.refundAddress, 147 | this.currentBPS, 148 | this.amount, 149 | ] = await this.gateway.getOrderInfo(orderId); 150 | // expect sender balance to increase by sender fee 151 | expect(await this.mockUSDT.balanceOf(this.sender.address)).to.eq( 152 | ZERO_AMOUNT 153 | ); 154 | 155 | expect(this.seller).to.eq(this.sender.address); 156 | expect(this.token).to.eq(this.mockUSDT.address); 157 | expect(this.senderRecipient).to.eq(this.sender.address); 158 | expect(this.senderFee).to.eq(this.senderFee); 159 | expect(this.isFulfilled).to.eq(false); 160 | expect(this.isRefunded).to.eq(false); 161 | expect(this.refundAddress).to.eq(this.alice.address); 162 | expect(this.currentBPS).to.eq(MAX_BPS); 163 | expect(this.amount).to.eq( 164 | BigNumber.from(this.orderAmount) 165 | ); 166 | 167 | expect(await this.mockUSDT.balanceOf(this.alice.address)).to.eq( 168 | ZERO_AMOUNT 169 | ); 170 | 171 | // =================== Create Order =================== 172 | var bytes = CryptoJS.AES.decrypt(messageHash.substring(2), password); 173 | var decryptedData = JSON.parse(bytes.toString(CryptoJS.enc.Utf8)); 174 | 175 | const mockUSDT = await this.gateway.isTokenSupported(this.mockUSDT.address); 176 | expect(mockUSDT).to.eq(true); 177 | expect(decryptedData[0].bank_account).to.eq("09090990901"); 178 | }); 179 | 180 | it("Should revert when creating order with non-supported token", async function () { 181 | const ret = await getSupportedInstitutions(); 182 | const fee = ethers.utils.formatBytes32String("fee"); 183 | 184 | await this.gateway 185 | .connect(this.deployer) 186 | .updateProtocolAddress(fee, this.treasuryAddress.address); 187 | 188 | await this.mockDAI 189 | .connect(this.sender) 190 | .approve(this.gateway.address, this.mintAmount); 191 | const rate = 750; 192 | const data = [ 193 | { bank_account: "09090990901" }, 194 | { bank_name: "ACCESS BANK" }, 195 | { account_name: "Jeff Dean" }, 196 | { institution_code: ret.accessBank.code }, 197 | ]; 198 | const password = "123"; 199 | 200 | const cipher = CryptoJS.AES.encrypt( 201 | JSON.stringify(data), 202 | password 203 | ).toString(); 204 | 205 | const messageHash = "0x" + cipher; 206 | 207 | const argOrderID = [this.sender.address, 1]; 208 | 209 | const encoded = ethers.utils.defaultAbiCoder.encode( 210 | ["address", "uint256"], 211 | argOrderID 212 | ); 213 | const orderId = ethers.utils.solidityKeccak256(["bytes"], [encoded]); 214 | 215 | await expect( 216 | this.gateway 217 | .connect(this.sender) 218 | .createOrder( 219 | this.mockDAI.address, 220 | this.orderAmount, 221 | rate, 222 | this.sender.address, 223 | this.senderFee, 224 | this.alice.address, 225 | messageHash.toString() 226 | ) 227 | ).to.be.revertedWith(Errors.Gateway.TokenNotSupported); 228 | 229 | [ 230 | this.seller, 231 | this.token, 232 | this.senderRecipient, 233 | this.senderFee, 234 | this.protocolFee, 235 | this.isFulfilled, 236 | this.isRefunded, 237 | this.refundAddress, 238 | this.currentBPS, 239 | this.amount, 240 | ] = await this.gateway.getOrderInfo(orderId); 241 | 242 | expect(this.seller).to.eq(ZERO_ADDRESS); 243 | expect(this.token).to.eq(ZERO_ADDRESS); 244 | expect(this.isFulfilled).to.eq(false); 245 | expect(this.isRefunded).to.eq(false); 246 | expect(this.refundAddress).to.eq(ZERO_ADDRESS); 247 | expect(this.currentBPS).to.eq(ZERO_AMOUNT); 248 | expect(this.amount).to.eq(ZERO_AMOUNT); 249 | 250 | expect(await this.mockDAI.balanceOf(this.alice.address)).to.eq( 251 | this.mintAmount 252 | ); 253 | }); 254 | 255 | it("Should revert when creating order with zero input amount", async function () { 256 | const ret = await getSupportedInstitutions(); 257 | const fee = ethers.utils.formatBytes32String("fee"); 258 | 259 | await this.gateway 260 | .connect(this.deployer) 261 | .updateProtocolAddress(fee, this.treasuryAddress.address); 262 | 263 | await this.mockUSDT 264 | .connect(this.sender) 265 | .approve(this.gateway.address, this.mintAmount); 266 | const rate = 750; 267 | const data = [ 268 | { bank_account: "09090990901" }, 269 | { bank_name: "ACCESS BANK" }, 270 | { account_name: "Jeff Dean" }, 271 | { institution_code: ret.accessBank.code }, 272 | ]; 273 | const password = "123"; 274 | 275 | const cipher = CryptoJS.AES.encrypt( 276 | JSON.stringify(data), 277 | password 278 | ).toString(); 279 | 280 | const messageHash = "0x" + cipher; 281 | 282 | const argOrderID = [this.sender.address, 1]; 283 | 284 | const encoded = ethers.utils.defaultAbiCoder.encode( 285 | ["address", "uint256"], 286 | argOrderID 287 | ); 288 | const orderId = ethers.utils.solidityKeccak256(["bytes"], [encoded]); 289 | 290 | await expect( 291 | this.gateway 292 | .connect(this.sender) 293 | .createOrder( 294 | this.mockUSDT.address, 295 | ZERO_AMOUNT, 296 | rate, 297 | this.sender.address, 298 | this.senderFee, 299 | this.alice.address, 300 | messageHash.toString() 301 | ) 302 | ).to.be.revertedWith(Errors.Gateway.AmountIsZero); 303 | 304 | [ 305 | this.seller, 306 | this.token, 307 | this.senderRecipient, 308 | this.senderFee, 309 | this.protocolFee, 310 | this.isFulfilled, 311 | this.isRefunded, 312 | this.refundAddress, 313 | this.currentBPS, 314 | this.amount, 315 | ] = await this.gateway.getOrderInfo(orderId); 316 | 317 | expect(this.seller).to.eq(ZERO_ADDRESS); 318 | expect(this.token).to.eq(ZERO_ADDRESS); 319 | expect(this.isFulfilled).to.eq(false); 320 | expect(this.isRefunded).to.eq(false); 321 | expect(this.refundAddress).to.eq(ZERO_ADDRESS); 322 | expect(this.currentBPS).to.eq(ZERO_AMOUNT); 323 | expect(this.amount).to.eq(ZERO_AMOUNT); 324 | 325 | expect(await this.mockDAI.balanceOf(this.alice.address)).to.eq( 326 | this.mintAmount 327 | ); 328 | }); 329 | 330 | it("Should revert when creating order with zero address as refundable address", async function () { 331 | const ret = await getSupportedInstitutions(); 332 | const fee = ethers.utils.formatBytes32String("fee"); 333 | 334 | await this.gateway 335 | .connect(this.deployer) 336 | .updateProtocolAddress(fee, this.treasuryAddress.address); 337 | 338 | await this.mockUSDT 339 | .connect(this.sender) 340 | .approve(this.gateway.address, this.mintAmount); 341 | const rate = 750; 342 | const data = [ 343 | { bank_account: "09090990901" }, 344 | { bank_name: "ACCESS BANK" }, 345 | { account_name: "Jeff Dean" }, 346 | { institution_code: ret.accessBank.code }, 347 | ]; 348 | const password = "123"; 349 | 350 | const cipher = CryptoJS.AES.encrypt( 351 | JSON.stringify(data), 352 | password 353 | ).toString(); 354 | 355 | const messageHash = "0x" + cipher; 356 | 357 | const argOrderID = [this.sender.address, 1]; 358 | 359 | const encoded = ethers.utils.defaultAbiCoder.encode( 360 | ["address", "uint256"], 361 | argOrderID 362 | ); 363 | const orderId = ethers.utils.solidityKeccak256(["bytes"], [encoded]); 364 | 365 | await expect( 366 | this.gateway 367 | .connect(this.sender) 368 | .createOrder( 369 | this.mockUSDT.address, 370 | this.orderAmount, 371 | rate, 372 | this.sender.address, 373 | this.senderFee, 374 | ZERO_ADDRESS, 375 | messageHash.toString() 376 | ) 377 | ).to.be.revertedWith(Errors.Gateway.ThrowZeroAddress); 378 | 379 | [ 380 | this.seller, 381 | this.token, 382 | this.senderRecipient, 383 | this.senderFee, 384 | this.protocolFee, 385 | this.isFulfilled, 386 | this.isRefunded, 387 | this.refundAddress, 388 | this.currentBPS, 389 | this.amount, 390 | ] = await this.gateway.getOrderInfo(orderId); 391 | 392 | expect(this.seller).to.eq(ZERO_ADDRESS); 393 | expect(this.token).to.eq(ZERO_ADDRESS); 394 | expect(this.isFulfilled).to.eq(false); 395 | expect(this.isRefunded).to.eq(false); 396 | expect(this.refundAddress).to.eq(ZERO_ADDRESS); 397 | expect(this.currentBPS).to.eq(ZERO_AMOUNT); 398 | expect(this.amount).to.eq(ZERO_AMOUNT); 399 | 400 | expect(await this.mockUSDT.balanceOf(this.sender.address)).to.eq( 401 | this.mintAmount 402 | ); 403 | }); 404 | 405 | it("Should revert when creating order with insufficient allowance", async function () { 406 | const fee = ethers.utils.formatBytes32String("fee"); 407 | 408 | await this.gateway 409 | .connect(this.deployer) 410 | .updateProtocolAddress(fee, this.treasuryAddress.address); 411 | 412 | await this.mockUSDT 413 | .connect(this.sender) 414 | .approve(this.gateway.address, this.protocolFee); 415 | const rate = 750; 416 | const data = [ 417 | { bank_account: "09090990901" }, 418 | { bank_name: "ACCESS BANK" }, 419 | { account_name: "Jeff Dean" }, 420 | { institution_code: "0000" }, 421 | ]; 422 | const password = "123"; 423 | 424 | const cipher = CryptoJS.AES.encrypt( 425 | JSON.stringify(data), 426 | password 427 | ).toString(); 428 | 429 | const messageHash = "0x" + cipher; 430 | 431 | const argOrderID = [this.sender.address, 1]; 432 | 433 | const encoded = ethers.utils.defaultAbiCoder.encode( 434 | ["address", "uint256"], 435 | argOrderID 436 | ); 437 | const orderId = ethers.utils.solidityKeccak256(["bytes"], [encoded]); 438 | 439 | await expect( 440 | this.gateway 441 | .connect(this.sender) 442 | .createOrder( 443 | this.mockUSDT.address, 444 | this.mintAmount, 445 | rate, 446 | this.sender.address, 447 | this.senderFee, 448 | this.alice.address, 449 | messageHash.toString() 450 | ) 451 | ).to.be.revertedWith(Errors.Gateway.Allowance); 452 | 453 | [ 454 | this.seller, 455 | this.token, 456 | this.senderRecipient, 457 | this.senderFee, 458 | this.protocolFee, 459 | this.isFulfilled, 460 | this.isRefunded, 461 | this.refundAddress, 462 | this.currentBPS, 463 | this.amount, 464 | ] = await this.gateway.getOrderInfo(orderId); 465 | 466 | expect(this.seller).to.eq(ZERO_ADDRESS); 467 | expect(this.token).to.eq(ZERO_ADDRESS); 468 | expect(this.isFulfilled).to.eq(false); 469 | expect(this.isRefunded).to.eq(false); 470 | expect(this.refundAddress).to.eq(ZERO_ADDRESS); 471 | expect(this.currentBPS).to.eq(ZERO_AMOUNT); 472 | expect(this.amount).to.eq(ZERO_AMOUNT); 473 | 474 | expect(await this.mockUSDT.balanceOf(this.sender.address)).to.eq( 475 | this.mintAmount 476 | ); 477 | }); 478 | }); 479 | -------------------------------------------------------------------------------- /test/gateway/gateway.ownable.test.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require("hardhat"); 2 | const { BigNumber } = require("@ethersproject/bignumber"); 3 | const { gatewayFixture } = require("../fixtures/gateway.js"); 4 | require("dotenv").config(); 5 | 6 | const { Errors, Events } = require("../utils/utils.manager.js"); 7 | const { expect } = require("chai"); 8 | 9 | describe("Ownable settings", function () { 10 | let gateway; 11 | let mockUSDT; 12 | let admin; 13 | let treasuryAddress; 14 | let aggregator; 15 | let keeper; 16 | let alice; 17 | let hacker; 18 | let sender; 19 | let Mark; 20 | 21 | async function setupAndResetFork() { 22 | ({ gateway, mockUSDT } = await gatewayFixture()); 23 | 24 | [admin, keeper, alice, hacker, sender, Mark, treasuryAddress, aggregator] = 25 | await ethers.getSigners(); 26 | 27 | const token = ethers.utils.formatBytes32String("token"); 28 | 29 | await expect( 30 | gateway 31 | .connect(admin) 32 | .settingManagerBool(token, mockUSDT.address, BigNumber.from(1)) 33 | ) 34 | .to.emit(gateway, Events.Gateway.SettingManagerBool) 35 | .withArgs(token, mockUSDT.address, BigNumber.from(1)); 36 | } 37 | 38 | it("should get supported token", async function () { 39 | await setupAndResetFork(); 40 | const _mockUSDT = await gateway.isTokenSupported(mockUSDT.address); 41 | expect(_mockUSDT).to.eq(true); 42 | }); 43 | 44 | it("should revert for unsupported token", async function () { 45 | await setupAndResetFork(); 46 | const Alice = await gateway.isTokenSupported(alice.address); 47 | expect(Alice).to.eq(false); 48 | }); 49 | 50 | it("should be able to set protocol fees and emit events", async function () { 51 | await setupAndResetFork(); 52 | // charge 10% as protocol fee 53 | const protocolFeePercent = BigNumber.from(10_000); 54 | 55 | await expect( 56 | gateway 57 | .connect(admin) 58 | .updateProtocolFee(protocolFeePercent) 59 | ) 60 | .to.emit(gateway, Events.Gateway.ProtocolFeeUpdated) 61 | .withArgs(protocolFeePercent); 62 | 63 | [this.protocolFeePecent, this.MAXBPS] = 64 | await gateway.getFeeDetails(); 65 | expect(this.protocolFeePecent).to.eq(protocolFeePercent); 66 | }); 67 | 68 | it("should not be able to set protocol fees by non-owner", async function () { 69 | await setupAndResetFork(); 70 | // charge 10% as protocol fee 71 | const protocolFeePercent = BigNumber.from(10_000); 72 | 73 | await expect( 74 | gateway 75 | .connect(hacker) 76 | .updateProtocolFee(protocolFeePercent) 77 | ).to.be.revertedWith(Errors.Ownable.onlyOwner); 78 | }); 79 | 80 | it("should update treasury address", async function () { 81 | await setupAndResetFork(); 82 | const treasury = ethers.utils.formatBytes32String("treasury"); 83 | 84 | await expect( 85 | gateway 86 | .connect(admin) 87 | .updateProtocolAddress(treasury, treasuryAddress.address) 88 | ).to.be.emit(gateway, Events.Gateway.ProtocolAddressUpdated); 89 | 90 | }); 91 | }); 92 | -------------------------------------------------------------------------------- /test/gateway/gateway.settleOrder.test.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require("hardhat"); 2 | const { BigNumber } = require("@ethersproject/bignumber"); 3 | const CryptoJS = require("crypto-js"); 4 | 5 | const { gatewayFixture } = require("../fixtures/gateway.js"); 6 | 7 | const { 8 | ZERO_AMOUNT, 9 | FEE_BPS, 10 | MAX_BPS, 11 | Events, 12 | getSupportedInstitutions, 13 | } = require("../utils/utils.manager.js"); 14 | const { expect } = require("chai"); 15 | 16 | describe("Gateway settle order", function () { 17 | beforeEach(async function () { 18 | [ 19 | this.deployer, 20 | this.treasuryAddress, 21 | this.primaryValidator, 22 | this.aggregator, 23 | this.alice, 24 | this.bob, 25 | this.liquidityProvider, 26 | this.sender, 27 | this.hacker, 28 | ...this.accounts 29 | ] = await ethers.getSigners(); 30 | 31 | ({ gateway, mockUSDT } = await gatewayFixture()); 32 | 33 | this.mintAmount = ethers.utils.parseEther("27000000"); 34 | this.orderAmount = ethers.utils.parseEther("27000000"); 35 | this.senderFee = ethers.utils.parseEther("0"); 36 | 37 | // 38 | 39 | // charge 0.1% as protocol fee 40 | const protocolFeePercent = BigNumber.from(100); 41 | 42 | this.protocolFee = ethers.utils.parseEther("27000") 43 | 44 | this.liquidityProviderAmount = this.orderAmount.sub(this.protocolFee); 45 | 46 | await expect( 47 | gateway.connect(this.deployer).updateProtocolFee(protocolFeePercent) 48 | ) 49 | .to.emit(gateway, Events.Gateway.ProtocolFeeUpdated) 50 | .withArgs(protocolFeePercent); 51 | 52 | await mockUSDT.connect(this.alice).mint(this.mintAmount); 53 | 54 | expect(await mockUSDT.balanceOf(this.alice.address)).to.eq(this.mintAmount); 55 | await mockUSDT 56 | .connect(this.alice) 57 | .transfer(this.sender.address, this.mintAmount); 58 | 59 | expect(await mockUSDT.balanceOf(this.alice.address)).to.eq(ZERO_AMOUNT); 60 | 61 | expect(await mockUSDT.balanceOf(this.treasuryAddress.address)).to.eq( 62 | ZERO_AMOUNT 63 | ); 64 | 65 | expect(await mockUSDT.balanceOf(this.aggregator.address)).to.eq( 66 | ZERO_AMOUNT 67 | ); 68 | expect(await mockUSDT.balanceOf(this.liquidityProvider.address)).to.eq( 69 | ZERO_AMOUNT 70 | ); 71 | 72 | const treasury = ethers.utils.formatBytes32String("treasury"); 73 | 74 | await expect( 75 | gateway 76 | .connect(this.deployer) 77 | .updateProtocolAddress(treasury, this.treasuryAddress.address) 78 | ).to.emit(gateway, Events.Gateway.ProtocolAddressUpdated); 79 | 80 | const aggregator = ethers.utils.formatBytes32String("aggregator"); 81 | 82 | await expect( 83 | gateway 84 | .connect(this.deployer) 85 | .updateProtocolAddress(aggregator, this.aggregator.address) 86 | ).to.emit(gateway, Events.Gateway.ProtocolAddressUpdated); 87 | 88 | await expect( 89 | gateway.connect(this.deployer).updateProtocolFee(FEE_BPS) 90 | ).to.emit(gateway, Events.Gateway.ProtocolFeeUpdated); 91 | 92 | expect( 93 | await mockUSDT.allowance(this.alice.address, gateway.address) 94 | ).to.equal(ZERO_AMOUNT); 95 | 96 | const token = ethers.utils.formatBytes32String("token"); 97 | 98 | await expect( 99 | gateway 100 | .connect(this.deployer) 101 | .settingManagerBool(token, mockUSDT.address, BigNumber.from(1)) 102 | ) 103 | .to.emit(gateway, Events.Gateway.SettingManagerBool) 104 | .withArgs(token, mockUSDT.address, BigNumber.from(1)); 105 | }); 106 | 107 | it("Should be able to create order by the sender and settled by the liquidity aggregator", async function () { 108 | const ret = await getSupportedInstitutions(); 109 | 110 | await mockUSDT 111 | .connect(this.sender) 112 | .approve(gateway.address, this.mintAmount); 113 | 114 | expect( 115 | await mockUSDT.allowance(this.sender.address, gateway.address) 116 | ).to.equal(this.mintAmount); 117 | 118 | const rate = 750; 119 | const data = [ 120 | { bank_account: "09090990901" }, 121 | { bank_name: "ACCESS BANK" }, 122 | { account_name: "Jeff Dean" }, 123 | { institution_code: ret.accessBank.code }, 124 | ]; 125 | const password = "123"; 126 | 127 | const cipher = CryptoJS.AES.encrypt( 128 | JSON.stringify(data), 129 | password 130 | ).toString(); 131 | 132 | const messageHash = "0x" + cipher; 133 | 134 | const argOrderID = [this.sender.address, 1]; 135 | 136 | const encoded = ethers.utils.defaultAbiCoder.encode( 137 | ["address", "uint256"], 138 | argOrderID 139 | ); 140 | const orderId = ethers.utils.solidityKeccak256(["bytes"], [encoded]); 141 | 142 | await expect( 143 | gateway 144 | .connect(this.sender) 145 | .createOrder( 146 | mockUSDT.address, 147 | this.orderAmount, 148 | rate, 149 | this.sender.address, 150 | this.senderFee, 151 | this.alice.address, 152 | messageHash.toString() 153 | ) 154 | ) 155 | .to.emit(gateway, Events.Gateway.OrderCreated) 156 | .withArgs( 157 | this.alice.address, 158 | mockUSDT.address, 159 | this.orderAmount, 160 | this.protocolFee, 161 | orderId, 162 | rate, 163 | messageHash.toString() 164 | ); 165 | 166 | [ 167 | this.seller, 168 | this.token, 169 | this.senderRecipient, 170 | this.senderFee, 171 | this.protocolFee, 172 | this.isFulfilled, 173 | this.isRefunded, 174 | this.refundAddress, 175 | this.currentBPS, 176 | this.amount, 177 | ] = await gateway.getOrderInfo(orderId); 178 | 179 | expect(this.seller).to.eq(this.sender.address); 180 | expect(this.token).to.eq(mockUSDT.address); 181 | expect(this.senderRecipient).to.eq(this.sender.address); 182 | expect(this.senderFee).to.eq(this.senderFee); 183 | expect(this.isFulfilled).to.eq(false); 184 | expect(this.isRefunded).to.eq(false); 185 | expect(this.refundAddress).to.eq(this.alice.address); 186 | expect(this.currentBPS).to.eq(MAX_BPS); 187 | expect(this.amount).to.eq(BigNumber.from(this.orderAmount)); 188 | 189 | expect(await mockUSDT.balanceOf(this.alice.address)).to.eq(ZERO_AMOUNT); 190 | 191 | expect( 192 | await mockUSDT.allowance(this.alice.address, gateway.address) 193 | ).to.equal(ZERO_AMOUNT); 194 | 195 | // =================== Create Order =================== 196 | 197 | expect( 198 | await gateway 199 | .connect(this.aggregator) 200 | .settle(orderId, orderId, this.liquidityProvider.address, MAX_BPS) 201 | ) 202 | .to.emit(gateway, Events.Gateway.OrderSettled) 203 | .withArgs(orderId, orderId, this.liquidityProvider.address, MAX_BPS); 204 | 205 | expect(await mockUSDT.balanceOf(this.liquidityProvider.address)).to.eq( 206 | this.liquidityProviderAmount 207 | ); 208 | expect(await mockUSDT.balanceOf(this.treasuryAddress.address)).to.eq( 209 | this.protocolFee 210 | ); 211 | expect(await mockUSDT.balanceOf(gateway.address)).to.eq(ZERO_AMOUNT); 212 | }); 213 | 214 | it("Should revert when trying to settle an already fulfilled order", async function () { 215 | const ret = await getSupportedInstitutions(); 216 | 217 | await mockUSDT 218 | .connect(this.sender) 219 | .approve(gateway.address, this.mintAmount); 220 | 221 | expect( 222 | await mockUSDT.allowance(this.sender.address, gateway.address) 223 | ).to.equal(this.mintAmount); 224 | 225 | const rate = 750; 226 | const data = [ 227 | { bank_account: "09090990901" }, 228 | { bank_name: "ACCESS BANK" }, 229 | { account_name: "Jeff Dean" }, 230 | { institution_code: ret.accessBank.code }, 231 | ]; 232 | const password = "123"; 233 | 234 | const cipher = CryptoJS.AES.encrypt( 235 | JSON.stringify(data), 236 | password 237 | ).toString(); 238 | 239 | const messageHash = "0x" + cipher; 240 | 241 | const argOrderID = [this.sender.address, 1]; 242 | 243 | const encoded = ethers.utils.defaultAbiCoder.encode( 244 | ["address", "uint256"], 245 | argOrderID 246 | ); 247 | const orderId = ethers.utils.solidityKeccak256(["bytes"], [encoded]); 248 | 249 | await expect( 250 | gateway 251 | .connect(this.sender) 252 | .createOrder( 253 | mockUSDT.address, 254 | this.orderAmount, 255 | rate, 256 | this.sender.address, 257 | this.senderFee, 258 | this.alice.address, 259 | messageHash.toString() 260 | ) 261 | ) 262 | .to.emit(gateway, Events.Gateway.OrderCreated) 263 | .withArgs( 264 | this.alice.address, 265 | mockUSDT.address, 266 | this.orderAmount, 267 | this.protocolFee, 268 | orderId, 269 | rate, 270 | messageHash.toString() 271 | ); 272 | 273 | [ 274 | this.seller, 275 | this.token, 276 | this.senderRecipient, 277 | this.senderFee, 278 | this.protocolFee, 279 | this.isFulfilled, 280 | this.isRefunded, 281 | this.refundAddress, 282 | this.currentBPS, 283 | this.amount, 284 | ] = await gateway.getOrderInfo(orderId); 285 | 286 | expect(this.seller).to.eq(this.sender.address); 287 | expect(this.token).to.eq(mockUSDT.address); 288 | expect(this.senderRecipient).to.eq(this.sender.address); 289 | expect(this.senderFee).to.eq(this.senderFee); 290 | expect(this.isFulfilled).to.eq(false); 291 | expect(this.isRefunded).to.eq(false); 292 | expect(this.refundAddress).to.eq(this.alice.address); 293 | expect(this.currentBPS).to.eq(MAX_BPS); 294 | expect(this.amount).to.eq( 295 | BigNumber.from(this.orderAmount) 296 | ); 297 | 298 | expect(await mockUSDT.balanceOf(this.alice.address)).to.eq(ZERO_AMOUNT); 299 | 300 | expect( 301 | await mockUSDT.allowance(this.alice.address, gateway.address) 302 | ).to.equal(ZERO_AMOUNT); 303 | 304 | // =================== Create Order =================== 305 | expect( 306 | await gateway 307 | .connect(this.aggregator) 308 | .settle(orderId, orderId, this.liquidityProvider.address, MAX_BPS) 309 | ) 310 | .to.emit(gateway, Events.Gateway.OrderSettled) 311 | .withArgs(orderId, orderId, this.liquidityProvider.address, MAX_BPS); 312 | 313 | expect(await mockUSDT.balanceOf(this.liquidityProvider.address)).to.eq( 314 | this.liquidityProviderAmount 315 | ); 316 | expect(await mockUSDT.balanceOf(this.treasuryAddress.address)).to.eq( 317 | this.protocolFee 318 | ); 319 | 320 | expect(await mockUSDT.balanceOf(gateway.address)).to.eq(ZERO_AMOUNT); 321 | }); 322 | }); 323 | -------------------------------------------------------------------------------- /test/utils/utils.manager.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require("hardhat"); 2 | const { BigNumber } = require("@ethersproject/bignumber"); 3 | 4 | const ZERO_AMOUNT = BigNumber.from("0"); 5 | const ZERO_ADDRESS = ethers.constants.AddressZero; 6 | const MAX_BPS = BigNumber.from("100000"); 7 | const FEE_BPS = BigNumber.from("100"); 8 | 9 | const Errors = { 10 | Ownable: { 11 | onlyOwner: "Ownable: caller is not the owner", 12 | }, 13 | 14 | Gateway: { 15 | OnlyAggregator: "OnlyAggregator", 16 | TokenNotSupported: "TokenNotSupported", 17 | AmountIsZero: "AmountIsZero", 18 | ThrowZeroAddress: "ThrowZeroAddress", 19 | InvalidSigner: "InvalidSigner", 20 | Unsupported: "Unsupported", 21 | OrderFulfilled: "OrderFulfilled", 22 | OrderRefunded: "OrderRefunded", 23 | UnableToProcessRewards: "UnableToProcessRewards", 24 | Allowance: "ERC20: insufficient allowance", 25 | }, 26 | }; 27 | 28 | const Events = { 29 | Gateway: { 30 | OrderCreated: "OrderCreated", 31 | OrderSettled: "OrderSettled", 32 | OrderRefunded: "OrderRefunded", 33 | SettingManagerBool: "SettingManagerBool", 34 | ProtocolFeeUpdated: "ProtocolFeeUpdated", 35 | ProtocolAddressUpdated: "ProtocolAddressUpdated", 36 | }, 37 | }; 38 | 39 | async function deployContract(name, args = [], value = 0) { 40 | const Contract = await ethers.getContractFactory(name); 41 | let instance; 42 | 43 | if (value > 0) instance = await Contract.deploy(...args, { value }); 44 | else instance = await Contract.deploy(...args); 45 | 46 | return instance; 47 | } 48 | 49 | async function getSupportedInstitutions() { 50 | const currency = ethers.utils.formatBytes32String("NGN"); 51 | 52 | const accessBank = { 53 | code: ethers.utils.formatBytes32String("ABNGNGLA"), 54 | name: ethers.utils.formatBytes32String("ACCESS BANK"), 55 | }; 56 | 57 | const diamondBank = { 58 | code: ethers.utils.formatBytes32String("DBLNNGLA"), 59 | name: ethers.utils.formatBytes32String("DIAMOND BANK"), 60 | }; 61 | 62 | return { 63 | currency, 64 | accessBank, 65 | diamondBank, 66 | }; 67 | } 68 | 69 | async function mockMintDeposit(gateway, account, usdc, amount) { 70 | await usdc.connect(account).mint(amount); 71 | await usdc.connect(account).approve(gateway.address, amount); 72 | } 73 | 74 | module.exports = { 75 | ZERO_AMOUNT, 76 | ZERO_ADDRESS, 77 | MAX_BPS, 78 | FEE_BPS, 79 | Errors, 80 | Events, 81 | deployContract, 82 | mockMintDeposit, 83 | getSupportedInstitutions, 84 | }; 85 | -------------------------------------------------------------------------------- /tronbox-config.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; 2 | -------------------------------------------------------------------------------- /tronbox.js: -------------------------------------------------------------------------------- 1 | const dotenv = require ("dotenv"); 2 | dotenv.config(); 3 | 4 | module.exports = { 5 | networks: { 6 | mainnet: { 7 | privateKey: process.env.DEPLOYER_PRIVATE_KEY_TRON, 8 | userFeePercentage: 100, 9 | feeLimit: 2e9, 10 | fullHost: "https://api.trongrid.io", 11 | network_id: "1", 12 | }, 13 | shasta: { 14 | privateKey: process.env.DEPLOYER_PRIVATE_KEY_TRON, 15 | userFeePercentage: 100, 16 | feeLimit: 2e9, 17 | fullHost: "https://api.shasta.trongrid.io", 18 | network_id: "2", 19 | }, 20 | // nile: { 21 | // privateKey: process.env.PRIVATE_KEY_NILE, 22 | // userFeePercentage: 100, 23 | // feeLimit: 1e9, 24 | // fullHost: "https://nile.trongrid.io", 25 | // network_id: "3", 26 | // }, 27 | compilers: { 28 | solc: { 29 | version: "0.8.18", 30 | }, 31 | }, 32 | }, 33 | // solc compiler optimize 34 | solc: {}, 35 | }; 36 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "module": "commonjs", 5 | "esModuleInterop": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "skipLibCheck": true, 9 | "resolveJsonModule": true 10 | }, 11 | "exclude": ["dist", "node_modules"], 12 | "include": ["./test", "./src", "./scripts", "./tasks"], 13 | "files": ["./hardhat.config.ts"] 14 | } 15 | --------------------------------------------------------------------------------